ns_gige.cc revision 1036
17322Sgblack@eecs.umich.edu/* 27322Sgblack@eecs.umich.edu * Copyright (c) 2004 The Regents of The University of Michigan 37322Sgblack@eecs.umich.edu * All rights reserved. 47322Sgblack@eecs.umich.edu * 57322Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67322Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77322Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87322Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97322Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107322Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117322Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127322Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137322Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147322Sgblack@eecs.umich.edu * this software without specific prior written permission. 157322Sgblack@eecs.umich.edu * 167322Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177322Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187322Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197322Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207322Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217322Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227322Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237322Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247322Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257322Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267322Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277322Sgblack@eecs.umich.edu */ 287322Sgblack@eecs.umich.edu 297322Sgblack@eecs.umich.edu/* @file 307322Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor 317322Sgblack@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 327322Sgblack@eecs.umich.edu */ 337322Sgblack@eecs.umich.edu#include <cstdio> 347322Sgblack@eecs.umich.edu#include <deque> 357322Sgblack@eecs.umich.edu#include <string> 367322Sgblack@eecs.umich.edu 377322Sgblack@eecs.umich.edu#include "base/inet.hh" 387322Sgblack@eecs.umich.edu#include "cpu/exec_context.hh" 397322Sgblack@eecs.umich.edu#include "cpu/intr_control.hh" 407376Sgblack@eecs.umich.edu#include "dev/dma.hh" 417376Sgblack@eecs.umich.edu#include "dev/etherlink.hh" 427376Sgblack@eecs.umich.edu#include "dev/ns_gige.hh" 437376Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh" 447376Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh" 457376Sgblack@eecs.umich.edu#include "mem/bus/bus.hh" 467376Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh" 477376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh" 487376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh" 497376Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh" 507376Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh" 517376Sgblack@eecs.umich.edu#include "sim/builder.hh" 527376Sgblack@eecs.umich.edu#include "sim/debug.hh" 537376Sgblack@eecs.umich.edu#include "sim/host.hh" 547376Sgblack@eecs.umich.edu#include "sim/sim_stats.hh" 557376Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh" 567376Sgblack@eecs.umich.edu 577376Sgblack@eecs.umich.educonst char *NsRxStateStrings[] = 587376Sgblack@eecs.umich.edu{ 597376Sgblack@eecs.umich.edu "rxIdle", 607376Sgblack@eecs.umich.edu "rxDescRefr", 617376Sgblack@eecs.umich.edu "rxDescRead", 627376Sgblack@eecs.umich.edu "rxFifoBlock", 637376Sgblack@eecs.umich.edu "rxFragWrite", 647376Sgblack@eecs.umich.edu "rxDescWrite", 657376Sgblack@eecs.umich.edu "rxAdvance" 667376Sgblack@eecs.umich.edu}; 677376Sgblack@eecs.umich.edu 687376Sgblack@eecs.umich.educonst char *NsTxStateStrings[] = 697376Sgblack@eecs.umich.edu{ 707376Sgblack@eecs.umich.edu "txIdle", 717376Sgblack@eecs.umich.edu "txDescRefr", 727376Sgblack@eecs.umich.edu "txDescRead", 737376Sgblack@eecs.umich.edu "txFifoBlock", 747376Sgblack@eecs.umich.edu "txFragRead", 757376Sgblack@eecs.umich.edu "txDescWrite", 767376Sgblack@eecs.umich.edu "txAdvance" 777376Sgblack@eecs.umich.edu}; 787376Sgblack@eecs.umich.edu 797376Sgblack@eecs.umich.educonst char *NsDmaState[] = 807376Sgblack@eecs.umich.edu{ 817376Sgblack@eecs.umich.edu "dmaIdle", 827376Sgblack@eecs.umich.edu "dmaReading", 837376Sgblack@eecs.umich.edu "dmaWriting", 847376Sgblack@eecs.umich.edu "dmaReadWaiting", 857376Sgblack@eecs.umich.edu "dmaWriteWaiting" 867376Sgblack@eecs.umich.edu}; 877376Sgblack@eecs.umich.edu 887376Sgblack@eecs.umich.eduusing namespace std; 897376Sgblack@eecs.umich.edu 907376Sgblack@eecs.umich.edu// helper function declarations 917376Sgblack@eecs.umich.edu// These functions reverse Endianness so we can evaluate network data 927376Sgblack@eecs.umich.edu// correctly 937376Sgblack@eecs.umich.eduuint16_t reverseEnd16(uint16_t); 947376Sgblack@eecs.umich.eduuint32_t reverseEnd32(uint32_t); 957376Sgblack@eecs.umich.edu 967376Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 977376Sgblack@eecs.umich.edu// 987376Sgblack@eecs.umich.edu// NSGigE PCI Device 997376Sgblack@eecs.umich.edu// 1007376Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 1017376Sgblack@eecs.umich.edu PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 1027376Sgblack@eecs.umich.edu MemoryController *mmu, HierParams *hier, Bus *header_bus, 1037376Sgblack@eecs.umich.edu Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 1047376Sgblack@eecs.umich.edu bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 1057376Sgblack@eecs.umich.edu Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 1067376Sgblack@eecs.umich.edu PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1077376Sgblack@eecs.umich.edu uint32_t func, bool rx_filter, const int eaddr[6], 1087376Sgblack@eecs.umich.edu uint32_t tx_fifo_size, uint32_t rx_fifo_size) 1097376Sgblack@eecs.umich.edu : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 1107376Sgblack@eecs.umich.edu maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), 1117376Sgblack@eecs.umich.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1127376Sgblack@eecs.umich.edu txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false), 1137376Sgblack@eecs.umich.edu CTDD(false), txFifoAvail(tx_fifo_size), 1147376Sgblack@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1157376Sgblack@eecs.umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0), 1167376Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1177376Sgblack@eecs.umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1187376Sgblack@eecs.umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1197376Sgblack@eecs.umich.edu dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1207376Sgblack@eecs.umich.edu txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1217376Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1227376Sgblack@eecs.umich.edu acceptMulticast(false), acceptUnicast(false), 1237376Sgblack@eecs.umich.edu acceptPerfect(false), acceptArp(false), 1247376Sgblack@eecs.umich.edu physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 1257376Sgblack@eecs.umich.edu intrEvent(0), interface(0) 1267376Sgblack@eecs.umich.edu{ 1277376Sgblack@eecs.umich.edu tsunami->ethernet = this; 1287376Sgblack@eecs.umich.edu 1297376Sgblack@eecs.umich.edu if (header_bus) { 1307376Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, header_bus, this, 1317376Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1327376Sgblack@eecs.umich.edu 1337376Sgblack@eecs.umich.edu pioLatency = pio_latency * header_bus->clockRatio; 1347376Sgblack@eecs.umich.edu 1357376Sgblack@eecs.umich.edu if (payload_bus) 1367376Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1377376Sgblack@eecs.umich.edu header_bus, payload_bus, 1); 1387376Sgblack@eecs.umich.edu else 1397376Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1407376Sgblack@eecs.umich.edu header_bus, header_bus, 1); 1417376Sgblack@eecs.umich.edu } else if (payload_bus) { 1427376Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, payload_bus, this, 1437376Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1447376Sgblack@eecs.umich.edu 1457376Sgblack@eecs.umich.edu pioLatency = pio_latency * payload_bus->clockRatio; 1467376Sgblack@eecs.umich.edu 1477376Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 1487376Sgblack@eecs.umich.edu payload_bus, 1); 1497376Sgblack@eecs.umich.edu } 1507376Sgblack@eecs.umich.edu 1517376Sgblack@eecs.umich.edu 1527376Sgblack@eecs.umich.edu intrDelay = US2Ticks(intr_delay); 1537376Sgblack@eecs.umich.edu dmaReadDelay = dma_read_delay; 1547376Sgblack@eecs.umich.edu dmaWriteDelay = dma_write_delay; 1557376Sgblack@eecs.umich.edu dmaReadFactor = dma_read_factor; 1567376Sgblack@eecs.umich.edu dmaWriteFactor = dma_write_factor; 1577376Sgblack@eecs.umich.edu 1587376Sgblack@eecs.umich.edu regsReset(); 1597376Sgblack@eecs.umich.edu rom.perfectMatch[0] = eaddr[0]; 1607376Sgblack@eecs.umich.edu rom.perfectMatch[1] = eaddr[1]; 1617376Sgblack@eecs.umich.edu rom.perfectMatch[2] = eaddr[2]; 1627376Sgblack@eecs.umich.edu rom.perfectMatch[3] = eaddr[3]; 1637376Sgblack@eecs.umich.edu rom.perfectMatch[4] = eaddr[4]; 1647376Sgblack@eecs.umich.edu rom.perfectMatch[5] = eaddr[5]; 1657376Sgblack@eecs.umich.edu} 1667376Sgblack@eecs.umich.edu 1677376Sgblack@eecs.umich.eduNSGigE::~NSGigE() 1687376Sgblack@eecs.umich.edu{} 1697376Sgblack@eecs.umich.edu 1707376Sgblack@eecs.umich.eduvoid 1717376Sgblack@eecs.umich.eduNSGigE::regStats() 1727376Sgblack@eecs.umich.edu{ 1737376Sgblack@eecs.umich.edu txBytes 1747376Sgblack@eecs.umich.edu .name(name() + ".txBytes") 1757376Sgblack@eecs.umich.edu .desc("Bytes Transmitted") 1767376Sgblack@eecs.umich.edu .prereq(txBytes) 1777376Sgblack@eecs.umich.edu ; 1787376Sgblack@eecs.umich.edu 1797376Sgblack@eecs.umich.edu rxBytes 1807376Sgblack@eecs.umich.edu .name(name() + ".rxBytes") 1817376Sgblack@eecs.umich.edu .desc("Bytes Received") 1827376Sgblack@eecs.umich.edu .prereq(rxBytes) 1837376Sgblack@eecs.umich.edu ; 1847376Sgblack@eecs.umich.edu 1857376Sgblack@eecs.umich.edu txPackets 1867376Sgblack@eecs.umich.edu .name(name() + ".txPackets") 1877376Sgblack@eecs.umich.edu .desc("Number of Packets Transmitted") 1887322Sgblack@eecs.umich.edu .prereq(txBytes) 1897322Sgblack@eecs.umich.edu ; 1907322Sgblack@eecs.umich.edu 1917322Sgblack@eecs.umich.edu rxPackets 1927322Sgblack@eecs.umich.edu .name(name() + ".rxPackets") 1937322Sgblack@eecs.umich.edu .desc("Number of Packets Received") 1947375Sgblack@eecs.umich.edu .prereq(rxBytes) 1957322Sgblack@eecs.umich.edu ; 1967322Sgblack@eecs.umich.edu 1977375Sgblack@eecs.umich.edu txIPChecksums 1987375Sgblack@eecs.umich.edu .name(name() + ".txIPChecksums") 1997322Sgblack@eecs.umich.edu .desc("Number of tx IP Checksums done by device") 2007324Sgblack@eecs.umich.edu .precision(0) 2017375Sgblack@eecs.umich.edu .prereq(txBytes) 2027324Sgblack@eecs.umich.edu ; 2037324Sgblack@eecs.umich.edu 2047375Sgblack@eecs.umich.edu rxIPChecksums 2057375Sgblack@eecs.umich.edu .name(name() + ".rxIPChecksums") 2067324Sgblack@eecs.umich.edu .desc("Number of rx IP Checksums done by device") 2077333Sgblack@eecs.umich.edu .precision(0) 2087333Sgblack@eecs.umich.edu .prereq(rxBytes) 2097333Sgblack@eecs.umich.edu ; 2107333Sgblack@eecs.umich.edu 2117375Sgblack@eecs.umich.edu txTCPChecksums 2127333Sgblack@eecs.umich.edu .name(name() + ".txTCPChecksums") 2137333Sgblack@eecs.umich.edu .desc("Number of tx TCP Checksums done by device") 2147375Sgblack@eecs.umich.edu .precision(0) 2157375Sgblack@eecs.umich.edu .prereq(txBytes) 2167333Sgblack@eecs.umich.edu ; 2177333Sgblack@eecs.umich.edu 2187333Sgblack@eecs.umich.edu rxTCPChecksums 2197333Sgblack@eecs.umich.edu .name(name() + ".rxTCPChecksums") 2207333Sgblack@eecs.umich.edu .desc("Number of rx TCP Checksums done by device") 2217333Sgblack@eecs.umich.edu .precision(0) 2227375Sgblack@eecs.umich.edu .prereq(rxBytes) 2237333Sgblack@eecs.umich.edu ; 2247333Sgblack@eecs.umich.edu 2257375Sgblack@eecs.umich.edu descDmaReads 2267375Sgblack@eecs.umich.edu .name(name() + ".descDMAReads") 2277333Sgblack@eecs.umich.edu .desc("Number of descriptors the device read w/ DMA") 2287333Sgblack@eecs.umich.edu .precision(0) 2297333Sgblack@eecs.umich.edu ; 2307333Sgblack@eecs.umich.edu 2317333Sgblack@eecs.umich.edu descDmaWrites 2327333Sgblack@eecs.umich.edu .name(name() + ".descDMAWrites") 2337333Sgblack@eecs.umich.edu .desc("Number of descriptors the device wrote w/ DMA") 2347333Sgblack@eecs.umich.edu .precision(0) 2357375Sgblack@eecs.umich.edu ; 2367333Sgblack@eecs.umich.edu 2377333Sgblack@eecs.umich.edu descDmaRdBytes 2387375Sgblack@eecs.umich.edu .name(name() + ".descDmaReadBytes") 2397375Sgblack@eecs.umich.edu .desc("number of descriptor bytes read w/ DMA") 2407333Sgblack@eecs.umich.edu .precision(0) 2417333Sgblack@eecs.umich.edu ; 2427333Sgblack@eecs.umich.edu 2437333Sgblack@eecs.umich.edu descDmaWrBytes 2447333Sgblack@eecs.umich.edu .name(name() + ".descDmaWriteBytes") 2457375Sgblack@eecs.umich.edu .desc("number of descriptor bytes write w/ DMA") 2467333Sgblack@eecs.umich.edu .precision(0) 2477333Sgblack@eecs.umich.edu ; 2487375Sgblack@eecs.umich.edu 2497375Sgblack@eecs.umich.edu 2507333Sgblack@eecs.umich.edu txBandwidth 2517333Sgblack@eecs.umich.edu .name(name() + ".txBandwidth") 2527333Sgblack@eecs.umich.edu .desc("Transmit Bandwidth (bits/s)") 2537333Sgblack@eecs.umich.edu .precision(0) 2547333Sgblack@eecs.umich.edu .prereq(txBytes) 2557333Sgblack@eecs.umich.edu ; 2567375Sgblack@eecs.umich.edu 2577333Sgblack@eecs.umich.edu rxBandwidth 2587333Sgblack@eecs.umich.edu .name(name() + ".rxBandwidth") 2597375Sgblack@eecs.umich.edu .desc("Receive Bandwidth (bits/s)") 2607375Sgblack@eecs.umich.edu .precision(0) 2617333Sgblack@eecs.umich.edu .prereq(rxBytes) 2627333Sgblack@eecs.umich.edu ; 2637333Sgblack@eecs.umich.edu 2647333Sgblack@eecs.umich.edu txPacketRate 2657333Sgblack@eecs.umich.edu .name(name() + ".txPPS") 2667333Sgblack@eecs.umich.edu .desc("Packet Tranmission Rate (packets/s)") 2677333Sgblack@eecs.umich.edu .precision(0) 2687333Sgblack@eecs.umich.edu .prereq(txBytes) 2697375Sgblack@eecs.umich.edu ; 2707333Sgblack@eecs.umich.edu 2717333Sgblack@eecs.umich.edu rxPacketRate 2727375Sgblack@eecs.umich.edu .name(name() + ".rxPPS") 2737375Sgblack@eecs.umich.edu .desc("Packet Reception Rate (packets/s)") 2747333Sgblack@eecs.umich.edu .precision(0) 2757333Sgblack@eecs.umich.edu .prereq(rxBytes) 2767333Sgblack@eecs.umich.edu ; 2777333Sgblack@eecs.umich.edu 2787333Sgblack@eecs.umich.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2797375Sgblack@eecs.umich.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2807333Sgblack@eecs.umich.edu txPacketRate = txPackets / simSeconds; 2817333Sgblack@eecs.umich.edu rxPacketRate = rxPackets / simSeconds; 2827375Sgblack@eecs.umich.edu} 2837375Sgblack@eecs.umich.edu 2847333Sgblack@eecs.umich.edu/** 2857333Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers 2867333Sgblack@eecs.umich.edu */ 2877333Sgblack@eecs.umich.eduvoid 2887333Sgblack@eecs.umich.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2897375Sgblack@eecs.umich.edu{ 2907333Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 2917333Sgblack@eecs.umich.edu PciDev::ReadConfig(offset, size, data); 2927375Sgblack@eecs.umich.edu else 2937375Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 2947333Sgblack@eecs.umich.edu} 2957333Sgblack@eecs.umich.edu 2967333Sgblack@eecs.umich.edu/** 2977333Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 2987333Sgblack@eecs.umich.edu */ 2997375Sgblack@eecs.umich.eduvoid 3007333Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 3017333Sgblack@eecs.umich.edu{ 3027375Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 3037375Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 3047333Sgblack@eecs.umich.edu else 3057333Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 3067333Sgblack@eecs.umich.edu 3077333Sgblack@eecs.umich.edu // Need to catch writes to BARs to update the PIO interface 3087333Sgblack@eecs.umich.edu switch (offset) { 3097375Sgblack@eecs.umich.edu // seems to work fine without all these PCI settings, but i 3107333Sgblack@eecs.umich.edu // put in the IO to double check, an assertion will fail if we 3117333Sgblack@eecs.umich.edu // need to properly implement it 3127375Sgblack@eecs.umich.edu case PCI_COMMAND: 3137375Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 3147333Sgblack@eecs.umich.edu ioEnable = true; 3157333Sgblack@eecs.umich.edu else 3167333Sgblack@eecs.umich.edu ioEnable = false; 3177333Sgblack@eecs.umich.edu 3187333Sgblack@eecs.umich.edu#if 0 3197375Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_BME) { 3207333Sgblack@eecs.umich.edu bmEnabled = true; 3217333Sgblack@eecs.umich.edu } 3227375Sgblack@eecs.umich.edu else { 3237375Sgblack@eecs.umich.edu bmEnabled = false; 3247333Sgblack@eecs.umich.edu } 3257333Sgblack@eecs.umich.edu 3267333Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_MSE) { 3277333Sgblack@eecs.umich.edu memEnable = true; 3287333Sgblack@eecs.umich.edu } 3297375Sgblack@eecs.umich.edu else { 3307333Sgblack@eecs.umich.edu memEnable = false; 3317333Sgblack@eecs.umich.edu } 3327375Sgblack@eecs.umich.edu#endif 3337375Sgblack@eecs.umich.edu break; 3347333Sgblack@eecs.umich.edu 3357333Sgblack@eecs.umich.edu case PCI0_BASE_ADDR0: 3367333Sgblack@eecs.umich.edu if (BARAddrs[0] != 0) { 3377333Sgblack@eecs.umich.edu if (pioInterface) 3387333Sgblack@eecs.umich.edu pioInterface->addAddrRange(BARAddrs[0], 3397375Sgblack@eecs.umich.edu BARAddrs[0] + BARSize[0] - 1); 3407333Sgblack@eecs.umich.edu 3417333Sgblack@eecs.umich.edu BARAddrs[0] &= PA_UNCACHED_MASK; 3427375Sgblack@eecs.umich.edu } 3437375Sgblack@eecs.umich.edu break; 3447333Sgblack@eecs.umich.edu case PCI0_BASE_ADDR1: 3457333Sgblack@eecs.umich.edu if (BARAddrs[1] != 0) { 3467333Sgblack@eecs.umich.edu if (pioInterface) 3477333Sgblack@eecs.umich.edu pioInterface->addAddrRange(BARAddrs[1], 3487333Sgblack@eecs.umich.edu BARAddrs[1] + BARSize[1] - 1); 3497375Sgblack@eecs.umich.edu 3507333Sgblack@eecs.umich.edu BARAddrs[1] &= PA_UNCACHED_MASK; 3517333Sgblack@eecs.umich.edu } 3527375Sgblack@eecs.umich.edu break; 3537375Sgblack@eecs.umich.edu } 3547333Sgblack@eecs.umich.edu} 3557333Sgblack@eecs.umich.edu 3567333Sgblack@eecs.umich.edu/** 3577333Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 3587333Sgblack@eecs.umich.edu * spec sheet 3597333Sgblack@eecs.umich.edu */ 3607375Sgblack@eecs.umich.eduFault 3617333Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3627333Sgblack@eecs.umich.edu{ 3637375Sgblack@eecs.umich.edu assert(ioEnable); 3647375Sgblack@eecs.umich.edu 3657333Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 3667333Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 3677333Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3687333Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 3697333Sgblack@eecs.umich.edu 3707333Sgblack@eecs.umich.edu 3717375Sgblack@eecs.umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 3727333Sgblack@eecs.umich.edu // the spec sheet for details 3737333Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 3747375Sgblack@eecs.umich.edu panic("Accessing reserved register"); 3757375Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 3767333Sgblack@eecs.umich.edu ReadConfig(daddr & 0xff, req->size, data); 3777381Sgblack@eecs.umich.edu return No_Fault; 3787381Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 3797381Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 3807381Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 3817381Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 3827381Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *) data; 3837381Sgblack@eecs.umich.edu reg = 0; 3847364Sgblack@eecs.umich.edu return No_Fault; 3857364Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 3867382Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 3877378Sgblack@eecs.umich.edu 3887381Sgblack@eecs.umich.edu switch (req->size) { 3897386Sgblack@eecs.umich.edu case sizeof(uint32_t): 3907381Sgblack@eecs.umich.edu { 3917378Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *)data; 3927364Sgblack@eecs.umich.edu 3937364Sgblack@eecs.umich.edu switch (daddr) { 3947364Sgblack@eecs.umich.edu case CR: 3957364Sgblack@eecs.umich.edu reg = regs.command; 3967375Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 3977364Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3987364Sgblack@eecs.umich.edu break; 3997375Sgblack@eecs.umich.edu 4007375Sgblack@eecs.umich.edu case CFG: 4017364Sgblack@eecs.umich.edu reg = regs.config; 4027364Sgblack@eecs.umich.edu break; 4037364Sgblack@eecs.umich.edu 4047364Sgblack@eecs.umich.edu case MEAR: 4057364Sgblack@eecs.umich.edu reg = regs.mear; 4067364Sgblack@eecs.umich.edu break; 4077382Sgblack@eecs.umich.edu 4087378Sgblack@eecs.umich.edu case PTSCR: 4097381Sgblack@eecs.umich.edu reg = regs.ptscr; 4107386Sgblack@eecs.umich.edu break; 4117381Sgblack@eecs.umich.edu 4127378Sgblack@eecs.umich.edu case ISR: 4137364Sgblack@eecs.umich.edu reg = regs.isr; 4147364Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 4157364Sgblack@eecs.umich.edu break; 4167364Sgblack@eecs.umich.edu 4177364Sgblack@eecs.umich.edu case IMR: 4187364Sgblack@eecs.umich.edu reg = regs.imr; 4197364Sgblack@eecs.umich.edu break; 4207375Sgblack@eecs.umich.edu 4217364Sgblack@eecs.umich.edu case IER: 4227364Sgblack@eecs.umich.edu reg = regs.ier; 4237375Sgblack@eecs.umich.edu break; 4247375Sgblack@eecs.umich.edu 4257364Sgblack@eecs.umich.edu case IHR: 4267365Sgblack@eecs.umich.edu reg = regs.ihr; 4277365Sgblack@eecs.umich.edu break; 4287365Sgblack@eecs.umich.edu 4297365Sgblack@eecs.umich.edu case TXDP: 4307375Sgblack@eecs.umich.edu reg = regs.txdp; 4317365Sgblack@eecs.umich.edu break; 4327365Sgblack@eecs.umich.edu 4337375Sgblack@eecs.umich.edu case TXDP_HI: 4347375Sgblack@eecs.umich.edu reg = regs.txdp_hi; 4357365Sgblack@eecs.umich.edu break; 4367365Sgblack@eecs.umich.edu 4377365Sgblack@eecs.umich.edu case TXCFG: 4387365Sgblack@eecs.umich.edu reg = regs.txcfg; 4397365Sgblack@eecs.umich.edu break; 4407365Sgblack@eecs.umich.edu 4417365Sgblack@eecs.umich.edu case GPIOR: 4427365Sgblack@eecs.umich.edu reg = regs.gpior; 4437365Sgblack@eecs.umich.edu break; 4447375Sgblack@eecs.umich.edu 4457365Sgblack@eecs.umich.edu case RXDP: 4467365Sgblack@eecs.umich.edu reg = regs.rxdp; 4477375Sgblack@eecs.umich.edu break; 4487375Sgblack@eecs.umich.edu 4497365Sgblack@eecs.umich.edu case RXDP_HI: 4507366Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 4517366Sgblack@eecs.umich.edu break; 4527366Sgblack@eecs.umich.edu 4537366Sgblack@eecs.umich.edu case RXCFG: 4547375Sgblack@eecs.umich.edu reg = regs.rxcfg; 4557366Sgblack@eecs.umich.edu break; 4567366Sgblack@eecs.umich.edu 4577375Sgblack@eecs.umich.edu case PQCR: 4587375Sgblack@eecs.umich.edu reg = regs.pqcr; 4597366Sgblack@eecs.umich.edu break; 4607366Sgblack@eecs.umich.edu 4617366Sgblack@eecs.umich.edu case WCSR: 4627366Sgblack@eecs.umich.edu reg = regs.wcsr; 4637366Sgblack@eecs.umich.edu break; 4647366Sgblack@eecs.umich.edu 4657366Sgblack@eecs.umich.edu case PCR: 4667366Sgblack@eecs.umich.edu reg = regs.pcr; 4677366Sgblack@eecs.umich.edu break; 4687375Sgblack@eecs.umich.edu 4697366Sgblack@eecs.umich.edu // see the spec sheet for how RFCR and RFDR work 4707366Sgblack@eecs.umich.edu // basically, you write to RFCR to tell the machine 4717375Sgblack@eecs.umich.edu // what you want to do next, then you act upon RFDR, 4727375Sgblack@eecs.umich.edu // and the device will be prepared b/c of what you 4737366Sgblack@eecs.umich.edu // wrote to RFCR 4747367Sgblack@eecs.umich.edu case RFCR: 4757367Sgblack@eecs.umich.edu reg = regs.rfcr; 4767382Sgblack@eecs.umich.edu break; 4777378Sgblack@eecs.umich.edu 4787381Sgblack@eecs.umich.edu case RFDR: 4797385Sgblack@eecs.umich.edu switch (regs.rfcr & RFCR_RFADDR) { 4807381Sgblack@eecs.umich.edu case 0x000: 4817378Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 4827367Sgblack@eecs.umich.edu reg = reg << 8; 4837375Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 4847367Sgblack@eecs.umich.edu break; 4857367Sgblack@eecs.umich.edu case 0x002: 4867375Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 4877375Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 4887367Sgblack@eecs.umich.edu break; 4897367Sgblack@eecs.umich.edu case 0x004: 4907367Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 4917367Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 4927367Sgblack@eecs.umich.edu break; 4937367Sgblack@eecs.umich.edu default: 4947385Sgblack@eecs.umich.edu panic("reading RFDR for something other than PMATCH!\n"); 4957385Sgblack@eecs.umich.edu // didn't implement other RFDR functionality b/c 4967382Sgblack@eecs.umich.edu // driver didn't use it 4977378Sgblack@eecs.umich.edu } 4987381Sgblack@eecs.umich.edu break; 4997385Sgblack@eecs.umich.edu 5007385Sgblack@eecs.umich.edu case SRR: 5017381Sgblack@eecs.umich.edu reg = regs.srr; 5027378Sgblack@eecs.umich.edu break; 5037367Sgblack@eecs.umich.edu 5047367Sgblack@eecs.umich.edu case MIBC: 5057367Sgblack@eecs.umich.edu reg = regs.mibc; 5067375Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 5077367Sgblack@eecs.umich.edu break; 5087367Sgblack@eecs.umich.edu 5097375Sgblack@eecs.umich.edu case VRCR: 5107375Sgblack@eecs.umich.edu reg = regs.vrcr; 5117367Sgblack@eecs.umich.edu break; 5127368Sgblack@eecs.umich.edu 5137368Sgblack@eecs.umich.edu case VTCR: 5147382Sgblack@eecs.umich.edu reg = regs.vtcr; 5157378Sgblack@eecs.umich.edu break; 5167381Sgblack@eecs.umich.edu 5177385Sgblack@eecs.umich.edu case VDR: 5187381Sgblack@eecs.umich.edu reg = regs.vdr; 5197378Sgblack@eecs.umich.edu break; 5207368Sgblack@eecs.umich.edu 5217375Sgblack@eecs.umich.edu case CCSR: 5227368Sgblack@eecs.umich.edu reg = regs.ccsr; 5237368Sgblack@eecs.umich.edu break; 5247375Sgblack@eecs.umich.edu 5257375Sgblack@eecs.umich.edu case TBICR: 5267368Sgblack@eecs.umich.edu reg = regs.tbicr; 5277368Sgblack@eecs.umich.edu break; 5287368Sgblack@eecs.umich.edu 5297368Sgblack@eecs.umich.edu case TBISR: 5307368Sgblack@eecs.umich.edu reg = regs.tbisr; 5317368Sgblack@eecs.umich.edu break; 5327382Sgblack@eecs.umich.edu 5337378Sgblack@eecs.umich.edu case TANAR: 5347381Sgblack@eecs.umich.edu reg = regs.tanar; 5357385Sgblack@eecs.umich.edu break; 5367381Sgblack@eecs.umich.edu 5377378Sgblack@eecs.umich.edu case TANLPAR: 5387368Sgblack@eecs.umich.edu reg = regs.tanlpar; 5397368Sgblack@eecs.umich.edu break; 5407368Sgblack@eecs.umich.edu 5417375Sgblack@eecs.umich.edu case TANER: 5427368Sgblack@eecs.umich.edu reg = regs.taner; 5437368Sgblack@eecs.umich.edu break; 5447375Sgblack@eecs.umich.edu 5457375Sgblack@eecs.umich.edu case TESR: 5467368Sgblack@eecs.umich.edu reg = regs.tesr; 5477369Sgblack@eecs.umich.edu break; 5487369Sgblack@eecs.umich.edu 5497382Sgblack@eecs.umich.edu default: 5507378Sgblack@eecs.umich.edu panic("reading unimplemented register: addr=%#x", daddr); 5517381Sgblack@eecs.umich.edu } 5527385Sgblack@eecs.umich.edu 5537381Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 5547378Sgblack@eecs.umich.edu daddr, reg, reg); 5557369Sgblack@eecs.umich.edu } 5567375Sgblack@eecs.umich.edu break; 5577369Sgblack@eecs.umich.edu 5587369Sgblack@eecs.umich.edu default: 5597375Sgblack@eecs.umich.edu panic("accessing register with invalid size: addr=%#x, size=%d", 5607375Sgblack@eecs.umich.edu daddr, req->size); 5617369Sgblack@eecs.umich.edu } 5627369Sgblack@eecs.umich.edu 5637369Sgblack@eecs.umich.edu return No_Fault; 5647369Sgblack@eecs.umich.edu} 5657369Sgblack@eecs.umich.edu 5667369Sgblack@eecs.umich.eduFault 5677382Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data) 5687378Sgblack@eecs.umich.edu{ 5697381Sgblack@eecs.umich.edu assert(ioEnable); 5707385Sgblack@eecs.umich.edu 5717381Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 5727378Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5737369Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 5747369Sgblack@eecs.umich.edu 5757369Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 5767375Sgblack@eecs.umich.edu panic("Accessing reserved register"); 5777369Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 5787369Sgblack@eecs.umich.edu WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5797375Sgblack@eecs.umich.edu return No_Fault; 5807375Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 5817369Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 5827369Sgblack@eecs.umich.edu 5837369Sgblack@eecs.umich.edu if (req->size == sizeof(uint32_t)) { 5847382Sgblack@eecs.umich.edu uint32_t reg = *(uint32_t *)data; 5857378Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5867381Sgblack@eecs.umich.edu 5877369Sgblack@eecs.umich.edu switch (daddr) { 5887381Sgblack@eecs.umich.edu case CR: 5897378Sgblack@eecs.umich.edu regs.command = reg; 5907369Sgblack@eecs.umich.edu if (reg & CR_TXD) { 5917369Sgblack@eecs.umich.edu txEnable = false; 5927369Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 5937369Sgblack@eecs.umich.edu txEnable = true; 5947375Sgblack@eecs.umich.edu 5957369Sgblack@eecs.umich.edu // the kernel is enabling the transmit machine 5967369Sgblack@eecs.umich.edu if (txState == txIdle) 5977375Sgblack@eecs.umich.edu txKick(); 5987375Sgblack@eecs.umich.edu } 5997369Sgblack@eecs.umich.edu 6007369Sgblack@eecs.umich.edu if (reg & CR_RXD) { 6017369Sgblack@eecs.umich.edu rxEnable = false; 6027369Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 6037369Sgblack@eecs.umich.edu rxEnable = true; 6047382Sgblack@eecs.umich.edu 6057378Sgblack@eecs.umich.edu if (rxState == rxIdle) 6067381Sgblack@eecs.umich.edu rxKick(); 6077369Sgblack@eecs.umich.edu } 6087381Sgblack@eecs.umich.edu 6097378Sgblack@eecs.umich.edu if (reg & CR_TXR) 6107369Sgblack@eecs.umich.edu txReset(); 6117369Sgblack@eecs.umich.edu 6127369Sgblack@eecs.umich.edu if (reg & CR_RXR) 6137369Sgblack@eecs.umich.edu rxReset(); 6147369Sgblack@eecs.umich.edu 6157369Sgblack@eecs.umich.edu if (reg & CR_SWI) 6167375Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 6177369Sgblack@eecs.umich.edu 6187369Sgblack@eecs.umich.edu if (reg & CR_RST) { 6197375Sgblack@eecs.umich.edu txReset(); 6207375Sgblack@eecs.umich.edu rxReset(); 6217369Sgblack@eecs.umich.edu 6227381Sgblack@eecs.umich.edu regsReset(); 6237381Sgblack@eecs.umich.edu } 6247381Sgblack@eecs.umich.edu break; 6257381Sgblack@eecs.umich.edu 6267381Sgblack@eecs.umich.edu case CFG: 6277381Sgblack@eecs.umich.edu if (reg & CFG_LNKSTS || 6287381Sgblack@eecs.umich.edu reg & CFG_SPDSTS || 6297370Sgblack@eecs.umich.edu reg & CFG_DUPSTS || 6307370Sgblack@eecs.umich.edu reg & CFG_RESERVED || 6317382Sgblack@eecs.umich.edu reg & CFG_T64ADDR || 6327378Sgblack@eecs.umich.edu reg & CFG_PCI64_DET) 6337381Sgblack@eecs.umich.edu panic("writing to read-only or reserved CFG bits!\n"); 6347385Sgblack@eecs.umich.edu 6357370Sgblack@eecs.umich.edu regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | 6367370Sgblack@eecs.umich.edu CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET); 6377370Sgblack@eecs.umich.edu 6387382Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to 6397385Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of 6407381Sgblack@eecs.umich.edu// these, you may need to add functionality in. 6417378Sgblack@eecs.umich.edu#if 0 6427370Sgblack@eecs.umich.edu if (reg & CFG_TBI_EN) ; 6437375Sgblack@eecs.umich.edu if (reg & CFG_MODE_1000) ; 6447370Sgblack@eecs.umich.edu#endif 6457370Sgblack@eecs.umich.edu 6467375Sgblack@eecs.umich.edu if (reg & CFG_AUTO_1000) 6477375Sgblack@eecs.umich.edu panic("CFG_AUTO_1000 not implemented!\n"); 6487370Sgblack@eecs.umich.edu 6497370Sgblack@eecs.umich.edu#if 0 6507370Sgblack@eecs.umich.edu if (reg & CFG_PINT_DUPSTS || 6517370Sgblack@eecs.umich.edu reg & CFG_PINT_LNKSTS || 6527370Sgblack@eecs.umich.edu reg & CFG_PINT_SPDSTS) 6537370Sgblack@eecs.umich.edu ; 6547370Sgblack@eecs.umich.edu 6557382Sgblack@eecs.umich.edu if (reg & CFG_TMRTEST) ; 6567378Sgblack@eecs.umich.edu if (reg & CFG_MRM_DIS) ; 6577381Sgblack@eecs.umich.edu if (reg & CFG_MWI_DIS) ; 6587385Sgblack@eecs.umich.edu 6597370Sgblack@eecs.umich.edu if (reg & CFG_T64ADDR) 6607370Sgblack@eecs.umich.edu panic("CFG_T64ADDR is read only register!\n"); 6617370Sgblack@eecs.umich.edu 6627370Sgblack@eecs.umich.edu if (reg & CFG_PCI64_DET) 6637382Sgblack@eecs.umich.edu panic("CFG_PCI64_DET is read only register!\n"); 6647385Sgblack@eecs.umich.edu 6657381Sgblack@eecs.umich.edu if (reg & CFG_DATA64_EN) ; 6667378Sgblack@eecs.umich.edu if (reg & CFG_M64ADDR) ; 6677370Sgblack@eecs.umich.edu if (reg & CFG_PHY_RST) ; 6687370Sgblack@eecs.umich.edu if (reg & CFG_PHY_DIS) ; 6697370Sgblack@eecs.umich.edu#endif 6707375Sgblack@eecs.umich.edu 6717370Sgblack@eecs.umich.edu if (reg & CFG_EXTSTS_EN) 6727370Sgblack@eecs.umich.edu extstsEnable = true; 6737375Sgblack@eecs.umich.edu else 6747375Sgblack@eecs.umich.edu extstsEnable = false; 6757370Sgblack@eecs.umich.edu 6767370Sgblack@eecs.umich.edu#if 0 6777370Sgblack@eecs.umich.edu if (reg & CFG_REQALG) ; 6787382Sgblack@eecs.umich.edu if (reg & CFG_SB) ; 6797378Sgblack@eecs.umich.edu if (reg & CFG_POW) ; 6807381Sgblack@eecs.umich.edu if (reg & CFG_EXD) ; 6817385Sgblack@eecs.umich.edu if (reg & CFG_PESEL) ; 6827370Sgblack@eecs.umich.edu if (reg & CFG_BROM_DIS) ; 6837370Sgblack@eecs.umich.edu if (reg & CFG_EXT_125) ; 6847370Sgblack@eecs.umich.edu if (reg & CFG_BEM) ; 6857382Sgblack@eecs.umich.edu#endif 6867386Sgblack@eecs.umich.edu break; 6877381Sgblack@eecs.umich.edu 6887378Sgblack@eecs.umich.edu case MEAR: 6897370Sgblack@eecs.umich.edu regs.mear = reg; 6907375Sgblack@eecs.umich.edu // since phy is completely faked, MEAR_MD* don't matter 6917370Sgblack@eecs.umich.edu // and since the driver never uses MEAR_EE*, they don't 6927370Sgblack@eecs.umich.edu // matter 6937375Sgblack@eecs.umich.edu#if 0 6947375Sgblack@eecs.umich.edu if (reg & MEAR_EEDI) ; 6957370Sgblack@eecs.umich.edu if (reg & MEAR_EEDO) ; // this one is read only 6967370Sgblack@eecs.umich.edu if (reg & MEAR_EECLK) ; 6977370Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) ; 6987370Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 6997370Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 7007370Sgblack@eecs.umich.edu if (reg & MEAR_MDC) ; 7017370Sgblack@eecs.umich.edu#endif 7027382Sgblack@eecs.umich.edu break; 7037378Sgblack@eecs.umich.edu 7047381Sgblack@eecs.umich.edu case PTSCR: 7057385Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 7067370Sgblack@eecs.umich.edu // these control BISTs for various parts of chip - we 7077370Sgblack@eecs.umich.edu // don't care or do just fake that the BIST is done 7087370Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 7097370Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 7107386Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 7117382Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 7127381Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 7137378Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 7147370Sgblack@eecs.umich.edu break; 7157370Sgblack@eecs.umich.edu 7167370Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 7177375Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 7187370Sgblack@eecs.umich.edu 7197370Sgblack@eecs.umich.edu case IMR: 7207375Sgblack@eecs.umich.edu regs.imr = reg; 7217375Sgblack@eecs.umich.edu devIntrChangeMask(); 7227370Sgblack@eecs.umich.edu break; 7237371Sgblack@eecs.umich.edu 7247371Sgblack@eecs.umich.edu case IER: 7257382Sgblack@eecs.umich.edu regs.ier = reg; 7267378Sgblack@eecs.umich.edu break; 7277381Sgblack@eecs.umich.edu 7287385Sgblack@eecs.umich.edu case IHR: 7297371Sgblack@eecs.umich.edu regs.ihr = reg; 7307371Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 7317371Sgblack@eecs.umich.edu break; 7327382Sgblack@eecs.umich.edu 7337386Sgblack@eecs.umich.edu case TXDP: 7347381Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 7357378Sgblack@eecs.umich.edu assert(txState == txIdle); 7367371Sgblack@eecs.umich.edu CTDD = false; 7377375Sgblack@eecs.umich.edu break; 7387371Sgblack@eecs.umich.edu 7397371Sgblack@eecs.umich.edu case TXDP_HI: 7407375Sgblack@eecs.umich.edu regs.txdp_hi = reg; 7417375Sgblack@eecs.umich.edu break; 7427371Sgblack@eecs.umich.edu 7437371Sgblack@eecs.umich.edu case TXCFG: 7447371Sgblack@eecs.umich.edu regs.txcfg = reg; 7457371Sgblack@eecs.umich.edu#if 0 7467371Sgblack@eecs.umich.edu if (reg & TXCFG_CSI) ; 7477371Sgblack@eecs.umich.edu if (reg & TXCFG_HBI) ; 7487371Sgblack@eecs.umich.edu if (reg & TXCFG_MLB) ; 7497382Sgblack@eecs.umich.edu if (reg & TXCFG_ATP) ; 7507378Sgblack@eecs.umich.edu if (reg & TXCFG_ECRETRY) { 7517381Sgblack@eecs.umich.edu /* 7527385Sgblack@eecs.umich.edu * this could easily be implemented, but considering 7537371Sgblack@eecs.umich.edu * the network is just a fake pipe, wouldn't make 7547371Sgblack@eecs.umich.edu * sense to do this 7557371Sgblack@eecs.umich.edu */ 7567371Sgblack@eecs.umich.edu } 7577382Sgblack@eecs.umich.edu 7587386Sgblack@eecs.umich.edu if (reg & TXCFG_BRST_DIS) ; 7597381Sgblack@eecs.umich.edu#endif 7607378Sgblack@eecs.umich.edu 7617371Sgblack@eecs.umich.edu#if 0 7627371Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 7637371Sgblack@eecs.umich.edu if (reg & TXCFG_MXDMA) ; 7647375Sgblack@eecs.umich.edu#endif 7657371Sgblack@eecs.umich.edu 7667371Sgblack@eecs.umich.edu // also, we currently don't care about fill/drain 7677375Sgblack@eecs.umich.edu // thresholds though this may change in the future with 7687375Sgblack@eecs.umich.edu // more realistic networks or a driver which changes it 7697371Sgblack@eecs.umich.edu // according to feedback 7707371Sgblack@eecs.umich.edu 7717371Sgblack@eecs.umich.edu break; 7727382Sgblack@eecs.umich.edu 7737378Sgblack@eecs.umich.edu case GPIOR: 7747381Sgblack@eecs.umich.edu regs.gpior = reg; 7757385Sgblack@eecs.umich.edu /* these just control general purpose i/o pins, don't matter */ 7767371Sgblack@eecs.umich.edu break; 7777371Sgblack@eecs.umich.edu 7787371Sgblack@eecs.umich.edu case RXDP: 7797382Sgblack@eecs.umich.edu regs.rxdp = reg; 7807386Sgblack@eecs.umich.edu CRDD = false; 7817381Sgblack@eecs.umich.edu break; 7827378Sgblack@eecs.umich.edu 7837371Sgblack@eecs.umich.edu case RXDP_HI: 7847375Sgblack@eecs.umich.edu regs.rxdp_hi = reg; 7857371Sgblack@eecs.umich.edu break; 7867371Sgblack@eecs.umich.edu 7877375Sgblack@eecs.umich.edu case RXCFG: 7887375Sgblack@eecs.umich.edu regs.rxcfg = reg; 7897371Sgblack@eecs.umich.edu#if 0 7907371Sgblack@eecs.umich.edu if (reg & RXCFG_AEP) ; 7917371Sgblack@eecs.umich.edu if (reg & RXCFG_ARP) ; 7927371Sgblack@eecs.umich.edu if (reg & RXCFG_STRIPCRC) ; 7937371Sgblack@eecs.umich.edu if (reg & RXCFG_RX_RD) ; 7947371Sgblack@eecs.umich.edu if (reg & RXCFG_ALP) ; 7957371Sgblack@eecs.umich.edu if (reg & RXCFG_AIRL) ; 7967382Sgblack@eecs.umich.edu 7977378Sgblack@eecs.umich.edu /* we handle our own DMA, ignore what kernel says about it */ 7987381Sgblack@eecs.umich.edu if (reg & RXCFG_MXDMA) ; 7997385Sgblack@eecs.umich.edu 8007371Sgblack@eecs.umich.edu //also, we currently don't care about fill/drain thresholds 8017371Sgblack@eecs.umich.edu //though this may change in the future with more realistic 8027371Sgblack@eecs.umich.edu //networks or a driver which changes it according to feedback 8037371Sgblack@eecs.umich.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 8047382Sgblack@eecs.umich.edu#endif 8057386Sgblack@eecs.umich.edu break; 8067381Sgblack@eecs.umich.edu 8077378Sgblack@eecs.umich.edu case PQCR: 8087371Sgblack@eecs.umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 8097371Sgblack@eecs.umich.edu regs.pqcr = reg; 8107371Sgblack@eecs.umich.edu break; 8117375Sgblack@eecs.umich.edu 8127371Sgblack@eecs.umich.edu case WCSR: 8137371Sgblack@eecs.umich.edu /* not going to implement wake on LAN */ 8147375Sgblack@eecs.umich.edu regs.wcsr = reg; 8157375Sgblack@eecs.umich.edu break; 8167371Sgblack@eecs.umich.edu 8177371Sgblack@eecs.umich.edu case PCR: 8187371Sgblack@eecs.umich.edu /* not going to implement pause control */ 8197382Sgblack@eecs.umich.edu regs.pcr = reg; 8207378Sgblack@eecs.umich.edu break; 8217381Sgblack@eecs.umich.edu 8227385Sgblack@eecs.umich.edu case RFCR: 8237371Sgblack@eecs.umich.edu regs.rfcr = reg; 8247371Sgblack@eecs.umich.edu 8257371Sgblack@eecs.umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8267371Sgblack@eecs.umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8277381Sgblack@eecs.umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 8287378Sgblack@eecs.umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 8297371Sgblack@eecs.umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 8307375Sgblack@eecs.umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 8317371Sgblack@eecs.umich.edu 8327371Sgblack@eecs.umich.edu#if 0 8337375Sgblack@eecs.umich.edu if (reg & RFCR_APAT) 8347375Sgblack@eecs.umich.edu panic("RFCR_APAT not implemented!\n"); 8357371Sgblack@eecs.umich.edu#endif 8367371Sgblack@eecs.umich.edu 8377371Sgblack@eecs.umich.edu if (reg & RFCR_MHEN || reg & RFCR_UHEN) 8387371Sgblack@eecs.umich.edu panic("hash filtering not implemented!\n"); 8397371Sgblack@eecs.umich.edu 8407371Sgblack@eecs.umich.edu if (reg & RFCR_ULM) 8417371Sgblack@eecs.umich.edu panic("RFCR_ULM not implemented!\n"); 8427382Sgblack@eecs.umich.edu 8437378Sgblack@eecs.umich.edu break; 8447381Sgblack@eecs.umich.edu 8457385Sgblack@eecs.umich.edu case RFDR: 8467371Sgblack@eecs.umich.edu panic("the driver never writes to RFDR, something is wrong!\n"); 8477371Sgblack@eecs.umich.edu 8487371Sgblack@eecs.umich.edu case BRAR: 8497371Sgblack@eecs.umich.edu panic("the driver never uses BRAR, something is wrong!\n"); 8507371Sgblack@eecs.umich.edu 8517381Sgblack@eecs.umich.edu case BRDR: 8527378Sgblack@eecs.umich.edu panic("the driver never uses BRDR, something is wrong!\n"); 8537371Sgblack@eecs.umich.edu 8547371Sgblack@eecs.umich.edu case SRR: 8557371Sgblack@eecs.umich.edu panic("SRR is read only register!\n"); 8567375Sgblack@eecs.umich.edu 8577371Sgblack@eecs.umich.edu case MIBC: 8587371Sgblack@eecs.umich.edu panic("the driver never uses MIBC, something is wrong!\n"); 8597375Sgblack@eecs.umich.edu 8607375Sgblack@eecs.umich.edu case VRCR: 8617371Sgblack@eecs.umich.edu regs.vrcr = reg; 8627381Sgblack@eecs.umich.edu break; 8637381Sgblack@eecs.umich.edu 8647381Sgblack@eecs.umich.edu case VTCR: 8657381Sgblack@eecs.umich.edu regs.vtcr = reg; 8667381Sgblack@eecs.umich.edu break; 8677381Sgblack@eecs.umich.edu 8687381Sgblack@eecs.umich.edu case VDR: 8697373Sgblack@eecs.umich.edu panic("the driver never uses VDR, something is wrong!\n"); 8707373Sgblack@eecs.umich.edu break; 8717378Sgblack@eecs.umich.edu 8727381Sgblack@eecs.umich.edu case CCSR: 8737373Sgblack@eecs.umich.edu /* not going to implement clockrun stuff */ 8747381Sgblack@eecs.umich.edu regs.ccsr = reg; 8757378Sgblack@eecs.umich.edu break; 8767373Sgblack@eecs.umich.edu 8777375Sgblack@eecs.umich.edu case TBICR: 8787373Sgblack@eecs.umich.edu regs.tbicr = reg; 8797373Sgblack@eecs.umich.edu if (reg & TBICR_MR_LOOPBACK) 8807375Sgblack@eecs.umich.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8817375Sgblack@eecs.umich.edu 8827373Sgblack@eecs.umich.edu if (reg & TBICR_MR_AN_ENABLE) { 8837373Sgblack@eecs.umich.edu regs.tanlpar = regs.tanar; 8847373Sgblack@eecs.umich.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8857373Sgblack@eecs.umich.edu } 8867378Sgblack@eecs.umich.edu 8877381Sgblack@eecs.umich.edu#if 0 8887373Sgblack@eecs.umich.edu if (reg & TBICR_MR_RESTART_AN) ; 8897381Sgblack@eecs.umich.edu#endif 8907378Sgblack@eecs.umich.edu 8917373Sgblack@eecs.umich.edu break; 8927373Sgblack@eecs.umich.edu 8937373Sgblack@eecs.umich.edu case TBISR: 8947375Sgblack@eecs.umich.edu panic("TBISR is read only register!\n"); 8957373Sgblack@eecs.umich.edu 8967373Sgblack@eecs.umich.edu case TANAR: 8977375Sgblack@eecs.umich.edu regs.tanar = reg; 8987375Sgblack@eecs.umich.edu if (reg & TANAR_PS2) 8997373Sgblack@eecs.umich.edu panic("this isn't used in driver, something wrong!\n"); 9007373Sgblack@eecs.umich.edu 9017373Sgblack@eecs.umich.edu if (reg & TANAR_PS1) 9027378Sgblack@eecs.umich.edu panic("this isn't used in driver, something wrong!\n"); 9037381Sgblack@eecs.umich.edu break; 9047373Sgblack@eecs.umich.edu 9057381Sgblack@eecs.umich.edu case TANLPAR: 9067378Sgblack@eecs.umich.edu panic("this should only be written to by the fake phy!\n"); 9077373Sgblack@eecs.umich.edu 9087375Sgblack@eecs.umich.edu case TANER: 9097373Sgblack@eecs.umich.edu panic("TANER is read only register!\n"); 9107373Sgblack@eecs.umich.edu 9117375Sgblack@eecs.umich.edu case TESR: 9127375Sgblack@eecs.umich.edu regs.tesr = reg; 9137373Sgblack@eecs.umich.edu break; 9147373Sgblack@eecs.umich.edu 9157373Sgblack@eecs.umich.edu default: 9167373Sgblack@eecs.umich.edu panic("invalid register access daddr=%#x", daddr); 9177378Sgblack@eecs.umich.edu } 9187381Sgblack@eecs.umich.edu } else { 9197373Sgblack@eecs.umich.edu panic("Invalid Request Size"); 9207381Sgblack@eecs.umich.edu } 9217378Sgblack@eecs.umich.edu 9227373Sgblack@eecs.umich.edu return No_Fault; 9237373Sgblack@eecs.umich.edu} 9247373Sgblack@eecs.umich.edu 9257375Sgblack@eecs.umich.eduvoid 9267373Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts) 9277373Sgblack@eecs.umich.edu{ 9287375Sgblack@eecs.umich.edu bool delay = false; 9297375Sgblack@eecs.umich.edu 9307373Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 9317373Sgblack@eecs.umich.edu panic("Cannot set a reserved interrupt"); 9327380Sgblack@eecs.umich.edu 9337382Sgblack@eecs.umich.edu if (interrupts & ISR_TXRCMP) 9347380Sgblack@eecs.umich.edu regs.isr |= ISR_TXRCMP; 9357381Sgblack@eecs.umich.edu 9367388Sgblack@eecs.umich.edu if (interrupts & ISR_RXRCMP) 9377381Sgblack@eecs.umich.edu regs.isr |= ISR_RXRCMP; 9387380Sgblack@eecs.umich.edu 9397380Sgblack@eecs.umich.edu//ISR_DPERR not implemented 9407380Sgblack@eecs.umich.edu//ISR_SSERR not implemented 9417380Sgblack@eecs.umich.edu//ISR_RMABT not implemented 9427380Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented 9437380Sgblack@eecs.umich.edu//ISR_HIBINT not implemented 9447380Sgblack@eecs.umich.edu//ISR_PHY not implemented 9457380Sgblack@eecs.umich.edu//ISR_PME not implemented 9467380Sgblack@eecs.umich.edu 9477380Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) 9487380Sgblack@eecs.umich.edu regs.isr |= ISR_SWI; 9497380Sgblack@eecs.umich.edu 9507382Sgblack@eecs.umich.edu//ISR_MIB not implemented 9517380Sgblack@eecs.umich.edu//ISR_TXURN not implemented 9527381Sgblack@eecs.umich.edu 9537388Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) 9547381Sgblack@eecs.umich.edu regs.isr |= ISR_TXIDLE; 9557380Sgblack@eecs.umich.edu 9567380Sgblack@eecs.umich.edu if (interrupts & ISR_TXERR) 9577380Sgblack@eecs.umich.edu regs.isr |= ISR_TXERR; 9587380Sgblack@eecs.umich.edu 9597380Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) 9607380Sgblack@eecs.umich.edu regs.isr |= ISR_TXDESC; 9617380Sgblack@eecs.umich.edu 9627380Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) { 9637380Sgblack@eecs.umich.edu regs.isr |= ISR_TXOK; 9647380Sgblack@eecs.umich.edu delay = true; 9657380Sgblack@eecs.umich.edu } 9667382Sgblack@eecs.umich.edu 9677380Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) 9687381Sgblack@eecs.umich.edu regs.isr |= ISR_RXORN; 9697388Sgblack@eecs.umich.edu 9707381Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) 9717380Sgblack@eecs.umich.edu regs.isr |= ISR_RXIDLE; 9727380Sgblack@eecs.umich.edu 9737380Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented 9747380Sgblack@eecs.umich.edu 9757380Sgblack@eecs.umich.edu if (interrupts & ISR_RXERR) 9767380Sgblack@eecs.umich.edu regs.isr |= ISR_RXERR; 9777380Sgblack@eecs.umich.edu 9787380Sgblack@eecs.umich.edu if (interrupts & ISR_RXDESC) 9797380Sgblack@eecs.umich.edu regs.isr |= ISR_RXDESC; 9807380Sgblack@eecs.umich.edu 9817380Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) { 9827380Sgblack@eecs.umich.edu delay = true; 9837382Sgblack@eecs.umich.edu regs.isr |= ISR_RXOK; 9847380Sgblack@eecs.umich.edu } 9857381Sgblack@eecs.umich.edu 9867388Sgblack@eecs.umich.edu if ((regs.isr & regs.imr)) { 9877381Sgblack@eecs.umich.edu Tick when = curTick; 9887380Sgblack@eecs.umich.edu if (delay) 9897380Sgblack@eecs.umich.edu when += intrDelay; 9907380Sgblack@eecs.umich.edu cpuIntrPost(when); 9917380Sgblack@eecs.umich.edu } 9927380Sgblack@eecs.umich.edu 9937380Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 9947380Sgblack@eecs.umich.edu "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9957380Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 9967380Sgblack@eecs.umich.edu} 9977380Sgblack@eecs.umich.edu 9987373Sgblack@eecs.umich.eduvoid 9997382Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts) 10007378Sgblack@eecs.umich.edu{ 10017380Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 10027381Sgblack@eecs.umich.edu panic("Cannot clear a reserved interrupt"); 10037387Sgblack@eecs.umich.edu 10047381Sgblack@eecs.umich.edu if (interrupts & ISR_TXRCMP) 10057378Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXRCMP; 10067373Sgblack@eecs.umich.edu 10077375Sgblack@eecs.umich.edu if (interrupts & ISR_RXRCMP) 10087373Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXRCMP; 10097373Sgblack@eecs.umich.edu 10107375Sgblack@eecs.umich.edu//ISR_DPERR not implemented 10117375Sgblack@eecs.umich.edu//ISR_SSERR not implemented 10127373Sgblack@eecs.umich.edu//ISR_RMABT not implemented 10137373Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented 10147373Sgblack@eecs.umich.edu//ISR_HIBINT not implemented 10157373Sgblack@eecs.umich.edu//ISR_PHY not implemented 10167373Sgblack@eecs.umich.edu//ISR_PME not implemented 10177382Sgblack@eecs.umich.edu 10187378Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) 10197380Sgblack@eecs.umich.edu regs.isr &= ~ISR_SWI; 10207381Sgblack@eecs.umich.edu 10217387Sgblack@eecs.umich.edu//ISR_MIB not implemented 10227381Sgblack@eecs.umich.edu//ISR_TXURN not implemented 10237378Sgblack@eecs.umich.edu 10247373Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) 10257373Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXIDLE; 10267375Sgblack@eecs.umich.edu 10277373Sgblack@eecs.umich.edu if (interrupts & ISR_TXERR) 10287373Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXERR; 10297375Sgblack@eecs.umich.edu 10307375Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) 10317373Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXDESC; 10327373Sgblack@eecs.umich.edu 10337373Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) 10347382Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXOK; 10357378Sgblack@eecs.umich.edu 10367380Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) 10377381Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXORN; 10387387Sgblack@eecs.umich.edu 10397381Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) 10407378Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXIDLE; 10417373Sgblack@eecs.umich.edu 10427375Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented 10437373Sgblack@eecs.umich.edu 10447373Sgblack@eecs.umich.edu if (interrupts & ISR_RXERR) 10457375Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXERR; 10467375Sgblack@eecs.umich.edu 10477373Sgblack@eecs.umich.edu if (interrupts & ISR_RXDESC) 10487373Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXDESC; 10497373Sgblack@eecs.umich.edu 10507373Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) 10517373Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXOK; 10527382Sgblack@eecs.umich.edu 10537378Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 10547380Sgblack@eecs.umich.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 10557381Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 10567387Sgblack@eecs.umich.edu 10577381Sgblack@eecs.umich.edu if (!(regs.isr & regs.imr)) 10587378Sgblack@eecs.umich.edu cpuIntrClear(); 10597373Sgblack@eecs.umich.edu} 10607373Sgblack@eecs.umich.edu 10617375Sgblack@eecs.umich.eduvoid 10627373Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask() 10637373Sgblack@eecs.umich.edu{ 10647375Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 10657375Sgblack@eecs.umich.edu regs.isr, regs.imr, regs.isr & regs.imr); 10667373Sgblack@eecs.umich.edu 10677374Sgblack@eecs.umich.edu if (regs.isr & regs.imr) 10687374Sgblack@eecs.umich.edu cpuIntrPost(curTick); 10697374Sgblack@eecs.umich.edu else 10707382Sgblack@eecs.umich.edu cpuIntrClear(); 10717378Sgblack@eecs.umich.edu} 10727381Sgblack@eecs.umich.edu 10737374Sgblack@eecs.umich.eduvoid 10747381Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when) 10757378Sgblack@eecs.umich.edu{ 10767374Sgblack@eecs.umich.edu // If the interrupt you want to post is later than an interrupt 10777374Sgblack@eecs.umich.edu // already scheduled, just let it post in the coming one and don't 10787374Sgblack@eecs.umich.edu // schedule another. 10797375Sgblack@eecs.umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 10807374Sgblack@eecs.umich.edu // future (this was formerly the source of a bug) 10817374Sgblack@eecs.umich.edu /** 10827375Sgblack@eecs.umich.edu * @todo this warning should be removed and the intrTick code should 10837375Sgblack@eecs.umich.edu * be fixed. 10847374Sgblack@eecs.umich.edu */ 10857374Sgblack@eecs.umich.edu if (intrTick < curTick && intrTick != 0) { 10867374Sgblack@eecs.umich.edu warn("intrTick < curTick !!! intrTick=%d curTick=%d\n", 10877374Sgblack@eecs.umich.edu intrTick, curTick); 10887374Sgblack@eecs.umich.edu intrTick = 0; 10897382Sgblack@eecs.umich.edu } 10907378Sgblack@eecs.umich.edu assert((intrTick >= curTick) || (intrTick == 0)); 10917381Sgblack@eecs.umich.edu if (when > intrTick && intrTick != 0) 10927386Sgblack@eecs.umich.edu return; 10937381Sgblack@eecs.umich.edu 10947378Sgblack@eecs.umich.edu intrTick = when; 10957374Sgblack@eecs.umich.edu 10967375Sgblack@eecs.umich.edu if (intrEvent) { 10977374Sgblack@eecs.umich.edu intrEvent->squash(); 10987374Sgblack@eecs.umich.edu intrEvent = 0; 10997375Sgblack@eecs.umich.edu } 11007375Sgblack@eecs.umich.edu 11017374Sgblack@eecs.umich.edu if (when < curTick) { 11027377Sgblack@eecs.umich.edu cpuInterrupt(); 11037377Sgblack@eecs.umich.edu } else { 11047389Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 11057377Sgblack@eecs.umich.edu "going to schedule an interrupt for intrTick=%d\n", 11067377Sgblack@eecs.umich.edu intrTick); 11077377Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 11087377Sgblack@eecs.umich.edu intrEvent->schedule(intrTick); 11097377Sgblack@eecs.umich.edu } 11107377Sgblack@eecs.umich.edu} 11117377Sgblack@eecs.umich.edu 11127377Sgblack@eecs.umich.eduvoid 11137389Sgblack@eecs.umich.eduNSGigE::cpuInterrupt() 11147389Sgblack@eecs.umich.edu{ 11157389Sgblack@eecs.umich.edu // Don't send an interrupt if there's already one 11167389Sgblack@eecs.umich.edu if (cpuPendingIntr) { 11177389Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 11187389Sgblack@eecs.umich.edu "would send an interrupt now, but there's already pending\n"); 11197389Sgblack@eecs.umich.edu intrTick = 0; 11207389Sgblack@eecs.umich.edu return; 11217389Sgblack@eecs.umich.edu } 11227389Sgblack@eecs.umich.edu // Don't send an interrupt if it's supposed to be delayed 11237389Sgblack@eecs.umich.edu if (intrTick > curTick) { 11247389Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 11257389Sgblack@eecs.umich.edu "an interrupt is scheduled for %d, wait til then\n", 11267389Sgblack@eecs.umich.edu intrTick); 11277377Sgblack@eecs.umich.edu return; 11287377Sgblack@eecs.umich.edu } 11297377Sgblack@eecs.umich.edu 11307377Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 11317377Sgblack@eecs.umich.edu // it anymore 11327377Sgblack@eecs.umich.edu intrEvent = 0; 11337377Sgblack@eecs.umich.edu intrTick = 0; 11347377Sgblack@eecs.umich.edu 11357377Sgblack@eecs.umich.edu // Send interrupt 11367377Sgblack@eecs.umich.edu cpuPendingIntr = true; 11377377Sgblack@eecs.umich.edu /** @todo rework the intctrl to be tsunami ok */ 11387377Sgblack@eecs.umich.edu //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11397377Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); 11407377Sgblack@eecs.umich.edu tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 11417377Sgblack@eecs.umich.edu} 11427382Sgblack@eecs.umich.edu 11437377Sgblack@eecs.umich.eduvoid 11447377Sgblack@eecs.umich.eduNSGigE::cpuIntrClear() 11457377Sgblack@eecs.umich.edu{ 11467377Sgblack@eecs.umich.edu if (!cpuPendingIntr) 11477377Sgblack@eecs.umich.edu return; 11487377Sgblack@eecs.umich.edu 11497377Sgblack@eecs.umich.edu cpuPendingIntr = false; 11507377Sgblack@eecs.umich.edu /** @todo rework the intctrl to be tsunami ok */ 11517389Sgblack@eecs.umich.edu //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11527389Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); 11537389Sgblack@eecs.umich.edu tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 11547389Sgblack@eecs.umich.edu} 11557389Sgblack@eecs.umich.edu 11567389Sgblack@eecs.umich.edubool 11577389Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const 11587377Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 11597377Sgblack@eecs.umich.edu 11607377Sgblack@eecs.umich.eduvoid 11617377Sgblack@eecs.umich.eduNSGigE::txReset() 11627377Sgblack@eecs.umich.edu{ 11637377Sgblack@eecs.umich.edu 11647377Sgblack@eecs.umich.edu DPRINTF(Ethernet, "transmit reset\n"); 11657377Sgblack@eecs.umich.edu 11667377Sgblack@eecs.umich.edu CTDD = false; 11677377Sgblack@eecs.umich.edu txFifoAvail = maxTxFifoSize; 11687377Sgblack@eecs.umich.edu txEnable = false;; 11697377Sgblack@eecs.umich.edu txFragPtr = 0; 11707389Sgblack@eecs.umich.edu assert(txDescCnt == 0); 11717377Sgblack@eecs.umich.edu txFifo.clear(); 11727389Sgblack@eecs.umich.edu txState = txIdle; 11737389Sgblack@eecs.umich.edu assert(txDmaState == dmaIdle); 11747377Sgblack@eecs.umich.edu} 11757377Sgblack@eecs.umich.edu 11767377Sgblack@eecs.umich.eduvoid 11777377Sgblack@eecs.umich.eduNSGigE::rxReset() 11787377Sgblack@eecs.umich.edu{ 11797377Sgblack@eecs.umich.edu DPRINTF(Ethernet, "receive reset\n"); 11807377Sgblack@eecs.umich.edu 11817389Sgblack@eecs.umich.edu CRDD = false; 11827389Sgblack@eecs.umich.edu assert(rxPktBytes == 0); 11837389Sgblack@eecs.umich.edu rxFifoCnt = 0; 11847389Sgblack@eecs.umich.edu rxEnable = false; 11857389Sgblack@eecs.umich.edu rxFragPtr = 0; 11867389Sgblack@eecs.umich.edu assert(rxDescCnt == 0); 11877389Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle); 11887389Sgblack@eecs.umich.edu rxFifo.clear(); 11897389Sgblack@eecs.umich.edu rxState = rxIdle; 11907389Sgblack@eecs.umich.edu} 11917389Sgblack@eecs.umich.edu 11927377Sgblack@eecs.umich.eduvoid 11937377Sgblack@eecs.umich.eduNSGigE::regsReset() 11947377Sgblack@eecs.umich.edu{ 11957377Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 11967377Sgblack@eecs.umich.edu regs.config = 0x80000000; 11977377Sgblack@eecs.umich.edu regs.mear = 0x12; 11987377Sgblack@eecs.umich.edu regs.isr = 0x00608000; 11997377Sgblack@eecs.umich.edu regs.txcfg = 0x120; 12007377Sgblack@eecs.umich.edu regs.rxcfg = 0x4; 12017377Sgblack@eecs.umich.edu regs.srr = 0x0103; 12027377Sgblack@eecs.umich.edu regs.mibc = 0x2; 12037377Sgblack@eecs.umich.edu regs.vdr = 0x81; 12047377Sgblack@eecs.umich.edu regs.tesr = 0xc000; 12057389Sgblack@eecs.umich.edu 12067389Sgblack@eecs.umich.edu extstsEnable = false; 12077377Sgblack@eecs.umich.edu acceptBroadcast = false; 12087382Sgblack@eecs.umich.edu acceptMulticast = false; 12097377Sgblack@eecs.umich.edu acceptUnicast = false; 12107377Sgblack@eecs.umich.edu acceptPerfect = false; 12117377Sgblack@eecs.umich.edu acceptArp = false; 12127377Sgblack@eecs.umich.edu} 12137377Sgblack@eecs.umich.edu 12147377Sgblack@eecs.umich.eduvoid 12157377Sgblack@eecs.umich.eduNSGigE::rxDmaReadCopy() 12167377Sgblack@eecs.umich.edu{ 12177389Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 12187389Sgblack@eecs.umich.edu 12197389Sgblack@eecs.umich.edu physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); 12207389Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 12217389Sgblack@eecs.umich.edu 12227377Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 12237377Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 12247377Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 12257377Sgblack@eecs.umich.edu} 12267377Sgblack@eecs.umich.edu 12277377Sgblack@eecs.umich.edubool 12287377Sgblack@eecs.umich.eduNSGigE::doRxDmaRead() 12297377Sgblack@eecs.umich.edu{ 12307377Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 12317377Sgblack@eecs.umich.edu rxDmaState = dmaReading; 12327389Sgblack@eecs.umich.edu 12337389Sgblack@eecs.umich.edu if (dmaInterface && !rxDmaFree) { 12347389Sgblack@eecs.umich.edu if (dmaInterface->busy()) 12357389Sgblack@eecs.umich.edu rxDmaState = dmaReadWaiting; 12367389Sgblack@eecs.umich.edu else 12377389Sgblack@eecs.umich.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 12387389Sgblack@eecs.umich.edu &rxDmaReadEvent, true); 12397389Sgblack@eecs.umich.edu return true; 12407389Sgblack@eecs.umich.edu } 12417389Sgblack@eecs.umich.edu 12427389Sgblack@eecs.umich.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 12437389Sgblack@eecs.umich.edu rxDmaReadCopy(); 12447389Sgblack@eecs.umich.edu return false; 12457389Sgblack@eecs.umich.edu } 12467389Sgblack@eecs.umich.edu 12477389Sgblack@eecs.umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 12487389Sgblack@eecs.umich.edu Tick start = curTick + dmaReadDelay + factor; 12497389Sgblack@eecs.umich.edu rxDmaReadEvent.schedule(start); 12507389Sgblack@eecs.umich.edu return true; 12517389Sgblack@eecs.umich.edu} 12527389Sgblack@eecs.umich.edu 12537389Sgblack@eecs.umich.eduvoid 12547389Sgblack@eecs.umich.eduNSGigE::rxDmaReadDone() 12557389Sgblack@eecs.umich.edu{ 12567389Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 12577389Sgblack@eecs.umich.edu rxDmaReadCopy(); 12587389Sgblack@eecs.umich.edu 12597389Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 12607389Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12617389Sgblack@eecs.umich.edu txKick(); 12627389Sgblack@eecs.umich.edu 12637389Sgblack@eecs.umich.edu rxKick(); 12647389Sgblack@eecs.umich.edu} 12657389Sgblack@eecs.umich.edu 12667389Sgblack@eecs.umich.eduvoid 12677389Sgblack@eecs.umich.eduNSGigE::rxDmaWriteCopy() 12687389Sgblack@eecs.umich.edu{ 12697389Sgblack@eecs.umich.edu assert(rxDmaState == dmaWriting); 12707389Sgblack@eecs.umich.edu 12717389Sgblack@eecs.umich.edu physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 12727389Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 12737389Sgblack@eecs.umich.edu 12747389Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 12757389Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 12767389Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 12777389Sgblack@eecs.umich.edu} 12787389Sgblack@eecs.umich.edu 12797389Sgblack@eecs.umich.edubool 12807389Sgblack@eecs.umich.eduNSGigE::doRxDmaWrite() 12817389Sgblack@eecs.umich.edu{ 12827389Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 12837389Sgblack@eecs.umich.edu rxDmaState = dmaWriting; 12847389Sgblack@eecs.umich.edu 12857389Sgblack@eecs.umich.edu if (dmaInterface && !rxDmaFree) { 12867389Sgblack@eecs.umich.edu if (dmaInterface->busy()) 12877389Sgblack@eecs.umich.edu rxDmaState = dmaWriteWaiting; 12887389Sgblack@eecs.umich.edu else 12897389Sgblack@eecs.umich.edu dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 12907389Sgblack@eecs.umich.edu &rxDmaWriteEvent, true); 12917389Sgblack@eecs.umich.edu return true; 12927389Sgblack@eecs.umich.edu } 12937389Sgblack@eecs.umich.edu 12947389Sgblack@eecs.umich.edu if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 12957389Sgblack@eecs.umich.edu rxDmaWriteCopy(); 12967389Sgblack@eecs.umich.edu return false; 12977389Sgblack@eecs.umich.edu } 12987389Sgblack@eecs.umich.edu 12997389Sgblack@eecs.umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 13007389Sgblack@eecs.umich.edu Tick start = curTick + dmaWriteDelay + factor; 13017389Sgblack@eecs.umich.edu rxDmaWriteEvent.schedule(start); 13027389Sgblack@eecs.umich.edu return true; 13037389Sgblack@eecs.umich.edu} 13047389Sgblack@eecs.umich.edu 13057389Sgblack@eecs.umich.eduvoid 13067389Sgblack@eecs.umich.eduNSGigE::rxDmaWriteDone() 13077389Sgblack@eecs.umich.edu{ 13087389Sgblack@eecs.umich.edu assert(rxDmaState == dmaWriting); 13097389Sgblack@eecs.umich.edu rxDmaWriteCopy(); 13107389Sgblack@eecs.umich.edu 13117389Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 13127389Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 13137389Sgblack@eecs.umich.edu txKick(); 13147389Sgblack@eecs.umich.edu 13157389Sgblack@eecs.umich.edu rxKick(); 13167389Sgblack@eecs.umich.edu} 13177389Sgblack@eecs.umich.edu 13187389Sgblack@eecs.umich.eduvoid 13197389Sgblack@eecs.umich.eduNSGigE::rxKick() 13207389Sgblack@eecs.umich.edu{ 13217389Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", 13227389Sgblack@eecs.umich.edu NsRxStateStrings[rxState], rxFifo.size()); 13237389Sgblack@eecs.umich.edu 13247389Sgblack@eecs.umich.edu if (rxKickTick > curTick) { 13257322Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 13267379Sgblack@eecs.umich.edu rxKickTick); 13277379Sgblack@eecs.umich.edu return; 13287379Sgblack@eecs.umich.edu } 13297379Sgblack@eecs.umich.edu 13307379Sgblack@eecs.umich.edu next: 13317379Sgblack@eecs.umich.edu switch(rxDmaState) { 13327379Sgblack@eecs.umich.edu case dmaReadWaiting: 13337379Sgblack@eecs.umich.edu if (doRxDmaRead()) 13347382Sgblack@eecs.umich.edu goto exit; 13357379Sgblack@eecs.umich.edu break; 13367381Sgblack@eecs.umich.edu case dmaWriteWaiting: 13377379Sgblack@eecs.umich.edu if (doRxDmaWrite()) 13387381Sgblack@eecs.umich.edu goto exit; 13397379Sgblack@eecs.umich.edu break; 13407379Sgblack@eecs.umich.edu default: 13417379Sgblack@eecs.umich.edu break; 13427379Sgblack@eecs.umich.edu } 13437379Sgblack@eecs.umich.edu 13447379Sgblack@eecs.umich.edu // see state machine from spec for details 13457379Sgblack@eecs.umich.edu // the way this works is, if you finish work on one state and can 13467379Sgblack@eecs.umich.edu // go directly to another, you do that through jumping to the 13477379Sgblack@eecs.umich.edu // label "next". however, if you have intermediate work, like DMA 13487379Sgblack@eecs.umich.edu // so that you can't go to the next state yet, you go to exit and 13497379Sgblack@eecs.umich.edu // exit the loop. however, when the DMA is done it will trigger 13507379Sgblack@eecs.umich.edu // an event and come back to this loop. 13517382Sgblack@eecs.umich.edu switch (rxState) { 13527379Sgblack@eecs.umich.edu case rxIdle: 13537381Sgblack@eecs.umich.edu if (!rxEnable) { 13547379Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 13557381Sgblack@eecs.umich.edu goto exit; 13567379Sgblack@eecs.umich.edu } 13577379Sgblack@eecs.umich.edu 13587379Sgblack@eecs.umich.edu if (CRDD) { 13597379Sgblack@eecs.umich.edu rxState = rxDescRefr; 13607379Sgblack@eecs.umich.edu 13617379Sgblack@eecs.umich.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 13627379Sgblack@eecs.umich.edu rxDmaData = &rxDescCache + offsetof(ns_desc, link); 13637379Sgblack@eecs.umich.edu rxDmaLen = sizeof(rxDescCache.link); 13647379Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 13657379Sgblack@eecs.umich.edu 13667379Sgblack@eecs.umich.edu descDmaReads++; 13677379Sgblack@eecs.umich.edu descDmaRdBytes += rxDmaLen; 13687382Sgblack@eecs.umich.edu 13697379Sgblack@eecs.umich.edu if (doRxDmaRead()) 13707381Sgblack@eecs.umich.edu goto exit; 13717379Sgblack@eecs.umich.edu } else { 13727381Sgblack@eecs.umich.edu rxState = rxDescRead; 13737379Sgblack@eecs.umich.edu 13747379Sgblack@eecs.umich.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 13757379Sgblack@eecs.umich.edu rxDmaData = &rxDescCache; 13767379Sgblack@eecs.umich.edu rxDmaLen = sizeof(ns_desc); 13777379Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 13787379Sgblack@eecs.umich.edu 13797379Sgblack@eecs.umich.edu descDmaReads++; 13807379Sgblack@eecs.umich.edu descDmaRdBytes += rxDmaLen; 13817379Sgblack@eecs.umich.edu 13827379Sgblack@eecs.umich.edu if (doRxDmaRead()) 13837379Sgblack@eecs.umich.edu goto exit; 13847379Sgblack@eecs.umich.edu } 13857382Sgblack@eecs.umich.edu break; 13867379Sgblack@eecs.umich.edu 13877381Sgblack@eecs.umich.edu case rxDescRefr: 13887379Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 13897381Sgblack@eecs.umich.edu goto exit; 13907379Sgblack@eecs.umich.edu 13917379Sgblack@eecs.umich.edu rxState = rxAdvance; 13927379Sgblack@eecs.umich.edu break; 13937379Sgblack@eecs.umich.edu 13947379Sgblack@eecs.umich.edu case rxDescRead: 13957379Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 13967379Sgblack@eecs.umich.edu goto exit; 13977379Sgblack@eecs.umich.edu 13987379Sgblack@eecs.umich.edu DPRINTF(EthernetDesc, 13997379Sgblack@eecs.umich.edu "rxDescCache: addr=%08x read descriptor\n", 14007379Sgblack@eecs.umich.edu regs.rxdp & 0x3fffffff); 14017379Sgblack@eecs.umich.edu DPRINTF(EthernetDesc, 14027379Sgblack@eecs.umich.edu "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 14037381Sgblack@eecs.umich.edu rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 14047386Sgblack@eecs.umich.edu rxDescCache.extsts); 14057381Sgblack@eecs.umich.edu 14067379Sgblack@eecs.umich.edu if (rxDescCache.cmdsts & CMDSTS_OWN) { 14077379Sgblack@eecs.umich.edu devIntrPost(ISR_RXIDLE); 14087379Sgblack@eecs.umich.edu rxState = rxIdle; 14097379Sgblack@eecs.umich.edu goto exit; 14107379Sgblack@eecs.umich.edu } else { 14117379Sgblack@eecs.umich.edu rxState = rxFifoBlock; 14127379Sgblack@eecs.umich.edu rxFragPtr = rxDescCache.bufptr; 14137379Sgblack@eecs.umich.edu rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 14147379Sgblack@eecs.umich.edu } 14157379Sgblack@eecs.umich.edu break; 14167379Sgblack@eecs.umich.edu 14177379Sgblack@eecs.umich.edu case rxFifoBlock: 14187379Sgblack@eecs.umich.edu if (!rxPacket) { 14197381Sgblack@eecs.umich.edu /** 14207386Sgblack@eecs.umich.edu * @todo in reality, we should be able to start processing 14217381Sgblack@eecs.umich.edu * the packet as it arrives, and not have to wait for the 14227379Sgblack@eecs.umich.edu * full packet ot be in the receive fifo. 14237379Sgblack@eecs.umich.edu */ 14247379Sgblack@eecs.umich.edu if (rxFifo.empty()) 14257379Sgblack@eecs.umich.edu goto exit; 14267379Sgblack@eecs.umich.edu 14277379Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 14287379Sgblack@eecs.umich.edu 14297379Sgblack@eecs.umich.edu // If we don't have a packet, grab a new one from the fifo. 14307379Sgblack@eecs.umich.edu rxPacket = rxFifo.front(); 14317379Sgblack@eecs.umich.edu rxPktBytes = rxPacket->length; 14327379Sgblack@eecs.umich.edu rxPacketBufPtr = rxPacket->data; 14337379Sgblack@eecs.umich.edu 14347379Sgblack@eecs.umich.edu#if TRACING_ON 14357381Sgblack@eecs.umich.edu if (DTRACE(Ethernet)) { 14367386Sgblack@eecs.umich.edu if (rxPacket->isIpPkt()) { 14377381Sgblack@eecs.umich.edu ip_header *ip = rxPacket->getIpHdr(); 14387379Sgblack@eecs.umich.edu DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 14397379Sgblack@eecs.umich.edu if (rxPacket->isTcpPkt()) { 14407379Sgblack@eecs.umich.edu tcp_header *tcp = rxPacket->getTcpHdr(ip); 14417379Sgblack@eecs.umich.edu DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 14427379Sgblack@eecs.umich.edu reverseEnd16(tcp->src_port_num), 14437379Sgblack@eecs.umich.edu reverseEnd16(tcp->dest_port_num)); 14447379Sgblack@eecs.umich.edu } 14457379Sgblack@eecs.umich.edu } 14467379Sgblack@eecs.umich.edu } 14477379Sgblack@eecs.umich.edu#endif 14487379Sgblack@eecs.umich.edu 14497379Sgblack@eecs.umich.edu // sanity check - i think the driver behaves like this 14507379Sgblack@eecs.umich.edu assert(rxDescCnt >= rxPktBytes); 14517381Sgblack@eecs.umich.edu 14527386Sgblack@eecs.umich.edu // Must clear the value before popping to decrement the 14537381Sgblack@eecs.umich.edu // reference count 14547379Sgblack@eecs.umich.edu rxFifo.front() = NULL; 14557379Sgblack@eecs.umich.edu rxFifo.pop_front(); 14567379Sgblack@eecs.umich.edu rxFifoCnt -= rxPacket->length; 14577379Sgblack@eecs.umich.edu } 14587379Sgblack@eecs.umich.edu 14597379Sgblack@eecs.umich.edu 14607379Sgblack@eecs.umich.edu // dont' need the && rxDescCnt > 0 if driver sanity check 14617379Sgblack@eecs.umich.edu // above holds 14627379Sgblack@eecs.umich.edu if (rxPktBytes > 0) { 14637379Sgblack@eecs.umich.edu rxState = rxFragWrite; 14647379Sgblack@eecs.umich.edu // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 14657379Sgblack@eecs.umich.edu // check holds 14667382Sgblack@eecs.umich.edu rxXferLen = rxPktBytes; 14677379Sgblack@eecs.umich.edu 14687381Sgblack@eecs.umich.edu rxDmaAddr = rxFragPtr & 0x3fffffff; 14697379Sgblack@eecs.umich.edu rxDmaData = rxPacketBufPtr; 14707381Sgblack@eecs.umich.edu rxDmaLen = rxXferLen; 14717379Sgblack@eecs.umich.edu rxDmaFree = dmaDataFree; 14727379Sgblack@eecs.umich.edu 14737379Sgblack@eecs.umich.edu if (doRxDmaWrite()) 14747379Sgblack@eecs.umich.edu goto exit; 14757379Sgblack@eecs.umich.edu 14767379Sgblack@eecs.umich.edu } else { 14777379Sgblack@eecs.umich.edu rxState = rxDescWrite; 14787379Sgblack@eecs.umich.edu 14797379Sgblack@eecs.umich.edu //if (rxPktBytes == 0) { /* packet is done */ 14807379Sgblack@eecs.umich.edu assert(rxPktBytes == 0); 14817379Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "done with receiving packet\n"); 14827379Sgblack@eecs.umich.edu 14837379Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_OWN; 14847382Sgblack@eecs.umich.edu rxDescCache.cmdsts &= ~CMDSTS_MORE; 14857379Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_OK; 14867381Sgblack@eecs.umich.edu rxDescCache.cmdsts &= 0xffff0000; 14877379Sgblack@eecs.umich.edu rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 14887381Sgblack@eecs.umich.edu 14897379Sgblack@eecs.umich.edu#if 0 14907379Sgblack@eecs.umich.edu /* 14917379Sgblack@eecs.umich.edu * all the driver uses these are for its own stats keeping 14927379Sgblack@eecs.umich.edu * which we don't care about, aren't necessary for 14937379Sgblack@eecs.umich.edu * functionality and doing this would just slow us down. 14947379Sgblack@eecs.umich.edu * if they end up using this in a later version for 14957379Sgblack@eecs.umich.edu * functional purposes, just undef 14967379Sgblack@eecs.umich.edu */ 14977379Sgblack@eecs.umich.edu if (rxFilterEnable) { 14987379Sgblack@eecs.umich.edu rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 14997379Sgblack@eecs.umich.edu if (rxFifo.front()->IsUnicast()) 15007379Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 15017379Sgblack@eecs.umich.edu if (rxFifo.front()->IsMulticast()) 15027382Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 15037379Sgblack@eecs.umich.edu if (rxFifo.front()->IsBroadcast()) 15047381Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 15057379Sgblack@eecs.umich.edu } 15067381Sgblack@eecs.umich.edu#endif 15077379Sgblack@eecs.umich.edu 15087379Sgblack@eecs.umich.edu if (rxPacket->isIpPkt() && extstsEnable) { 15097379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_IPPKT; 15107379Sgblack@eecs.umich.edu rxIPChecksums++; 15117379Sgblack@eecs.umich.edu if (!ipChecksum(rxPacket, false)) { 15127379Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 15137379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_IPERR; 15147379Sgblack@eecs.umich.edu } 15157379Sgblack@eecs.umich.edu if (rxPacket->isTcpPkt()) { 15167379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_TCPPKT; 15177379Sgblack@eecs.umich.edu rxTCPChecksums++; 15187379Sgblack@eecs.umich.edu if (!tcpChecksum(rxPacket, false)) { 15197379Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 15207382Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_TCPERR; 15217379Sgblack@eecs.umich.edu 15227381Sgblack@eecs.umich.edu } 15237379Sgblack@eecs.umich.edu } else if (rxPacket->isUdpPkt()) { 15247381Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_UDPPKT; 15257379Sgblack@eecs.umich.edu if (!udpChecksum(rxPacket, false)) { 15267379Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 15277379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_UDPERR; 15287379Sgblack@eecs.umich.edu } 15297379Sgblack@eecs.umich.edu } 15307379Sgblack@eecs.umich.edu } 15317379Sgblack@eecs.umich.edu rxPacket = 0; 15327379Sgblack@eecs.umich.edu 15337379Sgblack@eecs.umich.edu /* 15347379Sgblack@eecs.umich.edu * the driver seems to always receive into desc buffers 15357379Sgblack@eecs.umich.edu * of size 1514, so you never have a pkt that is split 15367379Sgblack@eecs.umich.edu * into multiple descriptors on the receive side, so 15377379Sgblack@eecs.umich.edu * i don't implement that case, hence the assert above. 15387379Sgblack@eecs.umich.edu */ 15397381Sgblack@eecs.umich.edu 15407386Sgblack@eecs.umich.edu DPRINTF(EthernetDesc, 15417381Sgblack@eecs.umich.edu "rxDescCache: addr=%08x writeback cmdsts extsts\n", 15427379Sgblack@eecs.umich.edu regs.rxdp & 0x3fffffff); 15437379Sgblack@eecs.umich.edu DPRINTF(EthernetDesc, 15447379Sgblack@eecs.umich.edu "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 15457379Sgblack@eecs.umich.edu rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 15467379Sgblack@eecs.umich.edu rxDescCache.extsts); 15477379Sgblack@eecs.umich.edu 15487379Sgblack@eecs.umich.edu rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 15497379Sgblack@eecs.umich.edu rxDmaData = &(rxDescCache.cmdsts); 15507379Sgblack@eecs.umich.edu rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 15517379Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 15527379Sgblack@eecs.umich.edu 15537379Sgblack@eecs.umich.edu descDmaWrites++; 15547379Sgblack@eecs.umich.edu descDmaWrBytes += rxDmaLen; 15557379Sgblack@eecs.umich.edu 15567381Sgblack@eecs.umich.edu if (doRxDmaWrite()) 15577386Sgblack@eecs.umich.edu goto exit; 15587381Sgblack@eecs.umich.edu } 15597379Sgblack@eecs.umich.edu break; 15607379Sgblack@eecs.umich.edu 15617379Sgblack@eecs.umich.edu case rxFragWrite: 15627379Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 15637379Sgblack@eecs.umich.edu goto exit; 15647379Sgblack@eecs.umich.edu 15657379Sgblack@eecs.umich.edu rxPacketBufPtr += rxXferLen; 15667379Sgblack@eecs.umich.edu rxFragPtr += rxXferLen; 15677379Sgblack@eecs.umich.edu rxPktBytes -= rxXferLen; 15687379Sgblack@eecs.umich.edu 15697379Sgblack@eecs.umich.edu rxState = rxFifoBlock; 15707379Sgblack@eecs.umich.edu break; 15717379Sgblack@eecs.umich.edu 15727379Sgblack@eecs.umich.edu case rxDescWrite: 15737381Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 15747386Sgblack@eecs.umich.edu goto exit; 15757381Sgblack@eecs.umich.edu 15767379Sgblack@eecs.umich.edu assert(rxDescCache.cmdsts & CMDSTS_OWN); 15777379Sgblack@eecs.umich.edu 15787379Sgblack@eecs.umich.edu assert(rxPacket == 0); 15797379Sgblack@eecs.umich.edu devIntrPost(ISR_RXOK); 15807379Sgblack@eecs.umich.edu 15817379Sgblack@eecs.umich.edu if (rxDescCache.cmdsts & CMDSTS_INTR) 15827379Sgblack@eecs.umich.edu devIntrPost(ISR_RXDESC); 15837379Sgblack@eecs.umich.edu 15847379Sgblack@eecs.umich.edu if (!rxEnable) { 15857379Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "Halting the RX state machine\n"); 15867379Sgblack@eecs.umich.edu rxState = rxIdle; 15877379Sgblack@eecs.umich.edu goto exit; 15887379Sgblack@eecs.umich.edu } else 15897379Sgblack@eecs.umich.edu rxState = rxAdvance; 15907381Sgblack@eecs.umich.edu break; 15917386Sgblack@eecs.umich.edu 15927381Sgblack@eecs.umich.edu case rxAdvance: 15937379Sgblack@eecs.umich.edu if (rxDescCache.link == 0) { 15947379Sgblack@eecs.umich.edu devIntrPost(ISR_RXIDLE); 15957379Sgblack@eecs.umich.edu rxState = rxIdle; 15967379Sgblack@eecs.umich.edu CRDD = true; 15977379Sgblack@eecs.umich.edu goto exit; 15987379Sgblack@eecs.umich.edu } else { 15997379Sgblack@eecs.umich.edu rxState = rxDescRead; 16007379Sgblack@eecs.umich.edu regs.rxdp = rxDescCache.link; 16017379Sgblack@eecs.umich.edu CRDD = false; 16027379Sgblack@eecs.umich.edu 16037379Sgblack@eecs.umich.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 16047379Sgblack@eecs.umich.edu rxDmaData = &rxDescCache; 1605 rxDmaLen = sizeof(ns_desc); 1606 rxDmaFree = dmaDescFree; 1607 1608 if (doRxDmaRead()) 1609 goto exit; 1610 } 1611 break; 1612 1613 default: 1614 panic("Invalid rxState!"); 1615 } 1616 1617 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1618 NsRxStateStrings[rxState]); 1619 1620 goto next; 1621 1622 exit: 1623 /** 1624 * @todo do we want to schedule a future kick? 1625 */ 1626 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1627 NsRxStateStrings[rxState]); 1628} 1629 1630void 1631NSGigE::transmit() 1632{ 1633 if (txFifo.empty()) { 1634 DPRINTF(Ethernet, "nothing to transmit\n"); 1635 return; 1636 } 1637 1638 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1639 maxTxFifoSize - txFifoAvail); 1640 if (interface->sendPacket(txFifo.front())) { 1641#if TRACING_ON 1642 if (DTRACE(Ethernet)) { 1643 if (txFifo.front()->isIpPkt()) { 1644 ip_header *ip = txFifo.front()->getIpHdr(); 1645 DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 1646 if (txFifo.front()->isTcpPkt()) { 1647 tcp_header *tcp = txFifo.front()->getTcpHdr(ip); 1648 DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 1649 reverseEnd16(tcp->src_port_num), 1650 reverseEnd16(tcp->dest_port_num)); 1651 } 1652 } 1653 } 1654#endif 1655 1656 DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 1657 txBytes += txFifo.front()->length; 1658 txPackets++; 1659 1660 txFifoAvail += txFifo.front()->length; 1661 1662 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1663 txFifoAvail); 1664 txFifo.front() = NULL; 1665 txFifo.pop_front(); 1666 1667 /* 1668 * normally do a writeback of the descriptor here, and ONLY 1669 * after that is done, send this interrupt. but since our 1670 * stuff never actually fails, just do this interrupt here, 1671 * otherwise the code has to stray from this nice format. 1672 * besides, it's functionally the same. 1673 */ 1674 devIntrPost(ISR_TXOK); 1675 } else { 1676 DPRINTF(Ethernet, 1677 "May need to rethink always sending the descriptors back?\n"); 1678 } 1679 1680 if (!txFifo.empty() && !txEvent.scheduled()) { 1681 DPRINTF(Ethernet, "reschedule transmit\n"); 1682 txEvent.schedule(curTick + 1000); 1683 } 1684} 1685 1686void 1687NSGigE::txDmaReadCopy() 1688{ 1689 assert(txDmaState == dmaReading); 1690 1691 physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); 1692 txDmaState = dmaIdle; 1693 1694 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1695 txDmaAddr, txDmaLen); 1696 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1697} 1698 1699bool 1700NSGigE::doTxDmaRead() 1701{ 1702 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1703 txDmaState = dmaReading; 1704 1705 if (dmaInterface && !txDmaFree) { 1706 if (dmaInterface->busy()) 1707 txDmaState = dmaReadWaiting; 1708 else 1709 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1710 &txDmaReadEvent, true); 1711 return true; 1712 } 1713 1714 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1715 txDmaReadCopy(); 1716 return false; 1717 } 1718 1719 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1720 Tick start = curTick + dmaReadDelay + factor; 1721 txDmaReadEvent.schedule(start); 1722 return true; 1723} 1724 1725void 1726NSGigE::txDmaReadDone() 1727{ 1728 assert(txDmaState == dmaReading); 1729 txDmaReadCopy(); 1730 1731 // If the receive state machine has a pending DMA, let it go first 1732 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1733 rxKick(); 1734 1735 txKick(); 1736} 1737 1738void 1739NSGigE::txDmaWriteCopy() 1740{ 1741 assert(txDmaState == dmaWriting); 1742 1743 physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); 1744 txDmaState = dmaIdle; 1745 1746 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1747 txDmaAddr, txDmaLen); 1748 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1749} 1750 1751bool 1752NSGigE::doTxDmaWrite() 1753{ 1754 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1755 txDmaState = dmaWriting; 1756 1757 if (dmaInterface && !txDmaFree) { 1758 if (dmaInterface->busy()) 1759 txDmaState = dmaWriteWaiting; 1760 else 1761 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1762 &txDmaWriteEvent, true); 1763 return true; 1764 } 1765 1766 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1767 txDmaWriteCopy(); 1768 return false; 1769 } 1770 1771 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1772 Tick start = curTick + dmaWriteDelay + factor; 1773 txDmaWriteEvent.schedule(start); 1774 return true; 1775} 1776 1777void 1778NSGigE::txDmaWriteDone() 1779{ 1780 assert(txDmaState == dmaWriting); 1781 txDmaWriteCopy(); 1782 1783 // If the receive state machine has a pending DMA, let it go first 1784 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1785 rxKick(); 1786 1787 txKick(); 1788} 1789 1790void 1791NSGigE::txKick() 1792{ 1793 DPRINTF(EthernetSM, "transmit kick txState=%s\n", 1794 NsTxStateStrings[txState]); 1795 1796 if (txKickTick > curTick) { 1797 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1798 txKickTick); 1799 1800 return; 1801 } 1802 1803 next: 1804 switch(txDmaState) { 1805 case dmaReadWaiting: 1806 if (doTxDmaRead()) 1807 goto exit; 1808 break; 1809 case dmaWriteWaiting: 1810 if (doTxDmaWrite()) 1811 goto exit; 1812 break; 1813 default: 1814 break; 1815 } 1816 1817 switch (txState) { 1818 case txIdle: 1819 if (!txEnable) { 1820 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1821 goto exit; 1822 } 1823 1824 if (CTDD) { 1825 txState = txDescRefr; 1826 1827 txDmaAddr = regs.txdp & 0x3fffffff; 1828 txDmaData = &txDescCache + offsetof(ns_desc, link); 1829 txDmaLen = sizeof(txDescCache.link); 1830 txDmaFree = dmaDescFree; 1831 1832 descDmaReads++; 1833 descDmaRdBytes += txDmaLen; 1834 1835 if (doTxDmaRead()) 1836 goto exit; 1837 1838 } else { 1839 txState = txDescRead; 1840 1841 txDmaAddr = regs.txdp & 0x3fffffff; 1842 txDmaData = &txDescCache; 1843 txDmaLen = sizeof(ns_desc); 1844 txDmaFree = dmaDescFree; 1845 1846 descDmaReads++; 1847 descDmaRdBytes += txDmaLen; 1848 1849 if (doTxDmaRead()) 1850 goto exit; 1851 } 1852 break; 1853 1854 case txDescRefr: 1855 if (txDmaState != dmaIdle) 1856 goto exit; 1857 1858 txState = txAdvance; 1859 break; 1860 1861 case txDescRead: 1862 if (txDmaState != dmaIdle) 1863 goto exit; 1864 1865 DPRINTF(EthernetDesc, 1866 "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 1867 txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1868 txDescCache.extsts); 1869 1870 if (txDescCache.cmdsts & CMDSTS_OWN) { 1871 txState = txFifoBlock; 1872 txFragPtr = txDescCache.bufptr; 1873 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1874 } else { 1875 devIntrPost(ISR_TXIDLE); 1876 txState = txIdle; 1877 goto exit; 1878 } 1879 break; 1880 1881 case txFifoBlock: 1882 if (!txPacket) { 1883 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1884 txPacket = new EtherPacket; 1885 txPacket->data = new uint8_t[16384]; 1886 txPacketBufPtr = txPacket->data; 1887 } 1888 1889 if (txDescCnt == 0) { 1890 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1891 if (txDescCache.cmdsts & CMDSTS_MORE) { 1892 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1893 txState = txDescWrite; 1894 1895 txDescCache.cmdsts &= ~CMDSTS_OWN; 1896 1897 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1898 txDmaAddr &= 0x3fffffff; 1899 txDmaData = &(txDescCache.cmdsts); 1900 txDmaLen = sizeof(txDescCache.cmdsts); 1901 txDmaFree = dmaDescFree; 1902 1903 if (doTxDmaWrite()) 1904 goto exit; 1905 1906 } else { /* this packet is totally done */ 1907 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1908 /* deal with the the packet that just finished */ 1909 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1910 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1911 udpChecksum(txPacket, true); 1912 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1913 tcpChecksum(txPacket, true); 1914 txTCPChecksums++; 1915 } 1916 if (txDescCache.extsts & EXTSTS_IPPKT) { 1917 ipChecksum(txPacket, true); 1918 txIPChecksums++; 1919 } 1920 } 1921 1922 txPacket->length = txPacketBufPtr - txPacket->data; 1923 // this is just because the receive can't handle a 1924 // packet bigger want to make sure 1925 assert(txPacket->length <= 1514); 1926 txFifo.push_back(txPacket); 1927 1928 /* 1929 * this following section is not tqo spec, but 1930 * functionally shouldn't be any different. normally, 1931 * the chip will wait til the transmit has occurred 1932 * before writing back the descriptor because it has 1933 * to wait to see that it was successfully transmitted 1934 * to decide whether to set CMDSTS_OK or not. 1935 * however, in the simulator since it is always 1936 * successfully transmitted, and writing it exactly to 1937 * spec would complicate the code, we just do it here 1938 */ 1939 1940 txDescCache.cmdsts &= ~CMDSTS_OWN; 1941 txDescCache.cmdsts |= CMDSTS_OK; 1942 1943 DPRINTF(EthernetDesc, 1944 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1945 txDescCache.cmdsts, txDescCache.extsts); 1946 1947 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1948 txDmaAddr &= 0x3fffffff; 1949 txDmaData = &(txDescCache.cmdsts); 1950 txDmaLen = sizeof(txDescCache.cmdsts) + 1951 sizeof(txDescCache.extsts); 1952 txDmaFree = dmaDescFree; 1953 1954 descDmaWrites++; 1955 descDmaWrBytes += txDmaLen; 1956 1957 transmit(); 1958 txPacket = 0; 1959 1960 if (!txEnable) { 1961 DPRINTF(EthernetSM, "halting TX state machine\n"); 1962 txState = txIdle; 1963 goto exit; 1964 } else 1965 txState = txAdvance; 1966 1967 if (doTxDmaWrite()) 1968 goto exit; 1969 } 1970 } else { 1971 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1972 if (txFifoAvail) { 1973 txState = txFragRead; 1974 1975 /* 1976 * The number of bytes transferred is either whatever 1977 * is left in the descriptor (txDescCnt), or if there 1978 * is not enough room in the fifo, just whatever room 1979 * is left in the fifo 1980 */ 1981 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1982 1983 txDmaAddr = txFragPtr & 0x3fffffff; 1984 txDmaData = txPacketBufPtr; 1985 txDmaLen = txXferLen; 1986 txDmaFree = dmaDataFree; 1987 1988 if (doTxDmaRead()) 1989 goto exit; 1990 } else { 1991 txState = txFifoBlock; 1992 transmit(); 1993 1994 goto exit; 1995 } 1996 1997 } 1998 break; 1999 2000 case txFragRead: 2001 if (txDmaState != dmaIdle) 2002 goto exit; 2003 2004 txPacketBufPtr += txXferLen; 2005 txFragPtr += txXferLen; 2006 txDescCnt -= txXferLen; 2007 txFifoAvail -= txXferLen; 2008 2009 txState = txFifoBlock; 2010 break; 2011 2012 case txDescWrite: 2013 if (txDmaState != dmaIdle) 2014 goto exit; 2015 2016 if (txDescCache.cmdsts & CMDSTS_INTR) 2017 devIntrPost(ISR_TXDESC); 2018 2019 txState = txAdvance; 2020 break; 2021 2022 case txAdvance: 2023 if (txDescCache.link == 0) { 2024 devIntrPost(ISR_TXIDLE); 2025 txState = txIdle; 2026 goto exit; 2027 } else { 2028 txState = txDescRead; 2029 regs.txdp = txDescCache.link; 2030 CTDD = false; 2031 2032 txDmaAddr = txDescCache.link & 0x3fffffff; 2033 txDmaData = &txDescCache; 2034 txDmaLen = sizeof(ns_desc); 2035 txDmaFree = dmaDescFree; 2036 2037 if (doTxDmaRead()) 2038 goto exit; 2039 } 2040 break; 2041 2042 default: 2043 panic("invalid state"); 2044 } 2045 2046 DPRINTF(EthernetSM, "entering next txState=%s\n", 2047 NsTxStateStrings[txState]); 2048 2049 goto next; 2050 2051 exit: 2052 /** 2053 * @todo do we want to schedule a future kick? 2054 */ 2055 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 2056 NsTxStateStrings[txState]); 2057} 2058 2059void 2060NSGigE::transferDone() 2061{ 2062 if (txFifo.empty()) { 2063 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2064 return; 2065 } 2066 2067 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2068 2069 if (txEvent.scheduled()) 2070 txEvent.reschedule(curTick + 1); 2071 else 2072 txEvent.schedule(curTick + 1); 2073} 2074 2075bool 2076NSGigE::rxFilter(PacketPtr packet) 2077{ 2078 bool drop = true; 2079 string type; 2080 2081 if (packet->IsUnicast()) { 2082 type = "unicast"; 2083 2084 // If we're accepting all unicast addresses 2085 if (acceptUnicast) 2086 drop = false; 2087 2088 // If we make a perfect match 2089 if (acceptPerfect && 2090 memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0) 2091 drop = false; 2092 2093 eth_header *eth = (eth_header *) packet->data; 2094 if ((acceptArp) && (eth->type == 0x608)) 2095 drop = false; 2096 2097 } else if (packet->IsBroadcast()) { 2098 type = "broadcast"; 2099 2100 // if we're accepting broadcasts 2101 if (acceptBroadcast) 2102 drop = false; 2103 2104 } else if (packet->IsMulticast()) { 2105 type = "multicast"; 2106 2107 // if we're accepting all multicasts 2108 if (acceptMulticast) 2109 drop = false; 2110 2111 } else { 2112 type = "unknown"; 2113 2114 // oh well, punt on this one 2115 } 2116 2117 if (drop) { 2118 DPRINTF(Ethernet, "rxFilter drop\n"); 2119 DDUMP(EthernetData, packet->data, packet->length); 2120 } 2121 2122 return drop; 2123} 2124 2125bool 2126NSGigE::recvPacket(PacketPtr packet) 2127{ 2128 rxBytes += packet->length; 2129 rxPackets++; 2130 2131 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2132 maxRxFifoSize - rxFifoCnt); 2133 2134 if (!rxEnable) { 2135 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2136 debug_break(); 2137 interface->recvDone(); 2138 return true; 2139 } 2140 2141 if (rxFilterEnable && rxFilter(packet)) { 2142 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2143 interface->recvDone(); 2144 return true; 2145 } 2146 2147 if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { 2148 DPRINTF(Ethernet, 2149 "packet will not fit in receive buffer...packet dropped\n"); 2150 devIntrPost(ISR_RXORN); 2151 return false; 2152 } 2153 2154 rxFifo.push_back(packet); 2155 rxFifoCnt += packet->length; 2156 interface->recvDone(); 2157 2158 rxKick(); 2159 return true; 2160} 2161 2162/** 2163 * does a udp checksum. if gen is true, then it generates it and puts 2164 * it in the right place else, it just checks what it calculates 2165 * against the value in the header in packet 2166 */ 2167bool 2168NSGigE::udpChecksum(PacketPtr packet, bool gen) 2169{ 2170 ip_header *ip = packet->getIpHdr(); 2171 udp_header *hdr = packet->getUdpHdr(ip); 2172 2173 pseudo_header *pseudo = new pseudo_header; 2174 2175 pseudo->src_ip_addr = ip->src_ip_addr; 2176 pseudo->dest_ip_addr = ip->dest_ip_addr; 2177 pseudo->protocol = ip->protocol; 2178 pseudo->len = hdr->len; 2179 2180 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2181 (uint32_t) hdr->len); 2182 2183 delete pseudo; 2184 if (gen) 2185 hdr->chksum = cksum; 2186 else 2187 if (cksum != 0) 2188 return false; 2189 2190 return true; 2191} 2192 2193bool 2194NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2195{ 2196 ip_header *ip = packet->getIpHdr(); 2197 tcp_header *hdr = packet->getTcpHdr(ip); 2198 2199 uint16_t cksum; 2200 pseudo_header *pseudo = new pseudo_header; 2201 if (!gen) { 2202 pseudo->src_ip_addr = ip->src_ip_addr; 2203 pseudo->dest_ip_addr = ip->dest_ip_addr; 2204 pseudo->protocol = reverseEnd16(ip->protocol); 2205 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - 2206 (ip->vers_len & 0xf)*4); 2207 2208 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2209 (uint32_t) reverseEnd16(pseudo->len)); 2210 } else { 2211 pseudo->src_ip_addr = 0; 2212 pseudo->dest_ip_addr = 0; 2213 pseudo->protocol = hdr->chksum; 2214 pseudo->len = 0; 2215 hdr->chksum = 0; 2216 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2217 (uint32_t) (reverseEnd16(ip->dgram_len) - 2218 (ip->vers_len & 0xf)*4)); 2219 } 2220 2221 delete pseudo; 2222 if (gen) 2223 hdr->chksum = cksum; 2224 else 2225 if (cksum != 0) 2226 return false; 2227 2228 return true; 2229} 2230 2231bool 2232NSGigE::ipChecksum(PacketPtr packet, bool gen) 2233{ 2234 ip_header *hdr = packet->getIpHdr(); 2235 2236 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, 2237 (hdr->vers_len & 0xf)*4); 2238 2239 if (gen) { 2240 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2241 hdr->hdr_chksum = cksum; 2242 } 2243 else 2244 if (cksum != 0) 2245 return false; 2246 2247 return true; 2248} 2249 2250uint16_t 2251NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2252{ 2253 uint32_t sum = 0; 2254 2255 uint16_t last_pad = 0; 2256 if (len & 1) { 2257 last_pad = buf[len/2] & 0xff; 2258 len--; 2259 sum += last_pad; 2260 } 2261 2262 if (pseudo) { 2263 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2264 pseudo[3] + pseudo[4] + pseudo[5]; 2265 } 2266 2267 for (int i=0; i < (len/2); ++i) { 2268 sum += buf[i]; 2269 } 2270 2271 while (sum >> 16) 2272 sum = (sum >> 16) + (sum & 0xffff); 2273 2274 return ~sum; 2275} 2276 2277//===================================================================== 2278// 2279// 2280void 2281NSGigE::serialize(ostream &os) 2282{ 2283 // Serialize the PciDev base class 2284 PciDev::serialize(os); 2285 2286 /* 2287 * Finalize any DMA events now. 2288 */ 2289 if (rxDmaReadEvent.scheduled()) 2290 rxDmaReadCopy(); 2291 if (rxDmaWriteEvent.scheduled()) 2292 rxDmaWriteCopy(); 2293 if (txDmaReadEvent.scheduled()) 2294 txDmaReadCopy(); 2295 if (txDmaWriteEvent.scheduled()) 2296 txDmaWriteCopy(); 2297 2298 /* 2299 * Serialize the device registers 2300 */ 2301 SERIALIZE_SCALAR(regs.command); 2302 SERIALIZE_SCALAR(regs.config); 2303 SERIALIZE_SCALAR(regs.mear); 2304 SERIALIZE_SCALAR(regs.ptscr); 2305 SERIALIZE_SCALAR(regs.isr); 2306 SERIALIZE_SCALAR(regs.imr); 2307 SERIALIZE_SCALAR(regs.ier); 2308 SERIALIZE_SCALAR(regs.ihr); 2309 SERIALIZE_SCALAR(regs.txdp); 2310 SERIALIZE_SCALAR(regs.txdp_hi); 2311 SERIALIZE_SCALAR(regs.txcfg); 2312 SERIALIZE_SCALAR(regs.gpior); 2313 SERIALIZE_SCALAR(regs.rxdp); 2314 SERIALIZE_SCALAR(regs.rxdp_hi); 2315 SERIALIZE_SCALAR(regs.rxcfg); 2316 SERIALIZE_SCALAR(regs.pqcr); 2317 SERIALIZE_SCALAR(regs.wcsr); 2318 SERIALIZE_SCALAR(regs.pcr); 2319 SERIALIZE_SCALAR(regs.rfcr); 2320 SERIALIZE_SCALAR(regs.rfdr); 2321 SERIALIZE_SCALAR(regs.srr); 2322 SERIALIZE_SCALAR(regs.mibc); 2323 SERIALIZE_SCALAR(regs.vrcr); 2324 SERIALIZE_SCALAR(regs.vtcr); 2325 SERIALIZE_SCALAR(regs.vdr); 2326 SERIALIZE_SCALAR(regs.ccsr); 2327 SERIALIZE_SCALAR(regs.tbicr); 2328 SERIALIZE_SCALAR(regs.tbisr); 2329 SERIALIZE_SCALAR(regs.tanar); 2330 SERIALIZE_SCALAR(regs.tanlpar); 2331 SERIALIZE_SCALAR(regs.taner); 2332 SERIALIZE_SCALAR(regs.tesr); 2333 2334 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2335 2336 SERIALIZE_SCALAR(ioEnable); 2337 2338 /* 2339 * Serialize the data Fifos 2340 */ 2341 int txNumPkts = txFifo.size(); 2342 SERIALIZE_SCALAR(txNumPkts); 2343 int i = 0; 2344 pktiter_t end = txFifo.end(); 2345 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2346 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2347 (*p)->serialize(os); 2348 } 2349 2350 int rxNumPkts = rxFifo.size(); 2351 SERIALIZE_SCALAR(rxNumPkts); 2352 i = 0; 2353 end = rxFifo.end(); 2354 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2355 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2356 (*p)->serialize(os); 2357 } 2358 2359 /* 2360 * Serialize the various helper variables 2361 */ 2362 bool txPacketExists = txPacket; 2363 SERIALIZE_SCALAR(txPacketExists); 2364 if (txPacketExists) { 2365 nameOut(os, csprintf("%s.txPacket", name())); 2366 txPacket->serialize(os); 2367 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2368 SERIALIZE_SCALAR(txPktBufPtr); 2369 } 2370 2371 bool rxPacketExists = rxPacket; 2372 SERIALIZE_SCALAR(rxPacketExists); 2373 if (rxPacketExists) { 2374 nameOut(os, csprintf("%s.rxPacket", name())); 2375 rxPacket->serialize(os); 2376 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2377 SERIALIZE_SCALAR(rxPktBufPtr); 2378 } 2379 2380 SERIALIZE_SCALAR(txXferLen); 2381 SERIALIZE_SCALAR(rxXferLen); 2382 2383 /* 2384 * Serialize DescCaches 2385 */ 2386 SERIALIZE_SCALAR(txDescCache.link); 2387 SERIALIZE_SCALAR(txDescCache.bufptr); 2388 SERIALIZE_SCALAR(txDescCache.cmdsts); 2389 SERIALIZE_SCALAR(txDescCache.extsts); 2390 SERIALIZE_SCALAR(rxDescCache.link); 2391 SERIALIZE_SCALAR(rxDescCache.bufptr); 2392 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2393 SERIALIZE_SCALAR(rxDescCache.extsts); 2394 2395 /* 2396 * Serialize tx state machine 2397 */ 2398 int txState = this->txState; 2399 SERIALIZE_SCALAR(txState); 2400 SERIALIZE_SCALAR(txEnable); 2401 SERIALIZE_SCALAR(CTDD); 2402 SERIALIZE_SCALAR(txFifoAvail); 2403 SERIALIZE_SCALAR(txFragPtr); 2404 SERIALIZE_SCALAR(txDescCnt); 2405 int txDmaState = this->txDmaState; 2406 SERIALIZE_SCALAR(txDmaState); 2407 2408 /* 2409 * Serialize rx state machine 2410 */ 2411 int rxState = this->rxState; 2412 SERIALIZE_SCALAR(rxState); 2413 SERIALIZE_SCALAR(rxEnable); 2414 SERIALIZE_SCALAR(CRDD); 2415 SERIALIZE_SCALAR(rxPktBytes); 2416 SERIALIZE_SCALAR(rxFifoCnt); 2417 SERIALIZE_SCALAR(rxDescCnt); 2418 int rxDmaState = this->rxDmaState; 2419 SERIALIZE_SCALAR(rxDmaState); 2420 2421 SERIALIZE_SCALAR(extstsEnable); 2422 2423 /* 2424 * If there's a pending transmit, store the time so we can 2425 * reschedule it later 2426 */ 2427 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2428 SERIALIZE_SCALAR(transmitTick); 2429 2430 /* 2431 * receive address filter settings 2432 */ 2433 SERIALIZE_SCALAR(rxFilterEnable); 2434 SERIALIZE_SCALAR(acceptBroadcast); 2435 SERIALIZE_SCALAR(acceptMulticast); 2436 SERIALIZE_SCALAR(acceptUnicast); 2437 SERIALIZE_SCALAR(acceptPerfect); 2438 SERIALIZE_SCALAR(acceptArp); 2439 2440 /* 2441 * Keep track of pending interrupt status. 2442 */ 2443 SERIALIZE_SCALAR(intrTick); 2444 SERIALIZE_SCALAR(cpuPendingIntr); 2445 Tick intrEventTick = 0; 2446 if (intrEvent) 2447 intrEventTick = intrEvent->when(); 2448 SERIALIZE_SCALAR(intrEventTick); 2449 2450} 2451 2452void 2453NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2454{ 2455 // Unserialize the PciDev base class 2456 PciDev::unserialize(cp, section); 2457 2458 UNSERIALIZE_SCALAR(regs.command); 2459 UNSERIALIZE_SCALAR(regs.config); 2460 UNSERIALIZE_SCALAR(regs.mear); 2461 UNSERIALIZE_SCALAR(regs.ptscr); 2462 UNSERIALIZE_SCALAR(regs.isr); 2463 UNSERIALIZE_SCALAR(regs.imr); 2464 UNSERIALIZE_SCALAR(regs.ier); 2465 UNSERIALIZE_SCALAR(regs.ihr); 2466 UNSERIALIZE_SCALAR(regs.txdp); 2467 UNSERIALIZE_SCALAR(regs.txdp_hi); 2468 UNSERIALIZE_SCALAR(regs.txcfg); 2469 UNSERIALIZE_SCALAR(regs.gpior); 2470 UNSERIALIZE_SCALAR(regs.rxdp); 2471 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2472 UNSERIALIZE_SCALAR(regs.rxcfg); 2473 UNSERIALIZE_SCALAR(regs.pqcr); 2474 UNSERIALIZE_SCALAR(regs.wcsr); 2475 UNSERIALIZE_SCALAR(regs.pcr); 2476 UNSERIALIZE_SCALAR(regs.rfcr); 2477 UNSERIALIZE_SCALAR(regs.rfdr); 2478 UNSERIALIZE_SCALAR(regs.srr); 2479 UNSERIALIZE_SCALAR(regs.mibc); 2480 UNSERIALIZE_SCALAR(regs.vrcr); 2481 UNSERIALIZE_SCALAR(regs.vtcr); 2482 UNSERIALIZE_SCALAR(regs.vdr); 2483 UNSERIALIZE_SCALAR(regs.ccsr); 2484 UNSERIALIZE_SCALAR(regs.tbicr); 2485 UNSERIALIZE_SCALAR(regs.tbisr); 2486 UNSERIALIZE_SCALAR(regs.tanar); 2487 UNSERIALIZE_SCALAR(regs.tanlpar); 2488 UNSERIALIZE_SCALAR(regs.taner); 2489 UNSERIALIZE_SCALAR(regs.tesr); 2490 2491 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2492 2493 UNSERIALIZE_SCALAR(ioEnable); 2494 2495 /* 2496 * unserialize the data fifos 2497 */ 2498 int txNumPkts; 2499 UNSERIALIZE_SCALAR(txNumPkts); 2500 int i; 2501 for (i = 0; i < txNumPkts; ++i) { 2502 PacketPtr p = new EtherPacket; 2503 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2504 txFifo.push_back(p); 2505 } 2506 2507 int rxNumPkts; 2508 UNSERIALIZE_SCALAR(rxNumPkts); 2509 for (i = 0; i < rxNumPkts; ++i) { 2510 PacketPtr p = new EtherPacket; 2511 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2512 rxFifo.push_back(p); 2513 } 2514 2515 /* 2516 * unserialize the various helper variables 2517 */ 2518 bool txPacketExists; 2519 UNSERIALIZE_SCALAR(txPacketExists); 2520 if (txPacketExists) { 2521 txPacket = new EtherPacket; 2522 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2523 uint32_t txPktBufPtr; 2524 UNSERIALIZE_SCALAR(txPktBufPtr); 2525 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2526 } else 2527 txPacket = 0; 2528 2529 bool rxPacketExists; 2530 UNSERIALIZE_SCALAR(rxPacketExists); 2531 rxPacket = 0; 2532 if (rxPacketExists) { 2533 rxPacket = new EtherPacket; 2534 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2535 uint32_t rxPktBufPtr; 2536 UNSERIALIZE_SCALAR(rxPktBufPtr); 2537 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2538 } else 2539 rxPacket = 0; 2540 2541 UNSERIALIZE_SCALAR(txXferLen); 2542 UNSERIALIZE_SCALAR(rxXferLen); 2543 2544 /* 2545 * Unserialize DescCaches 2546 */ 2547 UNSERIALIZE_SCALAR(txDescCache.link); 2548 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2549 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2550 UNSERIALIZE_SCALAR(txDescCache.extsts); 2551 UNSERIALIZE_SCALAR(rxDescCache.link); 2552 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2553 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2554 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2555 2556 /* 2557 * unserialize tx state machine 2558 */ 2559 int txState; 2560 UNSERIALIZE_SCALAR(txState); 2561 this->txState = (TxState) txState; 2562 UNSERIALIZE_SCALAR(txEnable); 2563 UNSERIALIZE_SCALAR(CTDD); 2564 UNSERIALIZE_SCALAR(txFifoAvail); 2565 UNSERIALIZE_SCALAR(txFragPtr); 2566 UNSERIALIZE_SCALAR(txDescCnt); 2567 int txDmaState; 2568 UNSERIALIZE_SCALAR(txDmaState); 2569 this->txDmaState = (DmaState) txDmaState; 2570 2571 /* 2572 * unserialize rx state machine 2573 */ 2574 int rxState; 2575 UNSERIALIZE_SCALAR(rxState); 2576 this->rxState = (RxState) rxState; 2577 UNSERIALIZE_SCALAR(rxEnable); 2578 UNSERIALIZE_SCALAR(CRDD); 2579 UNSERIALIZE_SCALAR(rxPktBytes); 2580 UNSERIALIZE_SCALAR(rxFifoCnt); 2581 UNSERIALIZE_SCALAR(rxDescCnt); 2582 int rxDmaState; 2583 UNSERIALIZE_SCALAR(rxDmaState); 2584 this->rxDmaState = (DmaState) rxDmaState; 2585 2586 UNSERIALIZE_SCALAR(extstsEnable); 2587 2588 /* 2589 * If there's a pending transmit, reschedule it now 2590 */ 2591 Tick transmitTick; 2592 UNSERIALIZE_SCALAR(transmitTick); 2593 if (transmitTick) 2594 txEvent.schedule(curTick + transmitTick); 2595 2596 /* 2597 * unserialize receive address filter settings 2598 */ 2599 UNSERIALIZE_SCALAR(rxFilterEnable); 2600 UNSERIALIZE_SCALAR(acceptBroadcast); 2601 UNSERIALIZE_SCALAR(acceptMulticast); 2602 UNSERIALIZE_SCALAR(acceptUnicast); 2603 UNSERIALIZE_SCALAR(acceptPerfect); 2604 UNSERIALIZE_SCALAR(acceptArp); 2605 2606 /* 2607 * Keep track of pending interrupt status. 2608 */ 2609 UNSERIALIZE_SCALAR(intrTick); 2610 UNSERIALIZE_SCALAR(cpuPendingIntr); 2611 Tick intrEventTick; 2612 UNSERIALIZE_SCALAR(intrEventTick); 2613 if (intrEventTick) { 2614 intrEvent = new IntrEvent(this, true); 2615 intrEvent->schedule(intrEventTick); 2616 } 2617 2618 /* 2619 * re-add addrRanges to bus bridges 2620 */ 2621 if (pioInterface) { 2622 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2623 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2624 } 2625} 2626 2627Tick 2628NSGigE::cacheAccess(MemReqPtr &req) 2629{ 2630 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2631 req->paddr, req->paddr - addr); 2632 return curTick + pioLatency; 2633} 2634//===================================================================== 2635 2636 2637//********** helper functions****************************************** 2638 2639uint16_t reverseEnd16(uint16_t num) 2640{ 2641 uint16_t reverse = (num & 0xff)<<8; 2642 reverse += ((num & 0xff00) >> 8); 2643 return reverse; 2644} 2645 2646uint32_t reverseEnd32(uint32_t num) 2647{ 2648 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2649 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2650 return reverse; 2651} 2652 2653 2654 2655//===================================================================== 2656 2657BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2658 2659 SimObjectParam<EtherInt *> peer; 2660 SimObjectParam<NSGigE *> device; 2661 2662END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2663 2664BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2665 2666 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2667 INIT_PARAM(device, "Ethernet device of this interface") 2668 2669END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2670 2671CREATE_SIM_OBJECT(NSGigEInt) 2672{ 2673 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2674 2675 EtherInt *p = (EtherInt *)peer; 2676 if (p) { 2677 dev_int->setPeer(p); 2678 p->setPeer(dev_int); 2679 } 2680 2681 return dev_int; 2682} 2683 2684REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2685 2686 2687BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2688 2689 Param<Tick> tx_delay; 2690 Param<Tick> rx_delay; 2691 SimObjectParam<IntrControl *> intr_ctrl; 2692 Param<Tick> intr_delay; 2693 SimObjectParam<MemoryController *> mmu; 2694 SimObjectParam<PhysicalMemory *> physmem; 2695 Param<bool> rx_filter; 2696 Param<string> hardware_address; 2697 SimObjectParam<Bus*> header_bus; 2698 SimObjectParam<Bus*> payload_bus; 2699 SimObjectParam<HierParams *> hier; 2700 Param<Tick> pio_latency; 2701 Param<bool> dma_desc_free; 2702 Param<bool> dma_data_free; 2703 Param<Tick> dma_read_delay; 2704 Param<Tick> dma_write_delay; 2705 Param<Tick> dma_read_factor; 2706 Param<Tick> dma_write_factor; 2707 SimObjectParam<PciConfigAll *> configspace; 2708 SimObjectParam<PciConfigData *> configdata; 2709 SimObjectParam<Tsunami *> tsunami; 2710 Param<uint32_t> pci_bus; 2711 Param<uint32_t> pci_dev; 2712 Param<uint32_t> pci_func; 2713 Param<uint32_t> tx_fifo_size; 2714 Param<uint32_t> rx_fifo_size; 2715 2716END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2717 2718BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2719 2720 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2721 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2722 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2723 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2724 INIT_PARAM(mmu, "Memory Controller"), 2725 INIT_PARAM(physmem, "Physical Memory"), 2726 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2727 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2728 "00:99:00:00:00:01"), 2729 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2730 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2731 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2732 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2733 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2734 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2735 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2736 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2737 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2738 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2739 INIT_PARAM(configspace, "PCI Configspace"), 2740 INIT_PARAM(configdata, "PCI Config data"), 2741 INIT_PARAM(tsunami, "Tsunami"), 2742 INIT_PARAM(pci_bus, "PCI bus"), 2743 INIT_PARAM(pci_dev, "PCI device number"), 2744 INIT_PARAM(pci_func, "PCI function code"), 2745 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2746 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) 2747 2748END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2749 2750 2751CREATE_SIM_OBJECT(NSGigE) 2752{ 2753 int eaddr[6]; 2754 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2755 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2756 2757 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2758 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2759 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2760 dma_read_delay, dma_write_delay, dma_read_factor, 2761 dma_write_factor, configspace, configdata, 2762 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, 2763 tx_fifo_size, rx_fifo_size); 2764} 2765 2766REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2767