ns_gige.cc revision 986
17202Sgblack@eecs.umich.edu/* 27202Sgblack@eecs.umich.edu * Copyright (c) 2004 The Regents of The University of Michigan 312503Snikos.nikoleris@arm.com * All rights reserved. 47202Sgblack@eecs.umich.edu * 57202Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67202Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77202Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87202Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97202Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107202Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117202Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127202Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137202Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147202Sgblack@eecs.umich.edu * this software without specific prior written permission. 157202Sgblack@eecs.umich.edu * 167202Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177202Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187202Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197202Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207202Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217202Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227202Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237202Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247202Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257202Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267202Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277202Sgblack@eecs.umich.edu */ 287202Sgblack@eecs.umich.edu 297202Sgblack@eecs.umich.edu/* @file 307202Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor 317202Sgblack@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 327202Sgblack@eecs.umich.edu */ 337202Sgblack@eecs.umich.edu#include <cstdio> 347202Sgblack@eecs.umich.edu#include <deque> 357202Sgblack@eecs.umich.edu#include <string> 367202Sgblack@eecs.umich.edu 377202Sgblack@eecs.umich.edu#include "base/inet.hh" 387202Sgblack@eecs.umich.edu#include "cpu/exec_context.hh" 397202Sgblack@eecs.umich.edu#include "cpu/intr_control.hh" 407202Sgblack@eecs.umich.edu#include "dev/dma.hh" 417202Sgblack@eecs.umich.edu#include "dev/ns_gige.hh" 427202Sgblack@eecs.umich.edu#include "dev/etherlink.hh" 437202Sgblack@eecs.umich.edu#include "mem/bus/bus.hh" 447202Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh" 457202Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh" 467202Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh" 4712616Sgabeblack@google.com#include "mem/functional_mem/memory_control.hh" 487202Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh" 497202Sgblack@eecs.umich.edu#include "sim/builder.hh" 507202Sgblack@eecs.umich.edu#include "sim/host.hh" 517202Sgblack@eecs.umich.edu#include "sim/sim_stats.hh" 5210184SCurtis.Dunham@arm.com#include "targetarch/vtophys.hh" 537202Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh" 547202Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh" 557202Sgblack@eecs.umich.edu 567202Sgblack@eecs.umich.educonst char *NsRxStateStrings[] = 577848SAli.Saidi@ARM.com{ 587848SAli.Saidi@ARM.com "rxIdle", 597848SAli.Saidi@ARM.com "rxDescRefr", 607848SAli.Saidi@ARM.com "rxDescRead", 617848SAli.Saidi@ARM.com "rxFifoBlock", 627202Sgblack@eecs.umich.edu "rxFragWrite", 637202Sgblack@eecs.umich.edu "rxDescWrite", 647202Sgblack@eecs.umich.edu "rxAdvance" 6510037SARM gem5 Developers}; 6610037SARM gem5 Developers 6710037SARM gem5 Developersconst char *NsTxStateStrings[] = 6810037SARM gem5 Developers{ 6910037SARM gem5 Developers "txIdle", 7010037SARM gem5 Developers "txDescRefr", 7110037SARM gem5 Developers "txDescRead", 7210037SARM gem5 Developers "txFifoBlock", 7310037SARM gem5 Developers "txFragRead", 7410037SARM gem5 Developers "txDescWrite", 7510037SARM gem5 Developers "txAdvance" 7612616Sgabeblack@google.com}; 7710037SARM gem5 Developers 7810037SARM gem5 Developersconst char *NsDmaState[] = 7910037SARM gem5 Developers{ 8010037SARM gem5 Developers "dmaIdle", 8110184SCurtis.Dunham@arm.com "dmaReading", 8210037SARM gem5 Developers "dmaWriting", 8310037SARM gem5 Developers "dmaReadWaiting", 8410037SARM gem5 Developers "dmaWriteWaiting" 8510037SARM gem5 Developers}; 8610037SARM gem5 Developers 8710037SARM gem5 Developersusing namespace std; 8810037SARM gem5 Developers 8910037SARM gem5 Developers//helper function declarations 9010037SARM gem5 Developers//These functions reverse Endianness so we can evaluate network data correctly 9110037SARM gem5 Developersuint16_t reverseEnd16(uint16_t); 9210037SARM gem5 Developersuint32_t reverseEnd32(uint32_t); 9310037SARM gem5 Developers 9410037SARM gem5 Developers/////////////////////////////////////////////////////////////////////// 9510037SARM gem5 Developers// 9610037SARM gem5 Developers// NSGigE PCI Device 9710037SARM gem5 Developers// 9810037SARM gem5 DevelopersNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 9910037SARM gem5 Developers PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 10010037SARM gem5 Developers MemoryController *mmu, HierParams *hier, Bus *header_bus, 10110037SARM gem5 Developers Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 10210037SARM gem5 Developers bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 10310037SARM gem5 Developers Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 10410037SARM gem5 Developers PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 10510037SARM gem5 Developers uint32_t func, bool rx_filter, const int eaddr[6]) 10610037SARM gem5 Developers : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 10712616Sgabeblack@google.com txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 10810037SARM gem5 Developers txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false), 10910037SARM gem5 Developers txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), 11010037SARM gem5 Developers txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 11110037SARM gem5 Developers CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 11210184SCurtis.Dunham@arm.com rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 11310037SARM gem5 Developers rxDmaReadEvent(this), rxDmaWriteEvent(this), 11410037SARM gem5 Developers txDmaReadEvent(this), txDmaWriteEvent(this), 11510037SARM gem5 Developers dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 11610037SARM gem5 Developers txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 11710037SARM gem5 Developers txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 11810037SARM gem5 Developers acceptMulticast(false), acceptUnicast(false), 11910037SARM gem5 Developers acceptPerfect(false), acceptArp(false), 12010037SARM gem5 Developers physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 12110037SARM gem5 Developers intrEvent(0), interface(0), pioLatency(pio_latency) 12210037SARM gem5 Developers{ 12310037SARM gem5 Developers tsunami->ethernet = this; 12410037SARM gem5 Developers 12510037SARM gem5 Developers if (header_bus) { 12610037SARM gem5 Developers pioInterface = newPioInterface(name, hier, header_bus, this, 12710037SARM gem5 Developers &NSGigE::cacheAccess); 1287202Sgblack@eecs.umich.edu 1297202Sgblack@eecs.umich.edu if (payload_bus) 1307202Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1317202Sgblack@eecs.umich.edu header_bus, payload_bus, 1); 1327202Sgblack@eecs.umich.edu else 1337202Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1347202Sgblack@eecs.umich.edu header_bus, header_bus, 1); 13512616Sgabeblack@google.com } else if (payload_bus) { 1367202Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, payload_bus, this, 1377202Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1387202Sgblack@eecs.umich.edu 1397202Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 14010184SCurtis.Dunham@arm.com payload_bus, 1); 1417202Sgblack@eecs.umich.edu 1427202Sgblack@eecs.umich.edu } 1437202Sgblack@eecs.umich.edu 1447202Sgblack@eecs.umich.edu 1457202Sgblack@eecs.umich.edu intrDelay = US2Ticks(intr_delay); 1467848SAli.Saidi@ARM.com dmaReadDelay = dma_read_delay; 1477848SAli.Saidi@ARM.com dmaWriteDelay = dma_write_delay; 1487848SAli.Saidi@ARM.com dmaReadFactor = dma_read_factor; 1497848SAli.Saidi@ARM.com dmaWriteFactor = dma_write_factor; 1507848SAli.Saidi@ARM.com 1517202Sgblack@eecs.umich.edu regsReset(); 1527202Sgblack@eecs.umich.edu rom.perfectMatch[0] = eaddr[0]; 1537202Sgblack@eecs.umich.edu rom.perfectMatch[1] = eaddr[1]; 1547202Sgblack@eecs.umich.edu rom.perfectMatch[2] = eaddr[2]; 1557202Sgblack@eecs.umich.edu rom.perfectMatch[3] = eaddr[3]; 1567202Sgblack@eecs.umich.edu rom.perfectMatch[4] = eaddr[4]; 1577202Sgblack@eecs.umich.edu rom.perfectMatch[5] = eaddr[5]; 1587202Sgblack@eecs.umich.edu} 1597202Sgblack@eecs.umich.edu 1607202Sgblack@eecs.umich.eduNSGigE::~NSGigE() 16112616Sgabeblack@google.com{} 1627202Sgblack@eecs.umich.edu 1637202Sgblack@eecs.umich.eduvoid 1647202Sgblack@eecs.umich.eduNSGigE::regStats() 1657202Sgblack@eecs.umich.edu{ 16610184SCurtis.Dunham@arm.com txBytes 1677202Sgblack@eecs.umich.edu .name(name() + ".txBytes") 1687202Sgblack@eecs.umich.edu .desc("Bytes Transmitted") 1697202Sgblack@eecs.umich.edu .prereq(txBytes) 1707202Sgblack@eecs.umich.edu ; 1717202Sgblack@eecs.umich.edu 1727848SAli.Saidi@ARM.com rxBytes 1737848SAli.Saidi@ARM.com .name(name() + ".rxBytes") 1747848SAli.Saidi@ARM.com .desc("Bytes Received") 1757848SAli.Saidi@ARM.com .prereq(rxBytes) 1767848SAli.Saidi@ARM.com ; 1777202Sgblack@eecs.umich.edu 1787202Sgblack@eecs.umich.edu txPackets 1797208Sgblack@eecs.umich.edu .name(name() + ".txPackets") 18010037SARM gem5 Developers .desc("Number of Packets Transmitted") 18110037SARM gem5 Developers .prereq(txBytes) 18210037SARM gem5 Developers ; 18310037SARM gem5 Developers 18410037SARM gem5 Developers rxPackets 18510037SARM gem5 Developers .name(name() + ".rxPackets") 18610420Sandreas.hansson@arm.com .desc("Number of Packets Received") 18710037SARM gem5 Developers .prereq(rxBytes) 18812616Sgabeblack@google.com ; 18910037SARM gem5 Developers 19010037SARM gem5 Developers txIPChecksums 19110037SARM gem5 Developers .name(name() + ".txIPChecksums") 19210037SARM gem5 Developers .desc("Number of tx IP Checksums done by device") 19310184SCurtis.Dunham@arm.com .precision(0) 19410420Sandreas.hansson@arm.com .prereq(txBytes) 19510037SARM gem5 Developers ; 19610037SARM gem5 Developers 19710037SARM gem5 Developers rxIPChecksums 19810037SARM gem5 Developers .name(name() + ".rxIPChecksums") 19910037SARM gem5 Developers .desc("Number of rx IP Checksums done by device") 20010037SARM gem5 Developers .precision(0) 20110037SARM gem5 Developers .prereq(rxBytes) 20210037SARM gem5 Developers ; 20310037SARM gem5 Developers 20410037SARM gem5 Developers txTCPChecksums 20510037SARM gem5 Developers .name(name() + ".txTCPChecksums") 20610037SARM gem5 Developers .desc("Number of tx TCP Checksums done by device") 20710037SARM gem5 Developers .precision(0) 20810037SARM gem5 Developers .prereq(txBytes) 20910037SARM gem5 Developers ; 21010037SARM gem5 Developers 21110037SARM gem5 Developers rxTCPChecksums 21210037SARM gem5 Developers .name(name() + ".rxTCPChecksums") 21310037SARM gem5 Developers .desc("Number of rx TCP Checksums done by device") 21410037SARM gem5 Developers .precision(0) 21510037SARM gem5 Developers .prereq(rxBytes) 21610037SARM gem5 Developers ; 21710420Sandreas.hansson@arm.com 21812616Sgabeblack@google.com descDmaReads 21910037SARM gem5 Developers .name(name() + ".descDMAReads") 22010037SARM gem5 Developers .desc("Number of descriptors the device read w/ DMA") 22110037SARM gem5 Developers .precision(0) 22210037SARM gem5 Developers ; 22310184SCurtis.Dunham@arm.com 22410037SARM gem5 Developers descDmaWrites 22510037SARM gem5 Developers .name(name() + ".descDMAWrites") 22610420Sandreas.hansson@arm.com .desc("Number of descriptors the device wrote w/ DMA") 22710037SARM gem5 Developers .precision(0) 22810037SARM gem5 Developers ; 22910037SARM gem5 Developers 23010037SARM gem5 Developers descDmaRdBytes 23110037SARM gem5 Developers .name(name() + ".descDmaReadBytes") 23210037SARM gem5 Developers .desc("number of descriptor bytes read w/ DMA") 23310037SARM gem5 Developers .precision(0) 23410037SARM gem5 Developers ; 23510037SARM gem5 Developers 23610037SARM gem5 Developers descDmaWrBytes 23710037SARM gem5 Developers .name(name() + ".descDmaWriteBytes") 23810037SARM gem5 Developers .desc("number of descriptor bytes write w/ DMA") 23910037SARM gem5 Developers .precision(0) 2407306Sgblack@eecs.umich.edu ; 2417306Sgblack@eecs.umich.edu 2427306Sgblack@eecs.umich.edu 2437306Sgblack@eecs.umich.edu txBandwidth 2447306Sgblack@eecs.umich.edu .name(name() + ".txBandwidth") 2457306Sgblack@eecs.umich.edu .desc("Transmit Bandwidth (bits/s)") 2467330Sgblack@eecs.umich.edu .precision(0) 24712616Sgabeblack@google.com .prereq(txBytes) 2487306Sgblack@eecs.umich.edu ; 2497306Sgblack@eecs.umich.edu 2507306Sgblack@eecs.umich.edu rxBandwidth 2517306Sgblack@eecs.umich.edu .name(name() + ".rxBandwidth") 25210184SCurtis.Dunham@arm.com .desc("Receive Bandwidth (bits/s)") 2537306Sgblack@eecs.umich.edu .precision(0) 2547306Sgblack@eecs.umich.edu .prereq(rxBytes) 2557306Sgblack@eecs.umich.edu ; 2567848SAli.Saidi@ARM.com 2577848SAli.Saidi@ARM.com txPacketRate 2587848SAli.Saidi@ARM.com .name(name() + ".txPPS") 2597848SAli.Saidi@ARM.com .desc("Packet Tranmission Rate (packets/s)") 2607848SAli.Saidi@ARM.com .precision(0) 2617306Sgblack@eecs.umich.edu .prereq(txBytes) 2627306Sgblack@eecs.umich.edu ; 2637306Sgblack@eecs.umich.edu 2647332Sgblack@eecs.umich.edu rxPacketRate 2657332Sgblack@eecs.umich.edu .name(name() + ".rxPPS") 2667332Sgblack@eecs.umich.edu .desc("Packet Reception Rate (packets/s)") 2677332Sgblack@eecs.umich.edu .precision(0) 2687332Sgblack@eecs.umich.edu .prereq(rxBytes) 2697332Sgblack@eecs.umich.edu ; 2707332Sgblack@eecs.umich.edu 27112616Sgabeblack@google.com txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2727332Sgblack@eecs.umich.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2737332Sgblack@eecs.umich.edu txPacketRate = txPackets / simSeconds; 2747332Sgblack@eecs.umich.edu rxPacketRate = rxPackets / simSeconds; 2757332Sgblack@eecs.umich.edu} 27610184SCurtis.Dunham@arm.com 2777332Sgblack@eecs.umich.edu/** 2787332Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers 2797332Sgblack@eecs.umich.edu */ 2807332Sgblack@eecs.umich.eduvoid 2817848SAli.Saidi@ARM.comNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2827848SAli.Saidi@ARM.com{ 2837848SAli.Saidi@ARM.com if (offset < PCI_DEVICE_SPECIFIC) 2847848SAli.Saidi@ARM.com PciDev::ReadConfig(offset, size, data); 2857848SAli.Saidi@ARM.com else 2867332Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 2877332Sgblack@eecs.umich.edu} 2887332Sgblack@eecs.umich.edu 2897261Sgblack@eecs.umich.edu/** 2907208Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 2917208Sgblack@eecs.umich.edu */ 2927208Sgblack@eecs.umich.eduvoid 2937208Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 2947208Sgblack@eecs.umich.edu{ 2957208Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 2967208Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 29712616Sgabeblack@google.com else 2987208Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 2997208Sgblack@eecs.umich.edu 3007208Sgblack@eecs.umich.edu // Need to catch writes to BARs to update the PIO interface 3017261Sgblack@eecs.umich.edu switch (offset) { 30210184SCurtis.Dunham@arm.com //seems to work fine without all these PCI settings, but i put in the IO 3037208Sgblack@eecs.umich.edu //to double check, an assertion will fail if we need to properly 3047208Sgblack@eecs.umich.edu // implement it 3057208Sgblack@eecs.umich.edu case PCI_COMMAND: 3067208Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 3077848SAli.Saidi@ARM.com ioEnable = true; 3087848SAli.Saidi@ARM.com else 3097848SAli.Saidi@ARM.com ioEnable = false; 3107848SAli.Saidi@ARM.com 3117848SAli.Saidi@ARM.com#if 0 3127208Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_BME) { 3137208Sgblack@eecs.umich.edu bmEnabled = true; 3147225Sgblack@eecs.umich.edu } 3157233Sgblack@eecs.umich.edu else { 3167233Sgblack@eecs.umich.edu bmEnabled = false; 3177233Sgblack@eecs.umich.edu } 3187233Sgblack@eecs.umich.edu 3197233Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_MSE) { 3207233Sgblack@eecs.umich.edu memEnable = true; 3217233Sgblack@eecs.umich.edu } 3227233Sgblack@eecs.umich.edu else { 3237330Sgblack@eecs.umich.edu memEnable = false; 32412616Sgabeblack@google.com } 3257233Sgblack@eecs.umich.edu#endif 3267233Sgblack@eecs.umich.edu break; 3277233Sgblack@eecs.umich.edu 3287233Sgblack@eecs.umich.edu case PCI0_BASE_ADDR0: 32910184SCurtis.Dunham@arm.com if (BARAddrs[0] != 0) { 3307233Sgblack@eecs.umich.edu 3317233Sgblack@eecs.umich.edu if (pioInterface) 3327233Sgblack@eecs.umich.edu pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 3337330Sgblack@eecs.umich.edu 3347233Sgblack@eecs.umich.edu BARAddrs[0] &= PA_UNCACHED_MASK; 3357233Sgblack@eecs.umich.edu 3367233Sgblack@eecs.umich.edu } 3377233Sgblack@eecs.umich.edu break; 3387848SAli.Saidi@ARM.com case PCI0_BASE_ADDR1: 3397848SAli.Saidi@ARM.com if (BARAddrs[1] != 0) { 3407848SAli.Saidi@ARM.com 3417848SAli.Saidi@ARM.com if (pioInterface) 3427848SAli.Saidi@ARM.com pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 3437233Sgblack@eecs.umich.edu 3447233Sgblack@eecs.umich.edu BARAddrs[1] &= PA_UNCACHED_MASK; 3457233Sgblack@eecs.umich.edu 3467241Sgblack@eecs.umich.edu } 3477241Sgblack@eecs.umich.edu break; 3487241Sgblack@eecs.umich.edu } 3497241Sgblack@eecs.umich.edu} 3507241Sgblack@eecs.umich.edu 3517241Sgblack@eecs.umich.edu/** 3527241Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 3537241Sgblack@eecs.umich.edu * spec sheet 3547241Sgblack@eecs.umich.edu */ 35512616Sgabeblack@google.comFault 3567241Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3577241Sgblack@eecs.umich.edu{ 3587241Sgblack@eecs.umich.edu assert(ioEnable); 3597241Sgblack@eecs.umich.edu 36010184SCurtis.Dunham@arm.com //The mask is to give you only the offset into the device register file 3617241Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 3627241Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3637241Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 3647241Sgblack@eecs.umich.edu 3657241Sgblack@eecs.umich.edu 3667241Sgblack@eecs.umich.edu //there are some reserved registers, you can see ns_gige_reg.h and 3677241Sgblack@eecs.umich.edu //the spec sheet for details 3687241Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 3697848SAli.Saidi@ARM.com panic("Accessing reserved register"); 3707848SAli.Saidi@ARM.com } else if (daddr > RESERVED && daddr <= 0x3FC) { 3717848SAli.Saidi@ARM.com ReadConfig(daddr & 0xff, req->size, data); 3727848SAli.Saidi@ARM.com return No_Fault; 3737848SAli.Saidi@ARM.com } else if (daddr >= MIB_START && daddr <= MIB_END) { 3747241Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 3757241Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 3767241Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 3777238Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *) data; 3787238Sgblack@eecs.umich.edu reg = 0; 3797238Sgblack@eecs.umich.edu return No_Fault; 3807238Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 3817238Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 3827238Sgblack@eecs.umich.edu 3837238Sgblack@eecs.umich.edu switch (req->size) { 3847238Sgblack@eecs.umich.edu case sizeof(uint32_t): 38512616Sgabeblack@google.com { 3867238Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *)data; 3877238Sgblack@eecs.umich.edu 3887238Sgblack@eecs.umich.edu switch (daddr) { 3897238Sgblack@eecs.umich.edu case CR: 39010184SCurtis.Dunham@arm.com reg = regs.command; 3917238Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 3927238Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3937238Sgblack@eecs.umich.edu break; 3947238Sgblack@eecs.umich.edu 3957238Sgblack@eecs.umich.edu case CFG: 3967238Sgblack@eecs.umich.edu reg = regs.config; 3977238Sgblack@eecs.umich.edu break; 3987848SAli.Saidi@ARM.com 3997848SAli.Saidi@ARM.com case MEAR: 4007848SAli.Saidi@ARM.com reg = regs.mear; 4017848SAli.Saidi@ARM.com break; 4027848SAli.Saidi@ARM.com 4037238Sgblack@eecs.umich.edu case PTSCR: 4047238Sgblack@eecs.umich.edu reg = regs.ptscr; 4057238Sgblack@eecs.umich.edu break; 4067331Sgblack@eecs.umich.edu 4077331Sgblack@eecs.umich.edu case ISR: 4087331Sgblack@eecs.umich.edu reg = regs.isr; 4097331Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 4107331Sgblack@eecs.umich.edu break; 4117331Sgblack@eecs.umich.edu 4127331Sgblack@eecs.umich.edu case IMR: 4137331Sgblack@eecs.umich.edu reg = regs.imr; 4147331Sgblack@eecs.umich.edu break; 41512616Sgabeblack@google.com 4167331Sgblack@eecs.umich.edu case IER: 4177331Sgblack@eecs.umich.edu reg = regs.ier; 4187331Sgblack@eecs.umich.edu break; 4197331Sgblack@eecs.umich.edu 42010184SCurtis.Dunham@arm.com case IHR: 4217331Sgblack@eecs.umich.edu reg = regs.ihr; 4227331Sgblack@eecs.umich.edu break; 4237331Sgblack@eecs.umich.edu 4247331Sgblack@eecs.umich.edu case TXDP: 4257331Sgblack@eecs.umich.edu reg = regs.txdp; 4267331Sgblack@eecs.umich.edu break; 4277331Sgblack@eecs.umich.edu 4287848SAli.Saidi@ARM.com case TXDP_HI: 4297848SAli.Saidi@ARM.com reg = regs.txdp_hi; 4307848SAli.Saidi@ARM.com break; 4317848SAli.Saidi@ARM.com 4327848SAli.Saidi@ARM.com case TXCFG: 4337331Sgblack@eecs.umich.edu reg = regs.txcfg; 4347331Sgblack@eecs.umich.edu break; 4357331Sgblack@eecs.umich.edu 43610418Sandreas.hansson@arm.com case GPIOR: 43710418Sandreas.hansson@arm.com reg = regs.gpior; 43810418Sandreas.hansson@arm.com break; 43910418Sandreas.hansson@arm.com 44010418Sandreas.hansson@arm.com case RXDP: 44110418Sandreas.hansson@arm.com reg = regs.rxdp; 44210418Sandreas.hansson@arm.com break; 44310418Sandreas.hansson@arm.com 44410418Sandreas.hansson@arm.com case RXDP_HI: 44512616Sgabeblack@google.com reg = regs.rxdp_hi; 44610418Sandreas.hansson@arm.com break; 44710418Sandreas.hansson@arm.com 44810418Sandreas.hansson@arm.com case RXCFG: 44910418Sandreas.hansson@arm.com reg = regs.rxcfg; 45010418Sandreas.hansson@arm.com break; 45110418Sandreas.hansson@arm.com 45210418Sandreas.hansson@arm.com case PQCR: 45310418Sandreas.hansson@arm.com reg = regs.pqcr; 45410418Sandreas.hansson@arm.com break; 45510418Sandreas.hansson@arm.com 45610418Sandreas.hansson@arm.com case WCSR: 45710418Sandreas.hansson@arm.com reg = regs.wcsr; 45810418Sandreas.hansson@arm.com break; 45910418Sandreas.hansson@arm.com 46010418Sandreas.hansson@arm.com case PCR: 46110418Sandreas.hansson@arm.com reg = regs.pcr; 46210418Sandreas.hansson@arm.com break; 46310418Sandreas.hansson@arm.com 46410418Sandreas.hansson@arm.com //see the spec sheet for how RFCR and RFDR work 46510418Sandreas.hansson@arm.com //basically, you write to RFCR to tell the machine what you want to do next 46610418Sandreas.hansson@arm.com //then you act upon RFDR, and the device will be prepared b/c 46710418Sandreas.hansson@arm.com //of what you wrote to RFCR 46810418Sandreas.hansson@arm.com case RFCR: 46910418Sandreas.hansson@arm.com reg = regs.rfcr; 47010418Sandreas.hansson@arm.com break; 47110418Sandreas.hansson@arm.com 47210418Sandreas.hansson@arm.com case RFDR: 47310418Sandreas.hansson@arm.com switch (regs.rfcr & RFCR_RFADDR) { 47410418Sandreas.hansson@arm.com case 0x000: 47512616Sgabeblack@google.com reg = rom.perfectMatch[1]; 47610418Sandreas.hansson@arm.com reg = reg << 8; 47710418Sandreas.hansson@arm.com reg += rom.perfectMatch[0]; 47810418Sandreas.hansson@arm.com break; 47910418Sandreas.hansson@arm.com case 0x002: 48010418Sandreas.hansson@arm.com reg = rom.perfectMatch[3] << 8; 48110418Sandreas.hansson@arm.com reg += rom.perfectMatch[2]; 48210418Sandreas.hansson@arm.com break; 48310418Sandreas.hansson@arm.com case 0x004: 48410418Sandreas.hansson@arm.com reg = rom.perfectMatch[5] << 8; 48510418Sandreas.hansson@arm.com reg += rom.perfectMatch[4]; 48610418Sandreas.hansson@arm.com break; 48710418Sandreas.hansson@arm.com default: 48810418Sandreas.hansson@arm.com panic("reading from RFDR for something for other than PMATCH!\n"); 48910418Sandreas.hansson@arm.com //didn't implement other RFDR functionality b/c driver didn't use 49010418Sandreas.hansson@arm.com } 49110418Sandreas.hansson@arm.com break; 49210418Sandreas.hansson@arm.com 49310418Sandreas.hansson@arm.com case SRR: 49410418Sandreas.hansson@arm.com reg = regs.srr; 49510418Sandreas.hansson@arm.com break; 49610037SARM gem5 Developers 49710037SARM gem5 Developers case MIBC: 49810037SARM gem5 Developers reg = regs.mibc; 49910037SARM gem5 Developers reg &= ~(MIBC_MIBS | MIBC_ACLR); 50010037SARM gem5 Developers break; 50110037SARM gem5 Developers 50210037SARM gem5 Developers case VRCR: 50310037SARM gem5 Developers reg = regs.vrcr; 50412616Sgabeblack@google.com break; 50510037SARM gem5 Developers 50610037SARM gem5 Developers case VTCR: 50710037SARM gem5 Developers reg = regs.vtcr; 50810037SARM gem5 Developers break; 50910184SCurtis.Dunham@arm.com 51010037SARM gem5 Developers case VDR: 51110037SARM gem5 Developers reg = regs.vdr; 51210037SARM gem5 Developers break; 51310037SARM gem5 Developers 51410037SARM gem5 Developers case CCSR: 51510037SARM gem5 Developers reg = regs.ccsr; 51610037SARM gem5 Developers break; 51710037SARM gem5 Developers 51810037SARM gem5 Developers case TBICR: 51910037SARM gem5 Developers reg = regs.tbicr; 52010037SARM gem5 Developers break; 52110037SARM gem5 Developers 52210037SARM gem5 Developers case TBISR: 52310037SARM gem5 Developers reg = regs.tbisr; 52410037SARM gem5 Developers break; 5257253Sgblack@eecs.umich.edu 5267253Sgblack@eecs.umich.edu case TANAR: 5277253Sgblack@eecs.umich.edu reg = regs.tanar; 5287253Sgblack@eecs.umich.edu break; 5297253Sgblack@eecs.umich.edu 5307253Sgblack@eecs.umich.edu case TANLPAR: 5317253Sgblack@eecs.umich.edu reg = regs.tanlpar; 5327253Sgblack@eecs.umich.edu break; 5337330Sgblack@eecs.umich.edu 53412616Sgabeblack@google.com case TANER: 5357253Sgblack@eecs.umich.edu reg = regs.taner; 5367253Sgblack@eecs.umich.edu break; 5377253Sgblack@eecs.umich.edu 5387253Sgblack@eecs.umich.edu case TESR: 53910184SCurtis.Dunham@arm.com reg = regs.tesr; 5407253Sgblack@eecs.umich.edu break; 5417253Sgblack@eecs.umich.edu 5427330Sgblack@eecs.umich.edu default: 5437330Sgblack@eecs.umich.edu panic("reading unimplemented register: addr = %#x", daddr); 5447253Sgblack@eecs.umich.edu } 5457253Sgblack@eecs.umich.edu 5467253Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 5477253Sgblack@eecs.umich.edu daddr, reg, reg); 5487848SAli.Saidi@ARM.com } 5497848SAli.Saidi@ARM.com break; 5507848SAli.Saidi@ARM.com 5517848SAli.Saidi@ARM.com default: 5527848SAli.Saidi@ARM.com panic("accessing register with invalid size: addr=%#x, size=%d", 5537253Sgblack@eecs.umich.edu daddr, req->size); 5547253Sgblack@eecs.umich.edu } 5557253Sgblack@eecs.umich.edu 5567232Sgblack@eecs.umich.edu return No_Fault; 5577225Sgblack@eecs.umich.edu} 5587225Sgblack@eecs.umich.edu 5597225Sgblack@eecs.umich.eduFault 5607225Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data) 5617225Sgblack@eecs.umich.edu{ 5627225Sgblack@eecs.umich.edu assert(ioEnable); 5637330Sgblack@eecs.umich.edu 56412616Sgabeblack@google.com Addr daddr = req->paddr & 0xfff; 5657225Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5667225Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 5677225Sgblack@eecs.umich.edu 5687232Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 56910184SCurtis.Dunham@arm.com panic("Accessing reserved register"); 5707225Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 5717330Sgblack@eecs.umich.edu WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5727225Sgblack@eecs.umich.edu return No_Fault; 5737225Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 5747232Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 5757225Sgblack@eecs.umich.edu 5767225Sgblack@eecs.umich.edu if (req->size == sizeof(uint32_t)) { 5777848SAli.Saidi@ARM.com uint32_t reg = *(uint32_t *)data; 5787848SAli.Saidi@ARM.com DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5797848SAli.Saidi@ARM.com 5807848SAli.Saidi@ARM.com switch (daddr) { 5817848SAli.Saidi@ARM.com case CR: 5827225Sgblack@eecs.umich.edu regs.command = reg; 5837225Sgblack@eecs.umich.edu if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 5847225Sgblack@eecs.umich.edu txHalt = true; 5857232Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 5867225Sgblack@eecs.umich.edu //the kernel is enabling the transmit machine 5877225Sgblack@eecs.umich.edu if (txState == txIdle) 5887225Sgblack@eecs.umich.edu txKick(); 5897225Sgblack@eecs.umich.edu } else if (reg & CR_TXD) { 5907225Sgblack@eecs.umich.edu txHalt = true; 5917225Sgblack@eecs.umich.edu } 5927330Sgblack@eecs.umich.edu 5937225Sgblack@eecs.umich.edu if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 59412616Sgabeblack@google.com rxHalt = true; 5957225Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 5967225Sgblack@eecs.umich.edu if (rxState == rxIdle) { 5977225Sgblack@eecs.umich.edu rxKick(); 5987232Sgblack@eecs.umich.edu } 59910184SCurtis.Dunham@arm.com } else if (reg & CR_RXD) { 6007225Sgblack@eecs.umich.edu rxHalt = true; 6017330Sgblack@eecs.umich.edu } 6027225Sgblack@eecs.umich.edu 6037225Sgblack@eecs.umich.edu if (reg & CR_TXR) 6047225Sgblack@eecs.umich.edu txReset(); 6057225Sgblack@eecs.umich.edu 6067232Sgblack@eecs.umich.edu if (reg & CR_RXR) 6077225Sgblack@eecs.umich.edu rxReset(); 6087225Sgblack@eecs.umich.edu 6097848SAli.Saidi@ARM.com if (reg & CR_SWI) 6107848SAli.Saidi@ARM.com devIntrPost(ISR_SWI); 6117848SAli.Saidi@ARM.com 6127848SAli.Saidi@ARM.com if (reg & CR_RST) { 6137848SAli.Saidi@ARM.com txReset(); 6147225Sgblack@eecs.umich.edu rxReset(); 6157225Sgblack@eecs.umich.edu 6167609SGene.Wu@arm.com regsReset(); 61712358Snikos.nikoleris@arm.com } 61812358Snikos.nikoleris@arm.com break; 61912358Snikos.nikoleris@arm.com 62012358Snikos.nikoleris@arm.com case CFG: 62112358Snikos.nikoleris@arm.com if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS 62212358Snikos.nikoleris@arm.com || reg & CFG_RESERVED || reg & CFG_T64ADDR 62312358Snikos.nikoleris@arm.com || reg & CFG_PCI64_DET) 62412358Snikos.nikoleris@arm.com panic("writing to read-only or reserved CFG bits!\n"); 62512358Snikos.nikoleris@arm.com 62612616Sgabeblack@google.com regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED | 62712616Sgabeblack@google.com CFG_T64ADDR | CFG_PCI64_DET); 62812616Sgabeblack@google.com 62912616Sgabeblack@google.com// all these #if 0's are because i don't THINK the kernel needs to have these implemented 63012358Snikos.nikoleris@arm.com// if there is a problem relating to one of these, you may need to add functionality in 63112358Snikos.nikoleris@arm.com#if 0 63212358Snikos.nikoleris@arm.com if (reg & CFG_TBI_EN) ; 63312358Snikos.nikoleris@arm.com if (reg & CFG_MODE_1000) ; 63412358Snikos.nikoleris@arm.com#endif 63512358Snikos.nikoleris@arm.com 63612358Snikos.nikoleris@arm.com if (reg & CFG_AUTO_1000) 63712358Snikos.nikoleris@arm.com panic("CFG_AUTO_1000 not implemented!\n"); 63812358Snikos.nikoleris@arm.com 63912358Snikos.nikoleris@arm.com#if 0 64012358Snikos.nikoleris@arm.com if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; 64112358Snikos.nikoleris@arm.com if (reg & CFG_TMRTEST) ; 64212358Snikos.nikoleris@arm.com if (reg & CFG_MRM_DIS) ; 64312358Snikos.nikoleris@arm.com if (reg & CFG_MWI_DIS) ; 64412358Snikos.nikoleris@arm.com 64512358Snikos.nikoleris@arm.com if (reg & CFG_T64ADDR) 64612358Snikos.nikoleris@arm.com panic("CFG_T64ADDR is read only register!\n"); 64712358Snikos.nikoleris@arm.com 64812358Snikos.nikoleris@arm.com if (reg & CFG_PCI64_DET) 64912358Snikos.nikoleris@arm.com panic("CFG_PCI64_DET is read only register!\n"); 65012503Snikos.nikoleris@arm.com 65112503Snikos.nikoleris@arm.com if (reg & CFG_DATA64_EN) ; 65212503Snikos.nikoleris@arm.com if (reg & CFG_M64ADDR) ; 65312358Snikos.nikoleris@arm.com if (reg & CFG_PHY_RST) ; 65412358Snikos.nikoleris@arm.com if (reg & CFG_PHY_DIS) ; 65512358Snikos.nikoleris@arm.com#endif 65612358Snikos.nikoleris@arm.com 65712358Snikos.nikoleris@arm.com if (reg & CFG_EXTSTS_EN) 65812358Snikos.nikoleris@arm.com extstsEnable = true; 65912358Snikos.nikoleris@arm.com else 66012358Snikos.nikoleris@arm.com extstsEnable = false; 66112358Snikos.nikoleris@arm.com 66212358Snikos.nikoleris@arm.com#if 0 66312358Snikos.nikoleris@arm.com if (reg & CFG_REQALG) ; 66412358Snikos.nikoleris@arm.com if (reg & CFG_SB) ; 66512358Snikos.nikoleris@arm.com if (reg & CFG_POW) ; 66612358Snikos.nikoleris@arm.com if (reg & CFG_EXD) ; 66712358Snikos.nikoleris@arm.com if (reg & CFG_PESEL) ; 66812358Snikos.nikoleris@arm.com if (reg & CFG_BROM_DIS) ; 66912358Snikos.nikoleris@arm.com if (reg & CFG_EXT_125) ; 67012358Snikos.nikoleris@arm.com if (reg & CFG_BEM) ; 67112358Snikos.nikoleris@arm.com#endif 67212358Snikos.nikoleris@arm.com break; 67312358Snikos.nikoleris@arm.com 67412358Snikos.nikoleris@arm.com case MEAR: 67512358Snikos.nikoleris@arm.com regs.mear = reg; 67612358Snikos.nikoleris@arm.com /* since phy is completely faked, MEAR_MD* don't matter 67712358Snikos.nikoleris@arm.com and since the driver never uses MEAR_EE*, they don't matter */ 67812358Snikos.nikoleris@arm.com#if 0 67912503Snikos.nikoleris@arm.com if (reg & MEAR_EEDI) ; 68012503Snikos.nikoleris@arm.com if (reg & MEAR_EEDO) ; //this one is read only 68112503Snikos.nikoleris@arm.com if (reg & MEAR_EECLK) ; 68212358Snikos.nikoleris@arm.com if (reg & MEAR_EESEL) ; 68312358Snikos.nikoleris@arm.com if (reg & MEAR_MDIO) ; 68412358Snikos.nikoleris@arm.com if (reg & MEAR_MDDIR) ; 68512358Snikos.nikoleris@arm.com if (reg & MEAR_MDC) ; 68612358Snikos.nikoleris@arm.com#endif 68712358Snikos.nikoleris@arm.com break; 68812358Snikos.nikoleris@arm.com 68912358Snikos.nikoleris@arm.com case PTSCR: 69012358Snikos.nikoleris@arm.com regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 69112358Snikos.nikoleris@arm.com /* these control BISTs for various parts of chip - we don't care or do 69212358Snikos.nikoleris@arm.com just fake that the BIST is done */ 69312358Snikos.nikoleris@arm.com if (reg & PTSCR_RBIST_EN) 69412358Snikos.nikoleris@arm.com regs.ptscr |= PTSCR_RBIST_DONE; 69512358Snikos.nikoleris@arm.com if (reg & PTSCR_EEBIST_EN) 69612358Snikos.nikoleris@arm.com regs.ptscr &= ~PTSCR_EEBIST_EN; 69712358Snikos.nikoleris@arm.com if (reg & PTSCR_EELOAD_EN) 69812358Snikos.nikoleris@arm.com regs.ptscr &= ~PTSCR_EELOAD_EN; 699 break; 700 701 case ISR: /* writing to the ISR has no effect */ 702 panic("ISR is a read only register!\n"); 703 704 case IMR: 705 regs.imr = reg; 706 devIntrChangeMask(); 707 break; 708 709 case IER: 710 regs.ier = reg; 711 break; 712 713 case IHR: 714 regs.ihr = reg; 715 /* not going to implement real interrupt holdoff */ 716 break; 717 718 case TXDP: 719 regs.txdp = (reg & 0xFFFFFFFC); 720 assert(txState == txIdle); 721 CTDD = false; 722 break; 723 724 case TXDP_HI: 725 regs.txdp_hi = reg; 726 break; 727 728 case TXCFG: 729 regs.txcfg = reg; 730#if 0 731 if (reg & TXCFG_CSI) ; 732 if (reg & TXCFG_HBI) ; 733 if (reg & TXCFG_MLB) ; 734 if (reg & TXCFG_ATP) ; 735 if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but 736 considering the network is just a fake 737 pipe, wouldn't make sense to do this */ 738 739 if (reg & TXCFG_BRST_DIS) ; 740#endif 741 742 743 /* we handle our own DMA, ignore the kernel's exhortations */ 744 //if (reg & TXCFG_MXDMA) ; 745 746 //also, we currently don't care about fill/drain thresholds 747 //though this may change in the future with more realistic 748 //networks or a driver which changes it according to feedback 749 750 break; 751 752 case GPIOR: 753 regs.gpior = reg; 754 /* these just control general purpose i/o pins, don't matter */ 755 break; 756 757 case RXDP: 758 regs.rxdp = reg; 759 break; 760 761 case RXDP_HI: 762 regs.rxdp_hi = reg; 763 break; 764 765 case RXCFG: 766 regs.rxcfg = reg; 767#if 0 768 if (reg & RXCFG_AEP) ; 769 if (reg & RXCFG_ARP) ; 770 if (reg & RXCFG_STRIPCRC) ; 771 if (reg & RXCFG_RX_RD) ; 772 if (reg & RXCFG_ALP) ; 773 if (reg & RXCFG_AIRL) ; 774#endif 775 776 /* we handle our own DMA, ignore what kernel says about it */ 777 //if (reg & RXCFG_MXDMA) ; 778 779#if 0 780 //also, we currently don't care about fill/drain thresholds 781 //though this may change in the future with more realistic 782 //networks or a driver which changes it according to feedback 783 if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 784#endif 785 break; 786 787 case PQCR: 788 /* there is no priority queueing used in the linux 2.6 driver */ 789 regs.pqcr = reg; 790 break; 791 792 case WCSR: 793 /* not going to implement wake on LAN */ 794 regs.wcsr = reg; 795 break; 796 797 case PCR: 798 /* not going to implement pause control */ 799 regs.pcr = reg; 800 break; 801 802 case RFCR: 803 regs.rfcr = reg; 804 805 rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 806 acceptBroadcast = (reg & RFCR_AAB) ? true : false; 807 acceptMulticast = (reg & RFCR_AAM) ? true : false; 808 acceptUnicast = (reg & RFCR_AAU) ? true : false; 809 acceptPerfect = (reg & RFCR_APM) ? true : false; 810 acceptArp = (reg & RFCR_AARP) ? true : false; 811 812 if (reg & RFCR_APAT) ; 813// panic("RFCR_APAT not implemented!\n"); 814 815 if (reg & RFCR_MHEN || reg & RFCR_UHEN) 816 panic("hash filtering not implemented!\n"); 817 818 if (reg & RFCR_ULM) 819 panic("RFCR_ULM not implemented!\n"); 820 821 break; 822 823 case RFDR: 824 panic("the driver never writes to RFDR, something is wrong!\n"); 825 826 case BRAR: 827 panic("the driver never uses BRAR, something is wrong!\n"); 828 829 case BRDR: 830 panic("the driver never uses BRDR, something is wrong!\n"); 831 832 case SRR: 833 panic("SRR is read only register!\n"); 834 835 case MIBC: 836 panic("the driver never uses MIBC, something is wrong!\n"); 837 838 case VRCR: 839 regs.vrcr = reg; 840 break; 841 842 case VTCR: 843 regs.vtcr = reg; 844 break; 845 846 case VDR: 847 panic("the driver never uses VDR, something is wrong!\n"); 848 break; 849 850 case CCSR: 851 /* not going to implement clockrun stuff */ 852 regs.ccsr = reg; 853 break; 854 855 case TBICR: 856 regs.tbicr = reg; 857 if (reg & TBICR_MR_LOOPBACK) 858 panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 859 860 if (reg & TBICR_MR_AN_ENABLE) { 861 regs.tanlpar = regs.tanar; 862 regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 863 } 864 865#if 0 866 if (reg & TBICR_MR_RESTART_AN) ; 867#endif 868 869 break; 870 871 case TBISR: 872 panic("TBISR is read only register!\n"); 873 874 case TANAR: 875 regs.tanar = reg; 876 if (reg & TANAR_PS2) 877 panic("this isn't used in driver, something wrong!\n"); 878 879 if (reg & TANAR_PS1) 880 panic("this isn't used in driver, something wrong!\n"); 881 break; 882 883 case TANLPAR: 884 panic("this should only be written to by the fake phy!\n"); 885 886 case TANER: 887 panic("TANER is read only register!\n"); 888 889 case TESR: 890 regs.tesr = reg; 891 break; 892 893 default: 894 panic("thought i covered all the register, what is this? addr=%#x", 895 daddr); 896 } 897 } else 898 panic("Invalid Request Size"); 899 900 return No_Fault; 901} 902 903void 904NSGigE::devIntrPost(uint32_t interrupts) 905{ 906 bool delay = false; 907 908 if (interrupts & ISR_RESERVE) 909 panic("Cannot set a reserved interrupt"); 910 911 if (interrupts & ISR_TXRCMP) 912 regs.isr |= ISR_TXRCMP; 913 914 if (interrupts & ISR_RXRCMP) 915 regs.isr |= ISR_RXRCMP; 916 917//ISR_DPERR not implemented 918//ISR_SSERR not implemented 919//ISR_RMABT not implemented 920//ISR_RXSOVR not implemented 921//ISR_HIBINT not implemented 922//ISR_PHY not implemented 923//ISR_PME not implemented 924 925 if (interrupts & ISR_SWI) 926 regs.isr |= ISR_SWI; 927 928//ISR_MIB not implemented 929//ISR_TXURN not implemented 930 931 if (interrupts & ISR_TXIDLE) 932 regs.isr |= ISR_TXIDLE; 933 934 if (interrupts & ISR_TXERR) 935 regs.isr |= ISR_TXERR; 936 937 if (interrupts & ISR_TXDESC) 938 regs.isr |= ISR_TXDESC; 939 940 if (interrupts & ISR_TXOK) { 941 regs.isr |= ISR_TXOK; 942 delay = true; 943 } 944 945 if (interrupts & ISR_RXORN) 946 regs.isr |= ISR_RXORN; 947 948 if (interrupts & ISR_RXIDLE) 949 regs.isr |= ISR_RXIDLE; 950 951//ISR_RXEARLY not implemented 952 953 if (interrupts & ISR_RXERR) 954 regs.isr |= ISR_RXERR; 955 956 if (interrupts & ISR_RXDESC) 957 regs.isr |= ISR_RXDESC; 958 959 if (interrupts & ISR_RXOK) { 960 delay = true; 961 regs.isr |= ISR_RXOK; 962 } 963 964 if ((regs.isr & regs.imr)) { 965 Tick when = curTick; 966 if (delay) 967 when += intrDelay; 968 cpuIntrPost(when); 969 } 970 971 DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 972 interrupts, regs.isr, regs.imr); 973} 974 975void 976NSGigE::devIntrClear(uint32_t interrupts) 977{ 978 if (interrupts & ISR_RESERVE) 979 panic("Cannot clear a reserved interrupt"); 980 981 if (interrupts & ISR_TXRCMP) 982 regs.isr &= ~ISR_TXRCMP; 983 984 if (interrupts & ISR_RXRCMP) 985 regs.isr &= ~ISR_RXRCMP; 986 987//ISR_DPERR not implemented 988//ISR_SSERR not implemented 989//ISR_RMABT not implemented 990//ISR_RXSOVR not implemented 991//ISR_HIBINT not implemented 992//ISR_PHY not implemented 993//ISR_PME not implemented 994 995 if (interrupts & ISR_SWI) 996 regs.isr &= ~ISR_SWI; 997 998//ISR_MIB not implemented 999//ISR_TXURN not implemented 1000 1001 if (interrupts & ISR_TXIDLE) 1002 regs.isr &= ~ISR_TXIDLE; 1003 1004 if (interrupts & ISR_TXERR) 1005 regs.isr &= ~ISR_TXERR; 1006 1007 if (interrupts & ISR_TXDESC) 1008 regs.isr &= ~ISR_TXDESC; 1009 1010 if (interrupts & ISR_TXOK) 1011 regs.isr &= ~ISR_TXOK; 1012 1013 if (interrupts & ISR_RXORN) 1014 regs.isr &= ~ISR_RXORN; 1015 1016 if (interrupts & ISR_RXIDLE) 1017 regs.isr &= ~ISR_RXIDLE; 1018 1019//ISR_RXEARLY not implemented 1020 1021 if (interrupts & ISR_RXERR) 1022 regs.isr &= ~ISR_RXERR; 1023 1024 if (interrupts & ISR_RXDESC) 1025 regs.isr &= ~ISR_RXDESC; 1026 1027 if (interrupts & ISR_RXOK) 1028 regs.isr &= ~ISR_RXOK; 1029 1030 if (!(regs.isr & regs.imr)) 1031 cpuIntrClear(); 1032 1033 DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 1034 interrupts, regs.isr, regs.imr); 1035} 1036 1037void 1038NSGigE::devIntrChangeMask() 1039{ 1040 DPRINTF(EthernetIntr, "interrupt mask changed\n"); 1041 1042 if (regs.isr & regs.imr) 1043 cpuIntrPost(curTick); 1044 else 1045 cpuIntrClear(); 1046} 1047 1048void 1049NSGigE::cpuIntrPost(Tick when) 1050{ 1051 //If the interrupt you want to post is later than an 1052 //interrupt already scheduled, just let it post in the coming one and 1053 //don't schedule another. 1054 //HOWEVER, must be sure that the scheduled intrTick is in the future 1055 //(this was formerly the source of a bug) 1056 assert((intrTick >= curTick) || (intrTick == 0)); 1057 if (when > intrTick && intrTick != 0) 1058 return; 1059 1060 intrTick = when; 1061 1062 if (intrEvent) { 1063 intrEvent->squash(); 1064 intrEvent = 0; 1065 } 1066 1067 if (when < curTick) { 1068 cpuInterrupt(); 1069 } else { 1070 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 1071 intrTick); 1072 intrEvent = new IntrEvent(this, true); 1073 intrEvent->schedule(intrTick); 1074 } 1075} 1076 1077void 1078NSGigE::cpuInterrupt() 1079{ 1080 // Don't send an interrupt if there's already one 1081 if (cpuPendingIntr) { 1082 DPRINTF(EthernetIntr, 1083 "would send an interrupt now, but there's already pending\n"); 1084 intrTick = 0; 1085 return; 1086 } 1087 // Don't send an interrupt if it's supposed to be delayed 1088 if (intrTick > curTick) { 1089 DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n", 1090 intrTick); 1091 return; 1092 } 1093 1094 // Whether or not there's a pending interrupt, we don't care about 1095 // it anymore 1096 intrEvent = 0; 1097 intrTick = 0; 1098 1099 // Send interrupt 1100 cpuPendingIntr = true; 1101 /** @todo rework the intctrl to be tsunami ok */ 1102 //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 1103 DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); 1104 tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 1105} 1106 1107void 1108NSGigE::cpuIntrClear() 1109{ 1110 if (cpuPendingIntr) { 1111 cpuPendingIntr = false; 1112 /** @todo rework the intctrl to be tsunami ok */ 1113 //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 1114 DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); 1115 tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 1116 } 1117} 1118 1119bool 1120NSGigE::cpuIntrPending() const 1121{ return cpuPendingIntr; } 1122 1123void 1124NSGigE::txReset() 1125{ 1126 1127 DPRINTF(Ethernet, "transmit reset\n"); 1128 1129 CTDD = false; 1130 txFifoAvail = MAX_TX_FIFO_SIZE; 1131 txHalt = false; 1132 txFragPtr = 0; 1133 assert(txDescCnt == 0); 1134 txFifo.clear(); 1135 regs.command &= ~CR_TXE; 1136 txState = txIdle; 1137 assert(txDmaState == dmaIdle); 1138} 1139 1140void 1141NSGigE::rxReset() 1142{ 1143 DPRINTF(Ethernet, "receive reset\n"); 1144 1145 CRDD = false; 1146 assert(rxPktBytes == 0); 1147 rxFifoCnt = 0; 1148 rxHalt = false; 1149 rxFragPtr = 0; 1150 assert(rxDescCnt == 0); 1151 assert(rxDmaState == dmaIdle); 1152 rxFifo.clear(); 1153 regs.command &= ~CR_RXE; 1154 rxState = rxIdle; 1155} 1156 1157void NSGigE::regsReset() 1158{ 1159 memset(®s, 0, sizeof(regs)); 1160 regs.config = 0x80000000; 1161 regs.mear = 0x12; 1162 regs.isr = 0x00608000; 1163 regs.txcfg = 0x120; 1164 regs.rxcfg = 0x4; 1165 regs.srr = 0x0103; 1166 regs.mibc = 0x2; 1167 regs.vdr = 0x81; 1168 regs.tesr = 0xc000; 1169 1170 extstsEnable = false; 1171 acceptBroadcast = false; 1172 acceptMulticast = false; 1173 acceptUnicast = false; 1174 acceptPerfect = false; 1175 acceptArp = false; 1176} 1177 1178void 1179NSGigE::rxDmaReadCopy() 1180{ 1181 assert(rxDmaState == dmaReading); 1182 1183 memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 1184 rxDmaState = dmaIdle; 1185 1186 DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 1187 rxDmaAddr, rxDmaLen); 1188 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1189} 1190 1191bool 1192NSGigE::doRxDmaRead() 1193{ 1194 assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 1195 rxDmaState = dmaReading; 1196 1197 if (dmaInterface && !rxDmaFree) { 1198 if (dmaInterface->busy()) 1199 rxDmaState = dmaReadWaiting; 1200 else 1201 dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 1202 &rxDmaReadEvent, true); 1203 return true; 1204 } 1205 1206 if (dmaReadDelay == 0 && dmaReadFactor == 0) { 1207 rxDmaReadCopy(); 1208 return false; 1209 } 1210 1211 Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1212 Tick start = curTick + dmaReadDelay + factor; 1213 rxDmaReadEvent.schedule(start); 1214 return true; 1215} 1216 1217void 1218NSGigE::rxDmaReadDone() 1219{ 1220 assert(rxDmaState == dmaReading); 1221 rxDmaReadCopy(); 1222 1223 // If the transmit state machine has a pending DMA, let it go first 1224 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1225 txKick(); 1226 1227 rxKick(); 1228} 1229 1230void 1231NSGigE::rxDmaWriteCopy() 1232{ 1233 assert(rxDmaState == dmaWriting); 1234 1235 memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 1236 rxDmaState = dmaIdle; 1237 1238 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 1239 rxDmaAddr, rxDmaLen); 1240 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1241} 1242 1243bool 1244NSGigE::doRxDmaWrite() 1245{ 1246 assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 1247 rxDmaState = dmaWriting; 1248 1249 if (dmaInterface && !rxDmaFree) { 1250 if (dmaInterface->busy()) 1251 rxDmaState = dmaWriteWaiting; 1252 else 1253 dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 1254 &rxDmaWriteEvent, true); 1255 return true; 1256 } 1257 1258 if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 1259 rxDmaWriteCopy(); 1260 return false; 1261 } 1262 1263 Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1264 Tick start = curTick + dmaWriteDelay + factor; 1265 rxDmaWriteEvent.schedule(start); 1266 return true; 1267} 1268 1269void 1270NSGigE::rxDmaWriteDone() 1271{ 1272 assert(rxDmaState == dmaWriting); 1273 rxDmaWriteCopy(); 1274 1275 // If the transmit state machine has a pending DMA, let it go first 1276 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1277 txKick(); 1278 1279 rxKick(); 1280} 1281 1282void 1283NSGigE::rxKick() 1284{ 1285 DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n", 1286 NsRxStateStrings[rxState], rxFifo.size()); 1287 1288 if (rxKickTick > curTick) { 1289 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1290 rxKickTick); 1291 return; 1292 } 1293 1294 next: 1295 switch(rxDmaState) { 1296 case dmaReadWaiting: 1297 if (doRxDmaRead()) 1298 goto exit; 1299 break; 1300 case dmaWriteWaiting: 1301 if (doRxDmaWrite()) 1302 goto exit; 1303 break; 1304 default: 1305 break; 1306 } 1307 1308 // see state machine from spec for details 1309 // the way this works is, if you finish work on one state and can go directly to 1310 // another, you do that through jumping to the label "next". however, if you have 1311 // intermediate work, like DMA so that you can't go to the next state yet, you go to 1312 // exit and exit the loop. however, when the DMA is done it will trigger an 1313 // event and come back to this loop. 1314 switch (rxState) { 1315 case rxIdle: 1316 if (!regs.command & CR_RXE) { 1317 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1318 goto exit; 1319 } 1320 1321 if (CRDD) { 1322 rxState = rxDescRefr; 1323 1324 rxDmaAddr = regs.rxdp & 0x3fffffff; 1325 rxDmaData = &rxDescCache + offsetof(ns_desc, link); 1326 rxDmaLen = sizeof(rxDescCache.link); 1327 rxDmaFree = dmaDescFree; 1328 1329 descDmaReads++; 1330 descDmaRdBytes += rxDmaLen; 1331 1332 if (doRxDmaRead()) 1333 goto exit; 1334 } else { 1335 rxState = rxDescRead; 1336 1337 rxDmaAddr = regs.rxdp & 0x3fffffff; 1338 rxDmaData = &rxDescCache; 1339 rxDmaLen = sizeof(ns_desc); 1340 rxDmaFree = dmaDescFree; 1341 1342 descDmaReads++; 1343 descDmaRdBytes += rxDmaLen; 1344 1345 if (doRxDmaRead()) 1346 goto exit; 1347 } 1348 break; 1349 1350 case rxDescRefr: 1351 if (rxDmaState != dmaIdle) 1352 goto exit; 1353 1354 rxState = rxAdvance; 1355 break; 1356 1357 case rxDescRead: 1358 if (rxDmaState != dmaIdle) 1359 goto exit; 1360 1361 DPRINTF(EthernetDesc, 1362 "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 1363 ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 1364 rxDescCache.extsts); 1365 1366 if (rxDescCache.cmdsts & CMDSTS_OWN) { 1367 rxState = rxIdle; 1368 } else { 1369 rxState = rxFifoBlock; 1370 rxFragPtr = rxDescCache.bufptr; 1371 rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 1372 } 1373 break; 1374 1375 case rxFifoBlock: 1376 if (!rxPacket) { 1377 /** 1378 * @todo in reality, we should be able to start processing 1379 * the packet as it arrives, and not have to wait for the 1380 * full packet ot be in the receive fifo. 1381 */ 1382 if (rxFifo.empty()) 1383 goto exit; 1384 1385 DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n"); 1386 1387 // If we don't have a packet, grab a new one from the fifo. 1388 rxPacket = rxFifo.front(); 1389 rxPktBytes = rxPacket->length; 1390 rxPacketBufPtr = rxPacket->data; 1391 1392 if (DTRACE(Ethernet)) { 1393 if (rxPacket->isIpPkt()) { 1394 ip_header *ip = rxPacket->getIpHdr(); 1395 DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 1396 if (rxPacket->isTcpPkt()) { 1397 tcp_header *tcp = rxPacket->getTcpHdr(ip); 1398 DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 1399 reverseEnd16(tcp->src_port_num), 1400 reverseEnd16(tcp->dest_port_num)); 1401 } 1402 } 1403 } 1404 1405 // sanity check - i think the driver behaves like this 1406 assert(rxDescCnt >= rxPktBytes); 1407 1408 // Must clear the value before popping to decrement the 1409 // reference count 1410 rxFifo.front() = NULL; 1411 rxFifo.pop_front(); 1412 rxFifoCnt -= rxPacket->length; 1413 } 1414 1415 1416 // dont' need the && rxDescCnt > 0 if driver sanity check above holds 1417 if (rxPktBytes > 0) { 1418 rxState = rxFragWrite; 1419 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds 1420 rxXferLen = rxPktBytes; 1421 1422 rxDmaAddr = rxFragPtr & 0x3fffffff; 1423 rxDmaData = rxPacketBufPtr; 1424 rxDmaLen = rxXferLen; 1425 rxDmaFree = dmaDataFree; 1426 1427 if (doRxDmaWrite()) 1428 goto exit; 1429 1430 } else { 1431 rxState = rxDescWrite; 1432 1433 //if (rxPktBytes == 0) { /* packet is done */ 1434 assert(rxPktBytes == 0); 1435 DPRINTF(EthernetSM, "done with receiving packet\n"); 1436 1437 rxDescCache.cmdsts |= CMDSTS_OWN; 1438 rxDescCache.cmdsts &= ~CMDSTS_MORE; 1439 rxDescCache.cmdsts |= CMDSTS_OK; 1440 rxDescCache.cmdsts &= 0xffff0000; 1441 rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1442 1443#if 0 1444 /* all the driver uses these are for its own stats keeping 1445 which we don't care about, aren't necessary for functionality 1446 and doing this would just slow us down. if they end up using 1447 this in a later version for functional purposes, just undef 1448 */ 1449 if (rxFilterEnable) { 1450 rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 1451 if (rxFifo.front()->IsUnicast()) 1452 rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 1453 if (rxFifo.front()->IsMulticast()) 1454 rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 1455 if (rxFifo.front()->IsBroadcast()) 1456 rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 1457 } 1458#endif 1459 1460 if (rxPacket->isIpPkt() && extstsEnable) { 1461 rxDescCache.extsts |= EXTSTS_IPPKT; 1462 rxIPChecksums++; 1463 if (!ipChecksum(rxPacket, false)) { 1464 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1465 rxDescCache.extsts |= EXTSTS_IPERR; 1466 } 1467 if (rxPacket->isTcpPkt()) { 1468 rxDescCache.extsts |= EXTSTS_TCPPKT; 1469 rxTCPChecksums++; 1470 if (!tcpChecksum(rxPacket, false)) { 1471 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1472 rxDescCache.extsts |= EXTSTS_TCPERR; 1473 1474 } 1475 } else if (rxPacket->isUdpPkt()) { 1476 rxDescCache.extsts |= EXTSTS_UDPPKT; 1477 if (!udpChecksum(rxPacket, false)) { 1478 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1479 rxDescCache.extsts |= EXTSTS_UDPERR; 1480 } 1481 } 1482 } 1483 rxPacket = 0; 1484 1485 /* the driver seems to always receive into desc buffers 1486 of size 1514, so you never have a pkt that is split 1487 into multiple descriptors on the receive side, so 1488 i don't implement that case, hence the assert above. 1489 */ 1490 1491 DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 1492 rxDescCache.cmdsts, rxDescCache.extsts); 1493 1494 rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1495 rxDmaData = &(rxDescCache.cmdsts); 1496 rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 1497 rxDmaFree = dmaDescFree; 1498 1499 descDmaWrites++; 1500 descDmaWrBytes += rxDmaLen; 1501 1502 if (doRxDmaWrite()) 1503 goto exit; 1504 } 1505 break; 1506 1507 case rxFragWrite: 1508 if (rxDmaState != dmaIdle) 1509 goto exit; 1510 1511 rxPacketBufPtr += rxXferLen; 1512 rxFragPtr += rxXferLen; 1513 rxPktBytes -= rxXferLen; 1514 1515 rxState = rxFifoBlock; 1516 break; 1517 1518 case rxDescWrite: 1519 if (rxDmaState != dmaIdle) 1520 goto exit; 1521 1522 assert(rxDescCache.cmdsts & CMDSTS_OWN); 1523 1524 assert(rxPacket == 0); 1525 devIntrPost(ISR_RXOK); 1526 1527 if (rxDescCache.cmdsts & CMDSTS_INTR) 1528 devIntrPost(ISR_RXDESC); 1529 1530 if (rxHalt) { 1531 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1532 rxState = rxIdle; 1533 rxHalt = false; 1534 } else 1535 rxState = rxAdvance; 1536 break; 1537 1538 case rxAdvance: 1539 if (rxDescCache.link == 0) { 1540 rxState = rxIdle; 1541 return; 1542 } else { 1543 rxState = rxDescRead; 1544 regs.rxdp = rxDescCache.link; 1545 CRDD = false; 1546 1547 rxDmaAddr = regs.rxdp & 0x3fffffff; 1548 rxDmaData = &rxDescCache; 1549 rxDmaLen = sizeof(ns_desc); 1550 rxDmaFree = dmaDescFree; 1551 1552 if (doRxDmaRead()) 1553 goto exit; 1554 } 1555 break; 1556 1557 default: 1558 panic("Invalid rxState!"); 1559 } 1560 1561 1562 DPRINTF(EthernetSM, "entering next rx state = %s\n", 1563 NsRxStateStrings[rxState]); 1564 1565 if (rxState == rxIdle) { 1566 regs.command &= ~CR_RXE; 1567 devIntrPost(ISR_RXIDLE); 1568 return; 1569 } 1570 1571 goto next; 1572 1573 exit: 1574 /** 1575 * @todo do we want to schedule a future kick? 1576 */ 1577 DPRINTF(EthernetSM, "rx state machine exited state=%s\n", 1578 NsRxStateStrings[rxState]); 1579} 1580 1581void 1582NSGigE::transmit() 1583{ 1584 if (txFifo.empty()) { 1585 DPRINTF(Ethernet, "nothing to transmit\n"); 1586 return; 1587 } 1588 1589 DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n", 1590 MAX_TX_FIFO_SIZE - txFifoAvail); 1591 if (interface->sendPacket(txFifo.front())) { 1592 if (DTRACE(Ethernet)) { 1593 if (txFifo.front()->isIpPkt()) { 1594 ip_header *ip = txFifo.front()->getIpHdr(); 1595 DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 1596 if (txFifo.front()->isTcpPkt()) { 1597 tcp_header *tcp = txFifo.front()->getTcpHdr(ip); 1598 DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 1599 reverseEnd16(tcp->src_port_num), 1600 reverseEnd16(tcp->dest_port_num)); 1601 } 1602 } 1603 } 1604 1605 DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 1606 txBytes += txFifo.front()->length; 1607 txPackets++; 1608 1609 txFifoAvail += txFifo.front()->length; 1610 1611 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail); 1612 txFifo.front() = NULL; 1613 txFifo.pop_front(); 1614 1615 /* normally do a writeback of the descriptor here, and ONLY after that is 1616 done, send this interrupt. but since our stuff never actually fails, 1617 just do this interrupt here, otherwise the code has to stray from this 1618 nice format. besides, it's functionally the same. 1619 */ 1620 devIntrPost(ISR_TXOK); 1621 } else 1622 DPRINTF(Ethernet, "May need to rethink always sending the descriptors back?\n"); 1623 1624 if (!txFifo.empty() && !txEvent.scheduled()) { 1625 DPRINTF(Ethernet, "reschedule transmit\n"); 1626 txEvent.schedule(curTick + 1000); 1627 } 1628} 1629 1630void 1631NSGigE::txDmaReadCopy() 1632{ 1633 assert(txDmaState == dmaReading); 1634 1635 memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); 1636 txDmaState = dmaIdle; 1637 1638 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1639 txDmaAddr, txDmaLen); 1640 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1641} 1642 1643bool 1644NSGigE::doTxDmaRead() 1645{ 1646 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1647 txDmaState = dmaReading; 1648 1649 if (dmaInterface && !txDmaFree) { 1650 if (dmaInterface->busy()) 1651 txDmaState = dmaReadWaiting; 1652 else 1653 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1654 &txDmaReadEvent, true); 1655 return true; 1656 } 1657 1658 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1659 txDmaReadCopy(); 1660 return false; 1661 } 1662 1663 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1664 Tick start = curTick + dmaReadDelay + factor; 1665 txDmaReadEvent.schedule(start); 1666 return true; 1667} 1668 1669void 1670NSGigE::txDmaReadDone() 1671{ 1672 assert(txDmaState == dmaReading); 1673 txDmaReadCopy(); 1674 1675 // If the receive state machine has a pending DMA, let it go first 1676 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1677 rxKick(); 1678 1679 txKick(); 1680} 1681 1682void 1683NSGigE::txDmaWriteCopy() 1684{ 1685 assert(txDmaState == dmaWriting); 1686 1687 memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); 1688 txDmaState = dmaIdle; 1689 1690 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1691 txDmaAddr, txDmaLen); 1692 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1693} 1694 1695bool 1696NSGigE::doTxDmaWrite() 1697{ 1698 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1699 txDmaState = dmaWriting; 1700 1701 if (dmaInterface && !txDmaFree) { 1702 if (dmaInterface->busy()) 1703 txDmaState = dmaWriteWaiting; 1704 else 1705 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1706 &txDmaWriteEvent, true); 1707 return true; 1708 } 1709 1710 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1711 txDmaWriteCopy(); 1712 return false; 1713 } 1714 1715 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1716 Tick start = curTick + dmaWriteDelay + factor; 1717 txDmaWriteEvent.schedule(start); 1718 return true; 1719} 1720 1721void 1722NSGigE::txDmaWriteDone() 1723{ 1724 assert(txDmaState == dmaWriting); 1725 txDmaWriteCopy(); 1726 1727 // If the receive state machine has a pending DMA, let it go first 1728 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1729 rxKick(); 1730 1731 txKick(); 1732} 1733 1734void 1735NSGigE::txKick() 1736{ 1737 DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]); 1738 1739 if (txKickTick > curTick) { 1740 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1741 txKickTick); 1742 1743 return; 1744 } 1745 1746 next: 1747 switch(txDmaState) { 1748 case dmaReadWaiting: 1749 if (doTxDmaRead()) 1750 goto exit; 1751 break; 1752 case dmaWriteWaiting: 1753 if (doTxDmaWrite()) 1754 goto exit; 1755 break; 1756 default: 1757 break; 1758 } 1759 1760 switch (txState) { 1761 case txIdle: 1762 if (!regs.command & CR_TXE) { 1763 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1764 goto exit; 1765 } 1766 1767 if (CTDD) { 1768 txState = txDescRefr; 1769 1770 txDmaAddr = regs.txdp & 0x3fffffff; 1771 txDmaData = &txDescCache + offsetof(ns_desc, link); 1772 txDmaLen = sizeof(txDescCache.link); 1773 txDmaFree = dmaDescFree; 1774 1775 descDmaReads++; 1776 descDmaRdBytes += txDmaLen; 1777 1778 if (doTxDmaRead()) 1779 goto exit; 1780 1781 } else { 1782 txState = txDescRead; 1783 1784 txDmaAddr = regs.txdp & 0x3fffffff; 1785 txDmaData = &txDescCache; 1786 txDmaLen = sizeof(ns_desc); 1787 txDmaFree = dmaDescFree; 1788 1789 descDmaReads++; 1790 descDmaRdBytes += txDmaLen; 1791 1792 if (doTxDmaRead()) 1793 goto exit; 1794 } 1795 break; 1796 1797 case txDescRefr: 1798 if (txDmaState != dmaIdle) 1799 goto exit; 1800 1801 txState = txAdvance; 1802 break; 1803 1804 case txDescRead: 1805 if (txDmaState != dmaIdle) 1806 goto exit; 1807 1808 DPRINTF(EthernetDesc, 1809 "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 1810 ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1811 txDescCache.extsts); 1812 1813 if (txDescCache.cmdsts & CMDSTS_OWN) { 1814 txState = txFifoBlock; 1815 txFragPtr = txDescCache.bufptr; 1816 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1817 } else { 1818 txState = txIdle; 1819 } 1820 break; 1821 1822 case txFifoBlock: 1823 if (!txPacket) { 1824 DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n"); 1825 txPacket = new EtherPacket; 1826 txPacket->data = new uint8_t[16384]; 1827 txPacketBufPtr = txPacket->data; 1828 } 1829 1830 if (txDescCnt == 0) { 1831 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1832 if (txDescCache.cmdsts & CMDSTS_MORE) { 1833 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1834 txState = txDescWrite; 1835 1836 txDescCache.cmdsts &= ~CMDSTS_OWN; 1837 1838 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1839 txDmaData = &(txDescCache.cmdsts); 1840 txDmaLen = sizeof(txDescCache.cmdsts); 1841 txDmaFree = dmaDescFree; 1842 1843 if (doTxDmaWrite()) 1844 goto exit; 1845 1846 } else { /* this packet is totally done */ 1847 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1848 /* deal with the the packet that just finished */ 1849 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1850 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1851 udpChecksum(txPacket, true); 1852 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1853 tcpChecksum(txPacket, true); 1854 txTCPChecksums++; 1855 } 1856 if (txDescCache.extsts & EXTSTS_IPPKT) { 1857 ipChecksum(txPacket, true); 1858 txIPChecksums++; 1859 } 1860 } 1861 1862 txPacket->length = txPacketBufPtr - txPacket->data; 1863 /* this is just because the receive can't handle a packet bigger 1864 want to make sure */ 1865 assert(txPacket->length <= 1514); 1866 txFifo.push_back(txPacket); 1867 1868 /* this following section is not to spec, but functionally shouldn't 1869 be any different. normally, the chip will wait til the transmit has 1870 occurred before writing back the descriptor because it has to wait 1871 to see that it was successfully transmitted to decide whether to set 1872 CMDSTS_OK or not. however, in the simulator since it is always 1873 successfully transmitted, and writing it exactly to spec would 1874 complicate the code, we just do it here 1875 */ 1876 1877 txDescCache.cmdsts &= ~CMDSTS_OWN; 1878 txDescCache.cmdsts |= CMDSTS_OK; 1879 1880 DPRINTF(EthernetDesc, 1881 "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 1882 txDescCache.cmdsts, txDescCache.extsts); 1883 1884 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1885 txDmaData = &(txDescCache.cmdsts); 1886 txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts); 1887 txDmaFree = dmaDescFree; 1888 1889 descDmaWrites++; 1890 descDmaWrBytes += txDmaLen; 1891 1892 transmit(); 1893 txPacket = 0; 1894 1895 if (txHalt) { 1896 DPRINTF(EthernetSM, "halting TX state machine\n"); 1897 txState = txIdle; 1898 txHalt = false; 1899 } else 1900 txState = txAdvance; 1901 1902 if (doTxDmaWrite()) 1903 goto exit; 1904 } 1905 } else { 1906 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1907 txState = txFragRead; 1908 1909 /* The number of bytes transferred is either whatever is left 1910 in the descriptor (txDescCnt), or if there is not enough 1911 room in the fifo, just whatever room is left in the fifo 1912 */ 1913 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1914 1915 txDmaAddr = txFragPtr & 0x3fffffff; 1916 txDmaData = txPacketBufPtr; 1917 txDmaLen = txXferLen; 1918 txDmaFree = dmaDataFree; 1919 1920 if (doTxDmaRead()) 1921 goto exit; 1922 } 1923 break; 1924 1925 case txFragRead: 1926 if (txDmaState != dmaIdle) 1927 goto exit; 1928 1929 txPacketBufPtr += txXferLen; 1930 txFragPtr += txXferLen; 1931 txDescCnt -= txXferLen; 1932 txFifoAvail -= txXferLen; 1933 1934 txState = txFifoBlock; 1935 break; 1936 1937 case txDescWrite: 1938 if (txDmaState != dmaIdle) 1939 goto exit; 1940 1941 if (txDescCache.cmdsts & CMDSTS_INTR) { 1942 devIntrPost(ISR_TXDESC); 1943 } 1944 1945 txState = txAdvance; 1946 break; 1947 1948 case txAdvance: 1949 if (txDescCache.link == 0) { 1950 txState = txIdle; 1951 } else { 1952 txState = txDescRead; 1953 regs.txdp = txDescCache.link; 1954 CTDD = false; 1955 1956 txDmaAddr = txDescCache.link & 0x3fffffff; 1957 txDmaData = &txDescCache; 1958 txDmaLen = sizeof(ns_desc); 1959 txDmaFree = dmaDescFree; 1960 1961 if (doTxDmaRead()) 1962 goto exit; 1963 } 1964 break; 1965 1966 default: 1967 panic("invalid state"); 1968 } 1969 1970 DPRINTF(EthernetSM, "entering next tx state=%s\n", 1971 NsTxStateStrings[txState]); 1972 1973 if (txState == txIdle) { 1974 regs.command &= ~CR_TXE; 1975 devIntrPost(ISR_TXIDLE); 1976 return; 1977 } 1978 1979 goto next; 1980 1981 exit: 1982 /** 1983 * @todo do we want to schedule a future kick? 1984 */ 1985 DPRINTF(EthernetSM, "tx state machine exited state=%s\n", 1986 NsTxStateStrings[txState]); 1987} 1988 1989void 1990NSGigE::transferDone() 1991{ 1992 if (txFifo.empty()) 1993 return; 1994 1995 if (txEvent.scheduled()) 1996 txEvent.reschedule(curTick + 1); 1997 else 1998 txEvent.schedule(curTick + 1); 1999} 2000 2001bool 2002NSGigE::rxFilter(PacketPtr packet) 2003{ 2004 bool drop = true; 2005 string type; 2006 2007 if (packet->IsUnicast()) { 2008 type = "unicast"; 2009 2010 // If we're accepting all unicast addresses 2011 if (acceptUnicast) 2012 drop = false; 2013 2014 // If we make a perfect match 2015 if ((acceptPerfect) 2016 && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0)) 2017 drop = false; 2018 2019 eth_header *eth = (eth_header *) packet->data; 2020 if ((acceptArp) && (eth->type == 0x608)) 2021 drop = false; 2022 2023 } else if (packet->IsBroadcast()) { 2024 type = "broadcast"; 2025 2026 // if we're accepting broadcasts 2027 if (acceptBroadcast) 2028 drop = false; 2029 2030 } else if (packet->IsMulticast()) { 2031 type = "multicast"; 2032 2033 // if we're accepting all multicasts 2034 if (acceptMulticast) 2035 drop = false; 2036 2037 } else { 2038 type = "unknown"; 2039 2040 // oh well, punt on this one 2041 } 2042 2043 if (drop) { 2044 DPRINTF(Ethernet, "rxFilter drop\n"); 2045 DDUMP(EthernetData, packet->data, packet->length); 2046 } 2047 2048 return drop; 2049} 2050 2051bool 2052NSGigE::recvPacket(PacketPtr packet) 2053{ 2054 rxBytes += packet->length; 2055 rxPackets++; 2056 2057 DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt); 2058 2059 if (rxState == rxIdle) { 2060 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2061 interface->recvDone(); 2062 return true; 2063 } 2064 2065 if (rxFilterEnable && rxFilter(packet)) { 2066 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2067 interface->recvDone(); 2068 return true; 2069 } 2070 2071 if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) { 2072 DPRINTF(Ethernet, 2073 "packet will not fit in receive buffer...packet dropped\n"); 2074 devIntrPost(ISR_RXORN); 2075 return false; 2076 } 2077 2078 rxFifo.push_back(packet); 2079 rxFifoCnt += packet->length; 2080 interface->recvDone(); 2081 2082 rxKick(); 2083 return true; 2084} 2085 2086/** 2087 * does a udp checksum. if gen is true, then it generates it and puts it in the right place 2088 * else, it just checks what it calculates against the value in the header in packet 2089 */ 2090bool 2091NSGigE::udpChecksum(PacketPtr packet, bool gen) 2092{ 2093 ip_header *ip = packet->getIpHdr(); 2094 udp_header *hdr = packet->getUdpHdr(ip); 2095 2096 pseudo_header *pseudo = new pseudo_header; 2097 2098 pseudo->src_ip_addr = ip->src_ip_addr; 2099 pseudo->dest_ip_addr = ip->dest_ip_addr; 2100 pseudo->protocol = ip->protocol; 2101 pseudo->len = hdr->len; 2102 2103 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2104 (uint32_t) hdr->len); 2105 2106 delete pseudo; 2107 if (gen) 2108 hdr->chksum = cksum; 2109 else 2110 if (cksum != 0) 2111 return false; 2112 2113 return true; 2114} 2115 2116bool 2117NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2118{ 2119 ip_header *ip = packet->getIpHdr(); 2120 tcp_header *hdr = packet->getTcpHdr(ip); 2121 2122 uint16_t cksum; 2123 pseudo_header *pseudo = new pseudo_header; 2124 if (!gen) { 2125 pseudo->src_ip_addr = ip->src_ip_addr; 2126 pseudo->dest_ip_addr = ip->dest_ip_addr; 2127 pseudo->protocol = reverseEnd16(ip->protocol); 2128 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4); 2129 2130 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2131 (uint32_t) reverseEnd16(pseudo->len)); 2132 } else { 2133 pseudo->src_ip_addr = 0; 2134 pseudo->dest_ip_addr = 0; 2135 pseudo->protocol = hdr->chksum; 2136 pseudo->len = 0; 2137 hdr->chksum = 0; 2138 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2139 (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4)); 2140 } 2141 2142 delete pseudo; 2143 if (gen) 2144 hdr->chksum = cksum; 2145 else 2146 if (cksum != 0) 2147 return false; 2148 2149 return true; 2150} 2151 2152bool 2153NSGigE::ipChecksum(PacketPtr packet, bool gen) 2154{ 2155 ip_header *hdr = packet->getIpHdr(); 2156 2157 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4); 2158 2159 if (gen) { 2160 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2161 hdr->hdr_chksum = cksum; 2162 } 2163 else 2164 if (cksum != 0) 2165 return false; 2166 2167 return true; 2168} 2169 2170uint16_t 2171NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2172{ 2173 uint32_t sum = 0; 2174 2175 uint16_t last_pad = 0; 2176 if (len & 1) { 2177 last_pad = buf[len/2] & 0xff; 2178 len--; 2179 sum += last_pad; 2180 } 2181 2182 if (pseudo) { 2183 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2184 pseudo[3] + pseudo[4] + pseudo[5]; 2185 } 2186 2187 for (int i=0; i < (len/2); ++i) { 2188 sum += buf[i]; 2189 } 2190 2191 while (sum >> 16) 2192 sum = (sum >> 16) + (sum & 0xffff); 2193 2194 return ~sum; 2195} 2196 2197//===================================================================== 2198// 2199// 2200void 2201NSGigE::serialize(ostream &os) 2202{ 2203 // Serialize the PciDev base class 2204 PciDev::serialize(os); 2205 2206 /* 2207 * Finalize any DMA events now. 2208 */ 2209 if (rxDmaReadEvent.scheduled()) 2210 rxDmaReadCopy(); 2211 if (rxDmaWriteEvent.scheduled()) 2212 rxDmaWriteCopy(); 2213 if (txDmaReadEvent.scheduled()) 2214 txDmaReadCopy(); 2215 if (txDmaWriteEvent.scheduled()) 2216 txDmaWriteCopy(); 2217 2218 /* 2219 * Serialize the device registers 2220 */ 2221 SERIALIZE_SCALAR(regs.command); 2222 SERIALIZE_SCALAR(regs.config); 2223 SERIALIZE_SCALAR(regs.mear); 2224 SERIALIZE_SCALAR(regs.ptscr); 2225 SERIALIZE_SCALAR(regs.isr); 2226 SERIALIZE_SCALAR(regs.imr); 2227 SERIALIZE_SCALAR(regs.ier); 2228 SERIALIZE_SCALAR(regs.ihr); 2229 SERIALIZE_SCALAR(regs.txdp); 2230 SERIALIZE_SCALAR(regs.txdp_hi); 2231 SERIALIZE_SCALAR(regs.txcfg); 2232 SERIALIZE_SCALAR(regs.gpior); 2233 SERIALIZE_SCALAR(regs.rxdp); 2234 SERIALIZE_SCALAR(regs.rxdp_hi); 2235 SERIALIZE_SCALAR(regs.rxcfg); 2236 SERIALIZE_SCALAR(regs.pqcr); 2237 SERIALIZE_SCALAR(regs.wcsr); 2238 SERIALIZE_SCALAR(regs.pcr); 2239 SERIALIZE_SCALAR(regs.rfcr); 2240 SERIALIZE_SCALAR(regs.rfdr); 2241 SERIALIZE_SCALAR(regs.srr); 2242 SERIALIZE_SCALAR(regs.mibc); 2243 SERIALIZE_SCALAR(regs.vrcr); 2244 SERIALIZE_SCALAR(regs.vtcr); 2245 SERIALIZE_SCALAR(regs.vdr); 2246 SERIALIZE_SCALAR(regs.ccsr); 2247 SERIALIZE_SCALAR(regs.tbicr); 2248 SERIALIZE_SCALAR(regs.tbisr); 2249 SERIALIZE_SCALAR(regs.tanar); 2250 SERIALIZE_SCALAR(regs.tanlpar); 2251 SERIALIZE_SCALAR(regs.taner); 2252 SERIALIZE_SCALAR(regs.tesr); 2253 2254 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2255 2256 SERIALIZE_SCALAR(ioEnable); 2257 2258 /* 2259 * Serialize the data Fifos 2260 */ 2261 int txNumPkts = txFifo.size(); 2262 SERIALIZE_SCALAR(txNumPkts); 2263 int i = 0; 2264 pktiter_t end = txFifo.end(); 2265 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2266 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2267 (*p)->serialize(os); 2268 } 2269 2270 int rxNumPkts = rxFifo.size(); 2271 SERIALIZE_SCALAR(rxNumPkts); 2272 i = 0; 2273 end = rxFifo.end(); 2274 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2275 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2276 (*p)->serialize(os); 2277 } 2278 2279 /* 2280 * Serialize the various helper variables 2281 */ 2282 bool txPacketExists = txPacket; 2283 SERIALIZE_SCALAR(txPacketExists); 2284 if (txPacketExists) { 2285 nameOut(os, csprintf("%s.txPacket", name())); 2286 txPacket->serialize(os); 2287 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2288 SERIALIZE_SCALAR(txPktBufPtr); 2289 } 2290 2291 bool rxPacketExists = rxPacket; 2292 SERIALIZE_SCALAR(rxPacketExists); 2293 if (rxPacketExists) { 2294 nameOut(os, csprintf("%s.rxPacket", name())); 2295 rxPacket->serialize(os); 2296 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2297 SERIALIZE_SCALAR(rxPktBufPtr); 2298 } 2299 2300 SERIALIZE_SCALAR(txXferLen); 2301 SERIALIZE_SCALAR(rxXferLen); 2302 2303 /* 2304 * Serialize DescCaches 2305 */ 2306 SERIALIZE_SCALAR(txDescCache.link); 2307 SERIALIZE_SCALAR(txDescCache.bufptr); 2308 SERIALIZE_SCALAR(txDescCache.cmdsts); 2309 SERIALIZE_SCALAR(txDescCache.extsts); 2310 SERIALIZE_SCALAR(rxDescCache.link); 2311 SERIALIZE_SCALAR(rxDescCache.bufptr); 2312 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2313 SERIALIZE_SCALAR(rxDescCache.extsts); 2314 2315 /* 2316 * Serialize tx state machine 2317 */ 2318 int txState = this->txState; 2319 SERIALIZE_SCALAR(txState); 2320 SERIALIZE_SCALAR(CTDD); 2321 SERIALIZE_SCALAR(txFifoAvail); 2322 SERIALIZE_SCALAR(txHalt); 2323 SERIALIZE_SCALAR(txFragPtr); 2324 SERIALIZE_SCALAR(txDescCnt); 2325 int txDmaState = this->txDmaState; 2326 SERIALIZE_SCALAR(txDmaState); 2327 2328 /* 2329 * Serialize rx state machine 2330 */ 2331 int rxState = this->rxState; 2332 SERIALIZE_SCALAR(rxState); 2333 SERIALIZE_SCALAR(CRDD); 2334 SERIALIZE_SCALAR(rxPktBytes); 2335 SERIALIZE_SCALAR(rxFifoCnt); 2336 SERIALIZE_SCALAR(rxHalt); 2337 SERIALIZE_SCALAR(rxDescCnt); 2338 int rxDmaState = this->rxDmaState; 2339 SERIALIZE_SCALAR(rxDmaState); 2340 2341 SERIALIZE_SCALAR(extstsEnable); 2342 2343 /* 2344 * If there's a pending transmit, store the time so we can 2345 * reschedule it later 2346 */ 2347 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2348 SERIALIZE_SCALAR(transmitTick); 2349 2350 /* 2351 * receive address filter settings 2352 */ 2353 SERIALIZE_SCALAR(rxFilterEnable); 2354 SERIALIZE_SCALAR(acceptBroadcast); 2355 SERIALIZE_SCALAR(acceptMulticast); 2356 SERIALIZE_SCALAR(acceptUnicast); 2357 SERIALIZE_SCALAR(acceptPerfect); 2358 SERIALIZE_SCALAR(acceptArp); 2359 2360 /* 2361 * Keep track of pending interrupt status. 2362 */ 2363 SERIALIZE_SCALAR(intrTick); 2364 SERIALIZE_SCALAR(cpuPendingIntr); 2365 Tick intrEventTick = 0; 2366 if (intrEvent) 2367 intrEventTick = intrEvent->when(); 2368 SERIALIZE_SCALAR(intrEventTick); 2369 2370} 2371 2372void 2373NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2374{ 2375 // Unserialize the PciDev base class 2376 PciDev::unserialize(cp, section); 2377 2378 UNSERIALIZE_SCALAR(regs.command); 2379 UNSERIALIZE_SCALAR(regs.config); 2380 UNSERIALIZE_SCALAR(regs.mear); 2381 UNSERIALIZE_SCALAR(regs.ptscr); 2382 UNSERIALIZE_SCALAR(regs.isr); 2383 UNSERIALIZE_SCALAR(regs.imr); 2384 UNSERIALIZE_SCALAR(regs.ier); 2385 UNSERIALIZE_SCALAR(regs.ihr); 2386 UNSERIALIZE_SCALAR(regs.txdp); 2387 UNSERIALIZE_SCALAR(regs.txdp_hi); 2388 UNSERIALIZE_SCALAR(regs.txcfg); 2389 UNSERIALIZE_SCALAR(regs.gpior); 2390 UNSERIALIZE_SCALAR(regs.rxdp); 2391 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2392 UNSERIALIZE_SCALAR(regs.rxcfg); 2393 UNSERIALIZE_SCALAR(regs.pqcr); 2394 UNSERIALIZE_SCALAR(regs.wcsr); 2395 UNSERIALIZE_SCALAR(regs.pcr); 2396 UNSERIALIZE_SCALAR(regs.rfcr); 2397 UNSERIALIZE_SCALAR(regs.rfdr); 2398 UNSERIALIZE_SCALAR(regs.srr); 2399 UNSERIALIZE_SCALAR(regs.mibc); 2400 UNSERIALIZE_SCALAR(regs.vrcr); 2401 UNSERIALIZE_SCALAR(regs.vtcr); 2402 UNSERIALIZE_SCALAR(regs.vdr); 2403 UNSERIALIZE_SCALAR(regs.ccsr); 2404 UNSERIALIZE_SCALAR(regs.tbicr); 2405 UNSERIALIZE_SCALAR(regs.tbisr); 2406 UNSERIALIZE_SCALAR(regs.tanar); 2407 UNSERIALIZE_SCALAR(regs.tanlpar); 2408 UNSERIALIZE_SCALAR(regs.taner); 2409 UNSERIALIZE_SCALAR(regs.tesr); 2410 2411 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2412 2413 UNSERIALIZE_SCALAR(ioEnable); 2414 2415 /* 2416 * unserialize the data fifos 2417 */ 2418 int txNumPkts; 2419 UNSERIALIZE_SCALAR(txNumPkts); 2420 int i; 2421 for (i = 0; i < txNumPkts; ++i) { 2422 PacketPtr p = new EtherPacket; 2423 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2424 txFifo.push_back(p); 2425 } 2426 2427 int rxNumPkts; 2428 UNSERIALIZE_SCALAR(rxNumPkts); 2429 for (i = 0; i < rxNumPkts; ++i) { 2430 PacketPtr p = new EtherPacket; 2431 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2432 rxFifo.push_back(p); 2433 } 2434 2435 /* 2436 * unserialize the various helper variables 2437 */ 2438 bool txPacketExists; 2439 UNSERIALIZE_SCALAR(txPacketExists); 2440 if (txPacketExists) { 2441 txPacket = new EtherPacket; 2442 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2443 uint32_t txPktBufPtr; 2444 UNSERIALIZE_SCALAR(txPktBufPtr); 2445 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2446 } else 2447 txPacket = 0; 2448 2449 bool rxPacketExists; 2450 UNSERIALIZE_SCALAR(rxPacketExists); 2451 rxPacket = 0; 2452 if (rxPacketExists) { 2453 rxPacket = new EtherPacket; 2454 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2455 uint32_t rxPktBufPtr; 2456 UNSERIALIZE_SCALAR(rxPktBufPtr); 2457 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2458 } else 2459 rxPacket = 0; 2460 2461 UNSERIALIZE_SCALAR(txXferLen); 2462 UNSERIALIZE_SCALAR(rxXferLen); 2463 2464 /* 2465 * Unserialize DescCaches 2466 */ 2467 UNSERIALIZE_SCALAR(txDescCache.link); 2468 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2469 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2470 UNSERIALIZE_SCALAR(txDescCache.extsts); 2471 UNSERIALIZE_SCALAR(rxDescCache.link); 2472 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2473 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2474 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2475 2476 /* 2477 * unserialize tx state machine 2478 */ 2479 int txState; 2480 UNSERIALIZE_SCALAR(txState); 2481 this->txState = (TxState) txState; 2482 UNSERIALIZE_SCALAR(CTDD); 2483 UNSERIALIZE_SCALAR(txFifoAvail); 2484 UNSERIALIZE_SCALAR(txHalt); 2485 UNSERIALIZE_SCALAR(txFragPtr); 2486 UNSERIALIZE_SCALAR(txDescCnt); 2487 int txDmaState; 2488 UNSERIALIZE_SCALAR(txDmaState); 2489 this->txDmaState = (DmaState) txDmaState; 2490 2491 /* 2492 * unserialize rx state machine 2493 */ 2494 int rxState; 2495 UNSERIALIZE_SCALAR(rxState); 2496 this->rxState = (RxState) rxState; 2497 UNSERIALIZE_SCALAR(CRDD); 2498 UNSERIALIZE_SCALAR(rxPktBytes); 2499 UNSERIALIZE_SCALAR(rxFifoCnt); 2500 UNSERIALIZE_SCALAR(rxHalt); 2501 UNSERIALIZE_SCALAR(rxDescCnt); 2502 int rxDmaState; 2503 UNSERIALIZE_SCALAR(rxDmaState); 2504 this->rxDmaState = (DmaState) rxDmaState; 2505 2506 UNSERIALIZE_SCALAR(extstsEnable); 2507 2508 /* 2509 * If there's a pending transmit, reschedule it now 2510 */ 2511 Tick transmitTick; 2512 UNSERIALIZE_SCALAR(transmitTick); 2513 if (transmitTick) 2514 txEvent.schedule(curTick + transmitTick); 2515 2516 /* 2517 * unserialize receive address filter settings 2518 */ 2519 UNSERIALIZE_SCALAR(rxFilterEnable); 2520 UNSERIALIZE_SCALAR(acceptBroadcast); 2521 UNSERIALIZE_SCALAR(acceptMulticast); 2522 UNSERIALIZE_SCALAR(acceptUnicast); 2523 UNSERIALIZE_SCALAR(acceptPerfect); 2524 UNSERIALIZE_SCALAR(acceptArp); 2525 2526 /* 2527 * Keep track of pending interrupt status. 2528 */ 2529 UNSERIALIZE_SCALAR(intrTick); 2530 UNSERIALIZE_SCALAR(cpuPendingIntr); 2531 Tick intrEventTick; 2532 UNSERIALIZE_SCALAR(intrEventTick); 2533 if (intrEventTick) { 2534 intrEvent = new IntrEvent(this, true); 2535 intrEvent->schedule(intrEventTick); 2536 } 2537 2538 /* 2539 * re-add addrRanges to bus bridges 2540 */ 2541 if (pioInterface) { 2542 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2543 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2544 } 2545} 2546 2547Tick 2548NSGigE::cacheAccess(MemReqPtr &req) 2549{ 2550 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2551 req->paddr, req->paddr - addr); 2552 return curTick + pioLatency; 2553} 2554//===================================================================== 2555 2556 2557//********** helper functions****************************************** 2558 2559uint16_t reverseEnd16(uint16_t num) 2560{ 2561 uint16_t reverse = (num & 0xff)<<8; 2562 reverse += ((num & 0xff00) >> 8); 2563 return reverse; 2564} 2565 2566uint32_t reverseEnd32(uint32_t num) 2567{ 2568 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2569 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2570 return reverse; 2571} 2572 2573 2574 2575//===================================================================== 2576 2577BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2578 2579 SimObjectParam<EtherInt *> peer; 2580 SimObjectParam<NSGigE *> device; 2581 2582END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2583 2584BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2585 2586 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2587 INIT_PARAM(device, "Ethernet device of this interface") 2588 2589END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2590 2591CREATE_SIM_OBJECT(NSGigEInt) 2592{ 2593 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2594 2595 EtherInt *p = (EtherInt *)peer; 2596 if (p) { 2597 dev_int->setPeer(p); 2598 p->setPeer(dev_int); 2599 } 2600 2601 return dev_int; 2602} 2603 2604REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2605 2606 2607BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2608 2609 Param<Tick> tx_delay; 2610 Param<Tick> rx_delay; 2611 SimObjectParam<IntrControl *> intr_ctrl; 2612 Param<Tick> intr_delay; 2613 SimObjectParam<MemoryController *> mmu; 2614 SimObjectParam<PhysicalMemory *> physmem; 2615 Param<bool> rx_filter; 2616 Param<string> hardware_address; 2617 SimObjectParam<Bus*> header_bus; 2618 SimObjectParam<Bus*> payload_bus; 2619 SimObjectParam<HierParams *> hier; 2620 Param<Tick> pio_latency; 2621 Param<bool> dma_desc_free; 2622 Param<bool> dma_data_free; 2623 Param<Tick> dma_read_delay; 2624 Param<Tick> dma_write_delay; 2625 Param<Tick> dma_read_factor; 2626 Param<Tick> dma_write_factor; 2627 SimObjectParam<PciConfigAll *> configspace; 2628 SimObjectParam<PciConfigData *> configdata; 2629 SimObjectParam<Tsunami *> tsunami; 2630 Param<uint32_t> pci_bus; 2631 Param<uint32_t> pci_dev; 2632 Param<uint32_t> pci_func; 2633 2634END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2635 2636BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2637 2638 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2639 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2640 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2641 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2642 INIT_PARAM(mmu, "Memory Controller"), 2643 INIT_PARAM(physmem, "Physical Memory"), 2644 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2645 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2646 "00:99:00:00:00:01"), 2647 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2648 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2649 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2650 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), 2651 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2652 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2653 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2654 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2655 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2656 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2657 INIT_PARAM(configspace, "PCI Configspace"), 2658 INIT_PARAM(configdata, "PCI Config data"), 2659 INIT_PARAM(tsunami, "Tsunami"), 2660 INIT_PARAM(pci_bus, "PCI bus"), 2661 INIT_PARAM(pci_dev, "PCI device number"), 2662 INIT_PARAM(pci_func, "PCI function code") 2663 2664END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2665 2666 2667CREATE_SIM_OBJECT(NSGigE) 2668{ 2669 int eaddr[6]; 2670 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2671 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2672 2673 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2674 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2675 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2676 dma_read_delay, dma_write_delay, dma_read_factor, 2677 dma_write_factor, configspace, configdata, 2678 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr); 2679} 2680 2681REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2682