ns_gige.cc revision 961
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan 36657Snate@binkert.org * All rights reserved. 46657Snate@binkert.org * 56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without 66657Snate@binkert.org * modification, are permitted provided that the following conditions are 76657Snate@binkert.org * met: redistributions of source code must retain the above copyright 86657Snate@binkert.org * notice, this list of conditions and the following disclaimer; 96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright 106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 116657Snate@binkert.org * documentation and/or other materials provided with the distribution; 126657Snate@binkert.org * neither the name of the copyright holders nor the names of its 136657Snate@binkert.org * contributors may be used to endorse or promote products derived from 146657Snate@binkert.org * this software without specific prior written permission. 156657Snate@binkert.org * 166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276657Snate@binkert.org */ 286999Snate@binkert.org 296657Snate@binkert.org/* @file 306657Snate@binkert.org * Device module for modelling the National Semiconductor 316657Snate@binkert.org * DP83820 ethernet controller. Does not support priority queueing 326657Snate@binkert.org */ 338189SLisa.Hsu@amd.com#include <cstdio> 346657Snate@binkert.org#include <deque> 359499Snilay@cs.wisc.edu#include <string> 369499Snilay@cs.wisc.edu 379364Snilay@cs.wisc.edu#include "base/inet.hh" 387055Snate@binkert.org#include "cpu/exec_context.hh" 396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh" 406882SBrad.Beckmann@amd.com#include "dev/dma.hh" 418191SLisa.Hsu@amd.com#include "dev/ns_gige.hh" 426882SBrad.Beckmann@amd.com#include "dev/etherlink.hh" 436882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh" 449102SNuwan.Jayasena@amd.com#include "mem/bus/dma_interface.hh" 459366Snilay@cs.wisc.edu#include "mem/bus/pio_interface.hh" 469499Snilay@cs.wisc.edu#include "mem/bus/pio_interface_impl.hh" 479499Snilay@cs.wisc.edu#include "mem/functional_mem/memory_control.hh" 489499Snilay@cs.wisc.edu#include "mem/functional_mem/physical_memory.hh" 496882SBrad.Beckmann@amd.com#include "sim/builder.hh" 506657Snate@binkert.org#include "sim/host.hh" 516657Snate@binkert.org#include "sim/sim_stats.hh" 526657Snate@binkert.org#include "targetarch/vtophys.hh" 536657Snate@binkert.org#include "dev/pciconfigall.hh" 5410311Snilay@cs.wisc.edu#include "dev/tsunami_cchip.hh" 5510311Snilay@cs.wisc.edu 5610311Snilay@cs.wisc.educonst char *NsRxStateStrings[] = 5710311Snilay@cs.wisc.edu{ 586657Snate@binkert.org "rxIdle", 5910311Snilay@cs.wisc.edu "rxDescRefr", 609366Snilay@cs.wisc.edu "rxDescRead", 617839Snilay@cs.wisc.edu "rxFifoBlock", 626657Snate@binkert.org "rxFragWrite", 636882SBrad.Beckmann@amd.com "rxDescWrite", 6410308Snilay@cs.wisc.edu "rxAdvance" 6510308Snilay@cs.wisc.edu}; 666882SBrad.Beckmann@amd.com 6710308Snilay@cs.wisc.educonst char *NsTxStateStrings[] = 6810308Snilay@cs.wisc.edu{ 6910308Snilay@cs.wisc.edu "txIdle", 7010308Snilay@cs.wisc.edu "txDescRefr", 7110308Snilay@cs.wisc.edu "txDescRead", 729366Snilay@cs.wisc.edu "txFifoBlock", 739366Snilay@cs.wisc.edu "txFragRead", 746657Snate@binkert.org "txDescWrite", 756657Snate@binkert.org "txAdvance" 766657Snate@binkert.org}; 776657Snate@binkert.org 789104Shestness@cs.utexas.educonst char *NsDmaState[] = 796657Snate@binkert.org{ 806657Snate@binkert.org "dmaIdle", 816657Snate@binkert.org "dmaReading", 8210311Snilay@cs.wisc.edu "dmaWriting", 8310311Snilay@cs.wisc.edu "dmaReadWaiting", 8410311Snilay@cs.wisc.edu "dmaWriteWaiting" 8510311Snilay@cs.wisc.edu}; 866657Snate@binkert.org 877839Snilay@cs.wisc.eduusing namespace std; 887839Snilay@cs.wisc.edu 896657Snate@binkert.org//helper function declarations 906657Snate@binkert.org//These functions reverse Endianness so we can evaluate network data correctly 916657Snate@binkert.orguint16_t reverseEnd16(uint16_t); 926657Snate@binkert.orguint32_t reverseEnd32(uint32_t); 936657Snate@binkert.org 946657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 956657Snate@binkert.org// 966657Snate@binkert.org// NSGigE PCI Device 976657Snate@binkert.org// 986657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 996657Snate@binkert.org PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 1006657Snate@binkert.org MemoryController *mmu, HierParams *hier, Bus *header_bus, 1016657Snate@binkert.org Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 1026657Snate@binkert.org bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 1036657Snate@binkert.org Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 1046657Snate@binkert.org PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1056657Snate@binkert.org uint32_t func, bool rx_filter, const int eaddr[6]) 1066657Snate@binkert.org : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 1076779SBrad.Beckmann@amd.com txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1086657Snate@binkert.org txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false), 1096657Snate@binkert.org txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), 1106657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1116657Snate@binkert.org CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 1126657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1136657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1146657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1156657Snate@binkert.org dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1166657Snate@binkert.org txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1179104Shestness@cs.utexas.edu txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1189104Shestness@cs.utexas.edu acceptMulticast(false), acceptUnicast(false), 1199104Shestness@cs.utexas.edu acceptPerfect(false), acceptArp(false), 1209104Shestness@cs.utexas.edu physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 1216657Snate@binkert.org intrEvent(0), interface(0), pioLatency(pio_latency) 1226657Snate@binkert.org{ 1236657Snate@binkert.org tsunami->ethernet = this; 1246657Snate@binkert.org 1256657Snate@binkert.org if (header_bus) { 1266657Snate@binkert.org pioInterface = newPioInterface(name, hier, header_bus, this, 1276657Snate@binkert.org &NSGigE::cacheAccess); 1286657Snate@binkert.org 1296657Snate@binkert.org if (payload_bus) 1306657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", 1316657Snate@binkert.org header_bus, payload_bus, 1); 1326657Snate@binkert.org else 1336657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", 13410307Snilay@cs.wisc.edu header_bus, header_bus, 1); 1356657Snate@binkert.org } else if (payload_bus) { 1366657Snate@binkert.org pioInterface = newPioInterface(name, hier, payload_bus, this, 1377839Snilay@cs.wisc.edu &NSGigE::cacheAccess); 1387839Snilay@cs.wisc.edu 1397839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 1407839Snilay@cs.wisc.edu payload_bus, 1); 1417839Snilay@cs.wisc.edu 1427839Snilay@cs.wisc.edu } 1437839Snilay@cs.wisc.edu 1447839Snilay@cs.wisc.edu 1457839Snilay@cs.wisc.edu intrDelay = US2Ticks(intr_delay); 1467839Snilay@cs.wisc.edu dmaReadDelay = dma_read_delay; 1477839Snilay@cs.wisc.edu dmaWriteDelay = dma_write_delay; 1487839Snilay@cs.wisc.edu dmaReadFactor = dma_read_factor; 1497839Snilay@cs.wisc.edu dmaWriteFactor = dma_write_factor; 1507839Snilay@cs.wisc.edu 1517839Snilay@cs.wisc.edu regsReset(); 1526657Snate@binkert.org rom.perfectMatch[0] = eaddr[0]; 1536657Snate@binkert.org rom.perfectMatch[1] = eaddr[1]; 1546657Snate@binkert.org rom.perfectMatch[2] = eaddr[2]; 1556657Snate@binkert.org rom.perfectMatch[3] = eaddr[3]; 1566657Snate@binkert.org rom.perfectMatch[4] = eaddr[4]; 1576657Snate@binkert.org rom.perfectMatch[5] = eaddr[5]; 1586657Snate@binkert.org} 1596657Snate@binkert.org 1606657Snate@binkert.orgNSGigE::~NSGigE() 1616657Snate@binkert.org{} 1626657Snate@binkert.org 1636657Snate@binkert.orgvoid 1646657Snate@binkert.orgNSGigE::regStats() 1656657Snate@binkert.org{ 1666657Snate@binkert.org txBytes 1676657Snate@binkert.org .name(name() + ".txBytes") 1686657Snate@binkert.org .desc("Bytes Transmitted") 1696657Snate@binkert.org .prereq(txBytes) 1706657Snate@binkert.org ; 1716657Snate@binkert.org 1726657Snate@binkert.org rxBytes 1736657Snate@binkert.org .name(name() + ".rxBytes") 1746657Snate@binkert.org .desc("Bytes Received") 1756657Snate@binkert.org .prereq(rxBytes) 1766657Snate@binkert.org ; 1776657Snate@binkert.org 1786657Snate@binkert.org txPackets 1796657Snate@binkert.org .name(name() + ".txPackets") 1806657Snate@binkert.org .desc("Number of Packets Transmitted") 1816657Snate@binkert.org .prereq(txBytes) 1829219Spower.jg@gmail.com ; 1836877Ssteve.reinhardt@amd.com 1846657Snate@binkert.org rxPackets 1859219Spower.jg@gmail.com .name(name() + ".rxPackets") 1866657Snate@binkert.org .desc("Number of Packets Received") 1879219Spower.jg@gmail.com .prereq(rxBytes) 1886657Snate@binkert.org ; 1896877Ssteve.reinhardt@amd.com 1906999Snate@binkert.org txIPChecksums 1916877Ssteve.reinhardt@amd.com .name(name() + ".txIPChecksums") 19210308Snilay@cs.wisc.edu .desc("Number of tx IP Checksums done by device") 1936877Ssteve.reinhardt@amd.com .precision(0) 1946877Ssteve.reinhardt@amd.com .prereq(txBytes) 19510308Snilay@cs.wisc.edu ; 1966877Ssteve.reinhardt@amd.com 1976877Ssteve.reinhardt@amd.com rxIPChecksums 1986877Ssteve.reinhardt@amd.com .name(name() + ".rxIPChecksums") 1996877Ssteve.reinhardt@amd.com .desc("Number of rx IP Checksums done by device") 2006877Ssteve.reinhardt@amd.com .precision(0) 2016877Ssteve.reinhardt@amd.com .prereq(rxBytes) 2026877Ssteve.reinhardt@amd.com ; 2039338SAndreas.Sandberg@arm.com 2046877Ssteve.reinhardt@amd.com txTCPChecksums 2056877Ssteve.reinhardt@amd.com .name(name() + ".txTCPChecksums") 2066877Ssteve.reinhardt@amd.com .desc("Number of tx TCP Checksums done by device") 2076877Ssteve.reinhardt@amd.com .precision(0) 20810308Snilay@cs.wisc.edu .prereq(txBytes) 20910308Snilay@cs.wisc.edu ; 21010308Snilay@cs.wisc.edu 21110308Snilay@cs.wisc.edu rxTCPChecksums 21210311Snilay@cs.wisc.edu .name(name() + ".rxTCPChecksums") 21310311Snilay@cs.wisc.edu .desc("Number of rx TCP Checksums done by device") 21410311Snilay@cs.wisc.edu .precision(0) 21510311Snilay@cs.wisc.edu .prereq(rxBytes) 21610311Snilay@cs.wisc.edu ; 21710311Snilay@cs.wisc.edu 21810311Snilay@cs.wisc.edu descDmaReads 2196882SBrad.Beckmann@amd.com .name(name() + ".descDMAReads") 22010308Snilay@cs.wisc.edu .desc("Number of descriptors the device read w/ DMA") 22110308Snilay@cs.wisc.edu .precision(0) 2226882SBrad.Beckmann@amd.com ; 2236882SBrad.Beckmann@amd.com 2246882SBrad.Beckmann@amd.com descDmaWrites 2256882SBrad.Beckmann@amd.com .name(name() + ".descDMAWrites") 2266877Ssteve.reinhardt@amd.com .desc("Number of descriptors the device wrote w/ DMA") 2276877Ssteve.reinhardt@amd.com .precision(0) 2286877Ssteve.reinhardt@amd.com ; 2296877Ssteve.reinhardt@amd.com 2306657Snate@binkert.org descDmaRdBytes 2316657Snate@binkert.org .name(name() + ".descDmaReadBytes") 2326999Snate@binkert.org .desc("number of descriptor bytes read w/ DMA") 2336657Snate@binkert.org .precision(0) 2346657Snate@binkert.org ; 2356657Snate@binkert.org 2366657Snate@binkert.org descDmaWrBytes 2377007Snate@binkert.org .name(name() + ".descDmaWriteBytes") 2386657Snate@binkert.org .desc("number of descriptor bytes write w/ DMA") 2396657Snate@binkert.org .precision(0) 2406657Snate@binkert.org ; 2416657Snate@binkert.org 2426657Snate@binkert.org 2437007Snate@binkert.org txBandwidth 2447007Snate@binkert.org .name(name() + ".txBandwidth") 2456657Snate@binkert.org .desc("Transmit Bandwidth (bits/s)") 2467002Snate@binkert.org .precision(0) 2477002Snate@binkert.org .prereq(txBytes) 2487002Snate@binkert.org ; 2497002Snate@binkert.org 2506657Snate@binkert.org rxBandwidth 2516657Snate@binkert.org .name(name() + ".rxBandwidth") 2528229Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 2538229Snate@binkert.org .precision(0) 2548229Snate@binkert.org .prereq(rxBytes) 2558229Snate@binkert.org ; 2566657Snate@binkert.org 2576657Snate@binkert.org txPacketRate 2586657Snate@binkert.org .name(name() + ".txPPS") 2596657Snate@binkert.org .desc("Packet Tranmission Rate (packets/s)") 2606793SBrad.Beckmann@amd.com .precision(0) 2616657Snate@binkert.org .prereq(txBytes) 26210311Snilay@cs.wisc.edu ; 2636657Snate@binkert.org 2646657Snate@binkert.org rxPacketRate 2656657Snate@binkert.org .name(name() + ".rxPPS") 2667002Snate@binkert.org .desc("Packet Reception Rate (packets/s)") 2676657Snate@binkert.org .precision(0) 2687007Snate@binkert.org .prereq(rxBytes) 2697007Snate@binkert.org ; 2709271Snilay@cs.wisc.edu 2716877Ssteve.reinhardt@amd.com txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2726877Ssteve.reinhardt@amd.com rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2736657Snate@binkert.org txPacketRate = txPackets / simSeconds; 2746877Ssteve.reinhardt@amd.com rxPacketRate = rxPackets / simSeconds; 27510311Snilay@cs.wisc.edu} 2766657Snate@binkert.org 27710311Snilay@cs.wisc.edu/** 2789745Snilay@cs.wisc.edu * This is to read the PCI general configuration registers 2797002Snate@binkert.org */ 2806657Snate@binkert.orgvoid 28110012Snilay@cs.wisc.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2829745Snilay@cs.wisc.edu{ 2839745Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 2849745Snilay@cs.wisc.edu PciDev::ReadConfig(offset, size, data); 2858683Snilay@cs.wisc.edu else 2868683Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 2877007Snate@binkert.org} 28810524Snilay@cs.wisc.edu 2899302Snilay@cs.wisc.edu/** 2909745Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers 2919745Snilay@cs.wisc.edu */ 2929745Snilay@cs.wisc.eduvoid 2939745Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 2949745Snilay@cs.wisc.edu{ 2959745Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 2966657Snate@binkert.org PciDev::WriteConfig(offset, size, data); 2976657Snate@binkert.org else 2986657Snate@binkert.org panic("Device specific PCI config space not implemented!\n"); 2996657Snate@binkert.org 3006657Snate@binkert.org // Need to catch writes to BARs to update the PIO interface 3016657Snate@binkert.org switch (offset) { 3026882SBrad.Beckmann@amd.com //seems to work fine without all these PCI settings, but i put in the IO 3036882SBrad.Beckmann@amd.com //to double check, an assertion will fail if we need to properly 3046882SBrad.Beckmann@amd.com // implement it 3056882SBrad.Beckmann@amd.com case PCI_COMMAND: 3066657Snate@binkert.org if (config.data[offset] & PCI_CMD_IOSE) 3076657Snate@binkert.org ioEnable = true; 3087007Snate@binkert.org else 3097839Snilay@cs.wisc.edu ioEnable = false; 3107839Snilay@cs.wisc.edu 3117839Snilay@cs.wisc.edu#if 0 3127839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_BME) { 3137839Snilay@cs.wisc.edu bmEnabled = true; 3147839Snilay@cs.wisc.edu } 3157839Snilay@cs.wisc.edu else { 3167839Snilay@cs.wisc.edu bmEnabled = false; 3177839Snilay@cs.wisc.edu } 3187839Snilay@cs.wisc.edu 3197839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_MSE) { 3207839Snilay@cs.wisc.edu memEnable = true; 32110010Snilay@cs.wisc.edu } 3227007Snate@binkert.org else { 3237007Snate@binkert.org memEnable = false; 3247007Snate@binkert.org } 3257007Snate@binkert.org#endif 3267839Snilay@cs.wisc.edu break; 3277839Snilay@cs.wisc.edu 3287839Snilay@cs.wisc.edu case PCI0_BASE_ADDR0: 3297839Snilay@cs.wisc.edu if (BARAddrs[0] != 0) { 3307839Snilay@cs.wisc.edu 3317839Snilay@cs.wisc.edu if (pioInterface) 3327839Snilay@cs.wisc.edu pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 3337839Snilay@cs.wisc.edu 3347839Snilay@cs.wisc.edu BARAddrs[0] &= PA_UNCACHED_MASK; 3357839Snilay@cs.wisc.edu 3367839Snilay@cs.wisc.edu } 3377839Snilay@cs.wisc.edu break; 3387007Snate@binkert.org case PCI0_BASE_ADDR1: 3397007Snate@binkert.org if (BARAddrs[1] != 0) { 3409745Snilay@cs.wisc.edu 3419745Snilay@cs.wisc.edu if (pioInterface) 3429745Snilay@cs.wisc.edu pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 3439745Snilay@cs.wisc.edu 3449745Snilay@cs.wisc.edu BARAddrs[1] &= PA_UNCACHED_MASK; 3459745Snilay@cs.wisc.edu 3466657Snate@binkert.org } 3477007Snate@binkert.org break; 3486657Snate@binkert.org } 3496657Snate@binkert.org} 3506657Snate@binkert.org 3516657Snate@binkert.org/** 3526657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820 3536657Snate@binkert.org * spec sheet 3546657Snate@binkert.org */ 3556657Snate@binkert.orgFault 3567839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3577839Snilay@cs.wisc.edu{ 3587839Snilay@cs.wisc.edu assert(ioEnable); 3597839Snilay@cs.wisc.edu 3607839Snilay@cs.wisc.edu //The mask is to give you only the offset into the device register file 3617839Snilay@cs.wisc.edu Addr daddr = req->paddr & 0xfff; 3627839Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3637839Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 3647839Snilay@cs.wisc.edu 3657839Snilay@cs.wisc.edu 3667839Snilay@cs.wisc.edu //there are some reserved registers, you can see ns_gige_reg.h and 3677839Snilay@cs.wisc.edu //the spec sheet for details 3687839Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 3697839Snilay@cs.wisc.edu panic("Accessing reserved register"); 3707839Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 3717839Snilay@cs.wisc.edu ReadConfig(daddr & 0xff, req->size, data); 37210121Snilay@cs.wisc.edu return No_Fault; 3736657Snate@binkert.org } else if (daddr >= MIB_START && daddr <= MIB_END) { 3746657Snate@binkert.org // don't implement all the MIB's. hopefully the kernel 3756657Snate@binkert.org // doesn't actually DEPEND upon their values 3766657Snate@binkert.org // MIB are just hardware stats keepers 3777839Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *) data; 3787839Snilay@cs.wisc.edu reg = 0; 3797839Snilay@cs.wisc.edu return No_Fault; 38010121Snilay@cs.wisc.edu } else if (daddr > 0x3FC) 38110121Snilay@cs.wisc.edu panic("Something is messed up!\n"); 38210121Snilay@cs.wisc.edu 3837839Snilay@cs.wisc.edu switch (req->size) { 3847839Snilay@cs.wisc.edu case sizeof(uint32_t): 3857839Snilay@cs.wisc.edu { 38610121Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *)data; 38710121Snilay@cs.wisc.edu 3887839Snilay@cs.wisc.edu switch (daddr) { 3897839Snilay@cs.wisc.edu case CR: 3907839Snilay@cs.wisc.edu reg = regs.command; 39110121Snilay@cs.wisc.edu //these are supposed to be cleared on a read 39210121Snilay@cs.wisc.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3937839Snilay@cs.wisc.edu break; 3947839Snilay@cs.wisc.edu 3957839Snilay@cs.wisc.edu case CFG: 3967839Snilay@cs.wisc.edu reg = regs.config; 3976657Snate@binkert.org break; 3986657Snate@binkert.org 3996657Snate@binkert.org case MEAR: 4006657Snate@binkert.org reg = regs.mear; 4017007Snate@binkert.org break; 4026657Snate@binkert.org 4036657Snate@binkert.org case PTSCR: 4049273Snilay@cs.wisc.edu reg = regs.ptscr; 40510305Snilay@cs.wisc.edu break; 4066657Snate@binkert.org 4076657Snate@binkert.org case ISR: 4086657Snate@binkert.org reg = regs.isr; 4097007Snate@binkert.org devIntrClear(ISR_ALL); 4106657Snate@binkert.org break; 4116657Snate@binkert.org 4129219Spower.jg@gmail.com case IMR: 4136657Snate@binkert.org reg = regs.imr; 4146657Snate@binkert.org break; 4156999Snate@binkert.org 4166657Snate@binkert.org case IER: 4176657Snate@binkert.org reg = regs.ier; 4186657Snate@binkert.org break; 4196657Snate@binkert.org 4207007Snate@binkert.org case IHR: 4216657Snate@binkert.org reg = regs.ihr; 4226657Snate@binkert.org break; 4236657Snate@binkert.org 4246657Snate@binkert.org case TXDP: 4256657Snate@binkert.org reg = regs.txdp; 4268946Sandreas.hansson@arm.com break; 4278946Sandreas.hansson@arm.com 4288946Sandreas.hansson@arm.com case TXDP_HI: 4297832Snate@binkert.org reg = regs.txdp_hi; 4307002Snate@binkert.org break; 4317002Snate@binkert.org 4327002Snate@binkert.org case TXCFG: 4338641Snate@binkert.org reg = regs.txcfg; 4347056Snate@binkert.org break; 4358232Snate@binkert.org 4368232Snate@binkert.org case GPIOR: 4376657Snate@binkert.org reg = regs.gpior; 4388229Snate@binkert.org break; 4396657Snate@binkert.org 4406657Snate@binkert.org case RXDP: 4417056Snate@binkert.org reg = regs.rxdp; 4426657Snate@binkert.org break; 4439219Spower.jg@gmail.com 4449219Spower.jg@gmail.com case RXDP_HI: 4459219Spower.jg@gmail.com reg = regs.rxdp_hi; 4469219Spower.jg@gmail.com break; 4479219Spower.jg@gmail.com 4487002Snate@binkert.org case RXCFG: 4497002Snate@binkert.org reg = regs.rxcfg; 4506657Snate@binkert.org break; 4516657Snate@binkert.org 4526657Snate@binkert.org case PQCR: 4536657Snate@binkert.org reg = regs.pqcr; 4546657Snate@binkert.org break; 4556793SBrad.Beckmann@amd.com 4566657Snate@binkert.org case WCSR: 4576657Snate@binkert.org reg = regs.wcsr; 4586657Snate@binkert.org break; 45910121Snilay@cs.wisc.edu 46010121Snilay@cs.wisc.edu case PCR: 4616657Snate@binkert.org reg = regs.pcr; 4626877Ssteve.reinhardt@amd.com break; 4636877Ssteve.reinhardt@amd.com 4646877Ssteve.reinhardt@amd.com //see the spec sheet for how RFCR and RFDR work 4656877Ssteve.reinhardt@amd.com //basically, you write to RFCR to tell the machine what you want to do next 4666877Ssteve.reinhardt@amd.com //then you act upon RFDR, and the device will be prepared b/c 4676877Ssteve.reinhardt@amd.com //of what you wrote to RFCR 4686657Snate@binkert.org case RFCR: 4699745Snilay@cs.wisc.edu reg = regs.rfcr; 4709745Snilay@cs.wisc.edu break; 4716657Snate@binkert.org 4727007Snate@binkert.org case RFDR: 4736657Snate@binkert.org switch (regs.rfcr & RFCR_RFADDR) { 4749801Snilay@cs.wisc.edu case 0x000: 4759801Snilay@cs.wisc.edu reg = rom.perfectMatch[1]; 4766657Snate@binkert.org reg = reg << 8; 4779801Snilay@cs.wisc.edu reg += rom.perfectMatch[0]; 4789801Snilay@cs.wisc.edu break; 4799801Snilay@cs.wisc.edu case 0x002: 4807007Snate@binkert.org reg = rom.perfectMatch[3] << 8; 4816657Snate@binkert.org reg += rom.perfectMatch[2]; 4826877Ssteve.reinhardt@amd.com break; 4836877Ssteve.reinhardt@amd.com case 0x004: 4846657Snate@binkert.org reg = rom.perfectMatch[5] << 8; 48510078Snilay@cs.wisc.edu reg += rom.perfectMatch[4]; 48610078Snilay@cs.wisc.edu break; 48710121Snilay@cs.wisc.edu default: 48810121Snilay@cs.wisc.edu panic("reading from RFDR for something for other than PMATCH!\n"); 48910121Snilay@cs.wisc.edu //didn't implement other RFDR functionality b/c driver didn't use 4906657Snate@binkert.org } 4916657Snate@binkert.org break; 4926882SBrad.Beckmann@amd.com 4936882SBrad.Beckmann@amd.com case SRR: 4946882SBrad.Beckmann@amd.com reg = regs.srr; 49510121Snilay@cs.wisc.edu break; 49610121Snilay@cs.wisc.edu 4976882SBrad.Beckmann@amd.com case MIBC: 4986877Ssteve.reinhardt@amd.com reg = regs.mibc; 49910311Snilay@cs.wisc.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 50010311Snilay@cs.wisc.edu break; 50110311Snilay@cs.wisc.edu 50210311Snilay@cs.wisc.edu case VRCR: 50310311Snilay@cs.wisc.edu reg = regs.vrcr; 50410311Snilay@cs.wisc.edu break; 5056882SBrad.Beckmann@amd.com 50610308Snilay@cs.wisc.edu case VTCR: 5076882SBrad.Beckmann@amd.com reg = regs.vtcr; 50810308Snilay@cs.wisc.edu break; 50910311Snilay@cs.wisc.edu 51010308Snilay@cs.wisc.edu case VDR: 51110308Snilay@cs.wisc.edu reg = regs.vdr; 5126888SBrad.Beckmann@amd.com break; 5136657Snate@binkert.org 5146657Snate@binkert.org case CCSR: 5159508Snilay@cs.wisc.edu reg = regs.ccsr; 51610305Snilay@cs.wisc.edu break; 51710305Snilay@cs.wisc.edu 5189508Snilay@cs.wisc.edu case TBICR: 5196657Snate@binkert.org reg = regs.tbicr; 5209595Snilay@cs.wisc.edu break; 5219745Snilay@cs.wisc.edu 5229745Snilay@cs.wisc.edu case TBISR: 5239745Snilay@cs.wisc.edu reg = regs.tbisr; 5249745Snilay@cs.wisc.edu break; 5259745Snilay@cs.wisc.edu 5269745Snilay@cs.wisc.edu case TANAR: 5279745Snilay@cs.wisc.edu reg = regs.tanar; 5289745Snilay@cs.wisc.edu break; 5299745Snilay@cs.wisc.edu 5309745Snilay@cs.wisc.edu case TANLPAR: 5319595Snilay@cs.wisc.edu reg = regs.tanlpar; 5326657Snate@binkert.org break; 5336657Snate@binkert.org 5346657Snate@binkert.org case TANER: 5356657Snate@binkert.org reg = regs.taner; 5367007Snate@binkert.org break; 53710311Snilay@cs.wisc.edu 53810311Snilay@cs.wisc.edu case TESR: 53910311Snilay@cs.wisc.edu reg = regs.tesr; 54010311Snilay@cs.wisc.edu break; 54110311Snilay@cs.wisc.edu 54210311Snilay@cs.wisc.edu default: 54310311Snilay@cs.wisc.edu panic("reading unimplemented register: addr = %#x", daddr); 54410311Snilay@cs.wisc.edu } 54510311Snilay@cs.wisc.edu 54610311Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 54710311Snilay@cs.wisc.edu daddr, reg, reg); 54810311Snilay@cs.wisc.edu } 54910311Snilay@cs.wisc.edu break; 55010311Snilay@cs.wisc.edu 55110311Snilay@cs.wisc.edu default: 55210311Snilay@cs.wisc.edu panic("accessing register with invalid size: addr=%#x, size=%d", 55310311Snilay@cs.wisc.edu daddr, req->size); 55410311Snilay@cs.wisc.edu } 55510311Snilay@cs.wisc.edu 55610311Snilay@cs.wisc.edu return No_Fault; 55710311Snilay@cs.wisc.edu} 55810311Snilay@cs.wisc.edu 55910311Snilay@cs.wisc.eduFault 56010311Snilay@cs.wisc.eduNSGigE::write(MemReqPtr &req, const uint8_t *data) 56110311Snilay@cs.wisc.edu{ 56210311Snilay@cs.wisc.edu assert(ioEnable); 56310311Snilay@cs.wisc.edu 56410311Snilay@cs.wisc.edu Addr daddr = req->paddr & 0xfff; 56510311Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 56610311Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 56710311Snilay@cs.wisc.edu 56810311Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 56910311Snilay@cs.wisc.edu panic("Accessing reserved register"); 57010311Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 57110311Snilay@cs.wisc.edu WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 57210311Snilay@cs.wisc.edu return No_Fault; 57310311Snilay@cs.wisc.edu } else if (daddr > 0x3FC) 57410311Snilay@cs.wisc.edu panic("Something is messed up!\n"); 57510311Snilay@cs.wisc.edu 57610311Snilay@cs.wisc.edu if (req->size == sizeof(uint32_t)) { 57710311Snilay@cs.wisc.edu uint32_t reg = *(uint32_t *)data; 57810311Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 57910311Snilay@cs.wisc.edu 58010311Snilay@cs.wisc.edu switch (daddr) { 58110311Snilay@cs.wisc.edu case CR: 58210311Snilay@cs.wisc.edu regs.command = reg; 58310311Snilay@cs.wisc.edu if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 58410311Snilay@cs.wisc.edu txHalt = true; 58510311Snilay@cs.wisc.edu } else if (reg & CR_TXE) { 58610311Snilay@cs.wisc.edu //the kernel is enabling the transmit machine 58710311Snilay@cs.wisc.edu if (txState == txIdle) 58810311Snilay@cs.wisc.edu txKick(); 58910311Snilay@cs.wisc.edu } else if (reg & CR_TXD) { 59010311Snilay@cs.wisc.edu txHalt = true; 59110311Snilay@cs.wisc.edu } 59210311Snilay@cs.wisc.edu 59310311Snilay@cs.wisc.edu if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 59410311Snilay@cs.wisc.edu rxHalt = true; 59510311Snilay@cs.wisc.edu } else if (reg & CR_RXE) { 59610311Snilay@cs.wisc.edu if (rxState == rxIdle) { 59710311Snilay@cs.wisc.edu rxKick(); 59810311Snilay@cs.wisc.edu } 59910311Snilay@cs.wisc.edu } else if (reg & CR_RXD) { 60010311Snilay@cs.wisc.edu rxHalt = true; 60110311Snilay@cs.wisc.edu } 60210311Snilay@cs.wisc.edu 60310311Snilay@cs.wisc.edu if (reg & CR_TXR) 60410311Snilay@cs.wisc.edu txReset(); 60510311Snilay@cs.wisc.edu 60610311Snilay@cs.wisc.edu if (reg & CR_RXR) 60710311Snilay@cs.wisc.edu rxReset(); 60810311Snilay@cs.wisc.edu 60910311Snilay@cs.wisc.edu if (reg & CR_SWI) 61010311Snilay@cs.wisc.edu devIntrPost(ISR_SWI); 61110311Snilay@cs.wisc.edu 61210311Snilay@cs.wisc.edu if (reg & CR_RST) { 61310311Snilay@cs.wisc.edu txReset(); 61410311Snilay@cs.wisc.edu rxReset(); 6157007Snate@binkert.org 6166657Snate@binkert.org regsReset(); 6177007Snate@binkert.org } 6187007Snate@binkert.org break; 6196657Snate@binkert.org 6206657Snate@binkert.org case CFG: 6216657Snate@binkert.org if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS 62210311Snilay@cs.wisc.edu || reg & CFG_RESERVED || reg & CFG_T64ADDR 6236657Snate@binkert.org || reg & CFG_PCI64_DET) 6246657Snate@binkert.org panic("writing to read-only or reserved CFG bits!\n"); 62510305Snilay@cs.wisc.edu 6266657Snate@binkert.org regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED | 6276657Snate@binkert.org CFG_T64ADDR | CFG_PCI64_DET); 6286657Snate@binkert.org 6296657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to have these implemented 6306657Snate@binkert.org// if there is a problem relating to one of these, you may need to add functionality in 6316657Snate@binkert.org#if 0 6326657Snate@binkert.org if (reg & CFG_TBI_EN) ; 6336657Snate@binkert.org if (reg & CFG_MODE_1000) ; 6349595Snilay@cs.wisc.edu#endif 6359273Snilay@cs.wisc.edu 6366657Snate@binkert.org if (reg & CFG_AUTO_1000) 6376657Snate@binkert.org panic("CFG_AUTO_1000 not implemented!\n"); 6386657Snate@binkert.org 6399364Snilay@cs.wisc.edu#if 0 6407007Snate@binkert.org if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; 6416657Snate@binkert.org if (reg & CFG_TMRTEST) ; 6426657Snate@binkert.org if (reg & CFG_MRM_DIS) ; 6436657Snate@binkert.org if (reg & CFG_MWI_DIS) ; 6446657Snate@binkert.org 6457007Snate@binkert.org if (reg & CFG_T64ADDR) 6466657Snate@binkert.org panic("CFG_T64ADDR is read only register!\n"); 6477007Snate@binkert.org 6487007Snate@binkert.org if (reg & CFG_PCI64_DET) 6496657Snate@binkert.org panic("CFG_PCI64_DET is read only register!\n"); 6506657Snate@binkert.org 6519508Snilay@cs.wisc.edu if (reg & CFG_DATA64_EN) ; 6526657Snate@binkert.org if (reg & CFG_M64ADDR) ; 6536657Snate@binkert.org if (reg & CFG_PHY_RST) ; 6546657Snate@binkert.org if (reg & CFG_PHY_DIS) ; 6556657Snate@binkert.org#endif 6566657Snate@binkert.org 6576657Snate@binkert.org if (reg & CFG_EXTSTS_EN) 6586657Snate@binkert.org extstsEnable = true; 6596657Snate@binkert.org else 6606657Snate@binkert.org extstsEnable = false; 6619508Snilay@cs.wisc.edu 6626657Snate@binkert.org#if 0 6637566SBrad.Beckmann@amd.com if (reg & CFG_REQALG) ; 6649508Snilay@cs.wisc.edu if (reg & CFG_SB) ; 6659508Snilay@cs.wisc.edu if (reg & CFG_POW) ; 6669508Snilay@cs.wisc.edu if (reg & CFG_EXD) ; 6679508Snilay@cs.wisc.edu if (reg & CFG_PESEL) ; 6689508Snilay@cs.wisc.edu if (reg & CFG_BROM_DIS) ; 6699508Snilay@cs.wisc.edu if (reg & CFG_EXT_125) ; 6709604Snilay@cs.wisc.edu if (reg & CFG_BEM) ; 6719604Snilay@cs.wisc.edu#endif 6729604Snilay@cs.wisc.edu break; 6739508Snilay@cs.wisc.edu 6747566SBrad.Beckmann@amd.com case MEAR: 6757566SBrad.Beckmann@amd.com regs.mear = reg; 6769499Snilay@cs.wisc.edu /* since phy is completely faked, MEAR_MD* don't matter 6779499Snilay@cs.wisc.edu and since the driver never uses MEAR_EE*, they don't matter */ 6787566SBrad.Beckmann@amd.com#if 0 6797566SBrad.Beckmann@amd.com if (reg & MEAR_EEDI) ; 6807566SBrad.Beckmann@amd.com if (reg & MEAR_EEDO) ; //this one is read only 6819366Snilay@cs.wisc.edu if (reg & MEAR_EECLK) ; 6829366Snilay@cs.wisc.edu if (reg & MEAR_EESEL) ; 6839366Snilay@cs.wisc.edu if (reg & MEAR_MDIO) ; 6849366Snilay@cs.wisc.edu if (reg & MEAR_MDDIR) ; 6857566SBrad.Beckmann@amd.com if (reg & MEAR_MDC) ; 6867672Snate@binkert.org#endif 6876657Snate@binkert.org break; 6889465Snilay@cs.wisc.edu 6896657Snate@binkert.org case PTSCR: 6909465Snilay@cs.wisc.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 6917056Snate@binkert.org /* these control BISTs for various parts of chip - we don't care or do 6926657Snate@binkert.org just fake that the BIST is done */ 6936657Snate@binkert.org if (reg & PTSCR_RBIST_EN) 6947672Snate@binkert.org regs.ptscr |= PTSCR_RBIST_DONE; 6956657Snate@binkert.org if (reg & PTSCR_EEBIST_EN) 6966657Snate@binkert.org regs.ptscr &= ~PTSCR_EEBIST_EN; 6976657Snate@binkert.org if (reg & PTSCR_EELOAD_EN) 6986657Snate@binkert.org regs.ptscr &= ~PTSCR_EELOAD_EN; 6996657Snate@binkert.org break; 7006657Snate@binkert.org 7016657Snate@binkert.org case ISR: /* writing to the ISR has no effect */ 7026657Snate@binkert.org panic("ISR is a read only register!\n"); 7036657Snate@binkert.org 7046657Snate@binkert.org case IMR: 7056657Snate@binkert.org regs.imr = reg; 7069745Snilay@cs.wisc.edu devIntrChangeMask(); 7076657Snate@binkert.org break; 7086657Snate@binkert.org 7099496Snilay@cs.wisc.edu case IER: 7109496Snilay@cs.wisc.edu regs.ier = reg; 71110012Snilay@cs.wisc.edu break; 7129496Snilay@cs.wisc.edu 7139496Snilay@cs.wisc.edu case IHR: 7146657Snate@binkert.org regs.ihr = reg; 71510121Snilay@cs.wisc.edu /* not going to implement real interrupt holdoff */ 7166657Snate@binkert.org break; 7176657Snate@binkert.org 71810305Snilay@cs.wisc.edu case TXDP: 7196657Snate@binkert.org regs.txdp = (reg & 0xFFFFFFFC); 7208683Snilay@cs.wisc.edu assert(txState == txIdle); 7218683Snilay@cs.wisc.edu CTDD = false; 72210308Snilay@cs.wisc.edu break; 7238683Snilay@cs.wisc.edu 72410308Snilay@cs.wisc.edu case TXDP_HI: 7258683Snilay@cs.wisc.edu regs.txdp_hi = reg; 7266657Snate@binkert.org break; 7279745Snilay@cs.wisc.edu 7289745Snilay@cs.wisc.edu case TXCFG: 7299745Snilay@cs.wisc.edu regs.txcfg = reg; 7309745Snilay@cs.wisc.edu#if 0 73110012Snilay@cs.wisc.edu if (reg & TXCFG_CSI) ; 73210012Snilay@cs.wisc.edu if (reg & TXCFG_HBI) ; 7339745Snilay@cs.wisc.edu if (reg & TXCFG_MLB) ; 7349745Snilay@cs.wisc.edu if (reg & TXCFG_ATP) ; 7359745Snilay@cs.wisc.edu if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but 7369745Snilay@cs.wisc.edu considering the network is just a fake 7379745Snilay@cs.wisc.edu pipe, wouldn't make sense to do this */ 73810012Snilay@cs.wisc.edu 73910012Snilay@cs.wisc.edu if (reg & TXCFG_BRST_DIS) ; 7409745Snilay@cs.wisc.edu#endif 7419745Snilay@cs.wisc.edu 7429745Snilay@cs.wisc.edu 7439745Snilay@cs.wisc.edu /* we handle our own DMA, ignore the kernel's exhortations */ 7449745Snilay@cs.wisc.edu //if (reg & TXCFG_MXDMA) ; 7459745Snilay@cs.wisc.edu 7469745Snilay@cs.wisc.edu //also, we currently don't care about fill/drain thresholds 7479745Snilay@cs.wisc.edu //though this may change in the future with more realistic 7489745Snilay@cs.wisc.edu //networks or a driver which changes it according to feedback 7499745Snilay@cs.wisc.edu 7509745Snilay@cs.wisc.edu break; 7519745Snilay@cs.wisc.edu 7529745Snilay@cs.wisc.edu case GPIOR: 7539745Snilay@cs.wisc.edu regs.gpior = reg; 7549745Snilay@cs.wisc.edu /* these just control general purpose i/o pins, don't matter */ 7559745Snilay@cs.wisc.edu break; 75610012Snilay@cs.wisc.edu 75710012Snilay@cs.wisc.edu case RXDP: 7589745Snilay@cs.wisc.edu regs.rxdp = reg; 7599745Snilay@cs.wisc.edu break; 7609745Snilay@cs.wisc.edu 7619745Snilay@cs.wisc.edu case RXDP_HI: 7629745Snilay@cs.wisc.edu regs.rxdp_hi = reg; 7639745Snilay@cs.wisc.edu break; 7649745Snilay@cs.wisc.edu 7659745Snilay@cs.wisc.edu case RXCFG: 7669745Snilay@cs.wisc.edu regs.rxcfg = reg; 7679745Snilay@cs.wisc.edu#if 0 7689745Snilay@cs.wisc.edu if (reg & RXCFG_AEP) ; 7699745Snilay@cs.wisc.edu if (reg & RXCFG_ARP) ; 7709745Snilay@cs.wisc.edu if (reg & RXCFG_STRIPCRC) ; 7719745Snilay@cs.wisc.edu if (reg & RXCFG_RX_RD) ; 7729745Snilay@cs.wisc.edu if (reg & RXCFG_ALP) ; 7739745Snilay@cs.wisc.edu if (reg & RXCFG_AIRL) ; 7749745Snilay@cs.wisc.edu#endif 7759745Snilay@cs.wisc.edu 7769745Snilay@cs.wisc.edu /* we handle our own DMA, ignore what kernel says about it */ 7779745Snilay@cs.wisc.edu //if (reg & RXCFG_MXDMA) ; 7789745Snilay@cs.wisc.edu 7799745Snilay@cs.wisc.edu#if 0 7809745Snilay@cs.wisc.edu //also, we currently don't care about fill/drain thresholds 7819745Snilay@cs.wisc.edu //though this may change in the future with more realistic 7829745Snilay@cs.wisc.edu //networks or a driver which changes it according to feedback 7839745Snilay@cs.wisc.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 7849745Snilay@cs.wisc.edu#endif 7859745Snilay@cs.wisc.edu break; 7869745Snilay@cs.wisc.edu 7879745Snilay@cs.wisc.edu case PQCR: 7889745Snilay@cs.wisc.edu /* there is no priority queueing used in the linux 2.6 driver */ 7899745Snilay@cs.wisc.edu regs.pqcr = reg; 7909745Snilay@cs.wisc.edu break; 7919745Snilay@cs.wisc.edu 7929745Snilay@cs.wisc.edu case WCSR: 7939745Snilay@cs.wisc.edu /* not going to implement wake on LAN */ 7949745Snilay@cs.wisc.edu regs.wcsr = reg; 7959745Snilay@cs.wisc.edu break; 7969745Snilay@cs.wisc.edu 7979745Snilay@cs.wisc.edu case PCR: 7989745Snilay@cs.wisc.edu /* not going to implement pause control */ 7999745Snilay@cs.wisc.edu regs.pcr = reg; 8009745Snilay@cs.wisc.edu break; 8019745Snilay@cs.wisc.edu 8029745Snilay@cs.wisc.edu case RFCR: 8039745Snilay@cs.wisc.edu regs.rfcr = reg; 8049745Snilay@cs.wisc.edu 8059745Snilay@cs.wisc.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8069745Snilay@cs.wisc.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8079745Snilay@cs.wisc.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 8089745Snilay@cs.wisc.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 8099745Snilay@cs.wisc.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 8109745Snilay@cs.wisc.edu acceptArp = (reg & RFCR_AARP) ? true : false; 8119745Snilay@cs.wisc.edu 8129745Snilay@cs.wisc.edu if (reg & RFCR_APAT) ; 8139745Snilay@cs.wisc.edu// panic("RFCR_APAT not implemented!\n"); 8149745Snilay@cs.wisc.edu 8159745Snilay@cs.wisc.edu if (reg & RFCR_MHEN || reg & RFCR_UHEN) 8169745Snilay@cs.wisc.edu panic("hash filtering not implemented!\n"); 8179745Snilay@cs.wisc.edu 8189745Snilay@cs.wisc.edu if (reg & RFCR_ULM) 8199745Snilay@cs.wisc.edu panic("RFCR_ULM not implemented!\n"); 8209745Snilay@cs.wisc.edu 8219745Snilay@cs.wisc.edu break; 8229745Snilay@cs.wisc.edu 8239745Snilay@cs.wisc.edu case RFDR: 8249745Snilay@cs.wisc.edu panic("the driver never writes to RFDR, something is wrong!\n"); 8259745Snilay@cs.wisc.edu 8269745Snilay@cs.wisc.edu case BRAR: 8279745Snilay@cs.wisc.edu panic("the driver never uses BRAR, something is wrong!\n"); 8289745Snilay@cs.wisc.edu 8299745Snilay@cs.wisc.edu case BRDR: 8309745Snilay@cs.wisc.edu panic("the driver never uses BRDR, something is wrong!\n"); 8319745Snilay@cs.wisc.edu 8327007Snate@binkert.org case SRR: 8337007Snate@binkert.org panic("SRR is read only register!\n"); 8347007Snate@binkert.org 8356657Snate@binkert.org case MIBC: 8366657Snate@binkert.org panic("the driver never uses MIBC, something is wrong!\n"); 8376657Snate@binkert.org 8387007Snate@binkert.org case VRCR: 8397007Snate@binkert.org regs.vrcr = reg; 8407007Snate@binkert.org break; 8416657Snate@binkert.org 8426657Snate@binkert.org case VTCR: 8436657Snate@binkert.org regs.vtcr = reg; 8448683Snilay@cs.wisc.edu break; 8458683Snilay@cs.wisc.edu 8468683Snilay@cs.wisc.edu case VDR: 8478683Snilay@cs.wisc.edu panic("the driver never uses VDR, something is wrong!\n"); 8488683Snilay@cs.wisc.edu break; 8498683Snilay@cs.wisc.edu 8507007Snate@binkert.org case CCSR: 8517007Snate@binkert.org /* not going to implement clockrun stuff */ 8527007Snate@binkert.org regs.ccsr = reg; 8537007Snate@binkert.org break; 8547007Snate@binkert.org 8556657Snate@binkert.org case TBICR: 85610012Snilay@cs.wisc.edu regs.tbicr = reg; 8579745Snilay@cs.wisc.edu if (reg & TBICR_MR_LOOPBACK) 8589745Snilay@cs.wisc.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8599745Snilay@cs.wisc.edu 8609745Snilay@cs.wisc.edu if (reg & TBICR_MR_AN_ENABLE) { 8619745Snilay@cs.wisc.edu regs.tanlpar = regs.tanar; 8629745Snilay@cs.wisc.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8636902SBrad.Beckmann@amd.com } 8649745Snilay@cs.wisc.edu 8659745Snilay@cs.wisc.edu#if 0 8669745Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 8679745Snilay@cs.wisc.edu#endif 86810012Snilay@cs.wisc.edu 8696902SBrad.Beckmann@amd.com break; 8707839Snilay@cs.wisc.edu 8717839Snilay@cs.wisc.edu case TBISR: 8727839Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 8737839Snilay@cs.wisc.edu 8747839Snilay@cs.wisc.edu case TANAR: 8757839Snilay@cs.wisc.edu regs.tanar = reg; 8767839Snilay@cs.wisc.edu if (reg & TANAR_PS2) 8777839Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8787839Snilay@cs.wisc.edu 8797839Snilay@cs.wisc.edu if (reg & TANAR_PS1) 8807839Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8817839Snilay@cs.wisc.edu break; 8827839Snilay@cs.wisc.edu 8837839Snilay@cs.wisc.edu case TANLPAR: 8847839Snilay@cs.wisc.edu panic("this should only be written to by the fake phy!\n"); 8857839Snilay@cs.wisc.edu 8867839Snilay@cs.wisc.edu case TANER: 8877839Snilay@cs.wisc.edu panic("TANER is read only register!\n"); 8887839Snilay@cs.wisc.edu 8897839Snilay@cs.wisc.edu case TESR: 8907839Snilay@cs.wisc.edu regs.tesr = reg; 8917839Snilay@cs.wisc.edu break; 8927839Snilay@cs.wisc.edu 8937839Snilay@cs.wisc.edu default: 8947839Snilay@cs.wisc.edu panic("thought i covered all the register, what is this? addr=%#x", 8957839Snilay@cs.wisc.edu daddr); 8967839Snilay@cs.wisc.edu } 8977839Snilay@cs.wisc.edu } else 8987839Snilay@cs.wisc.edu panic("Invalid Request Size"); 8997839Snilay@cs.wisc.edu 9007839Snilay@cs.wisc.edu return No_Fault; 9017839Snilay@cs.wisc.edu} 9027839Snilay@cs.wisc.edu 9037839Snilay@cs.wisc.eduvoid 9047839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts) 9057839Snilay@cs.wisc.edu{ 9067839Snilay@cs.wisc.edu bool delay = false; 9076902SBrad.Beckmann@amd.com 9088683Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 9098683Snilay@cs.wisc.edu panic("Cannot set a reserved interrupt"); 9108683Snilay@cs.wisc.edu 9118683Snilay@cs.wisc.edu if (interrupts & ISR_TXRCMP) 9128683Snilay@cs.wisc.edu regs.isr |= ISR_TXRCMP; 9138683Snilay@cs.wisc.edu 9148683Snilay@cs.wisc.edu if (interrupts & ISR_RXRCMP) 9158683Snilay@cs.wisc.edu regs.isr |= ISR_RXRCMP; 9168683Snilay@cs.wisc.edu 9178683Snilay@cs.wisc.edu//ISR_DPERR not implemented 9188683Snilay@cs.wisc.edu//ISR_SSERR not implemented 9198683Snilay@cs.wisc.edu//ISR_RMABT not implemented 9208683Snilay@cs.wisc.edu//ISR_RXSOVR not implemented 9218683Snilay@cs.wisc.edu//ISR_HIBINT not implemented 9228683Snilay@cs.wisc.edu//ISR_PHY not implemented 9238683Snilay@cs.wisc.edu//ISR_PME not implemented 9248683Snilay@cs.wisc.edu 9256657Snate@binkert.org if (interrupts & ISR_SWI) 9266657Snate@binkert.org regs.isr |= ISR_SWI; 9277839Snilay@cs.wisc.edu 9287839Snilay@cs.wisc.edu//ISR_MIB not implemented 9297839Snilay@cs.wisc.edu//ISR_TXURN not implemented 9307839Snilay@cs.wisc.edu 9316657Snate@binkert.org if (interrupts & ISR_TXIDLE) 9327839Snilay@cs.wisc.edu regs.isr |= ISR_TXIDLE; 9337839Snilay@cs.wisc.edu 9347839Snilay@cs.wisc.edu if (interrupts & ISR_TXERR) 9357839Snilay@cs.wisc.edu regs.isr |= ISR_TXERR; 9367839Snilay@cs.wisc.edu 9378055Sksewell@umich.edu if (interrupts & ISR_TXDESC) 9387839Snilay@cs.wisc.edu regs.isr |= ISR_TXDESC; 9397839Snilay@cs.wisc.edu 9406657Snate@binkert.org if (interrupts & ISR_TXOK) { 9417839Snilay@cs.wisc.edu regs.isr |= ISR_TXOK; 9427839Snilay@cs.wisc.edu delay = true; 9437839Snilay@cs.wisc.edu } 9447839Snilay@cs.wisc.edu 9457839Snilay@cs.wisc.edu if (interrupts & ISR_RXORN) 9467839Snilay@cs.wisc.edu regs.isr |= ISR_RXORN; 9477839Snilay@cs.wisc.edu 9487839Snilay@cs.wisc.edu if (interrupts & ISR_RXIDLE) 9497839Snilay@cs.wisc.edu regs.isr |= ISR_RXIDLE; 9507839Snilay@cs.wisc.edu 9517839Snilay@cs.wisc.edu//ISR_RXEARLY not implemented 9528055Sksewell@umich.edu 9537839Snilay@cs.wisc.edu if (interrupts & ISR_RXERR) 9547839Snilay@cs.wisc.edu regs.isr |= ISR_RXERR; 9557839Snilay@cs.wisc.edu 9567839Snilay@cs.wisc.edu if (interrupts & ISR_RXDESC) 9577839Snilay@cs.wisc.edu regs.isr |= ISR_RXDESC; 9587839Snilay@cs.wisc.edu 9597839Snilay@cs.wisc.edu if (interrupts & ISR_RXOK) { 9607839Snilay@cs.wisc.edu delay = true; 9617839Snilay@cs.wisc.edu regs.isr |= ISR_RXOK; 9627839Snilay@cs.wisc.edu } 9637839Snilay@cs.wisc.edu 9647839Snilay@cs.wisc.edu if ((regs.isr & regs.imr)) { 9657839Snilay@cs.wisc.edu Tick when = curTick; 9667839Snilay@cs.wisc.edu if (delay) 9678055Sksewell@umich.edu when += intrDelay; 9687839Snilay@cs.wisc.edu cpuIntrPost(when); 9697839Snilay@cs.wisc.edu } 9707839Snilay@cs.wisc.edu 9717839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9727839Snilay@cs.wisc.edu interrupts, regs.isr, regs.imr); 9737839Snilay@cs.wisc.edu} 9747839Snilay@cs.wisc.edu 9757839Snilay@cs.wisc.eduvoid 9767839Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts) 9777839Snilay@cs.wisc.edu{ 9786657Snate@binkert.org if (interrupts & ISR_RESERVE) 9797007Snate@binkert.org panic("Cannot clear a reserved interrupt"); 9807007Snate@binkert.org 9816657Snate@binkert.org if (interrupts & ISR_TXRCMP) 9828055Sksewell@umich.edu regs.isr &= ~ISR_TXRCMP; 9836657Snate@binkert.org 9846657Snate@binkert.org if (interrupts & ISR_RXRCMP) 9856657Snate@binkert.org regs.isr &= ~ISR_RXRCMP; 9866657Snate@binkert.org 9878478Snilay@cs.wisc.edu//ISR_DPERR not implemented 9888478Snilay@cs.wisc.edu//ISR_SSERR not implemented 9898478Snilay@cs.wisc.edu//ISR_RMABT not implemented 9909302Snilay@cs.wisc.edu//ISR_RXSOVR not implemented 9919302Snilay@cs.wisc.edu//ISR_HIBINT not implemented 99210524Snilay@cs.wisc.edu//ISR_PHY not implemented 9939302Snilay@cs.wisc.edu//ISR_PME not implemented 9949302Snilay@cs.wisc.edu 99510524Snilay@cs.wisc.edu if (interrupts & ISR_SWI) 9969302Snilay@cs.wisc.edu regs.isr &= ~ISR_SWI; 9979302Snilay@cs.wisc.edu 9989302Snilay@cs.wisc.edu//ISR_MIB not implemented 9999302Snilay@cs.wisc.edu//ISR_TXURN not implemented 100010305Snilay@cs.wisc.edu 10019302Snilay@cs.wisc.edu if (interrupts & ISR_TXIDLE) 100210311Snilay@cs.wisc.edu regs.isr &= ~ISR_TXIDLE; 100310311Snilay@cs.wisc.edu 100410311Snilay@cs.wisc.edu if (interrupts & ISR_TXERR) 100510311Snilay@cs.wisc.edu regs.isr &= ~ISR_TXERR; 100610311Snilay@cs.wisc.edu 100710311Snilay@cs.wisc.edu if (interrupts & ISR_TXDESC) 100810311Snilay@cs.wisc.edu regs.isr &= ~ISR_TXDESC; 10099302Snilay@cs.wisc.edu 10109302Snilay@cs.wisc.edu if (interrupts & ISR_TXOK) 10119302Snilay@cs.wisc.edu regs.isr &= ~ISR_TXOK; 10129302Snilay@cs.wisc.edu 10139302Snilay@cs.wisc.edu if (interrupts & ISR_RXORN) 10146657Snate@binkert.org regs.isr &= ~ISR_RXORN; 10156657Snate@binkert.org 10169219Spower.jg@gmail.com if (interrupts & ISR_RXIDLE) 10176657Snate@binkert.org regs.isr &= ~ISR_RXIDLE; 10186657Snate@binkert.org 10196999Snate@binkert.org//ISR_RXEARLY not implemented 10206657Snate@binkert.org 10216657Snate@binkert.org if (interrupts & ISR_RXERR) 10229104Shestness@cs.utexas.edu regs.isr &= ~ISR_RXERR; 10239104Shestness@cs.utexas.edu 10249104Shestness@cs.utexas.edu if (interrupts & ISR_RXDESC) 10259104Shestness@cs.utexas.edu regs.isr &= ~ISR_RXDESC; 10266657Snate@binkert.org 10276657Snate@binkert.org if (interrupts & ISR_RXOK) 10286657Snate@binkert.org regs.isr &= ~ISR_RXOK; 10296657Snate@binkert.org 10308946Sandreas.hansson@arm.com if (!(regs.isr & regs.imr)) 10318946Sandreas.hansson@arm.com cpuIntrClear(); 10328946Sandreas.hansson@arm.com 10337832Snate@binkert.org DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 10347832Snate@binkert.org interrupts, regs.isr, regs.imr); 10357007Snate@binkert.org} 10368232Snate@binkert.org 10378229Snate@binkert.orgvoid 10388229Snate@binkert.orgNSGigE::devIntrChangeMask() 10398229Snate@binkert.org{ 10409104Shestness@cs.utexas.edu DPRINTF(EthernetIntr, "interrupt mask changed\n"); 10419104Shestness@cs.utexas.edu 10429104Shestness@cs.utexas.edu if (regs.isr & regs.imr) 10439104Shestness@cs.utexas.edu cpuIntrPost(curTick); 10449104Shestness@cs.utexas.edu else 10459104Shestness@cs.utexas.edu cpuIntrClear(); 10468229Snate@binkert.org} 10476657Snate@binkert.org 10486657Snate@binkert.orgvoid 10499219Spower.jg@gmail.comNSGigE::cpuIntrPost(Tick when) 10509219Spower.jg@gmail.com{ 10519219Spower.jg@gmail.com //If the interrupt you want to post is later than an 10529219Spower.jg@gmail.com //interrupt already scheduled, just let it post in the coming one and 10539219Spower.jg@gmail.com //don't schedule another. 10549219Spower.jg@gmail.com //HOWEVER, must be sure that the scheduled intrTick is in the future 10559219Spower.jg@gmail.com //(this was formerly the source of a bug) 10566657Snate@binkert.org assert((intrTick >= curTick) || (intrTick == 0)); 10577055Snate@binkert.org if (when > intrTick && intrTick != 0) 10587055Snate@binkert.org return; 10597007Snate@binkert.org 10607007Snate@binkert.org intrTick = when; 10616657Snate@binkert.org 10626657Snate@binkert.org if (intrEvent) { 10636657Snate@binkert.org intrEvent->squash(); 10646657Snate@binkert.org intrEvent = 0; 10656657Snate@binkert.org } 10666657Snate@binkert.org 10677007Snate@binkert.org if (when < curTick) { 10689496Snilay@cs.wisc.edu cpuInterrupt(); 10697007Snate@binkert.org } else { 10707007Snate@binkert.org DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 10719499Snilay@cs.wisc.edu intrTick); 10726657Snate@binkert.org intrEvent = new IntrEvent(this, true); 10736657Snate@binkert.org intrEvent->schedule(intrTick); 10746657Snate@binkert.org } 10756657Snate@binkert.org} 10766657Snate@binkert.org 10776657Snate@binkert.orgvoid 10786657Snate@binkert.orgNSGigE::cpuInterrupt() 10796657Snate@binkert.org{ 10806657Snate@binkert.org // Don't send an interrupt if there's already one 10816657Snate@binkert.org if (cpuPendingIntr) { 10826657Snate@binkert.org DPRINTF(EthernetIntr, 10836657Snate@binkert.org "would send an interrupt now, but there's already pending\n"); 10847567SBrad.Beckmann@amd.com intrTick = 0; 10859996Snilay@cs.wisc.edu return; 10867567SBrad.Beckmann@amd.com } 10879996Snilay@cs.wisc.edu // Don't send an interrupt if it's supposed to be delayed 10886657Snate@binkert.org if (intrTick > curTick) { 10896657Snate@binkert.org DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n", 10906657Snate@binkert.org intrTick); 10916657Snate@binkert.org return; 10926657Snate@binkert.org } 10936657Snate@binkert.org 10946657Snate@binkert.org // Whether or not there's a pending interrupt, we don't care about 10956657Snate@binkert.org // it anymore 10966657Snate@binkert.org intrEvent = 0; 10976657Snate@binkert.org intrTick = 0; 10986657Snate@binkert.org 10996657Snate@binkert.org // Send interrupt 11006657Snate@binkert.org cpuPendingIntr = true; 11016657Snate@binkert.org /** @todo rework the intctrl to be tsunami ok */ 11026657Snate@binkert.org //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11036657Snate@binkert.org DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); 11046657Snate@binkert.org tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 11056657Snate@binkert.org} 11066999Snate@binkert.org 11076657Snate@binkert.orgvoid 11086657Snate@binkert.orgNSGigE::cpuIntrClear() 11096657Snate@binkert.org{ 11106657Snate@binkert.org if (cpuPendingIntr) { 11116657Snate@binkert.org cpuPendingIntr = false; 11126657Snate@binkert.org /** @todo rework the intctrl to be tsunami ok */ 11137832Snate@binkert.org //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11147832Snate@binkert.org DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); 11157805Snilay@cs.wisc.edu tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 11167832Snate@binkert.org } 11178232Snate@binkert.org} 11188232Snate@binkert.org 11198229Snate@binkert.orgbool 11208229Snate@binkert.orgNSGigE::cpuIntrPending() const 11218229Snate@binkert.org{ return cpuPendingIntr; } 11228229Snate@binkert.org 11236657Snate@binkert.orgvoid 11246657Snate@binkert.orgNSGigE::txReset() 11256657Snate@binkert.org{ 11266657Snate@binkert.org 11276657Snate@binkert.org DPRINTF(Ethernet, "transmit reset\n"); 11286657Snate@binkert.org 11296657Snate@binkert.org CTDD = false; 11306657Snate@binkert.org txFifoAvail = MAX_TX_FIFO_SIZE; 11317007Snate@binkert.org txHalt = false; 11327007Snate@binkert.org txFragPtr = 0; 11337839Snilay@cs.wisc.edu assert(txDescCnt == 0); 11347839Snilay@cs.wisc.edu txFifo.clear(); 11357839Snilay@cs.wisc.edu regs.command &= ~CR_TXE; 11367839Snilay@cs.wisc.edu txState = txIdle; 11377839Snilay@cs.wisc.edu assert(txDmaState == dmaIdle); 11387839Snilay@cs.wisc.edu} 11397839Snilay@cs.wisc.edu 11407839Snilay@cs.wisc.eduvoid 11417839Snilay@cs.wisc.eduNSGigE::rxReset() 11427839Snilay@cs.wisc.edu{ 114310010Snilay@cs.wisc.edu DPRINTF(Ethernet, "receive reset\n"); 11446657Snate@binkert.org 11457839Snilay@cs.wisc.edu CRDD = false; 114610305Snilay@cs.wisc.edu assert(rxPktBytes == 0); 114710305Snilay@cs.wisc.edu rxFifoCnt = 0; 11487839Snilay@cs.wisc.edu rxHalt = false; 11498337Snilay@cs.wisc.edu rxFragPtr = 0; 11507839Snilay@cs.wisc.edu assert(rxDescCnt == 0); 11518337Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle); 11527839Snilay@cs.wisc.edu rxFifo.clear(); 11538337Snilay@cs.wisc.edu regs.command &= ~CR_RXE; 11547839Snilay@cs.wisc.edu rxState = rxIdle; 11558337Snilay@cs.wisc.edu} 11567839Snilay@cs.wisc.edu 11577839Snilay@cs.wisc.eduvoid NSGigE::regsReset() 115810305Snilay@cs.wisc.edu{ 11596657Snate@binkert.org memset(®s, 0, sizeof(regs)); 116010305Snilay@cs.wisc.edu regs.config = 0x80000000; 116110305Snilay@cs.wisc.edu regs.mear = 0x12; 116210305Snilay@cs.wisc.edu regs.isr = 0x00608000; 11636657Snate@binkert.org regs.txcfg = 0x120; 116410305Snilay@cs.wisc.edu regs.rxcfg = 0x4; 11657839Snilay@cs.wisc.edu regs.srr = 0x0103; 11667839Snilay@cs.wisc.edu regs.mibc = 0x2; 11677839Snilay@cs.wisc.edu regs.vdr = 0x81; 11687839Snilay@cs.wisc.edu regs.tesr = 0xc000; 11697839Snilay@cs.wisc.edu 11707839Snilay@cs.wisc.edu extstsEnable = false; 11717839Snilay@cs.wisc.edu acceptBroadcast = false; 11727839Snilay@cs.wisc.edu acceptMulticast = false; 11737839Snilay@cs.wisc.edu acceptUnicast = false; 11746657Snate@binkert.org acceptPerfect = false; 11757839Snilay@cs.wisc.edu acceptArp = false; 11766657Snate@binkert.org} 117710305Snilay@cs.wisc.edu 117810305Snilay@cs.wisc.eduvoid 117910305Snilay@cs.wisc.eduNSGigE::rxDmaReadCopy() 118010305Snilay@cs.wisc.edu{ 118110305Snilay@cs.wisc.edu assert(rxDmaState == dmaReading); 118210305Snilay@cs.wisc.edu 118310305Snilay@cs.wisc.edu memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 118410305Snilay@cs.wisc.edu rxDmaState = dmaIdle; 118510305Snilay@cs.wisc.edu 118610305Snilay@cs.wisc.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 118710305Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 118810305Snilay@cs.wisc.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 118910305Snilay@cs.wisc.edu} 11907839Snilay@cs.wisc.edu 11917839Snilay@cs.wisc.edubool 11928337Snilay@cs.wisc.eduNSGigE::doRxDmaRead() 11938341Snilay@cs.wisc.edu{ 11947839Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 11958337Snilay@cs.wisc.edu rxDmaState = dmaReading; 11968341Snilay@cs.wisc.edu 11977839Snilay@cs.wisc.edu if (dmaInterface && !rxDmaFree) { 11988337Snilay@cs.wisc.edu if (dmaInterface->busy()) 11998341Snilay@cs.wisc.edu rxDmaState = dmaReadWaiting; 12007839Snilay@cs.wisc.edu else 12018337Snilay@cs.wisc.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 12028341Snilay@cs.wisc.edu &rxDmaReadEvent, true); 12037839Snilay@cs.wisc.edu return true; 12047839Snilay@cs.wisc.edu } 120510305Snilay@cs.wisc.edu 120610305Snilay@cs.wisc.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 120710305Snilay@cs.wisc.edu rxDmaReadCopy(); 120810305Snilay@cs.wisc.edu return false; 120910305Snilay@cs.wisc.edu } 121010305Snilay@cs.wisc.edu 121110305Snilay@cs.wisc.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 121210305Snilay@cs.wisc.edu Tick start = curTick + dmaReadDelay + factor; 121310305Snilay@cs.wisc.edu rxDmaReadEvent.schedule(start); 121410305Snilay@cs.wisc.edu return true; 121510305Snilay@cs.wisc.edu} 121610305Snilay@cs.wisc.edu 121710305Snilay@cs.wisc.eduvoid 121810305Snilay@cs.wisc.eduNSGigE::rxDmaReadDone() 121910305Snilay@cs.wisc.edu{ 122010305Snilay@cs.wisc.edu assert(rxDmaState == dmaReading); 12216657Snate@binkert.org rxDmaReadCopy(); 122210305Snilay@cs.wisc.edu 122310305Snilay@cs.wisc.edu // If the transmit state machine has a pending DMA, let it go first 122410305Snilay@cs.wisc.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 122510305Snilay@cs.wisc.edu txKick(); 12266657Snate@binkert.org 12276657Snate@binkert.org rxKick(); 12287007Snate@binkert.org} 12297007Snate@binkert.org 12307007Snate@binkert.orgvoid 12317007Snate@binkert.orgNSGigE::rxDmaWriteCopy() 12327839Snilay@cs.wisc.edu{ 12337839Snilay@cs.wisc.edu assert(rxDmaState == dmaWriting); 12347839Snilay@cs.wisc.edu 12357839Snilay@cs.wisc.edu memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 12367839Snilay@cs.wisc.edu rxDmaState = dmaIdle; 12377839Snilay@cs.wisc.edu 12387839Snilay@cs.wisc.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 12397839Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 12407839Snilay@cs.wisc.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 12417839Snilay@cs.wisc.edu} 12427839Snilay@cs.wisc.edu 12437007Snate@binkert.orgbool 12446657Snate@binkert.orgNSGigE::doRxDmaWrite() 12456657Snate@binkert.org{ 12466657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 12476657Snate@binkert.org rxDmaState = dmaWriting; 12486657Snate@binkert.org 12496657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 12506657Snate@binkert.org if (dmaInterface->busy()) 12516657Snate@binkert.org rxDmaState = dmaWriteWaiting; 12526657Snate@binkert.org else 12536657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 12546657Snate@binkert.org &rxDmaWriteEvent, true); 12556999Snate@binkert.org return true; 12566657Snate@binkert.org } 12576657Snate@binkert.org 12586657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 12596657Snate@binkert.org rxDmaWriteCopy(); 12606657Snate@binkert.org return false; 12616657Snate@binkert.org } 12629104Shestness@cs.utexas.edu 12636657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 12646657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 12656657Snate@binkert.org rxDmaWriteEvent.schedule(start); 12666657Snate@binkert.org return true; 12676657Snate@binkert.org} 126810228Snilay@cs.wisc.edu 12697007Snate@binkert.orgvoid 12706657Snate@binkert.orgNSGigE::rxDmaWriteDone() 12716657Snate@binkert.org{ 12726657Snate@binkert.org assert(rxDmaState == dmaWriting); 12736657Snate@binkert.org rxDmaWriteCopy(); 12749105SBrad.Beckmann@amd.com 12759105SBrad.Beckmann@amd.com // If the transmit state machine has a pending DMA, let it go first 12769105SBrad.Beckmann@amd.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12779105SBrad.Beckmann@amd.com txKick(); 12789105SBrad.Beckmann@amd.com 12799105SBrad.Beckmann@amd.com rxKick(); 12809105SBrad.Beckmann@amd.com} 12819105SBrad.Beckmann@amd.com 12826657Snate@binkert.orgvoid 12836657Snate@binkert.orgNSGigE::rxKick() 12846657Snate@binkert.org{ 12856657Snate@binkert.org DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n", 12866657Snate@binkert.org NsRxStateStrings[rxState], rxFifo.size()); 12876657Snate@binkert.org 12886657Snate@binkert.org if (rxKickTick > curTick) { 12899104Shestness@cs.utexas.edu DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 12909104Shestness@cs.utexas.edu rxKickTick); 12919104Shestness@cs.utexas.edu return; 12929104Shestness@cs.utexas.edu } 12936657Snate@binkert.org 12946657Snate@binkert.org next: 12956657Snate@binkert.org switch(rxDmaState) { 12966657Snate@binkert.org case dmaReadWaiting: 12976657Snate@binkert.org if (doRxDmaRead()) 12986657Snate@binkert.org goto exit; 12996657Snate@binkert.org break; 13006657Snate@binkert.org case dmaWriteWaiting: 13016657Snate@binkert.org if (doRxDmaWrite()) 13026657Snate@binkert.org goto exit; 13037839Snilay@cs.wisc.edu break; 13047839Snilay@cs.wisc.edu default: 13057839Snilay@cs.wisc.edu break; 13067839Snilay@cs.wisc.edu } 13077839Snilay@cs.wisc.edu 13087839Snilay@cs.wisc.edu // see state machine from spec for details 13097839Snilay@cs.wisc.edu // the way this works is, if you finish work on one state and can go directly to 13107839Snilay@cs.wisc.edu // another, you do that through jumping to the label "next". however, if you have 13117839Snilay@cs.wisc.edu // intermediate work, like DMA so that you can't go to the next state yet, you go to 13127839Snilay@cs.wisc.edu // exit and exit the loop. however, when the DMA is done it will trigger an 13137839Snilay@cs.wisc.edu // event and come back to this loop. 13147839Snilay@cs.wisc.edu switch (rxState) { 13156657Snate@binkert.org case rxIdle: 13166657Snate@binkert.org if (!regs.command & CR_RXE) { 13176657Snate@binkert.org DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 13186657Snate@binkert.org goto exit; 13196657Snate@binkert.org } 13206657Snate@binkert.org 13216657Snate@binkert.org if (CRDD) { 13226657Snate@binkert.org rxState = rxDescRefr; 13236657Snate@binkert.org 13246657Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 13256657Snate@binkert.org rxDmaData = &rxDescCache + offsetof(ns_desc, link); 13266657Snate@binkert.org rxDmaLen = sizeof(rxDescCache.link); 13276657Snate@binkert.org rxDmaFree = dmaDescFree; 13286657Snate@binkert.org 13296657Snate@binkert.org descDmaReads++; 13306657Snate@binkert.org descDmaRdBytes += rxDmaLen; 13316657Snate@binkert.org 133210305Snilay@cs.wisc.edu if (doRxDmaRead()) 13336657Snate@binkert.org goto exit; 13346657Snate@binkert.org } else { 13356657Snate@binkert.org rxState = rxDescRead; 13367805Snilay@cs.wisc.edu 13378159SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 13389465Snilay@cs.wisc.edu rxDmaData = &rxDescCache; 13396657Snate@binkert.org rxDmaLen = sizeof(ns_desc); 134010305Snilay@cs.wisc.edu rxDmaFree = dmaDescFree; 13416657Snate@binkert.org 13426657Snate@binkert.org descDmaReads++; 13436657Snate@binkert.org descDmaRdBytes += rxDmaLen; 13446657Snate@binkert.org 13456657Snate@binkert.org if (doRxDmaRead()) 13466657Snate@binkert.org goto exit; 13476657Snate@binkert.org } 13486657Snate@binkert.org break; 13496657Snate@binkert.org 13507007Snate@binkert.org case rxDescRefr: 13516999Snate@binkert.org if (rxDmaState != dmaIdle) 13527007Snate@binkert.org goto exit; 13537007Snate@binkert.org 13547007Snate@binkert.org rxState = rxAdvance; 13557007Snate@binkert.org break; 13567007Snate@binkert.org 13577007Snate@binkert.org case rxDescRead: 13586657Snate@binkert.org if (rxDmaState != dmaIdle) 13596657Snate@binkert.org goto exit; 13606657Snate@binkert.org 13616657Snate@binkert.org DPRINTF(EthernetDesc, 13626657Snate@binkert.org "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 13636657Snate@binkert.org ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 13646657Snate@binkert.org rxDescCache.extsts); 13656657Snate@binkert.org 13666657Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_OWN) { 13676657Snate@binkert.org rxState = rxIdle; 13686657Snate@binkert.org } else { 13696657Snate@binkert.org rxState = rxFifoBlock; 13706657Snate@binkert.org rxFragPtr = rxDescCache.bufptr; 13716657Snate@binkert.org rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 13726657Snate@binkert.org } 13736657Snate@binkert.org break; 13746657Snate@binkert.org 13756657Snate@binkert.org case rxFifoBlock: 13766657Snate@binkert.org if (!rxPacket) { 13776657Snate@binkert.org /** 13786657Snate@binkert.org * @todo in reality, we should be able to start processing 13796657Snate@binkert.org * the packet as it arrives, and not have to wait for the 13806657Snate@binkert.org * full packet ot be in the receive fifo. 13816657Snate@binkert.org */ 13826657Snate@binkert.org if (rxFifo.empty()) 13836657Snate@binkert.org goto exit; 13846657Snate@binkert.org 13856657Snate@binkert.org DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n"); 13866657Snate@binkert.org 13876999Snate@binkert.org // If we don't have a packet, grab a new one from the fifo. 13886657Snate@binkert.org rxPacket = rxFifo.front(); 13896657Snate@binkert.org rxPktBytes = rxPacket->length; 13907007Snate@binkert.org rxPacketBufPtr = rxPacket->data; 13917007Snate@binkert.org 13926657Snate@binkert.org if (DTRACE(Ethernet)) { 13936657Snate@binkert.org if (rxPacket->isIpPkt()) { 13946657Snate@binkert.org ip_header *ip = rxPacket->getIpHdr(); 13956657Snate@binkert.org DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 13966657Snate@binkert.org if (rxPacket->isTcpPkt()) { 13976657Snate@binkert.org tcp_header *tcp = rxPacket->getTcpHdr(ip); 13986657Snate@binkert.org DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 13996657Snate@binkert.org reverseEnd16(tcp->src_port_num), 14006657Snate@binkert.org reverseEnd16(tcp->dest_port_num)); 14016657Snate@binkert.org } 14026657Snate@binkert.org } 14036657Snate@binkert.org } 14046657Snate@binkert.org 14056657Snate@binkert.org // sanity check - i think the driver behaves like this 14066657Snate@binkert.org assert(rxDescCnt >= rxPktBytes); 14076657Snate@binkert.org 14086657Snate@binkert.org // Must clear the value before popping to decrement the 14096657Snate@binkert.org // reference count 14106657Snate@binkert.org rxFifo.front() = NULL; 14116657Snate@binkert.org rxFifo.pop_front(); 14126657Snate@binkert.org rxFifoCnt -= rxPacket->length; 14136657Snate@binkert.org } 14146657Snate@binkert.org 14156657Snate@binkert.org 14166657Snate@binkert.org // dont' need the && rxDescCnt > 0 if driver sanity check above holds 14176657Snate@binkert.org if (rxPktBytes > 0) { 14186657Snate@binkert.org rxState = rxFragWrite; 14196657Snate@binkert.org // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds 14206657Snate@binkert.org rxXferLen = rxPktBytes; 14216657Snate@binkert.org 14226657Snate@binkert.org rxDmaAddr = rxFragPtr & 0x3fffffff; 14236657Snate@binkert.org rxDmaData = rxPacketBufPtr; 14246657Snate@binkert.org rxDmaLen = rxXferLen; 14256657Snate@binkert.org rxDmaFree = dmaDataFree; 14266657Snate@binkert.org 14276657Snate@binkert.org if (doRxDmaWrite()) 14286657Snate@binkert.org goto exit; 14296657Snate@binkert.org 14306657Snate@binkert.org } else { 14316657Snate@binkert.org rxState = rxDescWrite; 14326657Snate@binkert.org 14336657Snate@binkert.org //if (rxPktBytes == 0) { /* packet is done */ 14346657Snate@binkert.org assert(rxPktBytes == 0); 14356657Snate@binkert.org DPRINTF(EthernetSM, "done with receiving packet\n"); 14366657Snate@binkert.org 14376657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_OWN; 14386657Snate@binkert.org rxDescCache.cmdsts &= ~CMDSTS_MORE; 14396657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_OK; 14406657Snate@binkert.org rxDescCache.cmdsts &= 0xffff0000; 14416657Snate@binkert.org rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 14426657Snate@binkert.org 14436657Snate@binkert.org#if 0 14446657Snate@binkert.org /* all the driver uses these are for its own stats keeping 14456657Snate@binkert.org which we don't care about, aren't necessary for functionality 14466657Snate@binkert.org and doing this would just slow us down. if they end up using 14476657Snate@binkert.org this in a later version for functional purposes, just undef 14486657Snate@binkert.org */ 14496657Snate@binkert.org if (rxFilterEnable) { 14506657Snate@binkert.org rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 14516657Snate@binkert.org if (rxFifo.front()->IsUnicast()) 14526657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 14536657Snate@binkert.org if (rxFifo.front()->IsMulticast()) 14546657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 14556657Snate@binkert.org if (rxFifo.front()->IsBroadcast()) 14566657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 14576657Snate@binkert.org } 14586657Snate@binkert.org#endif 14596657Snate@binkert.org 14606657Snate@binkert.org if (rxPacket->isIpPkt() && extstsEnable) { 14616657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPPKT; 14626657Snate@binkert.org rxIPChecksums++; 14636657Snate@binkert.org if (!ipChecksum(rxPacket, false)) { 14646657Snate@binkert.org DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 14656657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPERR; 14666657Snate@binkert.org } 14676657Snate@binkert.org if (rxPacket->isTcpPkt()) { 14686657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPPKT; 14696657Snate@binkert.org rxTCPChecksums++; 14706657Snate@binkert.org if (!tcpChecksum(rxPacket, false)) { 14716657Snate@binkert.org DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 14726657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPERR; 14736657Snate@binkert.org 14746657Snate@binkert.org } 14756657Snate@binkert.org } else if (rxPacket->isUdpPkt()) { 14766657Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPPKT; 14776657Snate@binkert.org if (!udpChecksum(rxPacket, false)) { 14786657Snate@binkert.org DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 14796657Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPERR; 14807007Snate@binkert.org } 14816657Snate@binkert.org } 14826657Snate@binkert.org } 14836657Snate@binkert.org rxPacket = 0; 14846657Snate@binkert.org 14856657Snate@binkert.org /* the driver seems to always receive into desc buffers 14866657Snate@binkert.org of size 1514, so you never have a pkt that is split 14876657Snate@binkert.org into multiple descriptors on the receive side, so 14887007Snate@binkert.org i don't implement that case, hence the assert above. 14896657Snate@binkert.org */ 14906657Snate@binkert.org 14916657Snate@binkert.org DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 14926657Snate@binkert.org rxDescCache.cmdsts, rxDescCache.extsts); 14936657Snate@binkert.org 14946657Snate@binkert.org rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 14956657Snate@binkert.org rxDmaData = &(rxDescCache.cmdsts); 14966657Snate@binkert.org rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 14976657Snate@binkert.org rxDmaFree = dmaDescFree; 14986657Snate@binkert.org 14996657Snate@binkert.org descDmaWrites++; 15006657Snate@binkert.org descDmaWrBytes += rxDmaLen; 15016657Snate@binkert.org 15026657Snate@binkert.org if (doRxDmaWrite()) 15036657Snate@binkert.org goto exit; 15047007Snate@binkert.org } 15056657Snate@binkert.org break; 15066657Snate@binkert.org 15076657Snate@binkert.org case rxFragWrite: 15086657Snate@binkert.org if (rxDmaState != dmaIdle) 15096657Snate@binkert.org goto exit; 15106657Snate@binkert.org 15116657Snate@binkert.org rxPacketBufPtr += rxXferLen; 15126657Snate@binkert.org rxFragPtr += rxXferLen; 15136657Snate@binkert.org rxPktBytes -= rxXferLen; 15146657Snate@binkert.org 15156657Snate@binkert.org rxState = rxFifoBlock; 15166657Snate@binkert.org break; 15176657Snate@binkert.org 15186657Snate@binkert.org case rxDescWrite: 15196657Snate@binkert.org if (rxDmaState != dmaIdle) 15206657Snate@binkert.org goto exit; 15216657Snate@binkert.org 15226657Snate@binkert.org assert(rxDescCache.cmdsts & CMDSTS_OWN); 15236657Snate@binkert.org 15246657Snate@binkert.org assert(rxPacket == 0); 15256657Snate@binkert.org devIntrPost(ISR_RXOK); 15266657Snate@binkert.org 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 if (doTxDmaWrite()) 1893 goto exit; 1894 1895 transmit(); 1896 1897 txPacket = 0; 1898 1899 if (txHalt) { 1900 DPRINTF(EthernetSM, "halting TX state machine\n"); 1901 txState = txIdle; 1902 txHalt = false; 1903 } else 1904 txState = txAdvance; 1905 } 1906 } else { 1907 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1908 txState = txFragRead; 1909 1910 /* The number of bytes transferred is either whatever is left 1911 in the descriptor (txDescCnt), or if there is not enough 1912 room in the fifo, just whatever room is left in the fifo 1913 */ 1914 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1915 1916 txDmaAddr = txFragPtr & 0x3fffffff; 1917 txDmaData = txPacketBufPtr; 1918 txDmaLen = txXferLen; 1919 txDmaFree = dmaDataFree; 1920 1921 if (doTxDmaRead()) 1922 goto exit; 1923 } 1924 break; 1925 1926 case txFragRead: 1927 if (txDmaState != dmaIdle) 1928 goto exit; 1929 1930 txPacketBufPtr += txXferLen; 1931 txFragPtr += txXferLen; 1932 txDescCnt -= txXferLen; 1933 txFifoAvail -= txXferLen; 1934 1935 txState = txFifoBlock; 1936 break; 1937 1938 case txDescWrite: 1939 if (txDmaState != dmaIdle) 1940 goto exit; 1941 1942 if (txDescCache.cmdsts & CMDSTS_INTR) { 1943 devIntrPost(ISR_TXDESC); 1944 } 1945 1946 txState = txAdvance; 1947 break; 1948 1949 case txAdvance: 1950 if (txDescCache.link == 0) { 1951 txState = txIdle; 1952 } else { 1953 txState = txDescRead; 1954 regs.txdp = txDescCache.link; 1955 CTDD = false; 1956 1957 txDmaAddr = txDescCache.link & 0x3fffffff; 1958 txDmaData = &txDescCache; 1959 txDmaLen = sizeof(ns_desc); 1960 txDmaFree = dmaDescFree; 1961 1962 if (doTxDmaRead()) 1963 goto exit; 1964 } 1965 break; 1966 1967 default: 1968 panic("invalid state"); 1969 } 1970 1971 DPRINTF(EthernetSM, "entering next tx state=%s\n", 1972 NsTxStateStrings[txState]); 1973 1974 if (txState == txIdle) { 1975 regs.command &= ~CR_TXE; 1976 devIntrPost(ISR_TXIDLE); 1977 return; 1978 } 1979 1980 goto next; 1981 1982 exit: 1983 /** 1984 * @todo do we want to schedule a future kick? 1985 */ 1986 DPRINTF(EthernetSM, "tx state machine exited state=%s\n", 1987 NsTxStateStrings[txState]); 1988} 1989 1990void 1991NSGigE::transferDone() 1992{ 1993 if (txFifo.empty()) 1994 return; 1995 1996 if (txEvent.scheduled()) 1997 txEvent.reschedule(curTick + 1); 1998 else 1999 txEvent.schedule(curTick + 1); 2000} 2001 2002bool 2003NSGigE::rxFilter(PacketPtr packet) 2004{ 2005 bool drop = true; 2006 string type; 2007 2008 if (packet->IsUnicast()) { 2009 type = "unicast"; 2010 2011 // If we're accepting all unicast addresses 2012 if (acceptUnicast) 2013 drop = false; 2014 2015 // If we make a perfect match 2016 if ((acceptPerfect) 2017 && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0)) 2018 drop = false; 2019 2020 eth_header *eth = (eth_header *) packet->data; 2021 if ((acceptArp) && (eth->type == 0x608)) 2022 drop = false; 2023 2024 } else if (packet->IsBroadcast()) { 2025 type = "broadcast"; 2026 2027 // if we're accepting broadcasts 2028 if (acceptBroadcast) 2029 drop = false; 2030 2031 } else if (packet->IsMulticast()) { 2032 type = "multicast"; 2033 2034 // if we're accepting all multicasts 2035 if (acceptMulticast) 2036 drop = false; 2037 2038 } else { 2039 type = "unknown"; 2040 2041 // oh well, punt on this one 2042 } 2043 2044 if (drop) { 2045 DPRINTF(Ethernet, "rxFilter drop\n"); 2046 DDUMP(EthernetData, packet->data, packet->length); 2047 } 2048 2049 return drop; 2050} 2051 2052bool 2053NSGigE::recvPacket(PacketPtr packet) 2054{ 2055 rxBytes += packet->length; 2056 rxPackets++; 2057 2058 DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt); 2059 2060 if (rxState == rxIdle) { 2061 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2062 interface->recvDone(); 2063 return true; 2064 } 2065 2066 if (rxFilterEnable && rxFilter(packet)) { 2067 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2068 interface->recvDone(); 2069 return true; 2070 } 2071 2072 if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) { 2073 DPRINTF(Ethernet, 2074 "packet will not fit in receive buffer...packet dropped\n"); 2075 devIntrPost(ISR_RXORN); 2076 return false; 2077 } 2078 2079 rxFifo.push_back(packet); 2080 rxFifoCnt += packet->length; 2081 interface->recvDone(); 2082 2083 rxKick(); 2084 return true; 2085} 2086 2087/** 2088 * does a udp checksum. if gen is true, then it generates it and puts it in the right place 2089 * else, it just checks what it calculates against the value in the header in packet 2090 */ 2091bool 2092NSGigE::udpChecksum(PacketPtr packet, bool gen) 2093{ 2094 ip_header *ip = packet->getIpHdr(); 2095 udp_header *hdr = packet->getUdpHdr(ip); 2096 2097 pseudo_header *pseudo = new pseudo_header; 2098 2099 pseudo->src_ip_addr = ip->src_ip_addr; 2100 pseudo->dest_ip_addr = ip->dest_ip_addr; 2101 pseudo->protocol = ip->protocol; 2102 pseudo->len = hdr->len; 2103 2104 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2105 (uint32_t) hdr->len); 2106 2107 delete pseudo; 2108 if (gen) 2109 hdr->chksum = cksum; 2110 else 2111 if (cksum != 0) 2112 return false; 2113 2114 return true; 2115} 2116 2117bool 2118NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2119{ 2120 ip_header *ip = packet->getIpHdr(); 2121 tcp_header *hdr = packet->getTcpHdr(ip); 2122 2123 uint16_t cksum; 2124 pseudo_header *pseudo = new pseudo_header; 2125 if (!gen) { 2126 pseudo->src_ip_addr = ip->src_ip_addr; 2127 pseudo->dest_ip_addr = ip->dest_ip_addr; 2128 pseudo->protocol = reverseEnd16(ip->protocol); 2129 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4); 2130 2131 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2132 (uint32_t) reverseEnd16(pseudo->len)); 2133 } else { 2134 pseudo->src_ip_addr = 0; 2135 pseudo->dest_ip_addr = 0; 2136 pseudo->protocol = hdr->chksum; 2137 pseudo->len = 0; 2138 hdr->chksum = 0; 2139 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2140 (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4)); 2141 } 2142 2143 delete pseudo; 2144 if (gen) 2145 hdr->chksum = cksum; 2146 else 2147 if (cksum != 0) 2148 return false; 2149 2150 return true; 2151} 2152 2153bool 2154NSGigE::ipChecksum(PacketPtr packet, bool gen) 2155{ 2156 ip_header *hdr = packet->getIpHdr(); 2157 2158 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4); 2159 2160 if (gen) { 2161 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2162 hdr->hdr_chksum = cksum; 2163 } 2164 else 2165 if (cksum != 0) 2166 return false; 2167 2168 return true; 2169} 2170 2171uint16_t 2172NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2173{ 2174 uint32_t sum = 0; 2175 2176 uint16_t last_pad = 0; 2177 if (len & 1) { 2178 last_pad = buf[len/2] & 0xff; 2179 len--; 2180 sum += last_pad; 2181 } 2182 2183 if (pseudo) { 2184 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2185 pseudo[3] + pseudo[4] + pseudo[5]; 2186 } 2187 2188 for (int i=0; i < (len/2); ++i) { 2189 sum += buf[i]; 2190 } 2191 2192 while (sum >> 16) 2193 sum = (sum >> 16) + (sum & 0xffff); 2194 2195 return ~sum; 2196} 2197 2198//===================================================================== 2199// 2200// 2201void 2202NSGigE::serialize(ostream &os) 2203{ 2204 // Serialize the PciDev base class 2205 PciDev::serialize(os); 2206 2207 /* 2208 * Finalize any DMA events now. 2209 */ 2210 if (rxDmaReadEvent.scheduled()) 2211 rxDmaReadCopy(); 2212 if (rxDmaWriteEvent.scheduled()) 2213 rxDmaWriteCopy(); 2214 if (txDmaReadEvent.scheduled()) 2215 txDmaReadCopy(); 2216 if (txDmaWriteEvent.scheduled()) 2217 txDmaWriteCopy(); 2218 2219 /* 2220 * Serialize the device registers 2221 */ 2222 SERIALIZE_SCALAR(regs.command); 2223 SERIALIZE_SCALAR(regs.config); 2224 SERIALIZE_SCALAR(regs.mear); 2225 SERIALIZE_SCALAR(regs.ptscr); 2226 SERIALIZE_SCALAR(regs.isr); 2227 SERIALIZE_SCALAR(regs.imr); 2228 SERIALIZE_SCALAR(regs.ier); 2229 SERIALIZE_SCALAR(regs.ihr); 2230 SERIALIZE_SCALAR(regs.txdp); 2231 SERIALIZE_SCALAR(regs.txdp_hi); 2232 SERIALIZE_SCALAR(regs.txcfg); 2233 SERIALIZE_SCALAR(regs.gpior); 2234 SERIALIZE_SCALAR(regs.rxdp); 2235 SERIALIZE_SCALAR(regs.rxdp_hi); 2236 SERIALIZE_SCALAR(regs.rxcfg); 2237 SERIALIZE_SCALAR(regs.pqcr); 2238 SERIALIZE_SCALAR(regs.wcsr); 2239 SERIALIZE_SCALAR(regs.pcr); 2240 SERIALIZE_SCALAR(regs.rfcr); 2241 SERIALIZE_SCALAR(regs.rfdr); 2242 SERIALIZE_SCALAR(regs.srr); 2243 SERIALIZE_SCALAR(regs.mibc); 2244 SERIALIZE_SCALAR(regs.vrcr); 2245 SERIALIZE_SCALAR(regs.vtcr); 2246 SERIALIZE_SCALAR(regs.vdr); 2247 SERIALIZE_SCALAR(regs.ccsr); 2248 SERIALIZE_SCALAR(regs.tbicr); 2249 SERIALIZE_SCALAR(regs.tbisr); 2250 SERIALIZE_SCALAR(regs.tanar); 2251 SERIALIZE_SCALAR(regs.tanlpar); 2252 SERIALIZE_SCALAR(regs.taner); 2253 SERIALIZE_SCALAR(regs.tesr); 2254 2255 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2256 2257 SERIALIZE_SCALAR(ioEnable); 2258 2259 /* 2260 * Serialize the data Fifos 2261 */ 2262 int txNumPkts = txFifo.size(); 2263 SERIALIZE_SCALAR(txNumPkts); 2264 int i = 0; 2265 pktiter_t end = txFifo.end(); 2266 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2267 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2268 (*p)->serialize(os); 2269 } 2270 2271 int rxNumPkts = rxFifo.size(); 2272 SERIALIZE_SCALAR(rxNumPkts); 2273 i = 0; 2274 end = rxFifo.end(); 2275 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2276 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2277 (*p)->serialize(os); 2278 } 2279 2280 /* 2281 * Serialize the various helper variables 2282 */ 2283 bool txPacketExists = txPacket; 2284 SERIALIZE_SCALAR(txPacketExists); 2285 if (txPacketExists) { 2286 nameOut(os, csprintf("%s.txPacket", name())); 2287 txPacket->serialize(os); 2288 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2289 SERIALIZE_SCALAR(txPktBufPtr); 2290 } 2291 2292 bool rxPacketExists = rxPacket; 2293 SERIALIZE_SCALAR(rxPacketExists); 2294 if (rxPacketExists) { 2295 nameOut(os, csprintf("%s.rxPacket", name())); 2296 rxPacket->serialize(os); 2297 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2298 SERIALIZE_SCALAR(rxPktBufPtr); 2299 } 2300 2301 SERIALIZE_SCALAR(txXferLen); 2302 SERIALIZE_SCALAR(rxXferLen); 2303 2304 /* 2305 * Serialize DescCaches 2306 */ 2307 SERIALIZE_SCALAR(txDescCache.link); 2308 SERIALIZE_SCALAR(txDescCache.bufptr); 2309 SERIALIZE_SCALAR(txDescCache.cmdsts); 2310 SERIALIZE_SCALAR(txDescCache.extsts); 2311 SERIALIZE_SCALAR(rxDescCache.link); 2312 SERIALIZE_SCALAR(rxDescCache.bufptr); 2313 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2314 SERIALIZE_SCALAR(rxDescCache.extsts); 2315 2316 /* 2317 * Serialize tx state machine 2318 */ 2319 int txState = this->txState; 2320 SERIALIZE_SCALAR(txState); 2321 SERIALIZE_SCALAR(CTDD); 2322 SERIALIZE_SCALAR(txFifoAvail); 2323 SERIALIZE_SCALAR(txHalt); 2324 SERIALIZE_SCALAR(txFragPtr); 2325 SERIALIZE_SCALAR(txDescCnt); 2326 int txDmaState = this->txDmaState; 2327 SERIALIZE_SCALAR(txDmaState); 2328 2329 /* 2330 * Serialize rx state machine 2331 */ 2332 int rxState = this->rxState; 2333 SERIALIZE_SCALAR(rxState); 2334 SERIALIZE_SCALAR(CRDD); 2335 SERIALIZE_SCALAR(rxPktBytes); 2336 SERIALIZE_SCALAR(rxFifoCnt); 2337 SERIALIZE_SCALAR(rxHalt); 2338 SERIALIZE_SCALAR(rxDescCnt); 2339 int rxDmaState = this->rxDmaState; 2340 SERIALIZE_SCALAR(rxDmaState); 2341 2342 SERIALIZE_SCALAR(extstsEnable); 2343 2344 /* 2345 * If there's a pending transmit, store the time so we can 2346 * reschedule it later 2347 */ 2348 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2349 SERIALIZE_SCALAR(transmitTick); 2350 2351 /* 2352 * receive address filter settings 2353 */ 2354 SERIALIZE_SCALAR(rxFilterEnable); 2355 SERIALIZE_SCALAR(acceptBroadcast); 2356 SERIALIZE_SCALAR(acceptMulticast); 2357 SERIALIZE_SCALAR(acceptUnicast); 2358 SERIALIZE_SCALAR(acceptPerfect); 2359 SERIALIZE_SCALAR(acceptArp); 2360 2361 /* 2362 * Keep track of pending interrupt status. 2363 */ 2364 SERIALIZE_SCALAR(intrTick); 2365 SERIALIZE_SCALAR(cpuPendingIntr); 2366 Tick intrEventTick = 0; 2367 if (intrEvent) 2368 intrEventTick = intrEvent->when(); 2369 SERIALIZE_SCALAR(intrEventTick); 2370 2371} 2372 2373void 2374NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2375{ 2376 // Unserialize the PciDev base class 2377 PciDev::unserialize(cp, section); 2378 2379 UNSERIALIZE_SCALAR(regs.command); 2380 UNSERIALIZE_SCALAR(regs.config); 2381 UNSERIALIZE_SCALAR(regs.mear); 2382 UNSERIALIZE_SCALAR(regs.ptscr); 2383 UNSERIALIZE_SCALAR(regs.isr); 2384 UNSERIALIZE_SCALAR(regs.imr); 2385 UNSERIALIZE_SCALAR(regs.ier); 2386 UNSERIALIZE_SCALAR(regs.ihr); 2387 UNSERIALIZE_SCALAR(regs.txdp); 2388 UNSERIALIZE_SCALAR(regs.txdp_hi); 2389 UNSERIALIZE_SCALAR(regs.txcfg); 2390 UNSERIALIZE_SCALAR(regs.gpior); 2391 UNSERIALIZE_SCALAR(regs.rxdp); 2392 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2393 UNSERIALIZE_SCALAR(regs.rxcfg); 2394 UNSERIALIZE_SCALAR(regs.pqcr); 2395 UNSERIALIZE_SCALAR(regs.wcsr); 2396 UNSERIALIZE_SCALAR(regs.pcr); 2397 UNSERIALIZE_SCALAR(regs.rfcr); 2398 UNSERIALIZE_SCALAR(regs.rfdr); 2399 UNSERIALIZE_SCALAR(regs.srr); 2400 UNSERIALIZE_SCALAR(regs.mibc); 2401 UNSERIALIZE_SCALAR(regs.vrcr); 2402 UNSERIALIZE_SCALAR(regs.vtcr); 2403 UNSERIALIZE_SCALAR(regs.vdr); 2404 UNSERIALIZE_SCALAR(regs.ccsr); 2405 UNSERIALIZE_SCALAR(regs.tbicr); 2406 UNSERIALIZE_SCALAR(regs.tbisr); 2407 UNSERIALIZE_SCALAR(regs.tanar); 2408 UNSERIALIZE_SCALAR(regs.tanlpar); 2409 UNSERIALIZE_SCALAR(regs.taner); 2410 UNSERIALIZE_SCALAR(regs.tesr); 2411 2412 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2413 2414 UNSERIALIZE_SCALAR(ioEnable); 2415 2416 /* 2417 * unserialize the data fifos 2418 */ 2419 int txNumPkts; 2420 UNSERIALIZE_SCALAR(txNumPkts); 2421 int i; 2422 for (i = 0; i < txNumPkts; ++i) { 2423 PacketPtr p = new EtherPacket; 2424 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2425 txFifo.push_back(p); 2426 } 2427 2428 int rxNumPkts; 2429 UNSERIALIZE_SCALAR(rxNumPkts); 2430 for (i = 0; i < rxNumPkts; ++i) { 2431 PacketPtr p = new EtherPacket; 2432 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2433 rxFifo.push_back(p); 2434 } 2435 2436 /* 2437 * unserialize the various helper variables 2438 */ 2439 bool txPacketExists; 2440 UNSERIALIZE_SCALAR(txPacketExists); 2441 if (txPacketExists) { 2442 txPacket = new EtherPacket; 2443 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2444 uint32_t txPktBufPtr; 2445 UNSERIALIZE_SCALAR(txPktBufPtr); 2446 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2447 } else 2448 txPacket = 0; 2449 2450 bool rxPacketExists; 2451 UNSERIALIZE_SCALAR(rxPacketExists); 2452 rxPacket = 0; 2453 if (rxPacketExists) { 2454 rxPacket = new EtherPacket; 2455 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2456 uint32_t rxPktBufPtr; 2457 UNSERIALIZE_SCALAR(rxPktBufPtr); 2458 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2459 } else 2460 rxPacket = 0; 2461 2462 UNSERIALIZE_SCALAR(txXferLen); 2463 UNSERIALIZE_SCALAR(rxXferLen); 2464 2465 /* 2466 * Unserialize DescCaches 2467 */ 2468 UNSERIALIZE_SCALAR(txDescCache.link); 2469 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2470 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2471 UNSERIALIZE_SCALAR(txDescCache.extsts); 2472 UNSERIALIZE_SCALAR(rxDescCache.link); 2473 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2474 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2475 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2476 2477 /* 2478 * unserialize tx state machine 2479 */ 2480 int txState; 2481 UNSERIALIZE_SCALAR(txState); 2482 this->txState = (TxState) txState; 2483 UNSERIALIZE_SCALAR(CTDD); 2484 UNSERIALIZE_SCALAR(txFifoAvail); 2485 UNSERIALIZE_SCALAR(txHalt); 2486 UNSERIALIZE_SCALAR(txFragPtr); 2487 UNSERIALIZE_SCALAR(txDescCnt); 2488 int txDmaState; 2489 UNSERIALIZE_SCALAR(txDmaState); 2490 this->txDmaState = (DmaState) txDmaState; 2491 2492 /* 2493 * unserialize rx state machine 2494 */ 2495 int rxState; 2496 UNSERIALIZE_SCALAR(rxState); 2497 this->rxState = (RxState) rxState; 2498 UNSERIALIZE_SCALAR(CRDD); 2499 UNSERIALIZE_SCALAR(rxPktBytes); 2500 UNSERIALIZE_SCALAR(rxFifoCnt); 2501 UNSERIALIZE_SCALAR(rxHalt); 2502 UNSERIALIZE_SCALAR(rxDescCnt); 2503 int rxDmaState; 2504 UNSERIALIZE_SCALAR(rxDmaState); 2505 this->rxDmaState = (DmaState) rxDmaState; 2506 2507 UNSERIALIZE_SCALAR(extstsEnable); 2508 2509 /* 2510 * If there's a pending transmit, reschedule it now 2511 */ 2512 Tick transmitTick; 2513 UNSERIALIZE_SCALAR(transmitTick); 2514 if (transmitTick) 2515 txEvent.schedule(curTick + transmitTick); 2516 2517 /* 2518 * unserialize receive address filter settings 2519 */ 2520 UNSERIALIZE_SCALAR(rxFilterEnable); 2521 UNSERIALIZE_SCALAR(acceptBroadcast); 2522 UNSERIALIZE_SCALAR(acceptMulticast); 2523 UNSERIALIZE_SCALAR(acceptUnicast); 2524 UNSERIALIZE_SCALAR(acceptPerfect); 2525 UNSERIALIZE_SCALAR(acceptArp); 2526 2527 /* 2528 * Keep track of pending interrupt status. 2529 */ 2530 UNSERIALIZE_SCALAR(intrTick); 2531 UNSERIALIZE_SCALAR(cpuPendingIntr); 2532 Tick intrEventTick; 2533 UNSERIALIZE_SCALAR(intrEventTick); 2534 if (intrEventTick) { 2535 intrEvent = new IntrEvent(this, true); 2536 intrEvent->schedule(intrEventTick); 2537 } 2538 2539 /* 2540 * re-add addrRanges to bus bridges 2541 */ 2542 if (pioInterface) { 2543 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2544 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2545 } 2546} 2547 2548Tick 2549NSGigE::cacheAccess(MemReqPtr &req) 2550{ 2551 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2552 req->paddr, req->paddr - addr); 2553 return curTick + pioLatency; 2554} 2555//===================================================================== 2556 2557 2558//********** helper functions****************************************** 2559 2560uint16_t reverseEnd16(uint16_t num) 2561{ 2562 uint16_t reverse = (num & 0xff)<<8; 2563 reverse += ((num & 0xff00) >> 8); 2564 return reverse; 2565} 2566 2567uint32_t reverseEnd32(uint32_t num) 2568{ 2569 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2570 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2571 return reverse; 2572} 2573 2574 2575 2576//===================================================================== 2577 2578BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2579 2580 SimObjectParam<EtherInt *> peer; 2581 SimObjectParam<NSGigE *> device; 2582 2583END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2584 2585BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2586 2587 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2588 INIT_PARAM(device, "Ethernet device of this interface") 2589 2590END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2591 2592CREATE_SIM_OBJECT(NSGigEInt) 2593{ 2594 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2595 2596 EtherInt *p = (EtherInt *)peer; 2597 if (p) { 2598 dev_int->setPeer(p); 2599 p->setPeer(dev_int); 2600 } 2601 2602 return dev_int; 2603} 2604 2605REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2606 2607 2608BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2609 2610 Param<Tick> tx_delay; 2611 Param<Tick> rx_delay; 2612 SimObjectParam<IntrControl *> intr_ctrl; 2613 Param<Tick> intr_delay; 2614 SimObjectParam<MemoryController *> mmu; 2615 SimObjectParam<PhysicalMemory *> physmem; 2616 Param<bool> rx_filter; 2617 Param<string> hardware_address; 2618 SimObjectParam<Bus*> header_bus; 2619 SimObjectParam<Bus*> payload_bus; 2620 SimObjectParam<HierParams *> hier; 2621 Param<Tick> pio_latency; 2622 Param<bool> dma_desc_free; 2623 Param<bool> dma_data_free; 2624 Param<Tick> dma_read_delay; 2625 Param<Tick> dma_write_delay; 2626 Param<Tick> dma_read_factor; 2627 Param<Tick> dma_write_factor; 2628 SimObjectParam<PciConfigAll *> configspace; 2629 SimObjectParam<PciConfigData *> configdata; 2630 SimObjectParam<Tsunami *> tsunami; 2631 Param<uint32_t> pci_bus; 2632 Param<uint32_t> pci_dev; 2633 Param<uint32_t> pci_func; 2634 2635END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2636 2637BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2638 2639 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2640 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2641 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2642 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2643 INIT_PARAM(mmu, "Memory Controller"), 2644 INIT_PARAM(physmem, "Physical Memory"), 2645 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2646 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2647 "00:99:00:00:00:01"), 2648 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2649 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2650 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2651 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), 2652 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2653 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2654 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2655 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2656 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2657 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2658 INIT_PARAM(configspace, "PCI Configspace"), 2659 INIT_PARAM(configdata, "PCI Config data"), 2660 INIT_PARAM(tsunami, "Tsunami"), 2661 INIT_PARAM(pci_bus, "PCI bus"), 2662 INIT_PARAM(pci_dev, "PCI device number"), 2663 INIT_PARAM(pci_func, "PCI function code") 2664 2665END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2666 2667 2668CREATE_SIM_OBJECT(NSGigE) 2669{ 2670 int eaddr[6]; 2671 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2672 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2673 2674 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2675 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2676 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2677 dma_read_delay, dma_write_delay, dma_read_factor, 2678 dma_write_factor, configspace, configdata, 2679 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr); 2680} 2681 2682REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2683