ns_gige.cc revision 944
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/ns_gige.hh" 427376Sgblack@eecs.umich.edu#include "dev/etherlink.hh" 437376Sgblack@eecs.umich.edu#include "mem/bus/bus.hh" 447376Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh" 457376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh" 467376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh" 477376Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh" 487376Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh" 497376Sgblack@eecs.umich.edu#include "sim/builder.hh" 507376Sgblack@eecs.umich.edu#include "sim/host.hh" 517376Sgblack@eecs.umich.edu#include "sim/sim_stats.hh" 527376Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh" 537376Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh" 547376Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh" 557376Sgblack@eecs.umich.edu 567376Sgblack@eecs.umich.educonst char *NsRxStateStrings[] = 577376Sgblack@eecs.umich.edu{ 587376Sgblack@eecs.umich.edu "rxIdle", 597376Sgblack@eecs.umich.edu "rxDescRefr", 607376Sgblack@eecs.umich.edu "rxDescRead", 617376Sgblack@eecs.umich.edu "rxFifoBlock", 627376Sgblack@eecs.umich.edu "rxFragWrite", 637376Sgblack@eecs.umich.edu "rxDescWrite", 647376Sgblack@eecs.umich.edu "rxAdvance" 657376Sgblack@eecs.umich.edu}; 667376Sgblack@eecs.umich.edu 677376Sgblack@eecs.umich.educonst char *NsTxStateStrings[] = 687376Sgblack@eecs.umich.edu{ 697376Sgblack@eecs.umich.edu "txIdle", 707376Sgblack@eecs.umich.edu "txDescRefr", 717376Sgblack@eecs.umich.edu "txDescRead", 727376Sgblack@eecs.umich.edu "txFifoBlock", 737376Sgblack@eecs.umich.edu "txFragRead", 747376Sgblack@eecs.umich.edu "txDescWrite", 757376Sgblack@eecs.umich.edu "txAdvance" 767376Sgblack@eecs.umich.edu}; 777376Sgblack@eecs.umich.edu 787376Sgblack@eecs.umich.educonst char *NsDmaState[] = 797376Sgblack@eecs.umich.edu{ 807376Sgblack@eecs.umich.edu "dmaIdle", 817376Sgblack@eecs.umich.edu "dmaReading", 827376Sgblack@eecs.umich.edu "dmaWriting", 837376Sgblack@eecs.umich.edu "dmaReadWaiting", 847376Sgblack@eecs.umich.edu "dmaWriteWaiting" 857376Sgblack@eecs.umich.edu}; 867376Sgblack@eecs.umich.edu 877376Sgblack@eecs.umich.eduusing namespace std; 887376Sgblack@eecs.umich.edu 897376Sgblack@eecs.umich.edu//helper function declarations 907376Sgblack@eecs.umich.edu//These functions reverse Endianness so we can evaluate network data correctly 917376Sgblack@eecs.umich.eduuint16_t reverseEnd16(uint16_t); 927376Sgblack@eecs.umich.eduuint32_t reverseEnd32(uint32_t); 937376Sgblack@eecs.umich.edu 947376Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 957376Sgblack@eecs.umich.edu// 967376Sgblack@eecs.umich.edu// NSGigE PCI Device 977376Sgblack@eecs.umich.edu// 987376Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 997376Sgblack@eecs.umich.edu PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 1007376Sgblack@eecs.umich.edu MemoryController *mmu, HierParams *hier, Bus *header_bus, 1017376Sgblack@eecs.umich.edu Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 1027376Sgblack@eecs.umich.edu bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 1037376Sgblack@eecs.umich.edu Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 1047376Sgblack@eecs.umich.edu PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1057376Sgblack@eecs.umich.edu uint32_t func, bool rx_filter, const int eaddr[6]) 1067376Sgblack@eecs.umich.edu : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 1077376Sgblack@eecs.umich.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1087376Sgblack@eecs.umich.edu txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false), 1097376Sgblack@eecs.umich.edu txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), 1107376Sgblack@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1117376Sgblack@eecs.umich.edu CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 1127376Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1137376Sgblack@eecs.umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1147376Sgblack@eecs.umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1157376Sgblack@eecs.umich.edu dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1167376Sgblack@eecs.umich.edu txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1177376Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1187376Sgblack@eecs.umich.edu acceptMulticast(false), acceptUnicast(false), 1197376Sgblack@eecs.umich.edu acceptPerfect(false), acceptArp(false), 1207376Sgblack@eecs.umich.edu physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 1217376Sgblack@eecs.umich.edu intrEvent(0), interface(0), pioLatency(pio_latency) 1227376Sgblack@eecs.umich.edu{ 1237376Sgblack@eecs.umich.edu tsunami->ethernet = this; 1247376Sgblack@eecs.umich.edu 1257376Sgblack@eecs.umich.edu if (header_bus) { 1267376Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, header_bus, this, 1277376Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1287376Sgblack@eecs.umich.edu 1297376Sgblack@eecs.umich.edu if (payload_bus) 1307376Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1317376Sgblack@eecs.umich.edu header_bus, payload_bus, 1); 1327376Sgblack@eecs.umich.edu else 1337376Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1347376Sgblack@eecs.umich.edu header_bus, header_bus, 1); 1357376Sgblack@eecs.umich.edu } else if (payload_bus) { 1367376Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, payload_bus, this, 1377376Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1387376Sgblack@eecs.umich.edu 1397376Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 1407376Sgblack@eecs.umich.edu payload_bus, 1); 1417376Sgblack@eecs.umich.edu 1427376Sgblack@eecs.umich.edu } 1437376Sgblack@eecs.umich.edu 1447376Sgblack@eecs.umich.edu 1457376Sgblack@eecs.umich.edu intrDelay = US2Ticks(intr_delay); 1467376Sgblack@eecs.umich.edu dmaReadDelay = dma_read_delay; 1477376Sgblack@eecs.umich.edu dmaWriteDelay = dma_write_delay; 1487376Sgblack@eecs.umich.edu dmaReadFactor = dma_read_factor; 1497376Sgblack@eecs.umich.edu dmaWriteFactor = dma_write_factor; 1507376Sgblack@eecs.umich.edu 1517376Sgblack@eecs.umich.edu regsReset(); 1527376Sgblack@eecs.umich.edu rom.perfectMatch[0] = eaddr[0]; 1537376Sgblack@eecs.umich.edu rom.perfectMatch[1] = eaddr[1]; 1547376Sgblack@eecs.umich.edu rom.perfectMatch[2] = eaddr[2]; 1557376Sgblack@eecs.umich.edu rom.perfectMatch[3] = eaddr[3]; 1567376Sgblack@eecs.umich.edu rom.perfectMatch[4] = eaddr[4]; 1577376Sgblack@eecs.umich.edu rom.perfectMatch[5] = eaddr[5]; 1587376Sgblack@eecs.umich.edu} 1597376Sgblack@eecs.umich.edu 1607376Sgblack@eecs.umich.eduNSGigE::~NSGigE() 1617376Sgblack@eecs.umich.edu{} 1627376Sgblack@eecs.umich.edu 1637376Sgblack@eecs.umich.eduvoid 1647376Sgblack@eecs.umich.eduNSGigE::regStats() 1657376Sgblack@eecs.umich.edu{ 1667376Sgblack@eecs.umich.edu txBytes 1677376Sgblack@eecs.umich.edu .name(name() + ".txBytes") 1687376Sgblack@eecs.umich.edu .desc("Bytes Transmitted") 1697376Sgblack@eecs.umich.edu .prereq(txBytes) 1707376Sgblack@eecs.umich.edu ; 1717376Sgblack@eecs.umich.edu 1727376Sgblack@eecs.umich.edu rxBytes 1737376Sgblack@eecs.umich.edu .name(name() + ".rxBytes") 1747376Sgblack@eecs.umich.edu .desc("Bytes Received") 1757376Sgblack@eecs.umich.edu .prereq(rxBytes) 1767376Sgblack@eecs.umich.edu ; 1777376Sgblack@eecs.umich.edu 1787376Sgblack@eecs.umich.edu txPackets 1797376Sgblack@eecs.umich.edu .name(name() + ".txPackets") 1807376Sgblack@eecs.umich.edu .desc("Number of Packets Transmitted") 1817376Sgblack@eecs.umich.edu .prereq(txBytes) 1827376Sgblack@eecs.umich.edu ; 1837376Sgblack@eecs.umich.edu 1847376Sgblack@eecs.umich.edu rxPackets 1857376Sgblack@eecs.umich.edu .name(name() + ".rxPackets") 1867376Sgblack@eecs.umich.edu .desc("Number of Packets Received") 1877376Sgblack@eecs.umich.edu .prereq(rxBytes) 1887322Sgblack@eecs.umich.edu ; 1897322Sgblack@eecs.umich.edu 1907322Sgblack@eecs.umich.edu txBandwidth 1917322Sgblack@eecs.umich.edu .name(name() + ".txBandwidth") 1927322Sgblack@eecs.umich.edu .desc("Transmit Bandwidth (bits/s)") 1937322Sgblack@eecs.umich.edu .precision(0) 1947396Sgblack@eecs.umich.edu .prereq(txBytes) 1957640Sgblack@eecs.umich.edu ; 1967640Sgblack@eecs.umich.edu 1977322Sgblack@eecs.umich.edu rxBandwidth 1987396Sgblack@eecs.umich.edu .name(name() + ".rxBandwidth") 1997396Sgblack@eecs.umich.edu .desc("Receive Bandwidth (bits/s)") 2007322Sgblack@eecs.umich.edu .precision(0) 2017324Sgblack@eecs.umich.edu .prereq(rxBytes) 2027643Sgblack@eecs.umich.edu ; 2037643Sgblack@eecs.umich.edu 2047643Sgblack@eecs.umich.edu txPacketRate 2057643Sgblack@eecs.umich.edu .name(name() + ".txPPS") 2067643Sgblack@eecs.umich.edu .desc("Packet Tranmission Rate (packets/s)") 2077643Sgblack@eecs.umich.edu .precision(0) 2087643Sgblack@eecs.umich.edu .prereq(txBytes) 2097643Sgblack@eecs.umich.edu ; 2107643Sgblack@eecs.umich.edu 2117643Sgblack@eecs.umich.edu rxPacketRate 2127643Sgblack@eecs.umich.edu .name(name() + ".rxPPS") 2137396Sgblack@eecs.umich.edu .desc("Packet Reception Rate (packets/s)") 2147640Sgblack@eecs.umich.edu .precision(0) 2157640Sgblack@eecs.umich.edu .prereq(rxBytes) 2167324Sgblack@eecs.umich.edu ; 2177396Sgblack@eecs.umich.edu 2187396Sgblack@eecs.umich.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2197324Sgblack@eecs.umich.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2207333Sgblack@eecs.umich.edu txPacketRate = txPackets / simSeconds; 2217643Sgblack@eecs.umich.edu rxPacketRate = rxPackets / simSeconds; 2227643Sgblack@eecs.umich.edu} 2237643Sgblack@eecs.umich.edu 2247643Sgblack@eecs.umich.edu/** 2257643Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers 2267643Sgblack@eecs.umich.edu */ 2277643Sgblack@eecs.umich.eduvoid 2287643Sgblack@eecs.umich.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2297643Sgblack@eecs.umich.edu{ 2307643Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 2317643Sgblack@eecs.umich.edu PciDev::ReadConfig(offset, size, data); 2327396Sgblack@eecs.umich.edu else 2337392Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 2347392Sgblack@eecs.umich.edu} 2357396Sgblack@eecs.umich.edu 2367396Sgblack@eecs.umich.edu/** 2377392Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 2387392Sgblack@eecs.umich.edu */ 2397643Sgblack@eecs.umich.eduvoid 2407643Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 2417643Sgblack@eecs.umich.edu{ 2427643Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 2437643Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 2447643Sgblack@eecs.umich.edu else 2457643Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 2467643Sgblack@eecs.umich.edu 2477643Sgblack@eecs.umich.edu // Need to catch writes to BARs to update the PIO interface 2487643Sgblack@eecs.umich.edu switch (offset) { 2497643Sgblack@eecs.umich.edu //seems to work fine without all these PCI settings, but i put in the IO 2507640Sgblack@eecs.umich.edu //to double check, an assertion will fail if we need to properly 2517333Sgblack@eecs.umich.edu // implement it 2527333Sgblack@eecs.umich.edu case PCI_COMMAND: 2537396Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 2547333Sgblack@eecs.umich.edu ioEnable = true; 2557333Sgblack@eecs.umich.edu else 2567396Sgblack@eecs.umich.edu ioEnable = false; 2577396Sgblack@eecs.umich.edu 2587333Sgblack@eecs.umich.edu#if 0 2597333Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_BME) { 2607640Sgblack@eecs.umich.edu bmEnabled = true; 2617333Sgblack@eecs.umich.edu } 2627333Sgblack@eecs.umich.edu else { 2637333Sgblack@eecs.umich.edu bmEnabled = false; 2647396Sgblack@eecs.umich.edu } 2657333Sgblack@eecs.umich.edu 2667333Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_MSE) { 2677396Sgblack@eecs.umich.edu memEnable = true; 2687396Sgblack@eecs.umich.edu } 2697333Sgblack@eecs.umich.edu else { 2707333Sgblack@eecs.umich.edu memEnable = false; 2717640Sgblack@eecs.umich.edu } 2727333Sgblack@eecs.umich.edu#endif 2737333Sgblack@eecs.umich.edu break; 2747333Sgblack@eecs.umich.edu 2757333Sgblack@eecs.umich.edu case PCI0_BASE_ADDR0: 2767333Sgblack@eecs.umich.edu if (BARAddrs[0] != 0) { 2777396Sgblack@eecs.umich.edu 2787333Sgblack@eecs.umich.edu if (pioInterface) 2797333Sgblack@eecs.umich.edu pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2807396Sgblack@eecs.umich.edu 2817396Sgblack@eecs.umich.edu BARAddrs[0] &= PA_UNCACHED_MASK; 2827333Sgblack@eecs.umich.edu 2837333Sgblack@eecs.umich.edu } 2847640Sgblack@eecs.umich.edu break; 2857333Sgblack@eecs.umich.edu case PCI0_BASE_ADDR1: 2867333Sgblack@eecs.umich.edu if (BARAddrs[1] != 0) { 2877396Sgblack@eecs.umich.edu 2887333Sgblack@eecs.umich.edu if (pioInterface) 2897333Sgblack@eecs.umich.edu pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2907396Sgblack@eecs.umich.edu 2917396Sgblack@eecs.umich.edu BARAddrs[1] &= PA_UNCACHED_MASK; 2927333Sgblack@eecs.umich.edu 2937333Sgblack@eecs.umich.edu } 2947640Sgblack@eecs.umich.edu break; 2957333Sgblack@eecs.umich.edu } 2967333Sgblack@eecs.umich.edu} 2977333Sgblack@eecs.umich.edu 2987396Sgblack@eecs.umich.edu/** 2997333Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 3007333Sgblack@eecs.umich.edu * spec sheet 3017396Sgblack@eecs.umich.edu */ 3027396Sgblack@eecs.umich.eduFault 3037333Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3047333Sgblack@eecs.umich.edu{ 3057640Sgblack@eecs.umich.edu assert(ioEnable); 3067333Sgblack@eecs.umich.edu 3077333Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 3087333Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 3097333Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3107333Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 3117396Sgblack@eecs.umich.edu 3127333Sgblack@eecs.umich.edu 3137333Sgblack@eecs.umich.edu //there are some reserved registers, you can see ns_gige_reg.h and 3147396Sgblack@eecs.umich.edu //the spec sheet for details 3157396Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 3167333Sgblack@eecs.umich.edu panic("Accessing reserved register"); 3177333Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 3187640Sgblack@eecs.umich.edu ReadConfig(daddr & 0xff, req->size, data); 3197639Sgblack@eecs.umich.edu return No_Fault; 3207333Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 3217396Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 3227333Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 3237333Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 3247396Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *) data; 3257396Sgblack@eecs.umich.edu reg = 0; 3267333Sgblack@eecs.umich.edu return No_Fault; 3277333Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 3287640Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 3297639Sgblack@eecs.umich.edu 3307333Sgblack@eecs.umich.edu switch (req->size) { 3317396Sgblack@eecs.umich.edu case sizeof(uint32_t): 3327333Sgblack@eecs.umich.edu { 3337333Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *)data; 3347396Sgblack@eecs.umich.edu 3357396Sgblack@eecs.umich.edu switch (daddr) { 3367333Sgblack@eecs.umich.edu case CR: 3377333Sgblack@eecs.umich.edu reg = regs.command; 3387640Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 3397333Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3407333Sgblack@eecs.umich.edu break; 3417396Sgblack@eecs.umich.edu 3427333Sgblack@eecs.umich.edu case CFG: 3437333Sgblack@eecs.umich.edu reg = regs.config; 3447396Sgblack@eecs.umich.edu break; 3457396Sgblack@eecs.umich.edu 3467333Sgblack@eecs.umich.edu case MEAR: 3477333Sgblack@eecs.umich.edu reg = regs.mear; 3487640Sgblack@eecs.umich.edu break; 3497639Sgblack@eecs.umich.edu 3507639Sgblack@eecs.umich.edu case PTSCR: 3517333Sgblack@eecs.umich.edu reg = regs.ptscr; 3527396Sgblack@eecs.umich.edu break; 3537333Sgblack@eecs.umich.edu 3547333Sgblack@eecs.umich.edu case ISR: 3557396Sgblack@eecs.umich.edu reg = regs.isr; 3567396Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 3577333Sgblack@eecs.umich.edu break; 3587333Sgblack@eecs.umich.edu 3597640Sgblack@eecs.umich.edu case IMR: 3607639Sgblack@eecs.umich.edu reg = regs.imr; 3617639Sgblack@eecs.umich.edu break; 3627333Sgblack@eecs.umich.edu 3637396Sgblack@eecs.umich.edu case IER: 3647333Sgblack@eecs.umich.edu reg = regs.ier; 3657333Sgblack@eecs.umich.edu break; 3667396Sgblack@eecs.umich.edu 3677396Sgblack@eecs.umich.edu case IHR: 3687333Sgblack@eecs.umich.edu reg = regs.ihr; 3697333Sgblack@eecs.umich.edu break; 3707640Sgblack@eecs.umich.edu 3717639Sgblack@eecs.umich.edu case TXDP: 3727639Sgblack@eecs.umich.edu reg = regs.txdp; 3737333Sgblack@eecs.umich.edu break; 3747396Sgblack@eecs.umich.edu 3757333Sgblack@eecs.umich.edu case TXDP_HI: 3767333Sgblack@eecs.umich.edu reg = regs.txdp_hi; 3777396Sgblack@eecs.umich.edu break; 3787396Sgblack@eecs.umich.edu 3797333Sgblack@eecs.umich.edu case TXCFG: 3807333Sgblack@eecs.umich.edu reg = regs.txcfg; 3817640Sgblack@eecs.umich.edu break; 3827639Sgblack@eecs.umich.edu 3837639Sgblack@eecs.umich.edu case GPIOR: 3847333Sgblack@eecs.umich.edu reg = regs.gpior; 3857396Sgblack@eecs.umich.edu break; 3867333Sgblack@eecs.umich.edu 3877333Sgblack@eecs.umich.edu case RXDP: 3887396Sgblack@eecs.umich.edu reg = regs.rxdp; 3897396Sgblack@eecs.umich.edu break; 3907333Sgblack@eecs.umich.edu 3917333Sgblack@eecs.umich.edu case RXDP_HI: 3927640Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 3937333Sgblack@eecs.umich.edu break; 3947333Sgblack@eecs.umich.edu 3957396Sgblack@eecs.umich.edu case RXCFG: 3967333Sgblack@eecs.umich.edu reg = regs.rxcfg; 3977333Sgblack@eecs.umich.edu break; 3987396Sgblack@eecs.umich.edu 3997396Sgblack@eecs.umich.edu case PQCR: 4007333Sgblack@eecs.umich.edu reg = regs.pqcr; 4017333Sgblack@eecs.umich.edu break; 4027640Sgblack@eecs.umich.edu 4037333Sgblack@eecs.umich.edu case WCSR: 4047333Sgblack@eecs.umich.edu reg = regs.wcsr; 4057333Sgblack@eecs.umich.edu break; 4067396Sgblack@eecs.umich.edu 4077333Sgblack@eecs.umich.edu case PCR: 4087333Sgblack@eecs.umich.edu reg = regs.pcr; 4097396Sgblack@eecs.umich.edu break; 4107396Sgblack@eecs.umich.edu 4117333Sgblack@eecs.umich.edu //see the spec sheet for how RFCR and RFDR work 4127333Sgblack@eecs.umich.edu //basically, you write to RFCR to tell the machine what you want to do next 4137640Sgblack@eecs.umich.edu //then you act upon RFDR, and the device will be prepared b/c 4147333Sgblack@eecs.umich.edu //of what you wrote to RFCR 4157333Sgblack@eecs.umich.edu case RFCR: 4167333Sgblack@eecs.umich.edu reg = regs.rfcr; 4177396Sgblack@eecs.umich.edu break; 4187333Sgblack@eecs.umich.edu 4197333Sgblack@eecs.umich.edu case RFDR: 4207396Sgblack@eecs.umich.edu switch (regs.rfcr & RFCR_RFADDR) { 4217396Sgblack@eecs.umich.edu case 0x000: 4227333Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 4237381Sgblack@eecs.umich.edu reg = reg << 8; 4247381Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 4257381Sgblack@eecs.umich.edu break; 4267381Sgblack@eecs.umich.edu case 0x002: 4277381Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 4287381Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 4297381Sgblack@eecs.umich.edu break; 4307364Sgblack@eecs.umich.edu case 0x004: 4317640Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 4327643Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 4337396Sgblack@eecs.umich.edu break; 4347643Sgblack@eecs.umich.edu default: 4357364Sgblack@eecs.umich.edu panic("reading from RFDR for something for other than PMATCH!\n"); 4367396Sgblack@eecs.umich.edu //didn't implement other RFDR functionality b/c driver didn't use 4377639Sgblack@eecs.umich.edu } 4387396Sgblack@eecs.umich.edu break; 4397640Sgblack@eecs.umich.edu 4407643Sgblack@eecs.umich.edu case SRR: 4417396Sgblack@eecs.umich.edu reg = regs.srr; 4427643Sgblack@eecs.umich.edu break; 4437396Sgblack@eecs.umich.edu 4447396Sgblack@eecs.umich.edu case MIBC: 4457396Sgblack@eecs.umich.edu reg = regs.mibc; 4467396Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 4477396Sgblack@eecs.umich.edu break; 4487396Sgblack@eecs.umich.edu 4497639Sgblack@eecs.umich.edu case VRCR: 4507396Sgblack@eecs.umich.edu reg = regs.vrcr; 4517396Sgblack@eecs.umich.edu break; 4527396Sgblack@eecs.umich.edu 4537396Sgblack@eecs.umich.edu case VTCR: 4547396Sgblack@eecs.umich.edu reg = regs.vtcr; 4557364Sgblack@eecs.umich.edu break; 4567396Sgblack@eecs.umich.edu 4577396Sgblack@eecs.umich.edu case VDR: 4587365Sgblack@eecs.umich.edu reg = regs.vdr; 4597396Sgblack@eecs.umich.edu break; 4607396Sgblack@eecs.umich.edu 4617396Sgblack@eecs.umich.edu case CCSR: 4627396Sgblack@eecs.umich.edu reg = regs.ccsr; 4637396Sgblack@eecs.umich.edu break; 4647396Sgblack@eecs.umich.edu 4657396Sgblack@eecs.umich.edu case TBICR: 4667396Sgblack@eecs.umich.edu reg = regs.tbicr; 4677365Sgblack@eecs.umich.edu break; 4687396Sgblack@eecs.umich.edu 4697396Sgblack@eecs.umich.edu case TBISR: 4707366Sgblack@eecs.umich.edu reg = regs.tbisr; 4717396Sgblack@eecs.umich.edu break; 4727396Sgblack@eecs.umich.edu 4737396Sgblack@eecs.umich.edu case TANAR: 4747396Sgblack@eecs.umich.edu reg = regs.tanar; 4757366Sgblack@eecs.umich.edu break; 4767396Sgblack@eecs.umich.edu 4777396Sgblack@eecs.umich.edu case TANLPAR: 4787396Sgblack@eecs.umich.edu reg = regs.tanlpar; 4797396Sgblack@eecs.umich.edu break; 4807367Sgblack@eecs.umich.edu 4817396Sgblack@eecs.umich.edu case TANER: 4827396Sgblack@eecs.umich.edu reg = regs.taner; 4837396Sgblack@eecs.umich.edu break; 4847396Sgblack@eecs.umich.edu 4857367Sgblack@eecs.umich.edu case TESR: 4867396Sgblack@eecs.umich.edu reg = regs.tesr; 4877396Sgblack@eecs.umich.edu break; 4887396Sgblack@eecs.umich.edu 4897396Sgblack@eecs.umich.edu default: 4907396Sgblack@eecs.umich.edu panic("reading unimplemented register: addr = %#x", daddr); 4917396Sgblack@eecs.umich.edu } 4927396Sgblack@eecs.umich.edu 4937396Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 4947368Sgblack@eecs.umich.edu daddr, reg, reg); 4957396Sgblack@eecs.umich.edu } 4967396Sgblack@eecs.umich.edu break; 4977368Sgblack@eecs.umich.edu 4987396Sgblack@eecs.umich.edu default: 4997396Sgblack@eecs.umich.edu panic("accessing register with invalid size: addr=%#x, size=%d", 5007396Sgblack@eecs.umich.edu daddr, req->size); 5017396Sgblack@eecs.umich.edu } 5027369Sgblack@eecs.umich.edu 5037396Sgblack@eecs.umich.edu return No_Fault; 5047369Sgblack@eecs.umich.edu} 5057396Sgblack@eecs.umich.edu 5067396Sgblack@eecs.umich.eduFault 5077396Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data) 5087396Sgblack@eecs.umich.edu{ 5097369Sgblack@eecs.umich.edu assert(ioEnable); 5107396Sgblack@eecs.umich.edu 5117396Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 5127396Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5137396Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 5147396Sgblack@eecs.umich.edu 5157396Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 5167369Sgblack@eecs.umich.edu panic("Accessing reserved register"); 5177396Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 5187396Sgblack@eecs.umich.edu WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5197396Sgblack@eecs.umich.edu return No_Fault; 5207396Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 5217396Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 5227396Sgblack@eecs.umich.edu 5237396Sgblack@eecs.umich.edu if (req->size == sizeof(uint32_t)) { 5247396Sgblack@eecs.umich.edu uint32_t reg = *(uint32_t *)data; 5257396Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5267396Sgblack@eecs.umich.edu 5277396Sgblack@eecs.umich.edu switch (daddr) { 5287396Sgblack@eecs.umich.edu case CR: 5297381Sgblack@eecs.umich.edu regs.command = reg; 5307381Sgblack@eecs.umich.edu if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 5317381Sgblack@eecs.umich.edu txHalt = true; 5327381Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 5337381Sgblack@eecs.umich.edu //the kernel is enabling the transmit machine 5347381Sgblack@eecs.umich.edu if (txState == txIdle) 5357381Sgblack@eecs.umich.edu txKick(); 5367370Sgblack@eecs.umich.edu } else if (reg & CR_TXD) { 5377640Sgblack@eecs.umich.edu txHalt = true; 5387643Sgblack@eecs.umich.edu } 5397396Sgblack@eecs.umich.edu 5407639Sgblack@eecs.umich.edu if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 5417639Sgblack@eecs.umich.edu rxHalt = true; 5427639Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 5437643Sgblack@eecs.umich.edu if (rxState == rxIdle) { 5447370Sgblack@eecs.umich.edu rxKick(); 5457396Sgblack@eecs.umich.edu } 5467370Sgblack@eecs.umich.edu } else if (reg & CR_RXD) { 5477370Sgblack@eecs.umich.edu rxHalt = true; 5487396Sgblack@eecs.umich.edu } 5497396Sgblack@eecs.umich.edu 5507370Sgblack@eecs.umich.edu if (reg & CR_TXR) 5517370Sgblack@eecs.umich.edu txReset(); 5527640Sgblack@eecs.umich.edu 5537643Sgblack@eecs.umich.edu if (reg & CR_RXR) 5547396Sgblack@eecs.umich.edu rxReset(); 5557396Sgblack@eecs.umich.edu 5567639Sgblack@eecs.umich.edu if (reg & CR_SWI) 5577396Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 5587639Sgblack@eecs.umich.edu 5597639Sgblack@eecs.umich.edu if (reg & CR_RST) { 5607643Sgblack@eecs.umich.edu txReset(); 5617396Sgblack@eecs.umich.edu rxReset(); 5627396Sgblack@eecs.umich.edu 5637370Sgblack@eecs.umich.edu regsReset(); 5647396Sgblack@eecs.umich.edu } 5657370Sgblack@eecs.umich.edu break; 5667370Sgblack@eecs.umich.edu 5677396Sgblack@eecs.umich.edu case CFG: 5687396Sgblack@eecs.umich.edu if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS 5697370Sgblack@eecs.umich.edu || reg & CFG_RESERVED || reg & CFG_T64ADDR 5707370Sgblack@eecs.umich.edu || reg & CFG_PCI64_DET) 5717640Sgblack@eecs.umich.edu panic("writing to read-only or reserved CFG bits!\n"); 5727643Sgblack@eecs.umich.edu 5737396Sgblack@eecs.umich.edu regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED | 5747639Sgblack@eecs.umich.edu CFG_T64ADDR | CFG_PCI64_DET); 5757639Sgblack@eecs.umich.edu 5767639Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to have these implemented 5777643Sgblack@eecs.umich.edu// if there is a problem relating to one of these, you may need to add functionality in 5787370Sgblack@eecs.umich.edu#if 0 5797396Sgblack@eecs.umich.edu if (reg & CFG_TBI_EN) ; 5807370Sgblack@eecs.umich.edu if (reg & CFG_MODE_1000) ; 5817370Sgblack@eecs.umich.edu#endif 5827396Sgblack@eecs.umich.edu 5837396Sgblack@eecs.umich.edu if (reg & CFG_AUTO_1000) 5847370Sgblack@eecs.umich.edu panic("CFG_AUTO_1000 not implemented!\n"); 5857370Sgblack@eecs.umich.edu 5867640Sgblack@eecs.umich.edu#if 0 5877643Sgblack@eecs.umich.edu if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; 5887396Sgblack@eecs.umich.edu if (reg & CFG_TMRTEST) ; 5897396Sgblack@eecs.umich.edu if (reg & CFG_MRM_DIS) ; 5907639Sgblack@eecs.umich.edu if (reg & CFG_MWI_DIS) ; 5917396Sgblack@eecs.umich.edu 5927639Sgblack@eecs.umich.edu if (reg & CFG_T64ADDR) 5937639Sgblack@eecs.umich.edu panic("CFG_T64ADDR is read only register!\n"); 5947643Sgblack@eecs.umich.edu 5957396Sgblack@eecs.umich.edu if (reg & CFG_PCI64_DET) 5967396Sgblack@eecs.umich.edu panic("CFG_PCI64_DET is read only register!\n"); 5977370Sgblack@eecs.umich.edu 5987396Sgblack@eecs.umich.edu if (reg & CFG_DATA64_EN) ; 5997370Sgblack@eecs.umich.edu if (reg & CFG_M64ADDR) ; 6007370Sgblack@eecs.umich.edu if (reg & CFG_PHY_RST) ; 6017396Sgblack@eecs.umich.edu if (reg & CFG_PHY_DIS) ; 6027396Sgblack@eecs.umich.edu#endif 6037370Sgblack@eecs.umich.edu 6047371Sgblack@eecs.umich.edu if (reg & CFG_EXTSTS_EN) 6057640Sgblack@eecs.umich.edu extstsEnable = true; 6067643Sgblack@eecs.umich.edu else 6077396Sgblack@eecs.umich.edu extstsEnable = false; 6087639Sgblack@eecs.umich.edu 6097639Sgblack@eecs.umich.edu#if 0 6107639Sgblack@eecs.umich.edu if (reg & CFG_REQALG) ; 6117643Sgblack@eecs.umich.edu if (reg & CFG_SB) ; 6127371Sgblack@eecs.umich.edu if (reg & CFG_POW) ; 6137396Sgblack@eecs.umich.edu if (reg & CFG_EXD) ; 6147371Sgblack@eecs.umich.edu if (reg & CFG_PESEL) ; 6157371Sgblack@eecs.umich.edu if (reg & CFG_BROM_DIS) ; 6167396Sgblack@eecs.umich.edu if (reg & CFG_EXT_125) ; 6177396Sgblack@eecs.umich.edu if (reg & CFG_BEM) ; 6187371Sgblack@eecs.umich.edu#endif 6197371Sgblack@eecs.umich.edu break; 6207640Sgblack@eecs.umich.edu 6217643Sgblack@eecs.umich.edu case MEAR: 6227396Sgblack@eecs.umich.edu regs.mear = reg; 6237396Sgblack@eecs.umich.edu /* since phy is completely faked, MEAR_MD* don't matter 6247639Sgblack@eecs.umich.edu and since the driver never uses MEAR_EE*, they don't matter */ 6257396Sgblack@eecs.umich.edu#if 0 6267639Sgblack@eecs.umich.edu if (reg & MEAR_EEDI) ; 6277639Sgblack@eecs.umich.edu if (reg & MEAR_EEDO) ; //this one is read only 6287643Sgblack@eecs.umich.edu if (reg & MEAR_EECLK) ; 6297396Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) ; 6307396Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 6317371Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 6327396Sgblack@eecs.umich.edu if (reg & MEAR_MDC) ; 6337371Sgblack@eecs.umich.edu#endif 6347371Sgblack@eecs.umich.edu break; 6357396Sgblack@eecs.umich.edu 6367396Sgblack@eecs.umich.edu case PTSCR: 6377371Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 6387371Sgblack@eecs.umich.edu /* these control BISTs for various parts of chip - we don't care or do 6397640Sgblack@eecs.umich.edu just fake that the BIST is done */ 6407643Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 6417396Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 6427639Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 6437639Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 6447639Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 6457643Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 6467371Sgblack@eecs.umich.edu break; 6477396Sgblack@eecs.umich.edu 6487371Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 6497371Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 6507396Sgblack@eecs.umich.edu 6517396Sgblack@eecs.umich.edu case IMR: 6527371Sgblack@eecs.umich.edu regs.imr = reg; 6537371Sgblack@eecs.umich.edu devIntrChangeMask(); 6547640Sgblack@eecs.umich.edu break; 6557643Sgblack@eecs.umich.edu 6567396Sgblack@eecs.umich.edu case IER: 6577396Sgblack@eecs.umich.edu regs.ier = reg; 6587639Sgblack@eecs.umich.edu break; 6597396Sgblack@eecs.umich.edu 6607639Sgblack@eecs.umich.edu case IHR: 6617639Sgblack@eecs.umich.edu regs.ihr = reg; 6627643Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 6637396Sgblack@eecs.umich.edu break; 6647396Sgblack@eecs.umich.edu 6657371Sgblack@eecs.umich.edu case TXDP: 6667396Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 6677371Sgblack@eecs.umich.edu assert(txState == txIdle); 6687371Sgblack@eecs.umich.edu CTDD = false; 6697396Sgblack@eecs.umich.edu break; 6707396Sgblack@eecs.umich.edu 6717371Sgblack@eecs.umich.edu case TXDP_HI: 6727371Sgblack@eecs.umich.edu regs.txdp_hi = reg; 6737640Sgblack@eecs.umich.edu break; 6747643Sgblack@eecs.umich.edu 6757639Sgblack@eecs.umich.edu case TXCFG: 6767639Sgblack@eecs.umich.edu regs.txcfg = reg; 6777643Sgblack@eecs.umich.edu#if 0 6787371Sgblack@eecs.umich.edu if (reg & TXCFG_CSI) ; 6797396Sgblack@eecs.umich.edu if (reg & TXCFG_HBI) ; 6807371Sgblack@eecs.umich.edu if (reg & TXCFG_MLB) ; 6817371Sgblack@eecs.umich.edu if (reg & TXCFG_ATP) ; 6827396Sgblack@eecs.umich.edu if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but 6837396Sgblack@eecs.umich.edu considering the network is just a fake 6847371Sgblack@eecs.umich.edu pipe, wouldn't make sense to do this */ 6857371Sgblack@eecs.umich.edu 6867640Sgblack@eecs.umich.edu if (reg & TXCFG_BRST_DIS) ; 6877643Sgblack@eecs.umich.edu#endif 6887396Sgblack@eecs.umich.edu 6897396Sgblack@eecs.umich.edu 6907639Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 6917639Sgblack@eecs.umich.edu //if (reg & TXCFG_MXDMA) ; 6927643Sgblack@eecs.umich.edu 6937396Sgblack@eecs.umich.edu //also, we currently don't care about fill/drain thresholds 6947396Sgblack@eecs.umich.edu //though this may change in the future with more realistic 6957371Sgblack@eecs.umich.edu //networks or a driver which changes it according to feedback 6967396Sgblack@eecs.umich.edu 6977371Sgblack@eecs.umich.edu break; 6987371Sgblack@eecs.umich.edu 6997396Sgblack@eecs.umich.edu case GPIOR: 7007396Sgblack@eecs.umich.edu regs.gpior = reg; 7017371Sgblack@eecs.umich.edu /* these just control general purpose i/o pins, don't matter */ 7027381Sgblack@eecs.umich.edu break; 7037381Sgblack@eecs.umich.edu 7047381Sgblack@eecs.umich.edu case RXDP: 7057381Sgblack@eecs.umich.edu regs.rxdp = reg; 7067381Sgblack@eecs.umich.edu break; 7077381Sgblack@eecs.umich.edu 7087381Sgblack@eecs.umich.edu case RXDP_HI: 7097373Sgblack@eecs.umich.edu regs.rxdp_hi = reg; 7107640Sgblack@eecs.umich.edu break; 7117643Sgblack@eecs.umich.edu 7127397Sgblack@eecs.umich.edu case RXCFG: 7137381Sgblack@eecs.umich.edu regs.rxcfg = reg; 7147373Sgblack@eecs.umich.edu#if 0 7157381Sgblack@eecs.umich.edu if (reg & RXCFG_AEP) ; 7167639Sgblack@eecs.umich.edu if (reg & RXCFG_ARP) ; 7177643Sgblack@eecs.umich.edu if (reg & RXCFG_STRIPCRC) ; 7187373Sgblack@eecs.umich.edu if (reg & RXCFG_RX_RD) ; 7197396Sgblack@eecs.umich.edu if (reg & RXCFG_ALP) ; 7207373Sgblack@eecs.umich.edu if (reg & RXCFG_AIRL) ; 7217373Sgblack@eecs.umich.edu#endif 7227396Sgblack@eecs.umich.edu 7237396Sgblack@eecs.umich.edu /* we handle our own DMA, ignore what kernel says about it */ 7247373Sgblack@eecs.umich.edu //if (reg & RXCFG_MXDMA) ; 7257373Sgblack@eecs.umich.edu 7267640Sgblack@eecs.umich.edu#if 0 7277643Sgblack@eecs.umich.edu //also, we currently don't care about fill/drain thresholds 7287397Sgblack@eecs.umich.edu //though this may change in the future with more realistic 7297381Sgblack@eecs.umich.edu //networks or a driver which changes it according to feedback 7307397Sgblack@eecs.umich.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 7317397Sgblack@eecs.umich.edu#endif 7327639Sgblack@eecs.umich.edu break; 7337643Sgblack@eecs.umich.edu 7347397Sgblack@eecs.umich.edu case PQCR: 7357397Sgblack@eecs.umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 7367373Sgblack@eecs.umich.edu regs.pqcr = reg; 7377396Sgblack@eecs.umich.edu break; 7387373Sgblack@eecs.umich.edu 7397373Sgblack@eecs.umich.edu case WCSR: 7407396Sgblack@eecs.umich.edu /* not going to implement wake on LAN */ 7417396Sgblack@eecs.umich.edu regs.wcsr = reg; 7427373Sgblack@eecs.umich.edu break; 7437373Sgblack@eecs.umich.edu 7447640Sgblack@eecs.umich.edu case PCR: 7457643Sgblack@eecs.umich.edu /* not going to implement pause control */ 7467397Sgblack@eecs.umich.edu regs.pcr = reg; 7477381Sgblack@eecs.umich.edu break; 7487373Sgblack@eecs.umich.edu 7497381Sgblack@eecs.umich.edu case RFCR: 7507639Sgblack@eecs.umich.edu regs.rfcr = reg; 7517643Sgblack@eecs.umich.edu 7527373Sgblack@eecs.umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 7537396Sgblack@eecs.umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 7547373Sgblack@eecs.umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 7557373Sgblack@eecs.umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 7567396Sgblack@eecs.umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 7577396Sgblack@eecs.umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 7587373Sgblack@eecs.umich.edu 7597373Sgblack@eecs.umich.edu if (reg & RFCR_APAT) ; 7607640Sgblack@eecs.umich.edu// panic("RFCR_APAT not implemented!\n"); 7617643Sgblack@eecs.umich.edu 7627397Sgblack@eecs.umich.edu if (reg & RFCR_MHEN || reg & RFCR_UHEN) 7637381Sgblack@eecs.umich.edu panic("hash filtering not implemented!\n"); 7647397Sgblack@eecs.umich.edu 7657397Sgblack@eecs.umich.edu if (reg & RFCR_ULM) 7667639Sgblack@eecs.umich.edu panic("RFCR_ULM not implemented!\n"); 7677643Sgblack@eecs.umich.edu 7687397Sgblack@eecs.umich.edu break; 7697397Sgblack@eecs.umich.edu 7707373Sgblack@eecs.umich.edu case RFDR: 7717396Sgblack@eecs.umich.edu panic("the driver never writes to RFDR, something is wrong!\n"); 7727373Sgblack@eecs.umich.edu 7737373Sgblack@eecs.umich.edu case BRAR: 7747396Sgblack@eecs.umich.edu panic("the driver never uses BRAR, something is wrong!\n"); 7757396Sgblack@eecs.umich.edu 7767373Sgblack@eecs.umich.edu case BRDR: 7777373Sgblack@eecs.umich.edu panic("the driver never uses BRDR, something is wrong!\n"); 7787640Sgblack@eecs.umich.edu 7797643Sgblack@eecs.umich.edu case SRR: 7807397Sgblack@eecs.umich.edu panic("SRR is read only register!\n"); 7817397Sgblack@eecs.umich.edu 7827381Sgblack@eecs.umich.edu case MIBC: 7837388Sgblack@eecs.umich.edu panic("the driver never uses MIBC, something is wrong!\n"); 7847381Sgblack@eecs.umich.edu 7857639Sgblack@eecs.umich.edu case VRCR: 7867643Sgblack@eecs.umich.edu regs.vrcr = reg; 7877380Sgblack@eecs.umich.edu break; 7887396Sgblack@eecs.umich.edu 7897380Sgblack@eecs.umich.edu case VTCR: 7907380Sgblack@eecs.umich.edu regs.vtcr = reg; 7917396Sgblack@eecs.umich.edu break; 7927396Sgblack@eecs.umich.edu 7937380Sgblack@eecs.umich.edu case VDR: 7947380Sgblack@eecs.umich.edu panic("the driver never uses VDR, something is wrong!\n"); 7957640Sgblack@eecs.umich.edu break; 7967643Sgblack@eecs.umich.edu 7977397Sgblack@eecs.umich.edu case CCSR: 7987397Sgblack@eecs.umich.edu /* not going to implement clockrun stuff */ 7997397Sgblack@eecs.umich.edu regs.ccsr = reg; 8007397Sgblack@eecs.umich.edu break; 8017397Sgblack@eecs.umich.edu 8027381Sgblack@eecs.umich.edu case TBICR: 8037639Sgblack@eecs.umich.edu regs.tbicr = reg; 8047643Sgblack@eecs.umich.edu if (reg & TBICR_MR_LOOPBACK) 8057380Sgblack@eecs.umich.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8067380Sgblack@eecs.umich.edu 8077396Sgblack@eecs.umich.edu if (reg & TBICR_MR_AN_ENABLE) { 8087380Sgblack@eecs.umich.edu regs.tanlpar = regs.tanar; 8097380Sgblack@eecs.umich.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8107396Sgblack@eecs.umich.edu } 8117396Sgblack@eecs.umich.edu 8127380Sgblack@eecs.umich.edu#if 0 8137380Sgblack@eecs.umich.edu if (reg & TBICR_MR_RESTART_AN) ; 8147640Sgblack@eecs.umich.edu#endif 8157643Sgblack@eecs.umich.edu 8167397Sgblack@eecs.umich.edu break; 8177397Sgblack@eecs.umich.edu 8187381Sgblack@eecs.umich.edu case TBISR: 8197388Sgblack@eecs.umich.edu panic("TBISR is read only register!\n"); 8207381Sgblack@eecs.umich.edu 8217639Sgblack@eecs.umich.edu case TANAR: 8227643Sgblack@eecs.umich.edu regs.tanar = reg; 8237380Sgblack@eecs.umich.edu if (reg & TANAR_PS2) 8247396Sgblack@eecs.umich.edu panic("this isn't used in driver, something wrong!\n"); 8257380Sgblack@eecs.umich.edu 8267380Sgblack@eecs.umich.edu if (reg & TANAR_PS1) 8277396Sgblack@eecs.umich.edu panic("this isn't used in driver, something wrong!\n"); 8287396Sgblack@eecs.umich.edu break; 8297380Sgblack@eecs.umich.edu 8307380Sgblack@eecs.umich.edu case TANLPAR: 8317640Sgblack@eecs.umich.edu panic("this should only be written to by the fake phy!\n"); 8327643Sgblack@eecs.umich.edu 8337397Sgblack@eecs.umich.edu case TANER: 8347397Sgblack@eecs.umich.edu panic("TANER is read only register!\n"); 8357397Sgblack@eecs.umich.edu 8367397Sgblack@eecs.umich.edu case TESR: 8377397Sgblack@eecs.umich.edu regs.tesr = reg; 8387381Sgblack@eecs.umich.edu break; 8397639Sgblack@eecs.umich.edu 8407643Sgblack@eecs.umich.edu default: 8417380Sgblack@eecs.umich.edu panic("thought i covered all the register, what is this? addr=%#x", 8427380Sgblack@eecs.umich.edu daddr); 8437396Sgblack@eecs.umich.edu } 8447380Sgblack@eecs.umich.edu } else 8457380Sgblack@eecs.umich.edu panic("Invalid Request Size"); 8467396Sgblack@eecs.umich.edu 8477396Sgblack@eecs.umich.edu return No_Fault; 8487380Sgblack@eecs.umich.edu} 8497380Sgblack@eecs.umich.edu 8507640Sgblack@eecs.umich.eduvoid 8517643Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts) 8527397Sgblack@eecs.umich.edu{ 8537397Sgblack@eecs.umich.edu bool delay = false; 8547380Sgblack@eecs.umich.edu 8557381Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 8567387Sgblack@eecs.umich.edu panic("Cannot set a reserved interrupt"); 8577381Sgblack@eecs.umich.edu 8587639Sgblack@eecs.umich.edu if (interrupts & ISR_TXRCMP) 8597643Sgblack@eecs.umich.edu regs.isr |= ISR_TXRCMP; 8607373Sgblack@eecs.umich.edu 8617396Sgblack@eecs.umich.edu if (interrupts & ISR_RXRCMP) 8627373Sgblack@eecs.umich.edu regs.isr |= ISR_RXRCMP; 8637373Sgblack@eecs.umich.edu 8647396Sgblack@eecs.umich.edu//ISR_DPERR not implemented 8657396Sgblack@eecs.umich.edu//ISR_SSERR not implemented 8667373Sgblack@eecs.umich.edu//ISR_RMABT not implemented 8677373Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented 8687640Sgblack@eecs.umich.edu//ISR_HIBINT not implemented 8697643Sgblack@eecs.umich.edu//ISR_PHY not implemented 8707397Sgblack@eecs.umich.edu//ISR_PME not implemented 8717397Sgblack@eecs.umich.edu 8727397Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) 8737380Sgblack@eecs.umich.edu regs.isr |= ISR_SWI; 8747397Sgblack@eecs.umich.edu 8757397Sgblack@eecs.umich.edu//ISR_MIB not implemented 8767381Sgblack@eecs.umich.edu//ISR_TXURN not implemented 8777639Sgblack@eecs.umich.edu 8787643Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) 8797373Sgblack@eecs.umich.edu regs.isr |= ISR_TXIDLE; 8807373Sgblack@eecs.umich.edu 8817396Sgblack@eecs.umich.edu if (interrupts & ISR_TXERR) 8827373Sgblack@eecs.umich.edu regs.isr |= ISR_TXERR; 8837373Sgblack@eecs.umich.edu 8847396Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) 8857396Sgblack@eecs.umich.edu regs.isr |= ISR_TXDESC; 8867373Sgblack@eecs.umich.edu 8877373Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) { 8887640Sgblack@eecs.umich.edu regs.isr |= ISR_TXOK; 8897643Sgblack@eecs.umich.edu delay = true; 8907397Sgblack@eecs.umich.edu } 8917397Sgblack@eecs.umich.edu 8927380Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) 8937381Sgblack@eecs.umich.edu regs.isr |= ISR_RXORN; 8947387Sgblack@eecs.umich.edu 8957381Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) 8967639Sgblack@eecs.umich.edu regs.isr |= ISR_RXIDLE; 8977643Sgblack@eecs.umich.edu 8987373Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented 8997396Sgblack@eecs.umich.edu 9007373Sgblack@eecs.umich.edu if (interrupts & ISR_RXERR) 9017373Sgblack@eecs.umich.edu regs.isr |= ISR_RXERR; 9027396Sgblack@eecs.umich.edu 9037396Sgblack@eecs.umich.edu if (interrupts & ISR_RXDESC) 9047373Sgblack@eecs.umich.edu regs.isr |= ISR_RXDESC; 9057373Sgblack@eecs.umich.edu 9067640Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) { 9077643Sgblack@eecs.umich.edu delay = true; 9087397Sgblack@eecs.umich.edu regs.isr |= ISR_RXOK; 9097397Sgblack@eecs.umich.edu } 9107397Sgblack@eecs.umich.edu 9117380Sgblack@eecs.umich.edu if ((regs.isr & regs.imr)) { 9127397Sgblack@eecs.umich.edu Tick when = curTick; 9137397Sgblack@eecs.umich.edu if (delay) 9147381Sgblack@eecs.umich.edu when += intrDelay; 9157639Sgblack@eecs.umich.edu cpuIntrPost(when); 9167643Sgblack@eecs.umich.edu } 9177373Sgblack@eecs.umich.edu 9187373Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9197396Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 9207373Sgblack@eecs.umich.edu} 9217373Sgblack@eecs.umich.edu 9227396Sgblack@eecs.umich.eduvoid 9237396Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts) 9247373Sgblack@eecs.umich.edu{ 9257374Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 9267640Sgblack@eecs.umich.edu panic("Cannot clear a reserved interrupt"); 9277643Sgblack@eecs.umich.edu 9287397Sgblack@eecs.umich.edu if (interrupts & ISR_TXRCMP) 9297397Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXRCMP; 9307381Sgblack@eecs.umich.edu 9317397Sgblack@eecs.umich.edu if (interrupts & ISR_RXRCMP) 9327397Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXRCMP; 9337639Sgblack@eecs.umich.edu 9347643Sgblack@eecs.umich.edu//ISR_DPERR not implemented 9357397Sgblack@eecs.umich.edu//ISR_SSERR not implemented 9367397Sgblack@eecs.umich.edu//ISR_RMABT not implemented 9377374Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented 9387396Sgblack@eecs.umich.edu//ISR_HIBINT not implemented 9397374Sgblack@eecs.umich.edu//ISR_PHY not implemented 9407374Sgblack@eecs.umich.edu//ISR_PME not implemented 9417396Sgblack@eecs.umich.edu 9427396Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) 9437374Sgblack@eecs.umich.edu regs.isr &= ~ISR_SWI; 9447374Sgblack@eecs.umich.edu 9457640Sgblack@eecs.umich.edu//ISR_MIB not implemented 9467643Sgblack@eecs.umich.edu//ISR_TXURN not implemented 9477397Sgblack@eecs.umich.edu 9487397Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) 9497397Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXIDLE; 9507397Sgblack@eecs.umich.edu 9517397Sgblack@eecs.umich.edu if (interrupts & ISR_TXERR) 9527381Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXERR; 9537639Sgblack@eecs.umich.edu 9547643Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) 9557374Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXDESC; 9567396Sgblack@eecs.umich.edu 9577374Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) 9587374Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXOK; 9597396Sgblack@eecs.umich.edu 9607396Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) 9617374Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXORN; 9627377Sgblack@eecs.umich.edu 9637640Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) 9647643Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXIDLE; 9657398Sgblack@eecs.umich.edu 9667398Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented 9677398Sgblack@eecs.umich.edu 9687639Sgblack@eecs.umich.edu if (interrupts & ISR_RXERR) 9697639Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXERR; 9707398Sgblack@eecs.umich.edu 9717639Sgblack@eecs.umich.edu if (interrupts & ISR_RXDESC) 9727643Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXDESC; 9737398Sgblack@eecs.umich.edu 9747398Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) 9757398Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXOK; 9767398Sgblack@eecs.umich.edu 9777398Sgblack@eecs.umich.edu if (!(regs.isr & regs.imr)) 9787398Sgblack@eecs.umich.edu cpuIntrClear(); 9797398Sgblack@eecs.umich.edu 9807398Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 9817640Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 9827643Sgblack@eecs.umich.edu} 9837398Sgblack@eecs.umich.edu 9847398Sgblack@eecs.umich.eduvoid 9857639Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask() 9867639Sgblack@eecs.umich.edu{ 9877398Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "interrupt mask changed\n"); 9887639Sgblack@eecs.umich.edu 9897643Sgblack@eecs.umich.edu if (regs.isr & regs.imr) 9907398Sgblack@eecs.umich.edu cpuIntrPost(curTick); 9917398Sgblack@eecs.umich.edu else 9927398Sgblack@eecs.umich.edu cpuIntrClear(); 9937398Sgblack@eecs.umich.edu} 9947398Sgblack@eecs.umich.edu 9957398Sgblack@eecs.umich.eduvoid 9967398Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when) 9977398Sgblack@eecs.umich.edu{ 9987640Sgblack@eecs.umich.edu //If the interrupt you want to post is later than an 9997643Sgblack@eecs.umich.edu //interrupt already scheduled, just let it post in the coming one and 10007398Sgblack@eecs.umich.edu //don't schedule another. 10017398Sgblack@eecs.umich.edu //HOWEVER, must be sure that the scheduled intrTick is in the future 10027639Sgblack@eecs.umich.edu //(this was formerly the source of a bug) 10037639Sgblack@eecs.umich.edu assert((intrTick >= curTick) || (intrTick == 0)); 10047639Sgblack@eecs.umich.edu if (when > intrTick && intrTick != 0) 10057639Sgblack@eecs.umich.edu return; 10067639Sgblack@eecs.umich.edu 10077639Sgblack@eecs.umich.edu intrTick = when; 10087639Sgblack@eecs.umich.edu 10097643Sgblack@eecs.umich.edu if (intrEvent) { 10107398Sgblack@eecs.umich.edu intrEvent->squash(); 10117398Sgblack@eecs.umich.edu intrEvent = 0; 10127398Sgblack@eecs.umich.edu } 10137398Sgblack@eecs.umich.edu 10147398Sgblack@eecs.umich.edu if (when < curTick) { 10157398Sgblack@eecs.umich.edu cpuInterrupt(); 10167398Sgblack@eecs.umich.edu } else { 10177398Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 10187640Sgblack@eecs.umich.edu intrTick); 10197643Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 10207398Sgblack@eecs.umich.edu intrEvent->schedule(intrTick); 10217398Sgblack@eecs.umich.edu } 10227639Sgblack@eecs.umich.edu} 10237639Sgblack@eecs.umich.edu 10247639Sgblack@eecs.umich.eduvoid 10257639Sgblack@eecs.umich.eduNSGigE::cpuInterrupt() 10267639Sgblack@eecs.umich.edu{ 10277639Sgblack@eecs.umich.edu // Don't send an interrupt if there's already one 10287639Sgblack@eecs.umich.edu if (cpuPendingIntr) { 10297643Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 10307398Sgblack@eecs.umich.edu "would send an interrupt now, but there's already pending\n"); 10317398Sgblack@eecs.umich.edu intrTick = 0; 10327398Sgblack@eecs.umich.edu return; 10337398Sgblack@eecs.umich.edu } 10347398Sgblack@eecs.umich.edu // Don't send an interrupt if it's supposed to be delayed 10357398Sgblack@eecs.umich.edu if (intrTick > curTick) { 10367398Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n", 10377398Sgblack@eecs.umich.edu intrTick); 10387640Sgblack@eecs.umich.edu return; 10397643Sgblack@eecs.umich.edu } 10407397Sgblack@eecs.umich.edu 10417377Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 10427377Sgblack@eecs.umich.edu // it anymore 10437377Sgblack@eecs.umich.edu intrEvent = 0; 10447377Sgblack@eecs.umich.edu intrTick = 0; 10457377Sgblack@eecs.umich.edu 10467377Sgblack@eecs.umich.edu // Send interrupt 10477377Sgblack@eecs.umich.edu cpuPendingIntr = true; 10487389Sgblack@eecs.umich.edu /** @todo rework the intctrl to be tsunami ok */ 10497389Sgblack@eecs.umich.edu //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 10507396Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); 10517389Sgblack@eecs.umich.edu tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 10527396Sgblack@eecs.umich.edu} 10537389Sgblack@eecs.umich.edu 10547389Sgblack@eecs.umich.eduvoid 10557377Sgblack@eecs.umich.eduNSGigE::cpuIntrClear() 10567377Sgblack@eecs.umich.edu{ 10577643Sgblack@eecs.umich.edu if (cpuPendingIntr) { 10587377Sgblack@eecs.umich.edu cpuPendingIntr = false; 10597396Sgblack@eecs.umich.edu /** @todo rework the intctrl to be tsunami ok */ 10607377Sgblack@eecs.umich.edu //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 10617377Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); 10627396Sgblack@eecs.umich.edu tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 10637396Sgblack@eecs.umich.edu } 10647377Sgblack@eecs.umich.edu} 10657377Sgblack@eecs.umich.edu 10667640Sgblack@eecs.umich.edubool 10677397Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const 10687397Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 10697643Sgblack@eecs.umich.edu 10707397Sgblack@eecs.umich.eduvoid 10717397Sgblack@eecs.umich.eduNSGigE::txReset() 10727377Sgblack@eecs.umich.edu{ 10737397Sgblack@eecs.umich.edu 10747377Sgblack@eecs.umich.edu DPRINTF(Ethernet, "transmit reset\n"); 10757397Sgblack@eecs.umich.edu 10767377Sgblack@eecs.umich.edu CTDD = false; 10777377Sgblack@eecs.umich.edu txFifoAvail = MAX_TX_FIFO_SIZE; 10787389Sgblack@eecs.umich.edu txHalt = false; 10797397Sgblack@eecs.umich.edu txFragPtr = 0; 10807397Sgblack@eecs.umich.edu assert(txDescCnt == 0); 10817397Sgblack@eecs.umich.edu txFifo.clear(); 10827397Sgblack@eecs.umich.edu regs.command &= ~CR_TXE; 10837389Sgblack@eecs.umich.edu txState = txIdle; 10847389Sgblack@eecs.umich.edu assert(txDmaState == dmaIdle); 10857377Sgblack@eecs.umich.edu} 10867377Sgblack@eecs.umich.edu 10877643Sgblack@eecs.umich.eduvoid 10887377Sgblack@eecs.umich.eduNSGigE::rxReset() 10897396Sgblack@eecs.umich.edu{ 10907377Sgblack@eecs.umich.edu DPRINTF(Ethernet, "receive reset\n"); 10917377Sgblack@eecs.umich.edu 10927396Sgblack@eecs.umich.edu CRDD = false; 10937396Sgblack@eecs.umich.edu assert(rxPktBytes == 0); 10947377Sgblack@eecs.umich.edu rxFifoCnt = 0; 10957377Sgblack@eecs.umich.edu rxHalt = false; 10967640Sgblack@eecs.umich.edu rxFragPtr = 0; 10977643Sgblack@eecs.umich.edu assert(rxDescCnt == 0); 10987397Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle); 10997389Sgblack@eecs.umich.edu rxFifo.clear(); 11007389Sgblack@eecs.umich.edu regs.command &= ~CR_RXE; 11017377Sgblack@eecs.umich.edu rxState = rxIdle; 11027377Sgblack@eecs.umich.edu} 11037377Sgblack@eecs.umich.edu 11047377Sgblack@eecs.umich.eduvoid NSGigE::regsReset() 11057377Sgblack@eecs.umich.edu{ 11067377Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 11077377Sgblack@eecs.umich.edu regs.config = 0x80000000; 11087389Sgblack@eecs.umich.edu regs.mear = 0x12; 11097389Sgblack@eecs.umich.edu regs.isr = 0x00608000; 11107396Sgblack@eecs.umich.edu regs.txcfg = 0x120; 11117389Sgblack@eecs.umich.edu regs.rxcfg = 0x4; 11127389Sgblack@eecs.umich.edu regs.srr = 0x0103; 11137377Sgblack@eecs.umich.edu regs.mibc = 0x2; 11147377Sgblack@eecs.umich.edu regs.vdr = 0x81; 11157643Sgblack@eecs.umich.edu regs.tesr = 0xc000; 11167377Sgblack@eecs.umich.edu 11177396Sgblack@eecs.umich.edu extstsEnable = false; 11187377Sgblack@eecs.umich.edu acceptBroadcast = false; 11197377Sgblack@eecs.umich.edu acceptMulticast = false; 11207396Sgblack@eecs.umich.edu acceptUnicast = false; 11217396Sgblack@eecs.umich.edu acceptPerfect = false; 11227377Sgblack@eecs.umich.edu acceptArp = false; 11237377Sgblack@eecs.umich.edu} 11247640Sgblack@eecs.umich.edu 11257389Sgblack@eecs.umich.eduvoid 11267389Sgblack@eecs.umich.eduNSGigE::rxDmaReadCopy() 11277397Sgblack@eecs.umich.edu{ 11287643Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 11297397Sgblack@eecs.umich.edu 11307397Sgblack@eecs.umich.edu memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 11317377Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 11327397Sgblack@eecs.umich.edu 11337377Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 11347397Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 11357377Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11367377Sgblack@eecs.umich.edu} 11377389Sgblack@eecs.umich.edu 11387397Sgblack@eecs.umich.edubool 11397397Sgblack@eecs.umich.eduNSGigE::doRxDmaRead() 11407389Sgblack@eecs.umich.edu{ 11417389Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 11427377Sgblack@eecs.umich.edu rxDmaState = dmaReading; 11437377Sgblack@eecs.umich.edu 11447643Sgblack@eecs.umich.edu if (dmaInterface && !rxDmaFree) { 11457377Sgblack@eecs.umich.edu if (dmaInterface->busy()) 11467396Sgblack@eecs.umich.edu rxDmaState = dmaReadWaiting; 11477377Sgblack@eecs.umich.edu else 11487377Sgblack@eecs.umich.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 11497396Sgblack@eecs.umich.edu &rxDmaReadEvent); 11507396Sgblack@eecs.umich.edu return true; 11517377Sgblack@eecs.umich.edu } 11527389Sgblack@eecs.umich.edu 11537640Sgblack@eecs.umich.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 11547643Sgblack@eecs.umich.edu rxDmaReadCopy(); 11557397Sgblack@eecs.umich.edu return false; 11567389Sgblack@eecs.umich.edu } 11577389Sgblack@eecs.umich.edu 11587389Sgblack@eecs.umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 11597389Sgblack@eecs.umich.edu Tick start = curTick + dmaReadDelay + factor; 11607389Sgblack@eecs.umich.edu rxDmaReadEvent.schedule(start); 11617389Sgblack@eecs.umich.edu return true; 11627389Sgblack@eecs.umich.edu} 11637389Sgblack@eecs.umich.edu 11647389Sgblack@eecs.umich.eduvoid 11657389Sgblack@eecs.umich.eduNSGigE::rxDmaReadDone() 11667643Sgblack@eecs.umich.edu{ 11677389Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 11687396Sgblack@eecs.umich.edu rxDmaReadCopy(); 11697389Sgblack@eecs.umich.edu 11707389Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 11717396Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11727396Sgblack@eecs.umich.edu txKick(); 11737389Sgblack@eecs.umich.edu 11747389Sgblack@eecs.umich.edu rxKick(); 11757640Sgblack@eecs.umich.edu} 11767397Sgblack@eecs.umich.edu 11777397Sgblack@eecs.umich.eduvoid 11787643Sgblack@eecs.umich.eduNSGigE::rxDmaWriteCopy() 11797397Sgblack@eecs.umich.edu{ 11807397Sgblack@eecs.umich.edu assert(rxDmaState == dmaWriting); 11817389Sgblack@eecs.umich.edu 11827397Sgblack@eecs.umich.edu memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 11837389Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 11847397Sgblack@eecs.umich.edu 11857389Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11867389Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 11877389Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11887389Sgblack@eecs.umich.edu} 11897389Sgblack@eecs.umich.edu 11907643Sgblack@eecs.umich.edubool 11917389Sgblack@eecs.umich.eduNSGigE::doRxDmaWrite() 11927396Sgblack@eecs.umich.edu{ 11937389Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11947389Sgblack@eecs.umich.edu rxDmaState = dmaWriting; 11957396Sgblack@eecs.umich.edu 11967396Sgblack@eecs.umich.edu if (dmaInterface && !rxDmaFree) { 11977389Sgblack@eecs.umich.edu if (dmaInterface->busy()) 11987389Sgblack@eecs.umich.edu rxDmaState = dmaWriteWaiting; 11997640Sgblack@eecs.umich.edu else 12007643Sgblack@eecs.umich.edu dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 12017397Sgblack@eecs.umich.edu &rxDmaWriteEvent); 12027389Sgblack@eecs.umich.edu return true; 12037389Sgblack@eecs.umich.edu } 12047389Sgblack@eecs.umich.edu 12057389Sgblack@eecs.umich.edu if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 12067389Sgblack@eecs.umich.edu rxDmaWriteCopy(); 12077389Sgblack@eecs.umich.edu return false; 12087389Sgblack@eecs.umich.edu } 12097389Sgblack@eecs.umich.edu 12107389Sgblack@eecs.umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 12117389Sgblack@eecs.umich.edu Tick start = curTick + dmaWriteDelay + factor; 12127643Sgblack@eecs.umich.edu rxDmaWriteEvent.schedule(start); 12137389Sgblack@eecs.umich.edu return true; 12147396Sgblack@eecs.umich.edu} 12157389Sgblack@eecs.umich.edu 12167389Sgblack@eecs.umich.eduvoid 12177396Sgblack@eecs.umich.eduNSGigE::rxDmaWriteDone() 12187396Sgblack@eecs.umich.edu{ 12197389Sgblack@eecs.umich.edu assert(rxDmaState == dmaWriting); 12207389Sgblack@eecs.umich.edu rxDmaWriteCopy(); 12217640Sgblack@eecs.umich.edu 12227397Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 12237643Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12247397Sgblack@eecs.umich.edu txKick(); 12257397Sgblack@eecs.umich.edu 12267389Sgblack@eecs.umich.edu rxKick(); 12277397Sgblack@eecs.umich.edu} 12287389Sgblack@eecs.umich.edu 12297397Sgblack@eecs.umich.eduvoid 12307389Sgblack@eecs.umich.eduNSGigE::rxKick() 12317389Sgblack@eecs.umich.edu{ 12327389Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n", 12337389Sgblack@eecs.umich.edu NsRxStateStrings[rxState], rxFifo.size()); 12347389Sgblack@eecs.umich.edu 12357643Sgblack@eecs.umich.edu if (rxKickTick > curTick) { 12367389Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 12377396Sgblack@eecs.umich.edu rxKickTick); 12387389Sgblack@eecs.umich.edu return; 12397389Sgblack@eecs.umich.edu } 12407396Sgblack@eecs.umich.edu 12417396Sgblack@eecs.umich.edu next: 12427389Sgblack@eecs.umich.edu switch(rxDmaState) { 12437322Sgblack@eecs.umich.edu case dmaReadWaiting: 12447379Sgblack@eecs.umich.edu if (doRxDmaRead()) 12457379Sgblack@eecs.umich.edu goto exit; 12467379Sgblack@eecs.umich.edu break; 12477379Sgblack@eecs.umich.edu case dmaWriteWaiting: 12487379Sgblack@eecs.umich.edu if (doRxDmaWrite()) 12497379Sgblack@eecs.umich.edu goto exit; 12507379Sgblack@eecs.umich.edu break; 12517640Sgblack@eecs.umich.edu default: 12527643Sgblack@eecs.umich.edu break; 12537397Sgblack@eecs.umich.edu } 12547397Sgblack@eecs.umich.edu 12557381Sgblack@eecs.umich.edu // see state machine from spec for details 12567379Sgblack@eecs.umich.edu // the way this works is, if you finish work on one state and can go directly to 12577381Sgblack@eecs.umich.edu // another, you do that through jumping to the label "next". however, if you have 12587639Sgblack@eecs.umich.edu // intermediate work, like DMA so that you can't go to the next state yet, you go to 12597643Sgblack@eecs.umich.edu // exit and exit the loop. however, when the DMA is done it will trigger an 12607379Sgblack@eecs.umich.edu // event and come back to this loop. 12617396Sgblack@eecs.umich.edu switch (rxState) { 12627379Sgblack@eecs.umich.edu case rxIdle: 12637379Sgblack@eecs.umich.edu if (!regs.command & CR_RXE) { 12647396Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 12657396Sgblack@eecs.umich.edu goto exit; 12667379Sgblack@eecs.umich.edu } 12677379Sgblack@eecs.umich.edu 12687640Sgblack@eecs.umich.edu if (CRDD) { 12697643Sgblack@eecs.umich.edu rxState = rxDescRefr; 12707397Sgblack@eecs.umich.edu 12717397Sgblack@eecs.umich.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 12727397Sgblack@eecs.umich.edu rxDmaData = &rxDescCache + offsetof(ns_desc, link); 12737397Sgblack@eecs.umich.edu rxDmaLen = sizeof(rxDescCache.link); 12747397Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 12757381Sgblack@eecs.umich.edu 12767639Sgblack@eecs.umich.edu if (doRxDmaRead()) 12777643Sgblack@eecs.umich.edu goto exit; 12787379Sgblack@eecs.umich.edu } else { 12797379Sgblack@eecs.umich.edu rxState = rxDescRead; 12807379Sgblack@eecs.umich.edu 12817396Sgblack@eecs.umich.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 12827379Sgblack@eecs.umich.edu rxDmaData = &rxDescCache; 12837379Sgblack@eecs.umich.edu rxDmaLen = sizeof(ns_desc); 12847396Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 12857396Sgblack@eecs.umich.edu 12867379Sgblack@eecs.umich.edu if (doRxDmaRead()) 12877379Sgblack@eecs.umich.edu goto exit; 12887640Sgblack@eecs.umich.edu } 12897643Sgblack@eecs.umich.edu break; 12907397Sgblack@eecs.umich.edu 12917397Sgblack@eecs.umich.edu case rxDescRefr: 12927381Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 12937379Sgblack@eecs.umich.edu goto exit; 12947381Sgblack@eecs.umich.edu 12957639Sgblack@eecs.umich.edu rxState = rxAdvance; 12967643Sgblack@eecs.umich.edu break; 12977379Sgblack@eecs.umich.edu 12987396Sgblack@eecs.umich.edu case rxDescRead: 12997379Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 13007379Sgblack@eecs.umich.edu goto exit; 13017396Sgblack@eecs.umich.edu 13027396Sgblack@eecs.umich.edu DPRINTF(EthernetDesc, 13037379Sgblack@eecs.umich.edu "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 13047379Sgblack@eecs.umich.edu ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 13057640Sgblack@eecs.umich.edu rxDescCache.extsts); 13067643Sgblack@eecs.umich.edu 13077397Sgblack@eecs.umich.edu if (rxDescCache.cmdsts & CMDSTS_OWN) { 13087397Sgblack@eecs.umich.edu rxState = rxIdle; 13097397Sgblack@eecs.umich.edu } else { 13107397Sgblack@eecs.umich.edu rxState = rxFifoBlock; 13117397Sgblack@eecs.umich.edu rxFragPtr = rxDescCache.bufptr; 13127381Sgblack@eecs.umich.edu rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 13137639Sgblack@eecs.umich.edu } 13147643Sgblack@eecs.umich.edu break; 13157379Sgblack@eecs.umich.edu 13167379Sgblack@eecs.umich.edu case rxFifoBlock: 13177379Sgblack@eecs.umich.edu if (!rxPacket) { 13187396Sgblack@eecs.umich.edu /** 13197379Sgblack@eecs.umich.edu * @todo in reality, we should be able to start processing 13207379Sgblack@eecs.umich.edu * the packet as it arrives, and not have to wait for the 13217396Sgblack@eecs.umich.edu * full packet ot be in the receive fifo. 13227396Sgblack@eecs.umich.edu */ 13237379Sgblack@eecs.umich.edu if (rxFifo.empty()) 13247379Sgblack@eecs.umich.edu goto exit; 13257640Sgblack@eecs.umich.edu 13267643Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n"); 13277397Sgblack@eecs.umich.edu 13287381Sgblack@eecs.umich.edu // If we don't have a packet, grab a new one from the fifo. 13297639Sgblack@eecs.umich.edu rxPacket = rxFifo.front(); 13307381Sgblack@eecs.umich.edu rxPktBytes = rxPacket->length; 13317639Sgblack@eecs.umich.edu rxPacketBufPtr = rxPacket->data; 13327643Sgblack@eecs.umich.edu 13337379Sgblack@eecs.umich.edu if (DTRACE(Ethernet)) { 13347396Sgblack@eecs.umich.edu if (rxPacket->isIpPkt()) { 13357379Sgblack@eecs.umich.edu ip_header *ip = rxPacket->getIpHdr(); 13367379Sgblack@eecs.umich.edu DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 13377396Sgblack@eecs.umich.edu if (rxPacket->isTcpPkt()) { 13387396Sgblack@eecs.umich.edu tcp_header *tcp = rxPacket->getTcpHdr(ip); 13397379Sgblack@eecs.umich.edu DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 13407379Sgblack@eecs.umich.edu reverseEnd16(tcp->src_port_num), 13417640Sgblack@eecs.umich.edu reverseEnd16(tcp->dest_port_num)); 13427643Sgblack@eecs.umich.edu } 13437379Sgblack@eecs.umich.edu } 13447397Sgblack@eecs.umich.edu } 13457381Sgblack@eecs.umich.edu 13467639Sgblack@eecs.umich.edu // sanity check - i think the driver behaves like this 13477397Sgblack@eecs.umich.edu assert(rxDescCnt >= rxPktBytes); 13487639Sgblack@eecs.umich.edu 13497643Sgblack@eecs.umich.edu // Must clear the value before popping to decrement the 13507397Sgblack@eecs.umich.edu // reference count 13517397Sgblack@eecs.umich.edu rxFifo.front() = NULL; 13527379Sgblack@eecs.umich.edu rxFifo.pop_front(); 13537396Sgblack@eecs.umich.edu rxFifoCnt -= rxPacket->length; 13547379Sgblack@eecs.umich.edu } 13557379Sgblack@eecs.umich.edu 13567396Sgblack@eecs.umich.edu 13577396Sgblack@eecs.umich.edu // dont' need the && rxDescCnt > 0 if driver sanity check above holds 13587379Sgblack@eecs.umich.edu if (rxPktBytes > 0) { 13597379Sgblack@eecs.umich.edu rxState = rxFragWrite; 13607640Sgblack@eecs.umich.edu // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds 13617643Sgblack@eecs.umich.edu rxXferLen = rxPktBytes; 13627397Sgblack@eecs.umich.edu 13637381Sgblack@eecs.umich.edu rxDmaAddr = rxFragPtr & 0x3fffffff; 13647639Sgblack@eecs.umich.edu rxDmaData = rxPacketBufPtr; 13657381Sgblack@eecs.umich.edu rxDmaLen = rxXferLen; 13667639Sgblack@eecs.umich.edu rxDmaFree = dmaDataFree; 13677643Sgblack@eecs.umich.edu 13687379Sgblack@eecs.umich.edu if (doRxDmaWrite()) 13697396Sgblack@eecs.umich.edu goto exit; 13707379Sgblack@eecs.umich.edu 13717379Sgblack@eecs.umich.edu } else { 13727396Sgblack@eecs.umich.edu rxState = rxDescWrite; 13737396Sgblack@eecs.umich.edu 13747379Sgblack@eecs.umich.edu //if (rxPktBytes == 0) { /* packet is done */ 13757379Sgblack@eecs.umich.edu assert(rxPktBytes == 0); 13767640Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "done with receiving packet\n"); 13777643Sgblack@eecs.umich.edu 13787379Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_OWN; 13797397Sgblack@eecs.umich.edu rxDescCache.cmdsts &= ~CMDSTS_MORE; 13807381Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_OK; 13817639Sgblack@eecs.umich.edu rxDescCache.cmdsts &= 0xffff0000; 13827397Sgblack@eecs.umich.edu rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 13837639Sgblack@eecs.umich.edu 13847643Sgblack@eecs.umich.edu#if 0 13857397Sgblack@eecs.umich.edu /* all the driver uses these are for its own stats keeping 13867397Sgblack@eecs.umich.edu which we don't care about, aren't necessary for functionality 13877379Sgblack@eecs.umich.edu and doing this would just slow us down. if they end up using 13887396Sgblack@eecs.umich.edu this in a later version for functional purposes, just undef 13897379Sgblack@eecs.umich.edu */ 13907379Sgblack@eecs.umich.edu if (rxFilterEnable) { 13917396Sgblack@eecs.umich.edu rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 13927396Sgblack@eecs.umich.edu if (rxFifo.front()->IsUnicast()) 13937379Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 13947379Sgblack@eecs.umich.edu if (rxFifo.front()->IsMulticast()) 13957640Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 13967643Sgblack@eecs.umich.edu if (rxFifo.front()->IsBroadcast()) 13977397Sgblack@eecs.umich.edu rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 13987397Sgblack@eecs.umich.edu } 13997381Sgblack@eecs.umich.edu#endif 14007379Sgblack@eecs.umich.edu 14017381Sgblack@eecs.umich.edu if (rxPacket->isIpPkt() && extstsEnable) { 14027639Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_IPPKT; 14037643Sgblack@eecs.umich.edu if (!ipChecksum(rxPacket, false)) { 14047379Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 14057379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_IPERR; 14067396Sgblack@eecs.umich.edu } 14077379Sgblack@eecs.umich.edu if (rxPacket->isTcpPkt()) { 14087379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_TCPPKT; 14097396Sgblack@eecs.umich.edu if (!tcpChecksum(rxPacket, false)) { 14107396Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 14117379Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_TCPERR; 14127379Sgblack@eecs.umich.edu } 14137640Sgblack@eecs.umich.edu } else if (rxPacket->isUdpPkt()) { 14147643Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_UDPPKT; 14157397Sgblack@eecs.umich.edu if (!udpChecksum(rxPacket, false)) { 14167397Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 14177397Sgblack@eecs.umich.edu rxDescCache.extsts |= EXTSTS_UDPERR; 14187397Sgblack@eecs.umich.edu } 14197397Sgblack@eecs.umich.edu } 14207381Sgblack@eecs.umich.edu } 14217639Sgblack@eecs.umich.edu rxPacket = 0; 14227643Sgblack@eecs.umich.edu 14237379Sgblack@eecs.umich.edu /* the driver seems to always receive into desc buffers 14247379Sgblack@eecs.umich.edu of size 1514, so you never have a pkt that is split 14257379Sgblack@eecs.umich.edu into multiple descriptors on the receive side, so 14267379Sgblack@eecs.umich.edu i don't implement that case, hence the assert above. 14277396Sgblack@eecs.umich.edu */ 14287379Sgblack@eecs.umich.edu 14297379Sgblack@eecs.umich.edu DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 14307396Sgblack@eecs.umich.edu rxDescCache.cmdsts, rxDescCache.extsts); 14317396Sgblack@eecs.umich.edu 14327379Sgblack@eecs.umich.edu rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 14337379Sgblack@eecs.umich.edu rxDmaData = &(rxDescCache.cmdsts); 14347640Sgblack@eecs.umich.edu rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 14357643Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 14367397Sgblack@eecs.umich.edu 14377397Sgblack@eecs.umich.edu if (doRxDmaWrite()) 14387381Sgblack@eecs.umich.edu goto exit; 14397379Sgblack@eecs.umich.edu } 14407381Sgblack@eecs.umich.edu break; 14417639Sgblack@eecs.umich.edu 14427643Sgblack@eecs.umich.edu case rxFragWrite: 14437379Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 14447379Sgblack@eecs.umich.edu goto exit; 14457396Sgblack@eecs.umich.edu 14467379Sgblack@eecs.umich.edu rxPacketBufPtr += rxXferLen; 14477379Sgblack@eecs.umich.edu rxFragPtr += rxXferLen; 14487396Sgblack@eecs.umich.edu rxPktBytes -= rxXferLen; 14497396Sgblack@eecs.umich.edu 14507379Sgblack@eecs.umich.edu rxState = rxFifoBlock; 14517379Sgblack@eecs.umich.edu break; 14527640Sgblack@eecs.umich.edu 14537643Sgblack@eecs.umich.edu case rxDescWrite: 14547397Sgblack@eecs.umich.edu if (rxDmaState != dmaIdle) 14557397Sgblack@eecs.umich.edu goto exit; 14567397Sgblack@eecs.umich.edu 14577397Sgblack@eecs.umich.edu assert(rxDescCache.cmdsts & CMDSTS_OWN); 14587397Sgblack@eecs.umich.edu 14597381Sgblack@eecs.umich.edu assert(rxPacket == 0); 14607639Sgblack@eecs.umich.edu devIntrPost(ISR_RXOK); 14617643Sgblack@eecs.umich.edu 14627379Sgblack@eecs.umich.edu if (rxDescCache.cmdsts & CMDSTS_INTR) 14637379Sgblack@eecs.umich.edu devIntrPost(ISR_RXDESC); 14647379Sgblack@eecs.umich.edu 14657379Sgblack@eecs.umich.edu if (rxHalt) { 14667396Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "Halting the RX state machine\n"); 14677379Sgblack@eecs.umich.edu rxState = rxIdle; 14687379Sgblack@eecs.umich.edu rxHalt = false; 14697396Sgblack@eecs.umich.edu } else 14707396Sgblack@eecs.umich.edu rxState = rxAdvance; 14717379Sgblack@eecs.umich.edu break; 14727379Sgblack@eecs.umich.edu 14737640Sgblack@eecs.umich.edu case rxAdvance: 14747643Sgblack@eecs.umich.edu if (rxDescCache.link == 0) { 14757397Sgblack@eecs.umich.edu rxState = rxIdle; 14767381Sgblack@eecs.umich.edu return; 14777639Sgblack@eecs.umich.edu } else { 14787381Sgblack@eecs.umich.edu rxState = rxDescRead; 14797639Sgblack@eecs.umich.edu regs.rxdp = rxDescCache.link; 14807643Sgblack@eecs.umich.edu CRDD = false; 14817379Sgblack@eecs.umich.edu 14827379Sgblack@eecs.umich.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 14837396Sgblack@eecs.umich.edu rxDmaData = &rxDescCache; 14847379Sgblack@eecs.umich.edu rxDmaLen = sizeof(ns_desc); 14857379Sgblack@eecs.umich.edu rxDmaFree = dmaDescFree; 14867396Sgblack@eecs.umich.edu 14877396Sgblack@eecs.umich.edu if (doRxDmaRead()) 14887379Sgblack@eecs.umich.edu goto exit; 14897379Sgblack@eecs.umich.edu } 14907640Sgblack@eecs.umich.edu break; 14917643Sgblack@eecs.umich.edu 14927379Sgblack@eecs.umich.edu default: 14937397Sgblack@eecs.umich.edu panic("Invalid rxState!"); 14947381Sgblack@eecs.umich.edu } 14957639Sgblack@eecs.umich.edu 14967397Sgblack@eecs.umich.edu 14977639Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "entering next rx state = %s\n", 14987643Sgblack@eecs.umich.edu NsRxStateStrings[rxState]); 14997397Sgblack@eecs.umich.edu 15007397Sgblack@eecs.umich.edu if (rxState == rxIdle) { 15017379Sgblack@eecs.umich.edu regs.command &= ~CR_RXE; 15027379Sgblack@eecs.umich.edu devIntrPost(ISR_RXIDLE); 15037396Sgblack@eecs.umich.edu return; 15047379Sgblack@eecs.umich.edu } 15057379Sgblack@eecs.umich.edu 15067396Sgblack@eecs.umich.edu goto next; 15077396Sgblack@eecs.umich.edu 15087379Sgblack@eecs.umich.edu exit: 15097379Sgblack@eecs.umich.edu /** 15107640Sgblack@eecs.umich.edu * @todo do we want to schedule a future kick? 15117643Sgblack@eecs.umich.edu */ 15127397Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "rx state machine exited state=%s\n", 15137381Sgblack@eecs.umich.edu NsRxStateStrings[rxState]); 15147639Sgblack@eecs.umich.edu} 15157381Sgblack@eecs.umich.edu 15167639Sgblack@eecs.umich.eduvoid 15177643Sgblack@eecs.umich.eduNSGigE::transmit() 15187379Sgblack@eecs.umich.edu{ 15197379Sgblack@eecs.umich.edu if (txFifo.empty()) { 15207396Sgblack@eecs.umich.edu DPRINTF(Ethernet, "nothing to transmit\n"); 15217379Sgblack@eecs.umich.edu return; 15227379Sgblack@eecs.umich.edu } 15237396Sgblack@eecs.umich.edu 15247396Sgblack@eecs.umich.edu DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n", 15257379Sgblack@eecs.umich.edu MAX_TX_FIFO_SIZE - txFifoAvail); 15267379Sgblack@eecs.umich.edu if (interface->sendPacket(txFifo.front())) { 15277640Sgblack@eecs.umich.edu if (DTRACE(Ethernet)) { 15287643Sgblack@eecs.umich.edu if (txFifo.front()->isIpPkt()) { 15297379Sgblack@eecs.umich.edu ip_header *ip = txFifo.front()->getIpHdr(); 15307397Sgblack@eecs.umich.edu DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 15317381Sgblack@eecs.umich.edu if (txFifo.front()->isTcpPkt()) { 15327639Sgblack@eecs.umich.edu tcp_header *tcp = txFifo.front()->getTcpHdr(ip); 15337397Sgblack@eecs.umich.edu DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 15347639Sgblack@eecs.umich.edu reverseEnd16(tcp->src_port_num), 15357643Sgblack@eecs.umich.edu reverseEnd16(tcp->dest_port_num)); 15367397Sgblack@eecs.umich.edu } 15377397Sgblack@eecs.umich.edu } 15387379Sgblack@eecs.umich.edu } 15397379Sgblack@eecs.umich.edu 15407396Sgblack@eecs.umich.edu DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 15417379Sgblack@eecs.umich.edu txBytes += txFifo.front()->length; 15427379Sgblack@eecs.umich.edu txPackets++; 15437396Sgblack@eecs.umich.edu 15447396Sgblack@eecs.umich.edu txFifoAvail += txFifo.front()->length; 15457379Sgblack@eecs.umich.edu 15467379Sgblack@eecs.umich.edu DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail); 1547 txFifo.front() = NULL; 1548 txFifo.pop_front(); 1549 1550 /* normally do a writeback of the descriptor here, and ONLY after that is 1551 done, send this interrupt. but since our stuff never actually fails, 1552 just do this interrupt here, otherwise the code has to stray from this 1553 nice format. besides, it's functionally the same. 1554 */ 1555 devIntrPost(ISR_TXOK); 1556 } else 1557 DPRINTF(Ethernet, "May need to rethink always sending the descriptors back?\n"); 1558 1559 if (!txFifo.empty() && !txEvent.scheduled()) { 1560 DPRINTF(Ethernet, "reschedule transmit\n"); 1561 txEvent.schedule(curTick + 1000); 1562 } 1563} 1564 1565void 1566NSGigE::txDmaReadCopy() 1567{ 1568 assert(txDmaState == dmaReading); 1569 1570 memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); 1571 txDmaState = dmaIdle; 1572 1573 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1574 txDmaAddr, txDmaLen); 1575 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1576} 1577 1578bool 1579NSGigE::doTxDmaRead() 1580{ 1581 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1582 txDmaState = dmaReading; 1583 1584 if (dmaInterface && !txDmaFree) { 1585 if (dmaInterface->busy()) 1586 txDmaState = dmaReadWaiting; 1587 else 1588 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1589 &txDmaReadEvent); 1590 return true; 1591 } 1592 1593 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1594 txDmaReadCopy(); 1595 return false; 1596 } 1597 1598 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1599 Tick start = curTick + dmaReadDelay + factor; 1600 txDmaReadEvent.schedule(start); 1601 return true; 1602} 1603 1604void 1605NSGigE::txDmaReadDone() 1606{ 1607 assert(txDmaState == dmaReading); 1608 txDmaReadCopy(); 1609 1610 // If the receive state machine has a pending DMA, let it go first 1611 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1612 rxKick(); 1613 1614 txKick(); 1615} 1616 1617void 1618NSGigE::txDmaWriteCopy() 1619{ 1620 assert(txDmaState == dmaWriting); 1621 1622 memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); 1623 txDmaState = dmaIdle; 1624 1625 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1626 txDmaAddr, txDmaLen); 1627 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1628} 1629 1630bool 1631NSGigE::doTxDmaWrite() 1632{ 1633 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1634 txDmaState = dmaWriting; 1635 1636 if (dmaInterface && !txDmaFree) { 1637 if (dmaInterface->busy()) 1638 txDmaState = dmaWriteWaiting; 1639 else 1640 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1641 &txDmaWriteEvent); 1642 return true; 1643 } 1644 1645 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1646 txDmaWriteCopy(); 1647 return false; 1648 } 1649 1650 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1651 Tick start = curTick + dmaWriteDelay + factor; 1652 txDmaWriteEvent.schedule(start); 1653 return true; 1654} 1655 1656void 1657NSGigE::txDmaWriteDone() 1658{ 1659 assert(txDmaState == dmaWriting); 1660 txDmaWriteCopy(); 1661 1662 // If the receive state machine has a pending DMA, let it go first 1663 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1664 rxKick(); 1665 1666 txKick(); 1667} 1668 1669void 1670NSGigE::txKick() 1671{ 1672 DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]); 1673 1674 if (txKickTick > curTick) { 1675 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1676 txKickTick); 1677 1678 return; 1679 } 1680 1681 next: 1682 switch(txDmaState) { 1683 case dmaReadWaiting: 1684 if (doTxDmaRead()) 1685 goto exit; 1686 break; 1687 case dmaWriteWaiting: 1688 if (doTxDmaWrite()) 1689 goto exit; 1690 break; 1691 default: 1692 break; 1693 } 1694 1695 switch (txState) { 1696 case txIdle: 1697 if (!regs.command & CR_TXE) { 1698 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1699 goto exit; 1700 } 1701 1702 if (CTDD) { 1703 txState = txDescRefr; 1704 1705 txDmaAddr = regs.txdp & 0x3fffffff; 1706 txDmaData = &txDescCache + offsetof(ns_desc, link); 1707 txDmaLen = sizeof(txDescCache.link); 1708 txDmaFree = dmaDescFree; 1709 1710 if (doTxDmaRead()) 1711 goto exit; 1712 1713 } else { 1714 txState = txDescRead; 1715 1716 txDmaAddr = regs.txdp & 0x3fffffff; 1717 txDmaData = &txDescCache; 1718 txDmaLen = sizeof(ns_desc); 1719 txDmaFree = dmaDescFree; 1720 1721 if (doTxDmaRead()) 1722 goto exit; 1723 } 1724 break; 1725 1726 case txDescRefr: 1727 if (txDmaState != dmaIdle) 1728 goto exit; 1729 1730 txState = txAdvance; 1731 break; 1732 1733 case txDescRead: 1734 if (txDmaState != dmaIdle) 1735 goto exit; 1736 1737 DPRINTF(EthernetDesc, 1738 "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 1739 ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1740 txDescCache.extsts); 1741 1742 if (txDescCache.cmdsts & CMDSTS_OWN) { 1743 txState = txFifoBlock; 1744 txFragPtr = txDescCache.bufptr; 1745 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1746 } else { 1747 txState = txIdle; 1748 } 1749 break; 1750 1751 case txFifoBlock: 1752 if (!txPacket) { 1753 DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n"); 1754 txPacket = new EtherPacket; 1755 txPacket->data = new uint8_t[16384]; 1756 txPacketBufPtr = txPacket->data; 1757 } 1758 1759 if (txDescCnt == 0) { 1760 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1761 if (txDescCache.cmdsts & CMDSTS_MORE) { 1762 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1763 txState = txDescWrite; 1764 1765 txDescCache.cmdsts &= ~CMDSTS_OWN; 1766 1767 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1768 txDmaData = &(txDescCache.cmdsts); 1769 txDmaLen = sizeof(txDescCache.cmdsts); 1770 txDmaFree = dmaDescFree; 1771 1772 if (doTxDmaWrite()) 1773 goto exit; 1774 1775 } else { /* this packet is totally done */ 1776 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1777 /* deal with the the packet that just finished */ 1778 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1779 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1780 udpChecksum(txPacket, true); 1781 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1782 tcpChecksum(txPacket, true); 1783 } 1784 if (txDescCache.extsts & EXTSTS_IPPKT) { 1785 ipChecksum(txPacket, true); 1786 } 1787 } 1788 1789 txPacket->length = txPacketBufPtr - txPacket->data; 1790 /* this is just because the receive can't handle a packet bigger 1791 want to make sure */ 1792 assert(txPacket->length <= 1514); 1793 txFifo.push_back(txPacket); 1794 1795 /* this following section is not to spec, but functionally shouldn't 1796 be any different. normally, the chip will wait til the transmit has 1797 occurred before writing back the descriptor because it has to wait 1798 to see that it was successfully transmitted to decide whether to set 1799 CMDSTS_OK or not. however, in the simulator since it is always 1800 successfully transmitted, and writing it exactly to spec would 1801 complicate the code, we just do it here 1802 */ 1803 1804 txDescCache.cmdsts &= ~CMDSTS_OWN; 1805 txDescCache.cmdsts |= CMDSTS_OK; 1806 1807 DPRINTF(EthernetDesc, 1808 "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 1809 txDescCache.cmdsts, txDescCache.extsts); 1810 1811 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1812 txDmaData = &(txDescCache.cmdsts); 1813 txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts); 1814 txDmaFree = dmaDescFree; 1815 1816 if (doTxDmaWrite()) 1817 goto exit; 1818 1819 transmit(); 1820 1821 txPacket = 0; 1822 1823 if (txHalt) { 1824 DPRINTF(EthernetSM, "halting TX state machine\n"); 1825 txState = txIdle; 1826 txHalt = false; 1827 } else 1828 txState = txAdvance; 1829 } 1830 } else { 1831 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1832 txState = txFragRead; 1833 1834 /* The number of bytes transferred is either whatever is left 1835 in the descriptor (txDescCnt), or if there is not enough 1836 room in the fifo, just whatever room is left in the fifo 1837 */ 1838 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1839 1840 txDmaAddr = txFragPtr & 0x3fffffff; 1841 txDmaData = txPacketBufPtr; 1842 txDmaLen = txXferLen; 1843 txDmaFree = dmaDataFree; 1844 1845 if (doTxDmaRead()) 1846 goto exit; 1847 } 1848 break; 1849 1850 case txFragRead: 1851 if (txDmaState != dmaIdle) 1852 goto exit; 1853 1854 txPacketBufPtr += txXferLen; 1855 txFragPtr += txXferLen; 1856 txDescCnt -= txXferLen; 1857 txFifoAvail -= txXferLen; 1858 1859 txState = txFifoBlock; 1860 break; 1861 1862 case txDescWrite: 1863 if (txDmaState != dmaIdle) 1864 goto exit; 1865 1866 if (txDescCache.cmdsts & CMDSTS_INTR) { 1867 devIntrPost(ISR_TXDESC); 1868 } 1869 1870 txState = txAdvance; 1871 break; 1872 1873 case txAdvance: 1874 if (txDescCache.link == 0) { 1875 txState = txIdle; 1876 } else { 1877 txState = txDescRead; 1878 regs.txdp = txDescCache.link; 1879 CTDD = false; 1880 1881 txDmaAddr = txDescCache.link & 0x3fffffff; 1882 txDmaData = &txDescCache; 1883 txDmaLen = sizeof(ns_desc); 1884 txDmaFree = dmaDescFree; 1885 1886 if (doTxDmaRead()) 1887 goto exit; 1888 } 1889 break; 1890 1891 default: 1892 panic("invalid state"); 1893 } 1894 1895 DPRINTF(EthernetSM, "entering next tx state=%s\n", 1896 NsTxStateStrings[txState]); 1897 1898 if (txState == txIdle) { 1899 regs.command &= ~CR_TXE; 1900 devIntrPost(ISR_TXIDLE); 1901 return; 1902 } 1903 1904 goto next; 1905 1906 exit: 1907 /** 1908 * @todo do we want to schedule a future kick? 1909 */ 1910 DPRINTF(EthernetSM, "tx state machine exited state=%s\n", 1911 NsTxStateStrings[txState]); 1912} 1913 1914void 1915NSGigE::transferDone() 1916{ 1917 if (txFifo.empty()) 1918 return; 1919 1920 if (txEvent.scheduled()) 1921 txEvent.reschedule(curTick + 1); 1922 else 1923 txEvent.schedule(curTick + 1); 1924} 1925 1926bool 1927NSGigE::rxFilter(PacketPtr packet) 1928{ 1929 bool drop = true; 1930 string type; 1931 1932 if (packet->IsUnicast()) { 1933 type = "unicast"; 1934 1935 // If we're accepting all unicast addresses 1936 if (acceptUnicast) 1937 drop = false; 1938 1939 // If we make a perfect match 1940 if ((acceptPerfect) 1941 && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0)) 1942 drop = false; 1943 1944 eth_header *eth = (eth_header *) packet->data; 1945 if ((acceptArp) && (eth->type == 0x608)) 1946 drop = false; 1947 1948 } else if (packet->IsBroadcast()) { 1949 type = "broadcast"; 1950 1951 // if we're accepting broadcasts 1952 if (acceptBroadcast) 1953 drop = false; 1954 1955 } else if (packet->IsMulticast()) { 1956 type = "multicast"; 1957 1958 // if we're accepting all multicasts 1959 if (acceptMulticast) 1960 drop = false; 1961 1962 } else { 1963 type = "unknown"; 1964 1965 // oh well, punt on this one 1966 } 1967 1968 if (drop) { 1969 DPRINTF(Ethernet, "rxFilter drop\n"); 1970 DDUMP(EthernetData, packet->data, packet->length); 1971 } 1972 1973 return drop; 1974} 1975 1976bool 1977NSGigE::recvPacket(PacketPtr packet) 1978{ 1979 rxBytes += packet->length; 1980 rxPackets++; 1981 1982 DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt); 1983 1984 if (rxState == rxIdle) { 1985 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1986 interface->recvDone(); 1987 return true; 1988 } 1989 1990 if (rxFilterEnable && rxFilter(packet)) { 1991 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1992 interface->recvDone(); 1993 return true; 1994 } 1995 1996 if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) { 1997 DPRINTF(Ethernet, 1998 "packet will not fit in receive buffer...packet dropped\n"); 1999 devIntrPost(ISR_RXORN); 2000 return false; 2001 } 2002 2003 rxFifo.push_back(packet); 2004 rxFifoCnt += packet->length; 2005 interface->recvDone(); 2006 2007 rxKick(); 2008 return true; 2009} 2010 2011/** 2012 * does a udp checksum. if gen is true, then it generates it and puts it in the right place 2013 * else, it just checks what it calculates against the value in the header in packet 2014 */ 2015bool 2016NSGigE::udpChecksum(PacketPtr packet, bool gen) 2017{ 2018 ip_header *ip = packet->getIpHdr(); 2019 udp_header *hdr = packet->getUdpHdr(ip); 2020 2021 pseudo_header *pseudo = new pseudo_header; 2022 2023 pseudo->src_ip_addr = ip->src_ip_addr; 2024 pseudo->dest_ip_addr = ip->dest_ip_addr; 2025 pseudo->protocol = ip->protocol; 2026 pseudo->len = hdr->len; 2027 2028 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2029 (uint32_t) hdr->len); 2030 2031 delete pseudo; 2032 if (gen) 2033 hdr->chksum = cksum; 2034 else 2035 if (cksum != 0) 2036 return false; 2037 2038 return true; 2039} 2040 2041bool 2042NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2043{ 2044 ip_header *ip = packet->getIpHdr(); 2045 tcp_header *hdr = packet->getTcpHdr(ip); 2046 2047 uint16_t cksum; 2048 pseudo_header *pseudo = new pseudo_header; 2049 if (!gen) { 2050 pseudo->src_ip_addr = ip->src_ip_addr; 2051 pseudo->dest_ip_addr = ip->dest_ip_addr; 2052 pseudo->protocol = reverseEnd16(ip->protocol); 2053 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4); 2054 2055 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2056 (uint32_t) reverseEnd16(pseudo->len)); 2057 } else { 2058 pseudo->src_ip_addr = 0; 2059 pseudo->dest_ip_addr = 0; 2060 pseudo->protocol = hdr->chksum; 2061 pseudo->len = 0; 2062 hdr->chksum = 0; 2063 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2064 (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4)); 2065 } 2066 2067 delete pseudo; 2068 if (gen) 2069 hdr->chksum = cksum; 2070 else 2071 if (cksum != 0) 2072 return false; 2073 2074 return true; 2075} 2076 2077bool 2078NSGigE::ipChecksum(PacketPtr packet, bool gen) 2079{ 2080 ip_header *hdr = packet->getIpHdr(); 2081 2082 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4); 2083 2084 if (gen) { 2085 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2086 hdr->hdr_chksum = cksum; 2087 } 2088 else 2089 if (cksum != 0) 2090 return false; 2091 2092 return true; 2093} 2094 2095uint16_t 2096NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2097{ 2098 uint32_t sum = 0; 2099 2100 uint16_t last_pad = 0; 2101 if (len & 1) { 2102 last_pad = buf[len/2] & 0xff; 2103 len--; 2104 sum += last_pad; 2105 } 2106 2107 if (pseudo) { 2108 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2109 pseudo[3] + pseudo[4] + pseudo[5]; 2110 } 2111 2112 for (int i=0; i < (len/2); ++i) { 2113 sum += buf[i]; 2114 } 2115 2116 while (sum >> 16) 2117 sum = (sum >> 16) + (sum & 0xffff); 2118 2119 return ~sum; 2120} 2121 2122//===================================================================== 2123// 2124// 2125void 2126NSGigE::serialize(ostream &os) 2127{ 2128 // Serialize the PciDev base class 2129 PciDev::serialize(os); 2130 2131 /* 2132 * Finalize any DMA events now. 2133 */ 2134 if (rxDmaReadEvent.scheduled()) 2135 rxDmaReadCopy(); 2136 if (rxDmaWriteEvent.scheduled()) 2137 rxDmaWriteCopy(); 2138 if (txDmaReadEvent.scheduled()) 2139 txDmaReadCopy(); 2140 if (txDmaWriteEvent.scheduled()) 2141 txDmaWriteCopy(); 2142 2143 /* 2144 * Serialize the device registers 2145 */ 2146 SERIALIZE_SCALAR(regs.command); 2147 SERIALIZE_SCALAR(regs.config); 2148 SERIALIZE_SCALAR(regs.mear); 2149 SERIALIZE_SCALAR(regs.ptscr); 2150 SERIALIZE_SCALAR(regs.isr); 2151 SERIALIZE_SCALAR(regs.imr); 2152 SERIALIZE_SCALAR(regs.ier); 2153 SERIALIZE_SCALAR(regs.ihr); 2154 SERIALIZE_SCALAR(regs.txdp); 2155 SERIALIZE_SCALAR(regs.txdp_hi); 2156 SERIALIZE_SCALAR(regs.txcfg); 2157 SERIALIZE_SCALAR(regs.gpior); 2158 SERIALIZE_SCALAR(regs.rxdp); 2159 SERIALIZE_SCALAR(regs.rxdp_hi); 2160 SERIALIZE_SCALAR(regs.rxcfg); 2161 SERIALIZE_SCALAR(regs.pqcr); 2162 SERIALIZE_SCALAR(regs.wcsr); 2163 SERIALIZE_SCALAR(regs.pcr); 2164 SERIALIZE_SCALAR(regs.rfcr); 2165 SERIALIZE_SCALAR(regs.rfdr); 2166 SERIALIZE_SCALAR(regs.srr); 2167 SERIALIZE_SCALAR(regs.mibc); 2168 SERIALIZE_SCALAR(regs.vrcr); 2169 SERIALIZE_SCALAR(regs.vtcr); 2170 SERIALIZE_SCALAR(regs.vdr); 2171 SERIALIZE_SCALAR(regs.ccsr); 2172 SERIALIZE_SCALAR(regs.tbicr); 2173 SERIALIZE_SCALAR(regs.tbisr); 2174 SERIALIZE_SCALAR(regs.tanar); 2175 SERIALIZE_SCALAR(regs.tanlpar); 2176 SERIALIZE_SCALAR(regs.taner); 2177 SERIALIZE_SCALAR(regs.tesr); 2178 2179 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2180 2181 SERIALIZE_SCALAR(ioEnable); 2182 2183 /* 2184 * Serialize the data Fifos 2185 */ 2186 int txNumPkts = txFifo.size(); 2187 SERIALIZE_SCALAR(txNumPkts); 2188 int i = 0; 2189 pktiter_t end = txFifo.end(); 2190 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2191 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2192 (*p)->serialize(os); 2193 } 2194 2195 int rxNumPkts = rxFifo.size(); 2196 SERIALIZE_SCALAR(rxNumPkts); 2197 i = 0; 2198 end = rxFifo.end(); 2199 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2200 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2201 (*p)->serialize(os); 2202 } 2203 2204 /* 2205 * Serialize the various helper variables 2206 */ 2207 bool txPacketExists = txPacket; 2208 SERIALIZE_SCALAR(txPacketExists); 2209 if (txPacketExists) { 2210 nameOut(os, csprintf("%s.txPacket", name())); 2211 txPacket->serialize(os); 2212 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2213 SERIALIZE_SCALAR(txPktBufPtr); 2214 } 2215 2216 bool rxPacketExists = rxPacket; 2217 SERIALIZE_SCALAR(rxPacketExists); 2218 if (rxPacketExists) { 2219 nameOut(os, csprintf("%s.rxPacket", name())); 2220 rxPacket->serialize(os); 2221 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2222 SERIALIZE_SCALAR(rxPktBufPtr); 2223 } 2224 2225 SERIALIZE_SCALAR(txXferLen); 2226 SERIALIZE_SCALAR(rxXferLen); 2227 2228 /* 2229 * Serialize DescCaches 2230 */ 2231 SERIALIZE_SCALAR(txDescCache.link); 2232 SERIALIZE_SCALAR(txDescCache.bufptr); 2233 SERIALIZE_SCALAR(txDescCache.cmdsts); 2234 SERIALIZE_SCALAR(txDescCache.extsts); 2235 SERIALIZE_SCALAR(rxDescCache.link); 2236 SERIALIZE_SCALAR(rxDescCache.bufptr); 2237 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2238 SERIALIZE_SCALAR(rxDescCache.extsts); 2239 2240 /* 2241 * Serialize tx state machine 2242 */ 2243 int txState = this->txState; 2244 SERIALIZE_SCALAR(txState); 2245 SERIALIZE_SCALAR(CTDD); 2246 SERIALIZE_SCALAR(txFifoAvail); 2247 SERIALIZE_SCALAR(txHalt); 2248 SERIALIZE_SCALAR(txFragPtr); 2249 SERIALIZE_SCALAR(txDescCnt); 2250 int txDmaState = this->txDmaState; 2251 SERIALIZE_SCALAR(txDmaState); 2252 2253 /* 2254 * Serialize rx state machine 2255 */ 2256 int rxState = this->rxState; 2257 SERIALIZE_SCALAR(rxState); 2258 SERIALIZE_SCALAR(CRDD); 2259 SERIALIZE_SCALAR(rxPktBytes); 2260 SERIALIZE_SCALAR(rxFifoCnt); 2261 SERIALIZE_SCALAR(rxHalt); 2262 SERIALIZE_SCALAR(rxDescCnt); 2263 int rxDmaState = this->rxDmaState; 2264 SERIALIZE_SCALAR(rxDmaState); 2265 2266 SERIALIZE_SCALAR(extstsEnable); 2267 2268 /* 2269 * If there's a pending transmit, store the time so we can 2270 * reschedule it later 2271 */ 2272 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2273 SERIALIZE_SCALAR(transmitTick); 2274 2275 /* 2276 * receive address filter settings 2277 */ 2278 SERIALIZE_SCALAR(rxFilterEnable); 2279 SERIALIZE_SCALAR(acceptBroadcast); 2280 SERIALIZE_SCALAR(acceptMulticast); 2281 SERIALIZE_SCALAR(acceptUnicast); 2282 SERIALIZE_SCALAR(acceptPerfect); 2283 SERIALIZE_SCALAR(acceptArp); 2284 2285 /* 2286 * Keep track of pending interrupt status. 2287 */ 2288 SERIALIZE_SCALAR(intrTick); 2289 SERIALIZE_SCALAR(cpuPendingIntr); 2290 Tick intrEventTick = 0; 2291 if (intrEvent) 2292 intrEventTick = intrEvent->when(); 2293 SERIALIZE_SCALAR(intrEventTick); 2294 2295} 2296 2297void 2298NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2299{ 2300 // Unserialize the PciDev base class 2301 PciDev::unserialize(cp, section); 2302 2303 UNSERIALIZE_SCALAR(regs.command); 2304 UNSERIALIZE_SCALAR(regs.config); 2305 UNSERIALIZE_SCALAR(regs.mear); 2306 UNSERIALIZE_SCALAR(regs.ptscr); 2307 UNSERIALIZE_SCALAR(regs.isr); 2308 UNSERIALIZE_SCALAR(regs.imr); 2309 UNSERIALIZE_SCALAR(regs.ier); 2310 UNSERIALIZE_SCALAR(regs.ihr); 2311 UNSERIALIZE_SCALAR(regs.txdp); 2312 UNSERIALIZE_SCALAR(regs.txdp_hi); 2313 UNSERIALIZE_SCALAR(regs.txcfg); 2314 UNSERIALIZE_SCALAR(regs.gpior); 2315 UNSERIALIZE_SCALAR(regs.rxdp); 2316 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2317 UNSERIALIZE_SCALAR(regs.rxcfg); 2318 UNSERIALIZE_SCALAR(regs.pqcr); 2319 UNSERIALIZE_SCALAR(regs.wcsr); 2320 UNSERIALIZE_SCALAR(regs.pcr); 2321 UNSERIALIZE_SCALAR(regs.rfcr); 2322 UNSERIALIZE_SCALAR(regs.rfdr); 2323 UNSERIALIZE_SCALAR(regs.srr); 2324 UNSERIALIZE_SCALAR(regs.mibc); 2325 UNSERIALIZE_SCALAR(regs.vrcr); 2326 UNSERIALIZE_SCALAR(regs.vtcr); 2327 UNSERIALIZE_SCALAR(regs.vdr); 2328 UNSERIALIZE_SCALAR(regs.ccsr); 2329 UNSERIALIZE_SCALAR(regs.tbicr); 2330 UNSERIALIZE_SCALAR(regs.tbisr); 2331 UNSERIALIZE_SCALAR(regs.tanar); 2332 UNSERIALIZE_SCALAR(regs.tanlpar); 2333 UNSERIALIZE_SCALAR(regs.taner); 2334 UNSERIALIZE_SCALAR(regs.tesr); 2335 2336 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2337 2338 UNSERIALIZE_SCALAR(ioEnable); 2339 2340 /* 2341 * unserialize the data fifos 2342 */ 2343 int txNumPkts; 2344 UNSERIALIZE_SCALAR(txNumPkts); 2345 int i; 2346 for (i = 0; i < txNumPkts; ++i) { 2347 PacketPtr p = new EtherPacket; 2348 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2349 txFifo.push_back(p); 2350 } 2351 2352 int rxNumPkts; 2353 UNSERIALIZE_SCALAR(rxNumPkts); 2354 for (i = 0; i < rxNumPkts; ++i) { 2355 PacketPtr p = new EtherPacket; 2356 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2357 rxFifo.push_back(p); 2358 } 2359 2360 /* 2361 * unserialize the various helper variables 2362 */ 2363 bool txPacketExists; 2364 UNSERIALIZE_SCALAR(txPacketExists); 2365 if (txPacketExists) { 2366 txPacket = new EtherPacket; 2367 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2368 uint32_t txPktBufPtr; 2369 UNSERIALIZE_SCALAR(txPktBufPtr); 2370 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2371 } else 2372 txPacket = 0; 2373 2374 bool rxPacketExists; 2375 UNSERIALIZE_SCALAR(rxPacketExists); 2376 rxPacket = 0; 2377 if (rxPacketExists) { 2378 rxPacket = new EtherPacket; 2379 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2380 uint32_t rxPktBufPtr; 2381 UNSERIALIZE_SCALAR(rxPktBufPtr); 2382 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2383 } else 2384 rxPacket = 0; 2385 2386 UNSERIALIZE_SCALAR(txXferLen); 2387 UNSERIALIZE_SCALAR(rxXferLen); 2388 2389 /* 2390 * Unserialize DescCaches 2391 */ 2392 UNSERIALIZE_SCALAR(txDescCache.link); 2393 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2394 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2395 UNSERIALIZE_SCALAR(txDescCache.extsts); 2396 UNSERIALIZE_SCALAR(rxDescCache.link); 2397 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2398 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2399 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2400 2401 /* 2402 * unserialize tx state machine 2403 */ 2404 int txState; 2405 UNSERIALIZE_SCALAR(txState); 2406 this->txState = (TxState) txState; 2407 UNSERIALIZE_SCALAR(CTDD); 2408 UNSERIALIZE_SCALAR(txFifoAvail); 2409 UNSERIALIZE_SCALAR(txHalt); 2410 UNSERIALIZE_SCALAR(txFragPtr); 2411 UNSERIALIZE_SCALAR(txDescCnt); 2412 int txDmaState; 2413 UNSERIALIZE_SCALAR(txDmaState); 2414 this->txDmaState = (DmaState) txDmaState; 2415 2416 /* 2417 * unserialize rx state machine 2418 */ 2419 int rxState; 2420 UNSERIALIZE_SCALAR(rxState); 2421 this->rxState = (RxState) rxState; 2422 UNSERIALIZE_SCALAR(CRDD); 2423 UNSERIALIZE_SCALAR(rxPktBytes); 2424 UNSERIALIZE_SCALAR(rxFifoCnt); 2425 UNSERIALIZE_SCALAR(rxHalt); 2426 UNSERIALIZE_SCALAR(rxDescCnt); 2427 int rxDmaState; 2428 UNSERIALIZE_SCALAR(rxDmaState); 2429 this->rxDmaState = (DmaState) rxDmaState; 2430 2431 UNSERIALIZE_SCALAR(extstsEnable); 2432 2433 /* 2434 * If there's a pending transmit, reschedule it now 2435 */ 2436 Tick transmitTick; 2437 UNSERIALIZE_SCALAR(transmitTick); 2438 if (transmitTick) 2439 txEvent.schedule(curTick + transmitTick); 2440 2441 /* 2442 * unserialize receive address filter settings 2443 */ 2444 UNSERIALIZE_SCALAR(rxFilterEnable); 2445 UNSERIALIZE_SCALAR(acceptBroadcast); 2446 UNSERIALIZE_SCALAR(acceptMulticast); 2447 UNSERIALIZE_SCALAR(acceptUnicast); 2448 UNSERIALIZE_SCALAR(acceptPerfect); 2449 UNSERIALIZE_SCALAR(acceptArp); 2450 2451 /* 2452 * Keep track of pending interrupt status. 2453 */ 2454 UNSERIALIZE_SCALAR(intrTick); 2455 UNSERIALIZE_SCALAR(cpuPendingIntr); 2456 Tick intrEventTick; 2457 UNSERIALIZE_SCALAR(intrEventTick); 2458 if (intrEventTick) { 2459 intrEvent = new IntrEvent(this, true); 2460 intrEvent->schedule(intrEventTick); 2461 } 2462 2463 /* 2464 * re-add addrRanges to bus bridges 2465 */ 2466 if (pioInterface) { 2467 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2468 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2469 } 2470} 2471 2472Tick 2473NSGigE::cacheAccess(MemReqPtr &req) 2474{ 2475 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2476 req->paddr, req->paddr - addr); 2477 return curTick + pioLatency; 2478} 2479//===================================================================== 2480 2481 2482//********** helper functions****************************************** 2483 2484uint16_t reverseEnd16(uint16_t num) 2485{ 2486 uint16_t reverse = (num & 0xff)<<8; 2487 reverse += ((num & 0xff00) >> 8); 2488 return reverse; 2489} 2490 2491uint32_t reverseEnd32(uint32_t num) 2492{ 2493 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2494 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2495 return reverse; 2496} 2497 2498 2499 2500//===================================================================== 2501 2502BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2503 2504 SimObjectParam<EtherInt *> peer; 2505 SimObjectParam<NSGigE *> device; 2506 2507END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2508 2509BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2510 2511 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2512 INIT_PARAM(device, "Ethernet device of this interface") 2513 2514END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2515 2516CREATE_SIM_OBJECT(NSGigEInt) 2517{ 2518 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2519 2520 EtherInt *p = (EtherInt *)peer; 2521 if (p) { 2522 dev_int->setPeer(p); 2523 p->setPeer(dev_int); 2524 } 2525 2526 return dev_int; 2527} 2528 2529REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2530 2531 2532BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2533 2534 Param<Tick> tx_delay; 2535 Param<Tick> rx_delay; 2536 SimObjectParam<IntrControl *> intr_ctrl; 2537 Param<Tick> intr_delay; 2538 SimObjectParam<MemoryController *> mmu; 2539 SimObjectParam<PhysicalMemory *> physmem; 2540 Param<bool> rx_filter; 2541 Param<string> hardware_address; 2542 SimObjectParam<Bus*> header_bus; 2543 SimObjectParam<Bus*> payload_bus; 2544 SimObjectParam<HierParams *> hier; 2545 Param<Tick> pio_latency; 2546 Param<bool> dma_desc_free; 2547 Param<bool> dma_data_free; 2548 Param<Tick> dma_read_delay; 2549 Param<Tick> dma_write_delay; 2550 Param<Tick> dma_read_factor; 2551 Param<Tick> dma_write_factor; 2552 SimObjectParam<PciConfigAll *> configspace; 2553 SimObjectParam<PciConfigData *> configdata; 2554 SimObjectParam<Tsunami *> tsunami; 2555 Param<uint32_t> pci_bus; 2556 Param<uint32_t> pci_dev; 2557 Param<uint32_t> pci_func; 2558 2559END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2560 2561BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2562 2563 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2564 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2565 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2566 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2567 INIT_PARAM(mmu, "Memory Controller"), 2568 INIT_PARAM(physmem, "Physical Memory"), 2569 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2570 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2571 "00:99:00:00:00:01"), 2572 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2573 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2574 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2575 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), 2576 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2577 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2578 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2579 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2580 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2581 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2582 INIT_PARAM(configspace, "PCI Configspace"), 2583 INIT_PARAM(configdata, "PCI Config data"), 2584 INIT_PARAM(tsunami, "Tsunami"), 2585 INIT_PARAM(pci_bus, "PCI bus"), 2586 INIT_PARAM(pci_dev, "PCI device number"), 2587 INIT_PARAM(pci_func, "PCI function code") 2588 2589END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2590 2591 2592CREATE_SIM_OBJECT(NSGigE) 2593{ 2594 int eaddr[6]; 2595 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2596 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2597 2598 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2599 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2600 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2601 dma_read_delay, dma_write_delay, dma_read_factor, 2602 dma_write_factor, configspace, configdata, 2603 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr); 2604} 2605 2606REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2607