ns_gige.cc revision 1205
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> 356882SBrad.Beckmann@amd.com#include <string> 367055Snate@binkert.org 376882SBrad.Beckmann@amd.com#include "base/inet.hh" 386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh" 398191SLisa.Hsu@amd.com#include "cpu/intr_control.hh" 406882SBrad.Beckmann@amd.com#include "dev/dma.hh" 416882SBrad.Beckmann@amd.com#include "dev/etherlink.hh" 426882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 436888SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh" 446882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh" 456882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh" 466657Snate@binkert.org#include "mem/bus/pio_interface.hh" 476657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh" 486657Snate@binkert.org#include "mem/functional_mem/memory_control.hh" 496657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh" 506657Snate@binkert.org#include "sim/builder.hh" 517839Snilay@cs.wisc.edu#include "sim/debug.hh" 526657Snate@binkert.org#include "sim/host.hh" 536882SBrad.Beckmann@amd.com#include "sim/stats.hh" 546882SBrad.Beckmann@amd.com#include "targetarch/vtophys.hh" 556882SBrad.Beckmann@amd.com 566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] = 576882SBrad.Beckmann@amd.com{ 586882SBrad.Beckmann@amd.com "rxIdle", 596657Snate@binkert.org "rxDescRefr", 606657Snate@binkert.org "rxDescRead", 616657Snate@binkert.org "rxFifoBlock", 626657Snate@binkert.org "rxFragWrite", 636657Snate@binkert.org "rxDescWrite", 646657Snate@binkert.org "rxAdvance" 656657Snate@binkert.org}; 666657Snate@binkert.org 676657Snate@binkert.orgconst char *NsTxStateStrings[] = 687839Snilay@cs.wisc.edu{ 697839Snilay@cs.wisc.edu "txIdle", 706657Snate@binkert.org "txDescRefr", 716657Snate@binkert.org "txDescRead", 726657Snate@binkert.org "txFifoBlock", 736657Snate@binkert.org "txFragRead", 746657Snate@binkert.org "txDescWrite", 756657Snate@binkert.org "txAdvance" 766657Snate@binkert.org}; 776657Snate@binkert.org 786657Snate@binkert.orgconst char *NsDmaState[] = 796657Snate@binkert.org{ 806657Snate@binkert.org "dmaIdle", 816657Snate@binkert.org "dmaReading", 826657Snate@binkert.org "dmaWriting", 836657Snate@binkert.org "dmaReadWaiting", 846657Snate@binkert.org "dmaWriteWaiting" 856657Snate@binkert.org}; 866657Snate@binkert.org 876657Snate@binkert.orgusing namespace std; 886657Snate@binkert.orgusing namespace Net; 896657Snate@binkert.org 906779SBrad.Beckmann@amd.com/////////////////////////////////////////////////////////////////////// 916657Snate@binkert.org// 926657Snate@binkert.org// NSGigE PCI Device 936657Snate@binkert.org// 946657Snate@binkert.orgNSGigE::NSGigE(Params *p) 956657Snate@binkert.org : PciDev(p), ioEnable(false), 966657Snate@binkert.org txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 976657Snate@binkert.org txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 986657Snate@binkert.org txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false), 996657Snate@binkert.org CTDD(false), 1006657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1016657Snate@binkert.org rxEnable(false), CRDD(false), rxPktBytes(0), 1026657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1036657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1046657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1056657Snate@binkert.org dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1066657Snate@binkert.org txDelay(p->tx_delay), rxDelay(p->rx_delay), 1076657Snate@binkert.org rxKickTick(0), txKickTick(0), 1086657Snate@binkert.org txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), 1096657Snate@binkert.org acceptMulticast(false), acceptUnicast(false), 1106657Snate@binkert.org acceptPerfect(false), acceptArp(false), 1116657Snate@binkert.org physmem(p->pmem), intrTick(0), cpuPendingIntr(false), 1126657Snate@binkert.org intrEvent(0), interface(0) 1136657Snate@binkert.org{ 1146657Snate@binkert.org if (p->header_bus) { 1157839Snilay@cs.wisc.edu pioInterface = newPioInterface(name(), p->hier, 1167839Snilay@cs.wisc.edu p->header_bus, this, 1177839Snilay@cs.wisc.edu &NSGigE::cacheAccess); 1187839Snilay@cs.wisc.edu 1197839Snilay@cs.wisc.edu pioLatency = p->pio_latency * p->header_bus->clockRatio; 1207839Snilay@cs.wisc.edu 1217839Snilay@cs.wisc.edu if (p->payload_bus) 1227839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1237839Snilay@cs.wisc.edu p->header_bus, 1247839Snilay@cs.wisc.edu p->payload_bus, 1); 1257839Snilay@cs.wisc.edu else 1267839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1277839Snilay@cs.wisc.edu p->header_bus, 1287839Snilay@cs.wisc.edu p->header_bus, 1); 1297839Snilay@cs.wisc.edu } else if (p->payload_bus) { 1306657Snate@binkert.org pioInterface = newPioInterface(name(), p->hier, 1316657Snate@binkert.org p->payload_bus, this, 1326657Snate@binkert.org &NSGigE::cacheAccess); 1336657Snate@binkert.org 1346657Snate@binkert.org pioLatency = p->pio_latency * p->payload_bus->clockRatio; 1356657Snate@binkert.org 1366657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1376657Snate@binkert.org p->payload_bus, 1386657Snate@binkert.org p->payload_bus, 1); 1396657Snate@binkert.org } 1406657Snate@binkert.org 1416657Snate@binkert.org 1426657Snate@binkert.org intrDelay = US2Ticks(p->intr_delay); 1436657Snate@binkert.org dmaReadDelay = p->dma_read_delay; 1446657Snate@binkert.org dmaWriteDelay = p->dma_write_delay; 1456657Snate@binkert.org dmaReadFactor = p->dma_read_factor; 1466657Snate@binkert.org dmaWriteFactor = p->dma_write_factor; 1476657Snate@binkert.org 1486657Snate@binkert.org regsReset(); 1496657Snate@binkert.org memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); 1506657Snate@binkert.org} 1516657Snate@binkert.org 1526657Snate@binkert.orgNSGigE::~NSGigE() 1536657Snate@binkert.org{} 1546657Snate@binkert.org 1556657Snate@binkert.orgvoid 1566657Snate@binkert.orgNSGigE::regStats() 1576657Snate@binkert.org{ 1586657Snate@binkert.org txBytes 1596657Snate@binkert.org .name(name() + ".txBytes") 1606657Snate@binkert.org .desc("Bytes Transmitted") 1616877Ssteve.reinhardt@amd.com .prereq(txBytes) 1626657Snate@binkert.org ; 1636657Snate@binkert.org 1646657Snate@binkert.org rxBytes 1656657Snate@binkert.org .name(name() + ".rxBytes") 1666657Snate@binkert.org .desc("Bytes Received") 1676657Snate@binkert.org .prereq(rxBytes) 1687542SBrad.Beckmann@amd.com ; 1697542SBrad.Beckmann@amd.com 1706657Snate@binkert.org txPackets 1716657Snate@binkert.org .name(name() + ".txPackets") 1726657Snate@binkert.org .desc("Number of Packets Transmitted") 1736657Snate@binkert.org .prereq(txBytes) 1746877Ssteve.reinhardt@amd.com ; 1756999Snate@binkert.org 1766877Ssteve.reinhardt@amd.com rxPackets 1776877Ssteve.reinhardt@amd.com .name(name() + ".rxPackets") 1786877Ssteve.reinhardt@amd.com .desc("Number of Packets Received") 1796877Ssteve.reinhardt@amd.com .prereq(rxBytes) 1806877Ssteve.reinhardt@amd.com ; 1816877Ssteve.reinhardt@amd.com 1826877Ssteve.reinhardt@amd.com txIpChecksums 1836877Ssteve.reinhardt@amd.com .name(name() + ".txIpChecksums") 1846877Ssteve.reinhardt@amd.com .desc("Number of tx IP Checksums done by device") 1856877Ssteve.reinhardt@amd.com .precision(0) 1866877Ssteve.reinhardt@amd.com .prereq(txBytes) 1876877Ssteve.reinhardt@amd.com ; 1886877Ssteve.reinhardt@amd.com 1896877Ssteve.reinhardt@amd.com rxIpChecksums 1906877Ssteve.reinhardt@amd.com .name(name() + ".rxIpChecksums") 1916877Ssteve.reinhardt@amd.com .desc("Number of rx IP Checksums done by device") 1926882SBrad.Beckmann@amd.com .precision(0) 1936882SBrad.Beckmann@amd.com .prereq(rxBytes) 1946882SBrad.Beckmann@amd.com ; 1956882SBrad.Beckmann@amd.com 1966882SBrad.Beckmann@amd.com txTcpChecksums 1976882SBrad.Beckmann@amd.com .name(name() + ".txTcpChecksums") 1986882SBrad.Beckmann@amd.com .desc("Number of tx TCP Checksums done by device") 1996877Ssteve.reinhardt@amd.com .precision(0) 2006877Ssteve.reinhardt@amd.com .prereq(txBytes) 2016877Ssteve.reinhardt@amd.com ; 2026877Ssteve.reinhardt@amd.com 2036657Snate@binkert.org rxTcpChecksums 2046657Snate@binkert.org .name(name() + ".rxTcpChecksums") 2056999Snate@binkert.org .desc("Number of rx TCP Checksums done by device") 2066657Snate@binkert.org .precision(0) 2076657Snate@binkert.org .prereq(rxBytes) 2086657Snate@binkert.org ; 2096657Snate@binkert.org 2106657Snate@binkert.org txUdpChecksums 2116657Snate@binkert.org .name(name() + ".txUdpChecksums") 2127007Snate@binkert.org .desc("Number of tx UDP Checksums done by device") 2136657Snate@binkert.org .precision(0) 2146657Snate@binkert.org .prereq(txBytes) 2156657Snate@binkert.org ; 2166657Snate@binkert.org 2176657Snate@binkert.org rxUdpChecksums 2187007Snate@binkert.org .name(name() + ".rxUdpChecksums") 2197007Snate@binkert.org .desc("Number of rx UDP Checksums done by device") 2206657Snate@binkert.org .precision(0) 2217002Snate@binkert.org .prereq(rxBytes) 2227002Snate@binkert.org ; 2237002Snate@binkert.org 2247002Snate@binkert.org descDmaReads 2258229Snate@binkert.org .name(name() + ".descDMAReads") 2268229Snate@binkert.org .desc("Number of descriptors the device read w/ DMA") 2276657Snate@binkert.org .precision(0) 2286657Snate@binkert.org ; 2298229Snate@binkert.org 2308229Snate@binkert.org descDmaWrites 2318229Snate@binkert.org .name(name() + ".descDMAWrites") 2328229Snate@binkert.org .desc("Number of descriptors the device wrote w/ DMA") 2336657Snate@binkert.org .precision(0) 2346657Snate@binkert.org ; 2356657Snate@binkert.org 2366657Snate@binkert.org descDmaRdBytes 2376793SBrad.Beckmann@amd.com .name(name() + ".descDmaReadBytes") 2386657Snate@binkert.org .desc("number of descriptor bytes read w/ DMA") 2396657Snate@binkert.org .precision(0) 2406657Snate@binkert.org ; 2416657Snate@binkert.org 2426657Snate@binkert.org descDmaWrBytes 2437002Snate@binkert.org .name(name() + ".descDmaWriteBytes") 2446657Snate@binkert.org .desc("number of descriptor bytes write w/ DMA") 2457007Snate@binkert.org .precision(0) 2467007Snate@binkert.org ; 2477007Snate@binkert.org 2487007Snate@binkert.org 2497007Snate@binkert.org txBandwidth 2506657Snate@binkert.org .name(name() + ".txBandwidth") 2516877Ssteve.reinhardt@amd.com .desc("Transmit Bandwidth (bits/s)") 2526877Ssteve.reinhardt@amd.com .precision(0) 2536657Snate@binkert.org .prereq(txBytes) 2546877Ssteve.reinhardt@amd.com ; 2556657Snate@binkert.org 2566657Snate@binkert.org rxBandwidth 2577002Snate@binkert.org .name(name() + ".rxBandwidth") 2587002Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 2596657Snate@binkert.org .precision(0) 2607567SBrad.Beckmann@amd.com .prereq(rxBytes) 2617567SBrad.Beckmann@amd.com ; 2627922SBrad.Beckmann@amd.com 2636881SBrad.Beckmann@amd.com txPacketRate 2647002Snate@binkert.org .name(name() + ".txPPS") 2657002Snate@binkert.org .desc("Packet Tranmission Rate (packets/s)") 2666657Snate@binkert.org .precision(0) 2677002Snate@binkert.org .prereq(txBytes) 2686902SBrad.Beckmann@amd.com ; 2696863Sdrh5@cs.wisc.edu 2706863Sdrh5@cs.wisc.edu rxPacketRate 2717007Snate@binkert.org .name(name() + ".rxPPS") 2726657Snate@binkert.org .desc("Packet Reception Rate (packets/s)") 2736657Snate@binkert.org .precision(0) 2746657Snate@binkert.org .prereq(rxBytes) 2756657Snate@binkert.org ; 2766657Snate@binkert.org 2776657Snate@binkert.org txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2786882SBrad.Beckmann@amd.com rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2796882SBrad.Beckmann@amd.com txPacketRate = txPackets / simSeconds; 2806882SBrad.Beckmann@amd.com rxPacketRate = rxPackets / simSeconds; 2816882SBrad.Beckmann@amd.com} 2826657Snate@binkert.org 2836657Snate@binkert.org/** 2846657Snate@binkert.org * This is to read the PCI general configuration registers 2856657Snate@binkert.org */ 2867007Snate@binkert.orgvoid 2877839Snilay@cs.wisc.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2887839Snilay@cs.wisc.edu{ 2897839Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 2907839Snilay@cs.wisc.edu PciDev::ReadConfig(offset, size, data); 2917839Snilay@cs.wisc.edu else 2927839Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 2937839Snilay@cs.wisc.edu} 2947839Snilay@cs.wisc.edu 2957839Snilay@cs.wisc.edu/** 2967839Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers 2977839Snilay@cs.wisc.edu */ 2987839Snilay@cs.wisc.eduvoid 2997007Snate@binkert.orgNSGigE::WriteConfig(int offset, int size, uint32_t data) 3007007Snate@binkert.org{ 3017007Snate@binkert.org if (offset < PCI_DEVICE_SPECIFIC) 3027007Snate@binkert.org PciDev::WriteConfig(offset, size, data); 3037007Snate@binkert.org else 3047839Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 3057839Snilay@cs.wisc.edu 3067839Snilay@cs.wisc.edu // Need to catch writes to BARs to update the PIO interface 3077839Snilay@cs.wisc.edu switch (offset) { 3087839Snilay@cs.wisc.edu // seems to work fine without all these PCI settings, but i 3097839Snilay@cs.wisc.edu // put in the IO to double check, an assertion will fail if we 3107839Snilay@cs.wisc.edu // need to properly implement it 3117839Snilay@cs.wisc.edu case PCI_COMMAND: 3127839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_IOSE) 3137839Snilay@cs.wisc.edu ioEnable = true; 3147839Snilay@cs.wisc.edu else 3157839Snilay@cs.wisc.edu ioEnable = false; 3167007Snate@binkert.org 3177007Snate@binkert.org#if 0 3187002Snate@binkert.org if (config.data[offset] & PCI_CMD_BME) { 3196657Snate@binkert.org bmEnabled = true; 3206657Snate@binkert.org } 3216657Snate@binkert.org else { 3227055Snate@binkert.org bmEnabled = false; 3236657Snate@binkert.org } 3246657Snate@binkert.org 3256657Snate@binkert.org if (config.data[offset] & PCI_CMD_MSE) { 3266863Sdrh5@cs.wisc.edu memEnable = true; 3277055Snate@binkert.org } 3287567SBrad.Beckmann@amd.com else { 3297567SBrad.Beckmann@amd.com memEnable = false; 3307567SBrad.Beckmann@amd.com } 3317567SBrad.Beckmann@amd.com#endif 3327567SBrad.Beckmann@amd.com break; 3337542SBrad.Beckmann@amd.com 3347542SBrad.Beckmann@amd.com case PCI0_BASE_ADDR0: 3356657Snate@binkert.org if (BARAddrs[0] != 0) { 3367007Snate@binkert.org if (pioInterface) 3376657Snate@binkert.org pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 3386657Snate@binkert.org 3396657Snate@binkert.org BARAddrs[0] &= EV5::PAddrUncachedMask; 3406657Snate@binkert.org } 3416657Snate@binkert.org break; 3426657Snate@binkert.org case PCI0_BASE_ADDR1: 3436657Snate@binkert.org if (BARAddrs[1] != 0) { 3446657Snate@binkert.org if (pioInterface) 3457839Snilay@cs.wisc.edu pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); 3467839Snilay@cs.wisc.edu 3477839Snilay@cs.wisc.edu BARAddrs[1] &= EV5::PAddrUncachedMask; 3487839Snilay@cs.wisc.edu } 3497839Snilay@cs.wisc.edu break; 3507839Snilay@cs.wisc.edu } 3518086SBrad.Beckmann@amd.com} 3528086SBrad.Beckmann@amd.com 3537839Snilay@cs.wisc.edu/** 3547839Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820 3557839Snilay@cs.wisc.edu * spec sheet 3567839Snilay@cs.wisc.edu */ 3577839Snilay@cs.wisc.eduFault 3587839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3597839Snilay@cs.wisc.edu{ 3607839Snilay@cs.wisc.edu assert(ioEnable); 3617839Snilay@cs.wisc.edu 3627839Snilay@cs.wisc.edu //The mask is to give you only the offset into the device register file 3636657Snate@binkert.org Addr daddr = req->paddr & 0xfff; 3646657Snate@binkert.org DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3656657Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 3666657Snate@binkert.org 3677839Snilay@cs.wisc.edu 3687839Snilay@cs.wisc.edu // there are some reserved registers, you can see ns_gige_reg.h and 3697839Snilay@cs.wisc.edu // the spec sheet for details 3707839Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 3717839Snilay@cs.wisc.edu panic("Accessing reserved register"); 3727839Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 3737839Snilay@cs.wisc.edu ReadConfig(daddr & 0xff, req->size, data); 3747839Snilay@cs.wisc.edu return No_Fault; 3757839Snilay@cs.wisc.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 3767839Snilay@cs.wisc.edu // don't implement all the MIB's. hopefully the kernel 3777839Snilay@cs.wisc.edu // doesn't actually DEPEND upon their values 3787839Snilay@cs.wisc.edu // MIB are just hardware stats keepers 3797839Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *) data; 3807839Snilay@cs.wisc.edu reg = 0; 3817839Snilay@cs.wisc.edu return No_Fault; 3827839Snilay@cs.wisc.edu } else if (daddr > 0x3FC) 3836657Snate@binkert.org panic("Something is messed up!\n"); 3846657Snate@binkert.org 3856657Snate@binkert.org switch (req->size) { 3866657Snate@binkert.org case sizeof(uint32_t): 3877007Snate@binkert.org { 3886657Snate@binkert.org uint32_t ® = *(uint32_t *)data; 3896657Snate@binkert.org 3906657Snate@binkert.org switch (daddr) { 3916657Snate@binkert.org case CR: 3926657Snate@binkert.org reg = regs.command; 3936657Snate@binkert.org //these are supposed to be cleared on a read 3946657Snate@binkert.org reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3956657Snate@binkert.org break; 3966657Snate@binkert.org 3976657Snate@binkert.org case CFG: 3987007Snate@binkert.org reg = regs.config; 3996657Snate@binkert.org break; 4006657Snate@binkert.org 4016657Snate@binkert.org case MEAR: 4026657Snate@binkert.org reg = regs.mear; 4036657Snate@binkert.org break; 4046999Snate@binkert.org 4056657Snate@binkert.org case PTSCR: 4066657Snate@binkert.org reg = regs.ptscr; 4076657Snate@binkert.org break; 4086657Snate@binkert.org 4097007Snate@binkert.org case ISR: 4106657Snate@binkert.org reg = regs.isr; 4116657Snate@binkert.org devIntrClear(ISR_ALL); 4126657Snate@binkert.org break; 4136657Snate@binkert.org 4146657Snate@binkert.org case IMR: 4157832Snate@binkert.org reg = regs.imr; 4167002Snate@binkert.org break; 4177002Snate@binkert.org 4187002Snate@binkert.org case IER: 4197056Snate@binkert.org reg = regs.ier; 4206657Snate@binkert.org break; 4218229Snate@binkert.org 4226657Snate@binkert.org case IHR: 4236657Snate@binkert.org reg = regs.ihr; 4247056Snate@binkert.org break; 4257056Snate@binkert.org 4266657Snate@binkert.org case TXDP: 4277002Snate@binkert.org reg = regs.txdp; 4287002Snate@binkert.org break; 4296657Snate@binkert.org 4306657Snate@binkert.org case TXDP_HI: 4316657Snate@binkert.org reg = regs.txdp_hi; 4326657Snate@binkert.org break; 4336657Snate@binkert.org 4346793SBrad.Beckmann@amd.com case TXCFG: 4356657Snate@binkert.org reg = regs.txcfg; 4366657Snate@binkert.org break; 4376657Snate@binkert.org 4386657Snate@binkert.org case GPIOR: 4396877Ssteve.reinhardt@amd.com reg = regs.gpior; 4406877Ssteve.reinhardt@amd.com break; 4416877Ssteve.reinhardt@amd.com 4426877Ssteve.reinhardt@amd.com case RXDP: 4436877Ssteve.reinhardt@amd.com reg = regs.rxdp; 4446877Ssteve.reinhardt@amd.com break; 4456657Snate@binkert.org 4467542SBrad.Beckmann@amd.com case RXDP_HI: 4476657Snate@binkert.org reg = regs.rxdp_hi; 4487007Snate@binkert.org break; 4496657Snate@binkert.org 4506657Snate@binkert.org case RXCFG: 4517007Snate@binkert.org reg = regs.rxcfg; 4526657Snate@binkert.org break; 4536877Ssteve.reinhardt@amd.com 4546877Ssteve.reinhardt@amd.com case PQCR: 4556657Snate@binkert.org reg = regs.pqcr; 4566877Ssteve.reinhardt@amd.com break; 4576877Ssteve.reinhardt@amd.com 4586877Ssteve.reinhardt@amd.com case WCSR: 4596877Ssteve.reinhardt@amd.com reg = regs.wcsr; 4606877Ssteve.reinhardt@amd.com break; 4616969SBrad.Beckmann@amd.com 4626657Snate@binkert.org case PCR: 4637567SBrad.Beckmann@amd.com reg = regs.pcr; 4647567SBrad.Beckmann@amd.com break; 4657567SBrad.Beckmann@amd.com 4667567SBrad.Beckmann@amd.com // see the spec sheet for how RFCR and RFDR work 4677567SBrad.Beckmann@amd.com // basically, you write to RFCR to tell the machine 4687567SBrad.Beckmann@amd.com // what you want to do next, then you act upon RFDR, 4696657Snate@binkert.org // and the device will be prepared b/c of what you 4706882SBrad.Beckmann@amd.com // wrote to RFCR 4716882SBrad.Beckmann@amd.com case RFCR: 4726882SBrad.Beckmann@amd.com reg = regs.rfcr; 4736882SBrad.Beckmann@amd.com break; 4746882SBrad.Beckmann@amd.com 4756882SBrad.Beckmann@amd.com case RFDR: 4766882SBrad.Beckmann@amd.com switch (regs.rfcr & RFCR_RFADDR) { 4778189SLisa.Hsu@amd.com case 0x000: 4788189SLisa.Hsu@amd.com reg = rom.perfectMatch[1]; 4796877Ssteve.reinhardt@amd.com reg = reg << 8; 4808189SLisa.Hsu@amd.com reg += rom.perfectMatch[0]; 4818189SLisa.Hsu@amd.com break; 4828189SLisa.Hsu@amd.com case 0x002: 4838189SLisa.Hsu@amd.com reg = rom.perfectMatch[3] << 8; 4846882SBrad.Beckmann@amd.com reg += rom.perfectMatch[2]; 4856882SBrad.Beckmann@amd.com break; 4866882SBrad.Beckmann@amd.com case 0x004: 4876882SBrad.Beckmann@amd.com reg = rom.perfectMatch[5] << 8; 4886882SBrad.Beckmann@amd.com reg += rom.perfectMatch[4]; 4896882SBrad.Beckmann@amd.com break; 4906882SBrad.Beckmann@amd.com default: 4916882SBrad.Beckmann@amd.com panic("reading RFDR for something other than PMATCH!\n"); 4926882SBrad.Beckmann@amd.com // didn't implement other RFDR functionality b/c 4936882SBrad.Beckmann@amd.com // driver didn't use it 4948189SLisa.Hsu@amd.com } 4956882SBrad.Beckmann@amd.com break; 4966882SBrad.Beckmann@amd.com 4976882SBrad.Beckmann@amd.com case SRR: 4988189SLisa.Hsu@amd.com reg = regs.srr; 4998189SLisa.Hsu@amd.com break; 5008189SLisa.Hsu@amd.com 5018189SLisa.Hsu@amd.com case MIBC: 5026888SBrad.Beckmann@amd.com reg = regs.mibc; 5036888SBrad.Beckmann@amd.com reg &= ~(MIBC_MIBS | MIBC_ACLR); 5046888SBrad.Beckmann@amd.com break; 5056888SBrad.Beckmann@amd.com 5066888SBrad.Beckmann@amd.com case VRCR: 5078189SLisa.Hsu@amd.com reg = regs.vrcr; 5086888SBrad.Beckmann@amd.com break; 5096888SBrad.Beckmann@amd.com 5106657Snate@binkert.org case VTCR: 5116888SBrad.Beckmann@amd.com reg = regs.vtcr; 5126888SBrad.Beckmann@amd.com break; 5136888SBrad.Beckmann@amd.com 5146888SBrad.Beckmann@amd.com case VDR: 5156657Snate@binkert.org reg = regs.vdr; 5166657Snate@binkert.org break; 5176657Snate@binkert.org 5186657Snate@binkert.org case CCSR: 5196657Snate@binkert.org reg = regs.ccsr; 5206657Snate@binkert.org break; 5216657Snate@binkert.org 5226657Snate@binkert.org case TBICR: 5236657Snate@binkert.org reg = regs.tbicr; 5247007Snate@binkert.org break; 5257007Snate@binkert.org 5266657Snate@binkert.org case TBISR: 5277007Snate@binkert.org reg = regs.tbisr; 5287007Snate@binkert.org break; 5297007Snate@binkert.org 5306657Snate@binkert.org case TANAR: 5316657Snate@binkert.org reg = regs.tanar; 5326657Snate@binkert.org break; 5337007Snate@binkert.org 5347542SBrad.Beckmann@amd.com case TANLPAR: 5357542SBrad.Beckmann@amd.com reg = regs.tanlpar; 5367007Snate@binkert.org break; 5376657Snate@binkert.org 5386657Snate@binkert.org case TANER: 5396657Snate@binkert.org reg = regs.taner; 5406657Snate@binkert.org break; 5416657Snate@binkert.org 5426657Snate@binkert.org case TESR: 5436657Snate@binkert.org reg = regs.tesr; 5446657Snate@binkert.org break; 5456657Snate@binkert.org 5466657Snate@binkert.org default: 5476657Snate@binkert.org panic("reading unimplemented register: addr=%#x", daddr); 5486657Snate@binkert.org } 5496657Snate@binkert.org 5506657Snate@binkert.org DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 5516657Snate@binkert.org daddr, reg, reg); 5526657Snate@binkert.org } 5536657Snate@binkert.org break; 5546657Snate@binkert.org 5556657Snate@binkert.org default: 5566657Snate@binkert.org panic("accessing register with invalid size: addr=%#x, size=%d", 5576657Snate@binkert.org daddr, req->size); 5586657Snate@binkert.org } 5596657Snate@binkert.org 5606657Snate@binkert.org return No_Fault; 5616657Snate@binkert.org} 5626657Snate@binkert.org 5636657Snate@binkert.orgFault 5646657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data) 5657007Snate@binkert.org{ 5666657Snate@binkert.org assert(ioEnable); 5676657Snate@binkert.org 5686657Snate@binkert.org Addr daddr = req->paddr & 0xfff; 5696657Snate@binkert.org DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5707007Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 5716657Snate@binkert.org 5727007Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 5737007Snate@binkert.org panic("Accessing reserved register"); 5746657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 5756657Snate@binkert.org WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5766657Snate@binkert.org return No_Fault; 5776657Snate@binkert.org } else if (daddr > 0x3FC) 5786657Snate@binkert.org panic("Something is messed up!\n"); 5796657Snate@binkert.org 5806657Snate@binkert.org if (req->size == sizeof(uint32_t)) { 5816657Snate@binkert.org uint32_t reg = *(uint32_t *)data; 5826657Snate@binkert.org DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5836657Snate@binkert.org 5846657Snate@binkert.org switch (daddr) { 5856657Snate@binkert.org case CR: 5866657Snate@binkert.org regs.command = reg; 5876657Snate@binkert.org if (reg & CR_TXD) { 5886657Snate@binkert.org txEnable = false; 5897566SBrad.Beckmann@amd.com } else if (reg & CR_TXE) { 5906657Snate@binkert.org txEnable = true; 5916657Snate@binkert.org 5926657Snate@binkert.org // the kernel is enabling the transmit machine 5936657Snate@binkert.org if (txState == txIdle) 5946657Snate@binkert.org txKick(); 5956657Snate@binkert.org } 5966657Snate@binkert.org 5976657Snate@binkert.org if (reg & CR_RXD) { 5987007Snate@binkert.org rxEnable = false; 5997007Snate@binkert.org } else if (reg & CR_RXE) { 6007007Snate@binkert.org rxEnable = true; 6016657Snate@binkert.org 6026657Snate@binkert.org if (rxState == rxIdle) 6036657Snate@binkert.org rxKick(); 6046657Snate@binkert.org } 6056657Snate@binkert.org 6066657Snate@binkert.org if (reg & CR_TXR) 6076657Snate@binkert.org txReset(); 6086657Snate@binkert.org 6096657Snate@binkert.org if (reg & CR_RXR) 6106657Snate@binkert.org rxReset(); 6116657Snate@binkert.org 6126657Snate@binkert.org if (reg & CR_SWI) 6138187SLisa.Hsu@amd.com devIntrPost(ISR_SWI); 6146657Snate@binkert.org 6156657Snate@binkert.org if (reg & CR_RST) { 6166657Snate@binkert.org txReset(); 6176657Snate@binkert.org rxReset(); 6186657Snate@binkert.org 6196657Snate@binkert.org regsReset(); 6206657Snate@binkert.org } 6216657Snate@binkert.org break; 6226657Snate@binkert.org 6237454Snate@binkert.org case CFG: 6246657Snate@binkert.org if (reg & CFG_LNKSTS || 6256657Snate@binkert.org reg & CFG_SPDSTS || 6266657Snate@binkert.org reg & CFG_DUPSTS || 6276657Snate@binkert.org reg & CFG_RESERVED || 6287007Snate@binkert.org reg & CFG_T64ADDR || 6297056Snate@binkert.org reg & CFG_PCI64_DET) 6307007Snate@binkert.org panic("writing to read-only or reserved CFG bits!\n"); 6317007Snate@binkert.org 6326657Snate@binkert.org regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | 6337566SBrad.Beckmann@amd.com CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET); 6347566SBrad.Beckmann@amd.com 6357566SBrad.Beckmann@amd.com// all these #if 0's are because i don't THINK the kernel needs to 6367566SBrad.Beckmann@amd.com// have these implemented. if there is a problem relating to one of 6377566SBrad.Beckmann@amd.com// these, you may need to add functionality in. 6387566SBrad.Beckmann@amd.com#if 0 6397566SBrad.Beckmann@amd.com if (reg & CFG_TBI_EN) ; 6406657Snate@binkert.org if (reg & CFG_MODE_1000) ; 6417672Snate@binkert.org#endif 6426657Snate@binkert.org 6436657Snate@binkert.org if (reg & CFG_AUTO_1000) 6446657Snate@binkert.org panic("CFG_AUTO_1000 not implemented!\n"); 6456657Snate@binkert.org 6467672Snate@binkert.org#if 0 6476657Snate@binkert.org if (reg & CFG_PINT_DUPSTS || 6487056Snate@binkert.org reg & CFG_PINT_LNKSTS || 6496657Snate@binkert.org reg & CFG_PINT_SPDSTS) 6506657Snate@binkert.org ; 6517672Snate@binkert.org 6526657Snate@binkert.org if (reg & CFG_TMRTEST) ; 6536657Snate@binkert.org if (reg & CFG_MRM_DIS) ; 6546657Snate@binkert.org if (reg & CFG_MWI_DIS) ; 6556657Snate@binkert.org 6566657Snate@binkert.org if (reg & CFG_T64ADDR) 6576657Snate@binkert.org panic("CFG_T64ADDR is read only register!\n"); 6586657Snate@binkert.org 6596657Snate@binkert.org if (reg & CFG_PCI64_DET) 6606657Snate@binkert.org panic("CFG_PCI64_DET is read only register!\n"); 6616657Snate@binkert.org 6626657Snate@binkert.org if (reg & CFG_DATA64_EN) ; 6637542SBrad.Beckmann@amd.com if (reg & CFG_M64ADDR) ; 6646657Snate@binkert.org if (reg & CFG_PHY_RST) ; 6656657Snate@binkert.org if (reg & CFG_PHY_DIS) ; 6666657Snate@binkert.org#endif 6676657Snate@binkert.org 6686657Snate@binkert.org if (reg & CFG_EXTSTS_EN) 6696657Snate@binkert.org extstsEnable = true; 6706657Snate@binkert.org else 6716657Snate@binkert.org extstsEnable = false; 6726657Snate@binkert.org 6736657Snate@binkert.org#if 0 6746657Snate@binkert.org if (reg & CFG_REQALG) ; 6756657Snate@binkert.org if (reg & CFG_SB) ; 6766657Snate@binkert.org if (reg & CFG_POW) ; 6776657Snate@binkert.org if (reg & CFG_EXD) ; 6786657Snate@binkert.org if (reg & CFG_PESEL) ; 6797007Snate@binkert.org if (reg & CFG_BROM_DIS) ; 6807007Snate@binkert.org if (reg & CFG_EXT_125) ; 6817007Snate@binkert.org if (reg & CFG_BEM) ; 6826657Snate@binkert.org#endif 6836657Snate@binkert.org break; 6846657Snate@binkert.org 6857007Snate@binkert.org case MEAR: 6867007Snate@binkert.org regs.mear = reg; 6877007Snate@binkert.org // since phy is completely faked, MEAR_MD* don't matter 6886657Snate@binkert.org // and since the driver never uses MEAR_EE*, they don't 6896657Snate@binkert.org // matter 6906657Snate@binkert.org#if 0 6917007Snate@binkert.org if (reg & MEAR_EEDI) ; 6927007Snate@binkert.org if (reg & MEAR_EEDO) ; // this one is read only 6937007Snate@binkert.org if (reg & MEAR_EECLK) ; 6946657Snate@binkert.org if (reg & MEAR_EESEL) ; 6956657Snate@binkert.org if (reg & MEAR_MDIO) ; 6966657Snate@binkert.org if (reg & MEAR_MDDIR) ; 6977007Snate@binkert.org if (reg & MEAR_MDC) ; 6987007Snate@binkert.org#endif 6997007Snate@binkert.org break; 7006657Snate@binkert.org 7016657Snate@binkert.org case PTSCR: 7026657Snate@binkert.org regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 7037007Snate@binkert.org // these control BISTs for various parts of chip - we 7047007Snate@binkert.org // don't care or do just fake that the BIST is done 7057007Snate@binkert.org if (reg & PTSCR_RBIST_EN) 7066657Snate@binkert.org regs.ptscr |= PTSCR_RBIST_DONE; 7076657Snate@binkert.org if (reg & PTSCR_EEBIST_EN) 7087007Snate@binkert.org regs.ptscr &= ~PTSCR_EEBIST_EN; 7097007Snate@binkert.org if (reg & PTSCR_EELOAD_EN) 7107007Snate@binkert.org regs.ptscr &= ~PTSCR_EELOAD_EN; 7117007Snate@binkert.org break; 7126657Snate@binkert.org 7136657Snate@binkert.org case ISR: /* writing to the ISR has no effect */ 7146657Snate@binkert.org panic("ISR is a read only register!\n"); 7157007Snate@binkert.org 7167567SBrad.Beckmann@amd.com case IMR: 7177567SBrad.Beckmann@amd.com regs.imr = reg; 7187567SBrad.Beckmann@amd.com devIntrChangeMask(); 7197567SBrad.Beckmann@amd.com break; 7207567SBrad.Beckmann@amd.com 7217567SBrad.Beckmann@amd.com case IER: 7227567SBrad.Beckmann@amd.com regs.ier = reg; 7237567SBrad.Beckmann@amd.com break; 7247567SBrad.Beckmann@amd.com 7257567SBrad.Beckmann@amd.com case IHR: 7267567SBrad.Beckmann@amd.com regs.ihr = reg; 7277567SBrad.Beckmann@amd.com /* not going to implement real interrupt holdoff */ 7287567SBrad.Beckmann@amd.com break; 7298155Snilay@cs.wisc.edu 7308155Snilay@cs.wisc.edu case TXDP: 7318155Snilay@cs.wisc.edu regs.txdp = (reg & 0xFFFFFFFC); 7328155Snilay@cs.wisc.edu assert(txState == txIdle); 7338155Snilay@cs.wisc.edu CTDD = false; 7348155Snilay@cs.wisc.edu break; 7358155Snilay@cs.wisc.edu 7368155Snilay@cs.wisc.edu case TXDP_HI: 7378155Snilay@cs.wisc.edu regs.txdp_hi = reg; 7388155Snilay@cs.wisc.edu break; 7398155Snilay@cs.wisc.edu 7407567SBrad.Beckmann@amd.com case TXCFG: 7418155Snilay@cs.wisc.edu regs.txcfg = reg; 7428155Snilay@cs.wisc.edu#if 0 7437567SBrad.Beckmann@amd.com if (reg & TXCFG_CSI) ; 7447567SBrad.Beckmann@amd.com if (reg & TXCFG_HBI) ; 7457567SBrad.Beckmann@amd.com if (reg & TXCFG_MLB) ; 7467567SBrad.Beckmann@amd.com if (reg & TXCFG_ATP) ; 7477922SBrad.Beckmann@amd.com if (reg & TXCFG_ECRETRY) { 7487922SBrad.Beckmann@amd.com /* 7497922SBrad.Beckmann@amd.com * this could easily be implemented, but considering 7507922SBrad.Beckmann@amd.com * the network is just a fake pipe, wouldn't make 7517922SBrad.Beckmann@amd.com * sense to do this 7527922SBrad.Beckmann@amd.com */ 7537922SBrad.Beckmann@amd.com } 7547922SBrad.Beckmann@amd.com 7558154Snilay@cs.wisc.edu if (reg & TXCFG_BRST_DIS) ; 7568154Snilay@cs.wisc.edu#endif 7578154Snilay@cs.wisc.edu 7588154Snilay@cs.wisc.edu#if 0 7598154Snilay@cs.wisc.edu /* we handle our own DMA, ignore the kernel's exhortations */ 7608154Snilay@cs.wisc.edu if (reg & TXCFG_MXDMA) ; 7618154Snilay@cs.wisc.edu#endif 7628154Snilay@cs.wisc.edu 7638154Snilay@cs.wisc.edu // also, we currently don't care about fill/drain 7648154Snilay@cs.wisc.edu // thresholds though this may change in the future with 7658154Snilay@cs.wisc.edu // more realistic networks or a driver which changes it 7668154Snilay@cs.wisc.edu // according to feedback 7678154Snilay@cs.wisc.edu 7688154Snilay@cs.wisc.edu break; 7698154Snilay@cs.wisc.edu 7708154Snilay@cs.wisc.edu case GPIOR: 7718154Snilay@cs.wisc.edu regs.gpior = reg; 7728154Snilay@cs.wisc.edu /* these just control general purpose i/o pins, don't matter */ 7738154Snilay@cs.wisc.edu break; 7748154Snilay@cs.wisc.edu 7758154Snilay@cs.wisc.edu case RXDP: 7767922SBrad.Beckmann@amd.com regs.rxdp = reg; 7777922SBrad.Beckmann@amd.com CRDD = false; 7787922SBrad.Beckmann@amd.com break; 7797922SBrad.Beckmann@amd.com 7807007Snate@binkert.org case RXDP_HI: 7817007Snate@binkert.org regs.rxdp_hi = reg; 7826863Sdrh5@cs.wisc.edu break; 7836863Sdrh5@cs.wisc.edu 7846863Sdrh5@cs.wisc.edu case RXCFG: 7857007Snate@binkert.org regs.rxcfg = reg; 7867007Snate@binkert.org#if 0 7877007Snate@binkert.org if (reg & RXCFG_AEP) ; 7887007Snate@binkert.org if (reg & RXCFG_ARP) ; 7896863Sdrh5@cs.wisc.edu if (reg & RXCFG_STRIPCRC) ; 7906863Sdrh5@cs.wisc.edu if (reg & RXCFG_RX_RD) ; 7916863Sdrh5@cs.wisc.edu if (reg & RXCFG_ALP) ; 7926863Sdrh5@cs.wisc.edu if (reg & RXCFG_AIRL) ; 7936863Sdrh5@cs.wisc.edu 7946863Sdrh5@cs.wisc.edu /* we handle our own DMA, ignore what kernel says about it */ 7957007Snate@binkert.org if (reg & RXCFG_MXDMA) ; 7967007Snate@binkert.org 7977007Snate@binkert.org //also, we currently don't care about fill/drain thresholds 7987007Snate@binkert.org //though this may change in the future with more realistic 7997007Snate@binkert.org //networks or a driver which changes it according to feedback 8006657Snate@binkert.org if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 8017007Snate@binkert.org#endif 8027007Snate@binkert.org break; 8037007Snate@binkert.org 8046657Snate@binkert.org case PQCR: 8056657Snate@binkert.org /* there is no priority queueing used in the linux 2.6 driver */ 8067007Snate@binkert.org regs.pqcr = reg; 8077007Snate@binkert.org break; 8087007Snate@binkert.org 8096657Snate@binkert.org case WCSR: 8106657Snate@binkert.org /* not going to implement wake on LAN */ 8117007Snate@binkert.org regs.wcsr = reg; 8127007Snate@binkert.org break; 8137007Snate@binkert.org 8146902SBrad.Beckmann@amd.com case PCR: 8156902SBrad.Beckmann@amd.com /* not going to implement pause control */ 8166902SBrad.Beckmann@amd.com regs.pcr = reg; 8176902SBrad.Beckmann@amd.com break; 8186902SBrad.Beckmann@amd.com 8196902SBrad.Beckmann@amd.com case RFCR: 8206902SBrad.Beckmann@amd.com regs.rfcr = reg; 8217025SBrad.Beckmann@amd.com 8226902SBrad.Beckmann@amd.com rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8236902SBrad.Beckmann@amd.com acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8246902SBrad.Beckmann@amd.com acceptMulticast = (reg & RFCR_AAM) ? true : false; 8256902SBrad.Beckmann@amd.com acceptUnicast = (reg & RFCR_AAU) ? true : false; 8266902SBrad.Beckmann@amd.com acceptPerfect = (reg & RFCR_APM) ? true : false; 8277542SBrad.Beckmann@amd.com acceptArp = (reg & RFCR_AARP) ? true : false; 8287542SBrad.Beckmann@amd.com 8297542SBrad.Beckmann@amd.com#if 0 8306902SBrad.Beckmann@amd.com if (reg & RFCR_APAT) 8316902SBrad.Beckmann@amd.com panic("RFCR_APAT not implemented!\n"); 8326902SBrad.Beckmann@amd.com#endif 8336902SBrad.Beckmann@amd.com 8346902SBrad.Beckmann@amd.com if (reg & RFCR_MHEN || reg & RFCR_UHEN) 8356902SBrad.Beckmann@amd.com panic("hash filtering not implemented!\n"); 8366902SBrad.Beckmann@amd.com 8376902SBrad.Beckmann@amd.com if (reg & RFCR_ULM) 8386902SBrad.Beckmann@amd.com panic("RFCR_ULM not implemented!\n"); 8396902SBrad.Beckmann@amd.com 8406902SBrad.Beckmann@amd.com break; 8416902SBrad.Beckmann@amd.com 8426902SBrad.Beckmann@amd.com case RFDR: 8436902SBrad.Beckmann@amd.com panic("the driver never writes to RFDR, something is wrong!\n"); 8446902SBrad.Beckmann@amd.com 8457542SBrad.Beckmann@amd.com case BRAR: 8466902SBrad.Beckmann@amd.com panic("the driver never uses BRAR, something is wrong!\n"); 8477839Snilay@cs.wisc.edu 8487839Snilay@cs.wisc.edu case BRDR: 8497839Snilay@cs.wisc.edu panic("the driver never uses BRDR, something is wrong!\n"); 8507839Snilay@cs.wisc.edu 8517839Snilay@cs.wisc.edu case SRR: 8527839Snilay@cs.wisc.edu panic("SRR is read only register!\n"); 8537839Snilay@cs.wisc.edu 8547839Snilay@cs.wisc.edu case MIBC: 8557839Snilay@cs.wisc.edu panic("the driver never uses MIBC, something is wrong!\n"); 8567839Snilay@cs.wisc.edu 8577839Snilay@cs.wisc.edu case VRCR: 8587839Snilay@cs.wisc.edu regs.vrcr = reg; 8597839Snilay@cs.wisc.edu break; 8607839Snilay@cs.wisc.edu 8617839Snilay@cs.wisc.edu case VTCR: 8627839Snilay@cs.wisc.edu regs.vtcr = reg; 8637839Snilay@cs.wisc.edu break; 8648086SBrad.Beckmann@amd.com 8658086SBrad.Beckmann@amd.com case VDR: 8668086SBrad.Beckmann@amd.com panic("the driver never uses VDR, something is wrong!\n"); 8678086SBrad.Beckmann@amd.com break; 8688086SBrad.Beckmann@amd.com 8698086SBrad.Beckmann@amd.com case CCSR: 8708086SBrad.Beckmann@amd.com /* not going to implement clockrun stuff */ 8718086SBrad.Beckmann@amd.com regs.ccsr = reg; 8728086SBrad.Beckmann@amd.com break; 8737839Snilay@cs.wisc.edu 8747839Snilay@cs.wisc.edu case TBICR: 8757839Snilay@cs.wisc.edu regs.tbicr = reg; 8767839Snilay@cs.wisc.edu if (reg & TBICR_MR_LOOPBACK) 8777839Snilay@cs.wisc.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8787839Snilay@cs.wisc.edu 8797839Snilay@cs.wisc.edu if (reg & TBICR_MR_AN_ENABLE) { 8807839Snilay@cs.wisc.edu regs.tanlpar = regs.tanar; 8817839Snilay@cs.wisc.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8827839Snilay@cs.wisc.edu } 8837839Snilay@cs.wisc.edu 8847839Snilay@cs.wisc.edu#if 0 8857839Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 8867839Snilay@cs.wisc.edu#endif 8877839Snilay@cs.wisc.edu 8887839Snilay@cs.wisc.edu break; 8897839Snilay@cs.wisc.edu 8907839Snilay@cs.wisc.edu case TBISR: 8917839Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 8927839Snilay@cs.wisc.edu 8936902SBrad.Beckmann@amd.com case TANAR: 8946657Snate@binkert.org regs.tanar = reg; 8956657Snate@binkert.org if (reg & TANAR_PS2) 8967839Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8977839Snilay@cs.wisc.edu 8987839Snilay@cs.wisc.edu if (reg & TANAR_PS1) 8997839Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 9006657Snate@binkert.org break; 9017839Snilay@cs.wisc.edu 9027839Snilay@cs.wisc.edu case TANLPAR: 9037839Snilay@cs.wisc.edu panic("this should only be written to by the fake phy!\n"); 9047839Snilay@cs.wisc.edu 9057839Snilay@cs.wisc.edu case TANER: 9068055Sksewell@umich.edu panic("TANER is read only register!\n"); 9077839Snilay@cs.wisc.edu 9087839Snilay@cs.wisc.edu case TESR: 9096657Snate@binkert.org regs.tesr = reg; 9107839Snilay@cs.wisc.edu break; 9117839Snilay@cs.wisc.edu 9127839Snilay@cs.wisc.edu default: 9137839Snilay@cs.wisc.edu panic("invalid register access daddr=%#x", daddr); 9147839Snilay@cs.wisc.edu } 9157839Snilay@cs.wisc.edu } else { 9167839Snilay@cs.wisc.edu panic("Invalid Request Size"); 9177839Snilay@cs.wisc.edu } 9187839Snilay@cs.wisc.edu 9197839Snilay@cs.wisc.edu return No_Fault; 9207839Snilay@cs.wisc.edu} 9218055Sksewell@umich.edu 9227839Snilay@cs.wisc.eduvoid 9237839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts) 9247839Snilay@cs.wisc.edu{ 9257839Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 9267839Snilay@cs.wisc.edu panic("Cannot set a reserved interrupt"); 9277839Snilay@cs.wisc.edu 9287839Snilay@cs.wisc.edu if (interrupts & ISR_NOIMPL) 9297839Snilay@cs.wisc.edu warn("interrupt not implemented %#x\n", interrupts); 9307839Snilay@cs.wisc.edu 9317839Snilay@cs.wisc.edu interrupts &= ~ISR_NOIMPL; 9327839Snilay@cs.wisc.edu regs.isr |= interrupts; 9337839Snilay@cs.wisc.edu 9347839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 9357839Snilay@cs.wisc.edu "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9368055Sksewell@umich.edu interrupts, regs.isr, regs.imr); 9377839Snilay@cs.wisc.edu 9387839Snilay@cs.wisc.edu if ((regs.isr & regs.imr)) { 9397839Snilay@cs.wisc.edu Tick when = curTick; 9407839Snilay@cs.wisc.edu if (!(regs.isr & regs.imr & ISR_NODELAY)) 9417839Snilay@cs.wisc.edu when += intrDelay; 9427839Snilay@cs.wisc.edu cpuIntrPost(when); 9437839Snilay@cs.wisc.edu } 9447839Snilay@cs.wisc.edu} 9457839Snilay@cs.wisc.edu 9467839Snilay@cs.wisc.eduvoid 9476657Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts) 9487007Snate@binkert.org{ 9497007Snate@binkert.org if (interrupts & ISR_RESERVE) 9506657Snate@binkert.org panic("Cannot clear a reserved interrupt"); 9518055Sksewell@umich.edu 9526657Snate@binkert.org interrupts &= ~ISR_NOIMPL; 9536657Snate@binkert.org regs.isr &= ~interrupts; 9546657Snate@binkert.org 9556657Snate@binkert.org DPRINTF(EthernetIntr, 9566657Snate@binkert.org "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 9576657Snate@binkert.org interrupts, regs.isr, regs.imr); 9586657Snate@binkert.org 9596657Snate@binkert.org if (!(regs.isr & regs.imr)) 9606657Snate@binkert.org cpuIntrClear(); 9616999Snate@binkert.org} 9626657Snate@binkert.org 9636657Snate@binkert.orgvoid 9646657Snate@binkert.orgNSGigE::devIntrChangeMask() 9656657Snate@binkert.org{ 9666657Snate@binkert.org DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9676657Snate@binkert.org regs.isr, regs.imr, regs.isr & regs.imr); 9687832Snate@binkert.org 9697832Snate@binkert.org if (regs.isr & regs.imr) 9707007Snate@binkert.org cpuIntrPost(curTick); 9718229Snate@binkert.org else 9728229Snate@binkert.org cpuIntrClear(); 9738229Snate@binkert.org} 9748229Snate@binkert.org 9756657Snate@binkert.orgvoid 9766657Snate@binkert.orgNSGigE::cpuIntrPost(Tick when) 9776657Snate@binkert.org{ 9786657Snate@binkert.org // If the interrupt you want to post is later than an interrupt 9797055Snate@binkert.org // already scheduled, just let it post in the coming one and don't 9807055Snate@binkert.org // schedule another. 9817007Snate@binkert.org // HOWEVER, must be sure that the scheduled intrTick is in the 9827007Snate@binkert.org // future (this was formerly the source of a bug) 9836657Snate@binkert.org /** 9846657Snate@binkert.org * @todo this warning should be removed and the intrTick code should 9856657Snate@binkert.org * be fixed. 9866657Snate@binkert.org */ 9876657Snate@binkert.org assert(when >= curTick); 9886657Snate@binkert.org assert(intrTick >= curTick || intrTick == 0); 9897007Snate@binkert.org if (when > intrTick && intrTick != 0) { 9907007Snate@binkert.org DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9917007Snate@binkert.org intrTick); 9927007Snate@binkert.org return; 9937007Snate@binkert.org } 9946657Snate@binkert.org 9956657Snate@binkert.org intrTick = when; 9966657Snate@binkert.org if (intrTick < curTick) { 9976657Snate@binkert.org debug_break(); 9986657Snate@binkert.org intrTick = curTick; 9996657Snate@binkert.org } 10006657Snate@binkert.org 10016657Snate@binkert.org DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 10026657Snate@binkert.org intrTick); 10036657Snate@binkert.org 10046657Snate@binkert.org if (intrEvent) 10056657Snate@binkert.org intrEvent->squash(); 10067567SBrad.Beckmann@amd.com intrEvent = new IntrEvent(this, true); 10077567SBrad.Beckmann@amd.com intrEvent->schedule(intrTick); 10087567SBrad.Beckmann@amd.com} 10097567SBrad.Beckmann@amd.com 10106657Snate@binkert.orgvoid 10116657Snate@binkert.orgNSGigE::cpuInterrupt() 10126657Snate@binkert.org{ 10136657Snate@binkert.org assert(intrTick == curTick); 10146657Snate@binkert.org 10156657Snate@binkert.org // Whether or not there's a pending interrupt, we don't care about 10166657Snate@binkert.org // it anymore 10176657Snate@binkert.org intrEvent = 0; 10186657Snate@binkert.org intrTick = 0; 10196657Snate@binkert.org 10207007Snate@binkert.org // Don't send an interrupt if there's already one 10216657Snate@binkert.org if (cpuPendingIntr) { 10226657Snate@binkert.org DPRINTF(EthernetIntr, 10236657Snate@binkert.org "would send an interrupt now, but there's already pending\n"); 10246657Snate@binkert.org } else { 10256657Snate@binkert.org // Send interrupt 10266657Snate@binkert.org cpuPendingIntr = true; 10276657Snate@binkert.org 10286657Snate@binkert.org DPRINTF(EthernetIntr, "posting interrupt\n"); 10296999Snate@binkert.org intrPost(); 10306657Snate@binkert.org } 10316657Snate@binkert.org} 10326657Snate@binkert.org 10336657Snate@binkert.orgvoid 10346657Snate@binkert.orgNSGigE::cpuIntrClear() 10356657Snate@binkert.org{ 10367832Snate@binkert.org if (!cpuPendingIntr) 10377832Snate@binkert.org return; 10387805Snilay@cs.wisc.edu 10397832Snate@binkert.org if (intrEvent) { 10408229Snate@binkert.org intrEvent->squash(); 10418229Snate@binkert.org intrEvent = 0; 10428229Snate@binkert.org } 10438229Snate@binkert.org 10446657Snate@binkert.org intrTick = 0; 10456657Snate@binkert.org 10466657Snate@binkert.org cpuPendingIntr = false; 10476657Snate@binkert.org 10486657Snate@binkert.org DPRINTF(EthernetIntr, "clearing interrupt\n"); 10496657Snate@binkert.org intrClear(); 10506657Snate@binkert.org} 10516657Snate@binkert.org 10527007Snate@binkert.orgbool 10537007Snate@binkert.orgNSGigE::cpuIntrPending() const 10547839Snilay@cs.wisc.edu{ return cpuPendingIntr; } 10557839Snilay@cs.wisc.edu 10567839Snilay@cs.wisc.eduvoid 10577839Snilay@cs.wisc.eduNSGigE::txReset() 10587839Snilay@cs.wisc.edu{ 10597839Snilay@cs.wisc.edu 10607839Snilay@cs.wisc.edu DPRINTF(Ethernet, "transmit reset\n"); 10617839Snilay@cs.wisc.edu 10627839Snilay@cs.wisc.edu CTDD = false; 10637839Snilay@cs.wisc.edu txEnable = false;; 10647007Snate@binkert.org txFragPtr = 0; 10656657Snate@binkert.org assert(txDescCnt == 0); 10667839Snilay@cs.wisc.edu txFifo.clear(); 10677839Snilay@cs.wisc.edu txState = txIdle; 10687839Snilay@cs.wisc.edu assert(txDmaState == dmaIdle); 10697839Snilay@cs.wisc.edu} 10707839Snilay@cs.wisc.edu 10717839Snilay@cs.wisc.eduvoid 10727839Snilay@cs.wisc.eduNSGigE::rxReset() 10737839Snilay@cs.wisc.edu{ 10747839Snilay@cs.wisc.edu DPRINTF(Ethernet, "receive reset\n"); 10757839Snilay@cs.wisc.edu 10767839Snilay@cs.wisc.edu CRDD = false; 10776657Snate@binkert.org assert(rxPktBytes == 0); 10786657Snate@binkert.org rxEnable = false; 10797780Snilay@cs.wisc.edu rxFragPtr = 0; 10807780Snilay@cs.wisc.edu assert(rxDescCnt == 0); 10817780Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle); 10827780Snilay@cs.wisc.edu rxFifo.clear(); 10837780Snilay@cs.wisc.edu rxState = rxIdle; 10847780Snilay@cs.wisc.edu} 10856657Snate@binkert.org 10867007Snate@binkert.orgvoid 10877839Snilay@cs.wisc.eduNSGigE::regsReset() 10887839Snilay@cs.wisc.edu{ 10897839Snilay@cs.wisc.edu memset(®s, 0, sizeof(regs)); 10907839Snilay@cs.wisc.edu regs.config = CFG_LNKSTS; 10917839Snilay@cs.wisc.edu regs.mear = MEAR_MDDIR | MEAR_EEDO; 10927839Snilay@cs.wisc.edu regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 10937839Snilay@cs.wisc.edu // fill threshold to 32 bytes 10947839Snilay@cs.wisc.edu regs.rxcfg = 0x4; // set drain threshold to 16 bytes 10957839Snilay@cs.wisc.edu regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 10966657Snate@binkert.org regs.mibc = MIBC_FRZ; 10977839Snilay@cs.wisc.edu regs.vdr = 0x81; // set the vlan tag type to 802.1q 10986657Snate@binkert.org regs.tesr = 0xc000; // TBI capable of both full and half duplex 10997780Snilay@cs.wisc.edu 11007780Snilay@cs.wisc.edu extstsEnable = false; 11017542SBrad.Beckmann@amd.com acceptBroadcast = false; 11027832Snate@binkert.org acceptMulticast = false; 11037832Snate@binkert.org acceptUnicast = false; 11047832Snate@binkert.org acceptPerfect = false; 11057832Snate@binkert.org acceptArp = false; 11067832Snate@binkert.org} 11077832Snate@binkert.org 11086657Snate@binkert.orgvoid 11097832Snate@binkert.orgNSGigE::rxDmaReadCopy() 11107839Snilay@cs.wisc.edu{ 11117839Snilay@cs.wisc.edu assert(rxDmaState == dmaReading); 11127839Snilay@cs.wisc.edu 11138086SBrad.Beckmann@amd.com physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); 11147839Snilay@cs.wisc.edu rxDmaState = dmaIdle; 11157839Snilay@cs.wisc.edu 11167839Snilay@cs.wisc.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 11177839Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 11188086SBrad.Beckmann@amd.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11197839Snilay@cs.wisc.edu} 11207839Snilay@cs.wisc.edu 11217839Snilay@cs.wisc.edubool 11227839Snilay@cs.wisc.eduNSGigE::doRxDmaRead() 11236657Snate@binkert.org{ 11247832Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 11257832Snate@binkert.org rxDmaState = dmaReading; 11267832Snate@binkert.org 11277832Snate@binkert.org if (dmaInterface && !rxDmaFree) { 11287832Snate@binkert.org if (dmaInterface->busy()) 11297832Snate@binkert.org rxDmaState = dmaReadWaiting; 11306657Snate@binkert.org else 11317780Snilay@cs.wisc.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 11327832Snate@binkert.org &rxDmaReadEvent, true); 11337832Snate@binkert.org return true; 11347832Snate@binkert.org } 11357832Snate@binkert.org 11367832Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0) { 11377832Snate@binkert.org rxDmaReadCopy(); 11386657Snate@binkert.org return false; 11396657Snate@binkert.org } 11406657Snate@binkert.org 11416657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 11426657Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 11437007Snate@binkert.org rxDmaReadEvent.schedule(start); 11447007Snate@binkert.org return true; 11457007Snate@binkert.org} 11467007Snate@binkert.org 11477839Snilay@cs.wisc.eduvoid 11487839Snilay@cs.wisc.eduNSGigE::rxDmaReadDone() 11497839Snilay@cs.wisc.edu{ 11507839Snilay@cs.wisc.edu assert(rxDmaState == dmaReading); 11517839Snilay@cs.wisc.edu rxDmaReadCopy(); 11527839Snilay@cs.wisc.edu 11537839Snilay@cs.wisc.edu // If the transmit state machine has a pending DMA, let it go first 11547839Snilay@cs.wisc.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11557839Snilay@cs.wisc.edu txKick(); 11567839Snilay@cs.wisc.edu 11577839Snilay@cs.wisc.edu rxKick(); 11587007Snate@binkert.org} 11596657Snate@binkert.org 11606657Snate@binkert.orgvoid 11616657Snate@binkert.orgNSGigE::rxDmaWriteCopy() 11626657Snate@binkert.org{ 11636657Snate@binkert.org assert(rxDmaState == dmaWriting); 11646657Snate@binkert.org 11656657Snate@binkert.org physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 11666657Snate@binkert.org rxDmaState = dmaIdle; 11676657Snate@binkert.org 11686657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11696657Snate@binkert.org rxDmaAddr, rxDmaLen); 11706999Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11716657Snate@binkert.org} 11726657Snate@binkert.org 11736657Snate@binkert.orgbool 11746657Snate@binkert.orgNSGigE::doRxDmaWrite() 11756657Snate@binkert.org{ 11766657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11776657Snate@binkert.org rxDmaState = dmaWriting; 11786657Snate@binkert.org 11796657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 11806657Snate@binkert.org if (dmaInterface->busy()) 11816657Snate@binkert.org rxDmaState = dmaWriteWaiting; 11826657Snate@binkert.org else 11836657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 11847007Snate@binkert.org &rxDmaWriteEvent, true); 11856657Snate@binkert.org return true; 11866657Snate@binkert.org } 11876657Snate@binkert.org 11886657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 11896657Snate@binkert.org rxDmaWriteCopy(); 11906657Snate@binkert.org return false; 11916657Snate@binkert.org } 11926657Snate@binkert.org 11936657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 11946657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 11956657Snate@binkert.org rxDmaWriteEvent.schedule(start); 11966657Snate@binkert.org return true; 11976657Snate@binkert.org} 11986657Snate@binkert.org 11996657Snate@binkert.orgvoid 12006657Snate@binkert.orgNSGigE::rxDmaWriteDone() 12016657Snate@binkert.org{ 12026657Snate@binkert.org assert(rxDmaState == dmaWriting); 12036657Snate@binkert.org rxDmaWriteCopy(); 12046657Snate@binkert.org 12056657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 12067839Snilay@cs.wisc.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12077839Snilay@cs.wisc.edu txKick(); 12087839Snilay@cs.wisc.edu 12097839Snilay@cs.wisc.edu rxKick(); 12107839Snilay@cs.wisc.edu} 12117839Snilay@cs.wisc.edu 12127839Snilay@cs.wisc.eduvoid 12137839Snilay@cs.wisc.eduNSGigE::rxKick() 12147839Snilay@cs.wisc.edu{ 12157839Snilay@cs.wisc.edu DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", 12167839Snilay@cs.wisc.edu NsRxStateStrings[rxState], rxFifo.size()); 12177839Snilay@cs.wisc.edu 12186657Snate@binkert.org if (rxKickTick > curTick) { 12196657Snate@binkert.org DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 12206657Snate@binkert.org rxKickTick); 12216657Snate@binkert.org return; 12226657Snate@binkert.org } 12236657Snate@binkert.org 12246657Snate@binkert.org next: 12256657Snate@binkert.org switch(rxDmaState) { 12266657Snate@binkert.org case dmaReadWaiting: 12276657Snate@binkert.org if (doRxDmaRead()) 12286657Snate@binkert.org goto exit; 12296657Snate@binkert.org break; 12306657Snate@binkert.org case dmaWriteWaiting: 12316657Snate@binkert.org if (doRxDmaWrite()) 12326657Snate@binkert.org goto exit; 12336657Snate@binkert.org break; 12346657Snate@binkert.org default: 12356657Snate@binkert.org break; 12366657Snate@binkert.org } 12376657Snate@binkert.org 12386657Snate@binkert.org // see state machine from spec for details 12397805Snilay@cs.wisc.edu // the way this works is, if you finish work on one state and can 12408159SBrad.Beckmann@amd.com // go directly to another, you do that through jumping to the 12418159SBrad.Beckmann@amd.com // label "next". however, if you have intermediate work, like DMA 12426657Snate@binkert.org // so that you can't go to the next state yet, you go to exit and 12436657Snate@binkert.org // exit the loop. however, when the DMA is done it will trigger 12446657Snate@binkert.org // an event and come back to this loop. 12456657Snate@binkert.org switch (rxState) { 12466657Snate@binkert.org case rxIdle: 12476657Snate@binkert.org if (!rxEnable) { 12487542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 12497542SBrad.Beckmann@amd.com goto exit; 12507542SBrad.Beckmann@amd.com } 12517542SBrad.Beckmann@amd.com 12527542SBrad.Beckmann@amd.com if (CRDD) { 12537542SBrad.Beckmann@amd.com rxState = rxDescRefr; 12547542SBrad.Beckmann@amd.com 12557542SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 12567542SBrad.Beckmann@amd.com rxDmaData = &rxDescCache + offsetof(ns_desc, link); 12577542SBrad.Beckmann@amd.com rxDmaLen = sizeof(rxDescCache.link); 12587542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 12597832Snate@binkert.org 12607542SBrad.Beckmann@amd.com descDmaReads++; 12617542SBrad.Beckmann@amd.com descDmaRdBytes += rxDmaLen; 12627542SBrad.Beckmann@amd.com 12638229Snate@binkert.org if (doRxDmaRead()) 12647542SBrad.Beckmann@amd.com goto exit; 12657542SBrad.Beckmann@amd.com } else { 12667542SBrad.Beckmann@amd.com rxState = rxDescRead; 12677542SBrad.Beckmann@amd.com 12687542SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 12697542SBrad.Beckmann@amd.com rxDmaData = &rxDescCache; 12707542SBrad.Beckmann@amd.com rxDmaLen = sizeof(ns_desc); 12717542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 12727542SBrad.Beckmann@amd.com 12737542SBrad.Beckmann@amd.com descDmaReads++; 12747542SBrad.Beckmann@amd.com descDmaRdBytes += rxDmaLen; 12757542SBrad.Beckmann@amd.com 12767542SBrad.Beckmann@amd.com if (doRxDmaRead()) 12777542SBrad.Beckmann@amd.com goto exit; 12787542SBrad.Beckmann@amd.com } 12797542SBrad.Beckmann@amd.com break; 12807542SBrad.Beckmann@amd.com 12817542SBrad.Beckmann@amd.com case rxDescRefr: 12827542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 12837542SBrad.Beckmann@amd.com goto exit; 12847542SBrad.Beckmann@amd.com 12857542SBrad.Beckmann@amd.com rxState = rxAdvance; 12867542SBrad.Beckmann@amd.com break; 12877542SBrad.Beckmann@amd.com 12887542SBrad.Beckmann@amd.com case rxDescRead: 12897542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 12907542SBrad.Beckmann@amd.com goto exit; 12917542SBrad.Beckmann@amd.com 12927542SBrad.Beckmann@amd.com DPRINTF(EthernetDesc, 12937542SBrad.Beckmann@amd.com "rxDescCache: addr=%08x read descriptor\n", 12947542SBrad.Beckmann@amd.com regs.rxdp & 0x3fffffff); 12957542SBrad.Beckmann@amd.com DPRINTF(EthernetDesc, 12967542SBrad.Beckmann@amd.com "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 12977542SBrad.Beckmann@amd.com rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 12987542SBrad.Beckmann@amd.com rxDescCache.extsts); 12997542SBrad.Beckmann@amd.com 13007542SBrad.Beckmann@amd.com if (rxDescCache.cmdsts & CMDSTS_OWN) { 13017542SBrad.Beckmann@amd.com devIntrPost(ISR_RXIDLE); 13027542SBrad.Beckmann@amd.com rxState = rxIdle; 13037542SBrad.Beckmann@amd.com goto exit; 13047542SBrad.Beckmann@amd.com } else { 13057542SBrad.Beckmann@amd.com rxState = rxFifoBlock; 13067542SBrad.Beckmann@amd.com rxFragPtr = rxDescCache.bufptr; 13077542SBrad.Beckmann@amd.com rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 13087542SBrad.Beckmann@amd.com } 13097542SBrad.Beckmann@amd.com break; 13107542SBrad.Beckmann@amd.com 13117542SBrad.Beckmann@amd.com case rxFifoBlock: 13127542SBrad.Beckmann@amd.com if (!rxPacket) { 13137542SBrad.Beckmann@amd.com /** 13147542SBrad.Beckmann@amd.com * @todo in reality, we should be able to start processing 13157542SBrad.Beckmann@amd.com * the packet as it arrives, and not have to wait for the 13167542SBrad.Beckmann@amd.com * full packet ot be in the receive fifo. 13177542SBrad.Beckmann@amd.com */ 13187542SBrad.Beckmann@amd.com if (rxFifo.empty()) 13197542SBrad.Beckmann@amd.com goto exit; 13207542SBrad.Beckmann@amd.com 13217542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 13227542SBrad.Beckmann@amd.com 13237542SBrad.Beckmann@amd.com // If we don't have a packet, grab a new one from the fifo. 13247542SBrad.Beckmann@amd.com rxPacket = rxFifo.front(); 13257542SBrad.Beckmann@amd.com rxPktBytes = rxPacket->length; 13267542SBrad.Beckmann@amd.com rxPacketBufPtr = rxPacket->data; 13277542SBrad.Beckmann@amd.com 13287542SBrad.Beckmann@amd.com#if TRACING_ON 13297542SBrad.Beckmann@amd.com if (DTRACE(Ethernet)) { 13307542SBrad.Beckmann@amd.com IpPtr ip(rxPacket); 13317542SBrad.Beckmann@amd.com if (ip) { 13327542SBrad.Beckmann@amd.com DPRINTF(Ethernet, "ID is %d\n", ip->id()); 13337542SBrad.Beckmann@amd.com TcpPtr tcp(ip); 13347542SBrad.Beckmann@amd.com if (tcp) { 13357542SBrad.Beckmann@amd.com DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 13367542SBrad.Beckmann@amd.com tcp->sport(), tcp->dport()); 13377542SBrad.Beckmann@amd.com } 13387542SBrad.Beckmann@amd.com } 13397542SBrad.Beckmann@amd.com } 13407542SBrad.Beckmann@amd.com#endif 13417542SBrad.Beckmann@amd.com 13427542SBrad.Beckmann@amd.com // sanity check - i think the driver behaves like this 13437542SBrad.Beckmann@amd.com assert(rxDescCnt >= rxPktBytes); 13446657Snate@binkert.org rxFifo.pop(); 13456999Snate@binkert.org } 13466657Snate@binkert.org 13476657Snate@binkert.org 13486657Snate@binkert.org // dont' need the && rxDescCnt > 0 if driver sanity check 13496657Snate@binkert.org // above holds 13506657Snate@binkert.org if (rxPktBytes > 0) { 13516657Snate@binkert.org rxState = rxFragWrite; 13527542SBrad.Beckmann@amd.com // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 13537542SBrad.Beckmann@amd.com // check holds 13546657Snate@binkert.org rxXferLen = rxPktBytes; 13557832Snate@binkert.org 13567002Snate@binkert.org rxDmaAddr = rxFragPtr & 0x3fffffff; 13577002Snate@binkert.org rxDmaData = rxPacketBufPtr; 13588229Snate@binkert.org rxDmaLen = rxXferLen; 13598229Snate@binkert.org rxDmaFree = dmaDataFree; 13606657Snate@binkert.org 13616657Snate@binkert.org if (doRxDmaWrite()) 13627007Snate@binkert.org goto exit; 13637007Snate@binkert.org 13646657Snate@binkert.org } else { 13656657Snate@binkert.org rxState = rxDescWrite; 13666657Snate@binkert.org 13676657Snate@binkert.org //if (rxPktBytes == 0) { /* packet is done */ 13686657Snate@binkert.org assert(rxPktBytes == 0); 13697542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "done with receiving packet\n"); 13707542SBrad.Beckmann@amd.com 13717542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_OWN; 13726657Snate@binkert.org rxDescCache.cmdsts &= ~CMDSTS_MORE; 13736657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_OK; 13746657Snate@binkert.org rxDescCache.cmdsts &= 0xffff0000; 13756657Snate@binkert.org rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 13766657Snate@binkert.org 13776657Snate@binkert.org#if 0 13786657Snate@binkert.org /* 13796657Snate@binkert.org * all the driver uses these are for its own stats keeping 13806657Snate@binkert.org * which we don't care about, aren't necessary for 13817007Snate@binkert.org * functionality and doing this would just slow us down. 13826657Snate@binkert.org * if they end up using this in a later version for 13836657Snate@binkert.org * functional purposes, just undef 13846657Snate@binkert.org */ 13856657Snate@binkert.org if (rxFilterEnable) { 13866999Snate@binkert.org rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 13876657Snate@binkert.org const EthAddr &dst = rxFifoFront()->dst(); 13886657Snate@binkert.org if (dst->unicast()) 13896657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 13906657Snate@binkert.org if (dst->multicast()) 13916657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 13926657Snate@binkert.org if (dst->broadcast()) 13937832Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 13947832Snate@binkert.org } 13956657Snate@binkert.org#endif 13966657Snate@binkert.org 13976657Snate@binkert.org IpPtr ip(rxPacket); 13986657Snate@binkert.org if (extstsEnable && ip) { 13996657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPPKT; 14006657Snate@binkert.org rxIpChecksums++; 14016657Snate@binkert.org if (cksum(ip) != 0) { 14026657Snate@binkert.org DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 14036657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPERR; 14046657Snate@binkert.org } 14056657Snate@binkert.org TcpPtr tcp(ip); 14066657Snate@binkert.org UdpPtr udp(ip); 14076657Snate@binkert.org if (tcp) { 14086657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPPKT; 14097007Snate@binkert.org rxTcpChecksums++; 14107007Snate@binkert.org if (cksum(tcp) != 0) { 14117007Snate@binkert.org DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 14126657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPERR; 14136657Snate@binkert.org 14146657Snate@binkert.org } 14157007Snate@binkert.org } else if (udp) { 14167007Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPPKT; 14177007Snate@binkert.org rxUdpChecksums++; 14186657Snate@binkert.org if (cksum(udp) != 0) { 14196657Snate@binkert.org DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 14206657Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPERR; 14216657Snate@binkert.org } 14226657Snate@binkert.org } 14236657Snate@binkert.org } 14246657Snate@binkert.org rxPacket = 0; 14256657Snate@binkert.org 14266657Snate@binkert.org /* 14276657Snate@binkert.org * the driver seems to always receive into desc buffers 14286657Snate@binkert.org * of size 1514, so you never have a pkt that is split 14297007Snate@binkert.org * into multiple descriptors on the receive side, so 14307007Snate@binkert.org * i don't implement that case, hence the assert above. 14316657Snate@binkert.org */ 14326657Snate@binkert.org 14336657Snate@binkert.org DPRINTF(EthernetDesc, 14346657Snate@binkert.org "rxDescCache: addr=%08x writeback cmdsts extsts\n", 14356657Snate@binkert.org regs.rxdp & 0x3fffffff); 14367007Snate@binkert.org DPRINTF(EthernetDesc, 14377007Snate@binkert.org "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 14387007Snate@binkert.org rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 14396657Snate@binkert.org rxDescCache.extsts); 14406657Snate@binkert.org 14416657Snate@binkert.org rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 14427007Snate@binkert.org rxDmaData = &(rxDescCache.cmdsts); 14437542SBrad.Beckmann@amd.com rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 14447542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 14456657Snate@binkert.org 14467542SBrad.Beckmann@amd.com descDmaWrites++; 14477542SBrad.Beckmann@amd.com descDmaWrBytes += rxDmaLen; 14487002Snate@binkert.org 14497542SBrad.Beckmann@amd.com if (doRxDmaWrite()) 14507542SBrad.Beckmann@amd.com goto exit; 14517542SBrad.Beckmann@amd.com } 14527542SBrad.Beckmann@amd.com break; 14536657Snate@binkert.org 14547542SBrad.Beckmann@amd.com case rxFragWrite: 14557542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 14567542SBrad.Beckmann@amd.com goto exit; 14577542SBrad.Beckmann@amd.com 14587542SBrad.Beckmann@amd.com rxPacketBufPtr += rxXferLen; 14597542SBrad.Beckmann@amd.com rxFragPtr += rxXferLen; 14607542SBrad.Beckmann@amd.com rxPktBytes -= rxXferLen; 14617542SBrad.Beckmann@amd.com 14626657Snate@binkert.org rxState = rxFifoBlock; 14636657Snate@binkert.org break; 14646657Snate@binkert.org 14656657Snate@binkert.org case rxDescWrite: 14666657Snate@binkert.org if (rxDmaState != dmaIdle) 14676657Snate@binkert.org goto exit; 14687007Snate@binkert.org 14696999Snate@binkert.org assert(rxDescCache.cmdsts & CMDSTS_OWN); 14707007Snate@binkert.org 14717007Snate@binkert.org assert(rxPacket == 0); 14727007Snate@binkert.org devIntrPost(ISR_RXOK); 14737007Snate@binkert.org 14747007Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_INTR) 14757007Snate@binkert.org devIntrPost(ISR_RXDESC); 14766657Snate@binkert.org 14776657Snate@binkert.org if (!rxEnable) { 14786657Snate@binkert.org DPRINTF(EthernetSM, "Halting the RX state machine\n"); 14796657Snate@binkert.org rxState = rxIdle; 14806657Snate@binkert.org goto exit; 14816657Snate@binkert.org } else 14826657Snate@binkert.org rxState = rxAdvance; 14836657Snate@binkert.org break; 14846657Snate@binkert.org 14856657Snate@binkert.org case rxAdvance: 14866657Snate@binkert.org if (rxDescCache.link == 0) { 14876657Snate@binkert.org devIntrPost(ISR_RXIDLE); 14886657Snate@binkert.org rxState = rxIdle; 14896657Snate@binkert.org CRDD = true; 14906657Snate@binkert.org goto exit; 14916657Snate@binkert.org } else { 14926657Snate@binkert.org rxState = rxDescRead; 14936657Snate@binkert.org regs.rxdp = rxDescCache.link; 14946657Snate@binkert.org CRDD = false; 14956657Snate@binkert.org 14966657Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 14976657Snate@binkert.org rxDmaData = &rxDescCache; 14986657Snate@binkert.org rxDmaLen = sizeof(ns_desc); 14996657Snate@binkert.org rxDmaFree = dmaDescFree; 15006657Snate@binkert.org 15016657Snate@binkert.org if (doRxDmaRead()) 15026657Snate@binkert.org goto exit; 15036657Snate@binkert.org } 15046657Snate@binkert.org break; 15056999Snate@binkert.org 15066657Snate@binkert.org default: 15076657Snate@binkert.org panic("Invalid rxState!"); 15087007Snate@binkert.org } 15097007Snate@binkert.org 15106657Snate@binkert.org DPRINTF(EthernetSM, "entering next rxState=%s\n", 15116657Snate@binkert.org NsRxStateStrings[rxState]); 15126657Snate@binkert.org 15136657Snate@binkert.org goto next; 15146657Snate@binkert.org 15156657Snate@binkert.org exit: 15166657Snate@binkert.org /** 15176657Snate@binkert.org * @todo do we want to schedule a future kick? 15186657Snate@binkert.org */ 15196657Snate@binkert.org DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 15206657Snate@binkert.org NsRxStateStrings[rxState]); 15216657Snate@binkert.org} 15226657Snate@binkert.org 15236657Snate@binkert.orgvoid 15246657Snate@binkert.orgNSGigE::transmit() 15256657Snate@binkert.org{ 15266657Snate@binkert.org if (txFifo.empty()) { 15276657Snate@binkert.org DPRINTF(Ethernet, "nothing to transmit\n"); 15286657Snate@binkert.org return; 15296657Snate@binkert.org } 15306657Snate@binkert.org 15316657Snate@binkert.org DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 15326657Snate@binkert.org txFifo.size()); 15336657Snate@binkert.org if (interface->sendPacket(txFifo.front())) { 15346657Snate@binkert.org#if TRACING_ON 15356657Snate@binkert.org if (DTRACE(Ethernet)) { 15366657Snate@binkert.org IpPtr ip(txFifo.front()); 15376657Snate@binkert.org if (ip) { 15386657Snate@binkert.org DPRINTF(Ethernet, "ID is %d\n", ip->id()); 15396657Snate@binkert.org TcpPtr tcp(ip); 15406657Snate@binkert.org if (tcp) { 15416657Snate@binkert.org DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 15426657Snate@binkert.org tcp->sport(), tcp->dport()); 15436657Snate@binkert.org } 15446657Snate@binkert.org } 15456657Snate@binkert.org } 15466657Snate@binkert.org#endif 15476657Snate@binkert.org 15486657Snate@binkert.org DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 15496657Snate@binkert.org txBytes += txFifo.front()->length; 15506657Snate@binkert.org txPackets++; 15516657Snate@binkert.org 15526657Snate@binkert.org DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 15536657Snate@binkert.org txFifo.avail()); 15546657Snate@binkert.org txFifo.pop(); 15556657Snate@binkert.org 15566657Snate@binkert.org /* 15576657Snate@binkert.org * normally do a writeback of the descriptor here, and ONLY 15586657Snate@binkert.org * after that is done, send this interrupt. but since our 15596657Snate@binkert.org * stuff never actually fails, just do this interrupt here, 15606657Snate@binkert.org * otherwise the code has to stray from this nice format. 15616657Snate@binkert.org * besides, it's functionally the same. 15626657Snate@binkert.org */ 15636657Snate@binkert.org devIntrPost(ISR_TXOK); 15646657Snate@binkert.org } 15656657Snate@binkert.org 15666657Snate@binkert.org if (!txFifo.empty() && !txEvent.scheduled()) { 15676657Snate@binkert.org DPRINTF(Ethernet, "reschedule transmit\n"); 15686657Snate@binkert.org txEvent.schedule(curTick + 1000); 15696657Snate@binkert.org } 15706657Snate@binkert.org} 15716657Snate@binkert.org 15726657Snate@binkert.orgvoid 15736657Snate@binkert.orgNSGigE::txDmaReadCopy() 15746657Snate@binkert.org{ 15756657Snate@binkert.org assert(txDmaState == dmaReading); 15766657Snate@binkert.org 15776657Snate@binkert.org physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); 15786657Snate@binkert.org txDmaState = dmaIdle; 15796657Snate@binkert.org 15806657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 15816657Snate@binkert.org txDmaAddr, txDmaLen); 15826657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 15836657Snate@binkert.org} 15846657Snate@binkert.org 15856657Snate@binkert.orgbool 15866657Snate@binkert.orgNSGigE::doTxDmaRead() 15876657Snate@binkert.org{ 15886657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 15896657Snate@binkert.org txDmaState = dmaReading; 15906657Snate@binkert.org 15916657Snate@binkert.org if (dmaInterface && !txDmaFree) { 15926657Snate@binkert.org if (dmaInterface->busy()) 15936657Snate@binkert.org txDmaState = dmaReadWaiting; 15946657Snate@binkert.org else 15956657Snate@binkert.org dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 15966657Snate@binkert.org &txDmaReadEvent, true); 15976657Snate@binkert.org return true; 15987007Snate@binkert.org } 15996657Snate@binkert.org 16006657Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 16016657Snate@binkert.org txDmaReadCopy(); 16026657Snate@binkert.org return false; 16036657Snate@binkert.org } 16046657Snate@binkert.org 16056657Snate@binkert.org Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 16067007Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 16076657Snate@binkert.org txDmaReadEvent.schedule(start); 16086657Snate@binkert.org return true; 16096657Snate@binkert.org} 16106657Snate@binkert.org 16116657Snate@binkert.orgvoid 16126657Snate@binkert.orgNSGigE::txDmaReadDone() 16136657Snate@binkert.org{ 16146657Snate@binkert.org assert(txDmaState == dmaReading); 16156657Snate@binkert.org txDmaReadCopy(); 16166657Snate@binkert.org 16176657Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 16186657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 16196657Snate@binkert.org rxKick(); 16206657Snate@binkert.org 16216657Snate@binkert.org txKick(); 16227007Snate@binkert.org} 16236657Snate@binkert.org 16246657Snate@binkert.orgvoid 16256657Snate@binkert.orgNSGigE::txDmaWriteCopy() 16266657Snate@binkert.org{ 16276657Snate@binkert.org assert(txDmaState == dmaWriting); 16286657Snate@binkert.org 16296657Snate@binkert.org physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); 16306657Snate@binkert.org txDmaState = dmaIdle; 16316657Snate@binkert.org 16326657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 16336657Snate@binkert.org txDmaAddr, txDmaLen); 16346657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 16356657Snate@binkert.org} 16366657Snate@binkert.org 16376657Snate@binkert.orgbool 16386657Snate@binkert.orgNSGigE::doTxDmaWrite() 16396657Snate@binkert.org{ 16406657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 16416657Snate@binkert.org txDmaState = dmaWriting; 16426657Snate@binkert.org 16436657Snate@binkert.org if (dmaInterface && !txDmaFree) { 16446657Snate@binkert.org if (dmaInterface->busy()) 1645 txDmaState = dmaWriteWaiting; 1646 else 1647 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1648 &txDmaWriteEvent, true); 1649 return true; 1650 } 1651 1652 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1653 txDmaWriteCopy(); 1654 return false; 1655 } 1656 1657 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1658 Tick start = curTick + dmaWriteDelay + factor; 1659 txDmaWriteEvent.schedule(start); 1660 return true; 1661} 1662 1663void 1664NSGigE::txDmaWriteDone() 1665{ 1666 assert(txDmaState == dmaWriting); 1667 txDmaWriteCopy(); 1668 1669 // If the receive state machine has a pending DMA, let it go first 1670 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1671 rxKick(); 1672 1673 txKick(); 1674} 1675 1676void 1677NSGigE::txKick() 1678{ 1679 DPRINTF(EthernetSM, "transmit kick txState=%s\n", 1680 NsTxStateStrings[txState]); 1681 1682 if (txKickTick > curTick) { 1683 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1684 txKickTick); 1685 1686 return; 1687 } 1688 1689 next: 1690 switch(txDmaState) { 1691 case dmaReadWaiting: 1692 if (doTxDmaRead()) 1693 goto exit; 1694 break; 1695 case dmaWriteWaiting: 1696 if (doTxDmaWrite()) 1697 goto exit; 1698 break; 1699 default: 1700 break; 1701 } 1702 1703 switch (txState) { 1704 case txIdle: 1705 if (!txEnable) { 1706 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1707 goto exit; 1708 } 1709 1710 if (CTDD) { 1711 txState = txDescRefr; 1712 1713 txDmaAddr = regs.txdp & 0x3fffffff; 1714 txDmaData = &txDescCache + offsetof(ns_desc, link); 1715 txDmaLen = sizeof(txDescCache.link); 1716 txDmaFree = dmaDescFree; 1717 1718 descDmaReads++; 1719 descDmaRdBytes += txDmaLen; 1720 1721 if (doTxDmaRead()) 1722 goto exit; 1723 1724 } else { 1725 txState = txDescRead; 1726 1727 txDmaAddr = regs.txdp & 0x3fffffff; 1728 txDmaData = &txDescCache; 1729 txDmaLen = sizeof(ns_desc); 1730 txDmaFree = dmaDescFree; 1731 1732 descDmaReads++; 1733 descDmaRdBytes += txDmaLen; 1734 1735 if (doTxDmaRead()) 1736 goto exit; 1737 } 1738 break; 1739 1740 case txDescRefr: 1741 if (txDmaState != dmaIdle) 1742 goto exit; 1743 1744 txState = txAdvance; 1745 break; 1746 1747 case txDescRead: 1748 if (txDmaState != dmaIdle) 1749 goto exit; 1750 1751 DPRINTF(EthernetDesc, 1752 "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 1753 txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1754 txDescCache.extsts); 1755 1756 if (txDescCache.cmdsts & CMDSTS_OWN) { 1757 txState = txFifoBlock; 1758 txFragPtr = txDescCache.bufptr; 1759 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1760 } else { 1761 devIntrPost(ISR_TXIDLE); 1762 txState = txIdle; 1763 goto exit; 1764 } 1765 break; 1766 1767 case txFifoBlock: 1768 if (!txPacket) { 1769 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1770 txPacket = new PacketData; 1771 txPacket->data = new uint8_t[16384]; 1772 txPacketBufPtr = txPacket->data; 1773 } 1774 1775 if (txDescCnt == 0) { 1776 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1777 if (txDescCache.cmdsts & CMDSTS_MORE) { 1778 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1779 txState = txDescWrite; 1780 1781 txDescCache.cmdsts &= ~CMDSTS_OWN; 1782 1783 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1784 txDmaAddr &= 0x3fffffff; 1785 txDmaData = &(txDescCache.cmdsts); 1786 txDmaLen = sizeof(txDescCache.cmdsts); 1787 txDmaFree = dmaDescFree; 1788 1789 if (doTxDmaWrite()) 1790 goto exit; 1791 1792 } else { /* this packet is totally done */ 1793 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1794 /* deal with the the packet that just finished */ 1795 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1796 IpPtr ip(txPacket); 1797 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1798 UdpPtr udp(ip); 1799 udp->sum(0); 1800 udp->sum(cksum(udp)); 1801 txUdpChecksums++; 1802 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1803 TcpPtr tcp(ip); 1804 tcp->sum(0); 1805 tcp->sum(cksum(tcp)); 1806 txTcpChecksums++; 1807 } 1808 if (txDescCache.extsts & EXTSTS_IPPKT) { 1809 ip->sum(0); 1810 ip->sum(cksum(ip)); 1811 txIpChecksums++; 1812 } 1813 } 1814 1815 txPacket->length = txPacketBufPtr - txPacket->data; 1816 // this is just because the receive can't handle a 1817 // packet bigger want to make sure 1818 assert(txPacket->length <= 1514); 1819#ifndef NDEBUG 1820 bool success = 1821#endif 1822 txFifo.push(txPacket); 1823 assert(success); 1824 1825 /* 1826 * this following section is not tqo spec, but 1827 * functionally shouldn't be any different. normally, 1828 * the chip will wait til the transmit has occurred 1829 * before writing back the descriptor because it has 1830 * to wait to see that it was successfully transmitted 1831 * to decide whether to set CMDSTS_OK or not. 1832 * however, in the simulator since it is always 1833 * successfully transmitted, and writing it exactly to 1834 * spec would complicate the code, we just do it here 1835 */ 1836 1837 txDescCache.cmdsts &= ~CMDSTS_OWN; 1838 txDescCache.cmdsts |= CMDSTS_OK; 1839 1840 DPRINTF(EthernetDesc, 1841 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1842 txDescCache.cmdsts, txDescCache.extsts); 1843 1844 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1845 txDmaAddr &= 0x3fffffff; 1846 txDmaData = &(txDescCache.cmdsts); 1847 txDmaLen = sizeof(txDescCache.cmdsts) + 1848 sizeof(txDescCache.extsts); 1849 txDmaFree = dmaDescFree; 1850 1851 descDmaWrites++; 1852 descDmaWrBytes += txDmaLen; 1853 1854 transmit(); 1855 txPacket = 0; 1856 1857 if (!txEnable) { 1858 DPRINTF(EthernetSM, "halting TX state machine\n"); 1859 txState = txIdle; 1860 goto exit; 1861 } else 1862 txState = txAdvance; 1863 1864 if (doTxDmaWrite()) 1865 goto exit; 1866 } 1867 } else { 1868 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1869 if (!txFifo.full()) { 1870 txState = txFragRead; 1871 1872 /* 1873 * The number of bytes transferred is either whatever 1874 * is left in the descriptor (txDescCnt), or if there 1875 * is not enough room in the fifo, just whatever room 1876 * is left in the fifo 1877 */ 1878 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1879 1880 txDmaAddr = txFragPtr & 0x3fffffff; 1881 txDmaData = txPacketBufPtr; 1882 txDmaLen = txXferLen; 1883 txDmaFree = dmaDataFree; 1884 1885 if (doTxDmaRead()) 1886 goto exit; 1887 } else { 1888 txState = txFifoBlock; 1889 transmit(); 1890 1891 goto exit; 1892 } 1893 1894 } 1895 break; 1896 1897 case txFragRead: 1898 if (txDmaState != dmaIdle) 1899 goto exit; 1900 1901 txPacketBufPtr += txXferLen; 1902 txFragPtr += txXferLen; 1903 txDescCnt -= txXferLen; 1904 txFifo.reserve(txXferLen); 1905 1906 txState = txFifoBlock; 1907 break; 1908 1909 case txDescWrite: 1910 if (txDmaState != dmaIdle) 1911 goto exit; 1912 1913 if (txDescCache.cmdsts & CMDSTS_INTR) 1914 devIntrPost(ISR_TXDESC); 1915 1916 txState = txAdvance; 1917 break; 1918 1919 case txAdvance: 1920 if (txDescCache.link == 0) { 1921 devIntrPost(ISR_TXIDLE); 1922 txState = txIdle; 1923 goto exit; 1924 } else { 1925 txState = txDescRead; 1926 regs.txdp = txDescCache.link; 1927 CTDD = false; 1928 1929 txDmaAddr = txDescCache.link & 0x3fffffff; 1930 txDmaData = &txDescCache; 1931 txDmaLen = sizeof(ns_desc); 1932 txDmaFree = dmaDescFree; 1933 1934 if (doTxDmaRead()) 1935 goto exit; 1936 } 1937 break; 1938 1939 default: 1940 panic("invalid state"); 1941 } 1942 1943 DPRINTF(EthernetSM, "entering next txState=%s\n", 1944 NsTxStateStrings[txState]); 1945 1946 goto next; 1947 1948 exit: 1949 /** 1950 * @todo do we want to schedule a future kick? 1951 */ 1952 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1953 NsTxStateStrings[txState]); 1954} 1955 1956void 1957NSGigE::transferDone() 1958{ 1959 if (txFifo.empty()) { 1960 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1961 return; 1962 } 1963 1964 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1965 1966 if (txEvent.scheduled()) 1967 txEvent.reschedule(curTick + 1); 1968 else 1969 txEvent.schedule(curTick + 1); 1970} 1971 1972bool 1973NSGigE::rxFilter(const PacketPtr &packet) 1974{ 1975 EthPtr eth = packet; 1976 bool drop = true; 1977 string type; 1978 1979 const EthAddr &dst = eth->dst(); 1980 if (dst.unicast()) { 1981 // If we're accepting all unicast addresses 1982 if (acceptUnicast) 1983 drop = false; 1984 1985 // If we make a perfect match 1986 if (acceptPerfect && dst == rom.perfectMatch) 1987 drop = false; 1988 1989 if (acceptArp && eth->type() == ETH_TYPE_ARP) 1990 drop = false; 1991 1992 } else if (dst.broadcast()) { 1993 // if we're accepting broadcasts 1994 if (acceptBroadcast) 1995 drop = false; 1996 1997 } else if (dst.multicast()) { 1998 // if we're accepting all multicasts 1999 if (acceptMulticast) 2000 drop = false; 2001 2002 } 2003 2004 if (drop) { 2005 DPRINTF(Ethernet, "rxFilter drop\n"); 2006 DDUMP(EthernetData, packet->data, packet->length); 2007 } 2008 2009 return drop; 2010} 2011 2012bool 2013NSGigE::recvPacket(PacketPtr packet) 2014{ 2015 rxBytes += packet->length; 2016 rxPackets++; 2017 2018 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2019 rxFifo.avail()); 2020 2021 if (!rxEnable) { 2022 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2023 debug_break(); 2024 interface->recvDone(); 2025 return true; 2026 } 2027 2028 if (rxFilterEnable && rxFilter(packet)) { 2029 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2030 interface->recvDone(); 2031 return true; 2032 } 2033 2034 if (rxFifo.avail() < packet->length) { 2035 DPRINTF(Ethernet, 2036 "packet will not fit in receive buffer...packet dropped\n"); 2037 devIntrPost(ISR_RXORN); 2038 return false; 2039 } 2040 2041 rxFifo.push(packet); 2042 interface->recvDone(); 2043 2044 rxKick(); 2045 return true; 2046} 2047 2048//===================================================================== 2049// 2050// 2051void 2052NSGigE::serialize(ostream &os) 2053{ 2054 // Serialize the PciDev base class 2055 PciDev::serialize(os); 2056 2057 /* 2058 * Finalize any DMA events now. 2059 */ 2060 if (rxDmaReadEvent.scheduled()) 2061 rxDmaReadCopy(); 2062 if (rxDmaWriteEvent.scheduled()) 2063 rxDmaWriteCopy(); 2064 if (txDmaReadEvent.scheduled()) 2065 txDmaReadCopy(); 2066 if (txDmaWriteEvent.scheduled()) 2067 txDmaWriteCopy(); 2068 2069 /* 2070 * Serialize the device registers 2071 */ 2072 SERIALIZE_SCALAR(regs.command); 2073 SERIALIZE_SCALAR(regs.config); 2074 SERIALIZE_SCALAR(regs.mear); 2075 SERIALIZE_SCALAR(regs.ptscr); 2076 SERIALIZE_SCALAR(regs.isr); 2077 SERIALIZE_SCALAR(regs.imr); 2078 SERIALIZE_SCALAR(regs.ier); 2079 SERIALIZE_SCALAR(regs.ihr); 2080 SERIALIZE_SCALAR(regs.txdp); 2081 SERIALIZE_SCALAR(regs.txdp_hi); 2082 SERIALIZE_SCALAR(regs.txcfg); 2083 SERIALIZE_SCALAR(regs.gpior); 2084 SERIALIZE_SCALAR(regs.rxdp); 2085 SERIALIZE_SCALAR(regs.rxdp_hi); 2086 SERIALIZE_SCALAR(regs.rxcfg); 2087 SERIALIZE_SCALAR(regs.pqcr); 2088 SERIALIZE_SCALAR(regs.wcsr); 2089 SERIALIZE_SCALAR(regs.pcr); 2090 SERIALIZE_SCALAR(regs.rfcr); 2091 SERIALIZE_SCALAR(regs.rfdr); 2092 SERIALIZE_SCALAR(regs.srr); 2093 SERIALIZE_SCALAR(regs.mibc); 2094 SERIALIZE_SCALAR(regs.vrcr); 2095 SERIALIZE_SCALAR(regs.vtcr); 2096 SERIALIZE_SCALAR(regs.vdr); 2097 SERIALIZE_SCALAR(regs.ccsr); 2098 SERIALIZE_SCALAR(regs.tbicr); 2099 SERIALIZE_SCALAR(regs.tbisr); 2100 SERIALIZE_SCALAR(regs.tanar); 2101 SERIALIZE_SCALAR(regs.tanlpar); 2102 SERIALIZE_SCALAR(regs.taner); 2103 SERIALIZE_SCALAR(regs.tesr); 2104 2105 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2106 2107 SERIALIZE_SCALAR(ioEnable); 2108 2109 /* 2110 * Serialize the data Fifos 2111 */ 2112 rxFifo.serialize("rxFifo", os); 2113 txFifo.serialize("txFifo", os); 2114 2115 /* 2116 * Serialize the various helper variables 2117 */ 2118 bool txPacketExists = txPacket; 2119 SERIALIZE_SCALAR(txPacketExists); 2120 if (txPacketExists) { 2121 txPacket->serialize("txPacket", os); 2122 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2123 SERIALIZE_SCALAR(txPktBufPtr); 2124 } 2125 2126 bool rxPacketExists = rxPacket; 2127 SERIALIZE_SCALAR(rxPacketExists); 2128 if (rxPacketExists) { 2129 rxPacket->serialize("rxPacket", os); 2130 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2131 SERIALIZE_SCALAR(rxPktBufPtr); 2132 } 2133 2134 SERIALIZE_SCALAR(txXferLen); 2135 SERIALIZE_SCALAR(rxXferLen); 2136 2137 /* 2138 * Serialize DescCaches 2139 */ 2140 SERIALIZE_SCALAR(txDescCache.link); 2141 SERIALIZE_SCALAR(txDescCache.bufptr); 2142 SERIALIZE_SCALAR(txDescCache.cmdsts); 2143 SERIALIZE_SCALAR(txDescCache.extsts); 2144 SERIALIZE_SCALAR(rxDescCache.link); 2145 SERIALIZE_SCALAR(rxDescCache.bufptr); 2146 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2147 SERIALIZE_SCALAR(rxDescCache.extsts); 2148 2149 /* 2150 * Serialize tx state machine 2151 */ 2152 int txState = this->txState; 2153 SERIALIZE_SCALAR(txState); 2154 SERIALIZE_SCALAR(txEnable); 2155 SERIALIZE_SCALAR(CTDD); 2156 SERIALIZE_SCALAR(txFragPtr); 2157 SERIALIZE_SCALAR(txDescCnt); 2158 int txDmaState = this->txDmaState; 2159 SERIALIZE_SCALAR(txDmaState); 2160 2161 /* 2162 * Serialize rx state machine 2163 */ 2164 int rxState = this->rxState; 2165 SERIALIZE_SCALAR(rxState); 2166 SERIALIZE_SCALAR(rxEnable); 2167 SERIALIZE_SCALAR(CRDD); 2168 SERIALIZE_SCALAR(rxPktBytes); 2169 SERIALIZE_SCALAR(rxDescCnt); 2170 int rxDmaState = this->rxDmaState; 2171 SERIALIZE_SCALAR(rxDmaState); 2172 2173 SERIALIZE_SCALAR(extstsEnable); 2174 2175 /* 2176 * If there's a pending transmit, store the time so we can 2177 * reschedule it later 2178 */ 2179 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2180 SERIALIZE_SCALAR(transmitTick); 2181 2182 /* 2183 * receive address filter settings 2184 */ 2185 SERIALIZE_SCALAR(rxFilterEnable); 2186 SERIALIZE_SCALAR(acceptBroadcast); 2187 SERIALIZE_SCALAR(acceptMulticast); 2188 SERIALIZE_SCALAR(acceptUnicast); 2189 SERIALIZE_SCALAR(acceptPerfect); 2190 SERIALIZE_SCALAR(acceptArp); 2191 2192 /* 2193 * Keep track of pending interrupt status. 2194 */ 2195 SERIALIZE_SCALAR(intrTick); 2196 SERIALIZE_SCALAR(cpuPendingIntr); 2197 Tick intrEventTick = 0; 2198 if (intrEvent) 2199 intrEventTick = intrEvent->when(); 2200 SERIALIZE_SCALAR(intrEventTick); 2201 2202} 2203 2204void 2205NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2206{ 2207 // Unserialize the PciDev base class 2208 PciDev::unserialize(cp, section); 2209 2210 UNSERIALIZE_SCALAR(regs.command); 2211 UNSERIALIZE_SCALAR(regs.config); 2212 UNSERIALIZE_SCALAR(regs.mear); 2213 UNSERIALIZE_SCALAR(regs.ptscr); 2214 UNSERIALIZE_SCALAR(regs.isr); 2215 UNSERIALIZE_SCALAR(regs.imr); 2216 UNSERIALIZE_SCALAR(regs.ier); 2217 UNSERIALIZE_SCALAR(regs.ihr); 2218 UNSERIALIZE_SCALAR(regs.txdp); 2219 UNSERIALIZE_SCALAR(regs.txdp_hi); 2220 UNSERIALIZE_SCALAR(regs.txcfg); 2221 UNSERIALIZE_SCALAR(regs.gpior); 2222 UNSERIALIZE_SCALAR(regs.rxdp); 2223 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2224 UNSERIALIZE_SCALAR(regs.rxcfg); 2225 UNSERIALIZE_SCALAR(regs.pqcr); 2226 UNSERIALIZE_SCALAR(regs.wcsr); 2227 UNSERIALIZE_SCALAR(regs.pcr); 2228 UNSERIALIZE_SCALAR(regs.rfcr); 2229 UNSERIALIZE_SCALAR(regs.rfdr); 2230 UNSERIALIZE_SCALAR(regs.srr); 2231 UNSERIALIZE_SCALAR(regs.mibc); 2232 UNSERIALIZE_SCALAR(regs.vrcr); 2233 UNSERIALIZE_SCALAR(regs.vtcr); 2234 UNSERIALIZE_SCALAR(regs.vdr); 2235 UNSERIALIZE_SCALAR(regs.ccsr); 2236 UNSERIALIZE_SCALAR(regs.tbicr); 2237 UNSERIALIZE_SCALAR(regs.tbisr); 2238 UNSERIALIZE_SCALAR(regs.tanar); 2239 UNSERIALIZE_SCALAR(regs.tanlpar); 2240 UNSERIALIZE_SCALAR(regs.taner); 2241 UNSERIALIZE_SCALAR(regs.tesr); 2242 2243 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2244 2245 UNSERIALIZE_SCALAR(ioEnable); 2246 2247 /* 2248 * unserialize the data fifos 2249 */ 2250 rxFifo.unserialize("rxFifo", cp, section); 2251 txFifo.unserialize("txFifo", cp, section); 2252 2253 /* 2254 * unserialize the various helper variables 2255 */ 2256 bool txPacketExists; 2257 UNSERIALIZE_SCALAR(txPacketExists); 2258 if (txPacketExists) { 2259 txPacket = new PacketData; 2260 txPacket->unserialize("txPacket", cp, section); 2261 uint32_t txPktBufPtr; 2262 UNSERIALIZE_SCALAR(txPktBufPtr); 2263 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2264 } else 2265 txPacket = 0; 2266 2267 bool rxPacketExists; 2268 UNSERIALIZE_SCALAR(rxPacketExists); 2269 rxPacket = 0; 2270 if (rxPacketExists) { 2271 rxPacket = new PacketData; 2272 rxPacket->unserialize("rxPacket", cp, section); 2273 uint32_t rxPktBufPtr; 2274 UNSERIALIZE_SCALAR(rxPktBufPtr); 2275 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2276 } else 2277 rxPacket = 0; 2278 2279 UNSERIALIZE_SCALAR(txXferLen); 2280 UNSERIALIZE_SCALAR(rxXferLen); 2281 2282 /* 2283 * Unserialize DescCaches 2284 */ 2285 UNSERIALIZE_SCALAR(txDescCache.link); 2286 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2287 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2288 UNSERIALIZE_SCALAR(txDescCache.extsts); 2289 UNSERIALIZE_SCALAR(rxDescCache.link); 2290 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2291 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2292 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2293 2294 /* 2295 * unserialize tx state machine 2296 */ 2297 int txState; 2298 UNSERIALIZE_SCALAR(txState); 2299 this->txState = (TxState) txState; 2300 UNSERIALIZE_SCALAR(txEnable); 2301 UNSERIALIZE_SCALAR(CTDD); 2302 UNSERIALIZE_SCALAR(txFragPtr); 2303 UNSERIALIZE_SCALAR(txDescCnt); 2304 int txDmaState; 2305 UNSERIALIZE_SCALAR(txDmaState); 2306 this->txDmaState = (DmaState) txDmaState; 2307 2308 /* 2309 * unserialize rx state machine 2310 */ 2311 int rxState; 2312 UNSERIALIZE_SCALAR(rxState); 2313 this->rxState = (RxState) rxState; 2314 UNSERIALIZE_SCALAR(rxEnable); 2315 UNSERIALIZE_SCALAR(CRDD); 2316 UNSERIALIZE_SCALAR(rxPktBytes); 2317 UNSERIALIZE_SCALAR(rxDescCnt); 2318 int rxDmaState; 2319 UNSERIALIZE_SCALAR(rxDmaState); 2320 this->rxDmaState = (DmaState) rxDmaState; 2321 2322 UNSERIALIZE_SCALAR(extstsEnable); 2323 2324 /* 2325 * If there's a pending transmit, reschedule it now 2326 */ 2327 Tick transmitTick; 2328 UNSERIALIZE_SCALAR(transmitTick); 2329 if (transmitTick) 2330 txEvent.schedule(curTick + transmitTick); 2331 2332 /* 2333 * unserialize receive address filter settings 2334 */ 2335 UNSERIALIZE_SCALAR(rxFilterEnable); 2336 UNSERIALIZE_SCALAR(acceptBroadcast); 2337 UNSERIALIZE_SCALAR(acceptMulticast); 2338 UNSERIALIZE_SCALAR(acceptUnicast); 2339 UNSERIALIZE_SCALAR(acceptPerfect); 2340 UNSERIALIZE_SCALAR(acceptArp); 2341 2342 /* 2343 * Keep track of pending interrupt status. 2344 */ 2345 UNSERIALIZE_SCALAR(intrTick); 2346 UNSERIALIZE_SCALAR(cpuPendingIntr); 2347 Tick intrEventTick; 2348 UNSERIALIZE_SCALAR(intrEventTick); 2349 if (intrEventTick) { 2350 intrEvent = new IntrEvent(this, true); 2351 intrEvent->schedule(intrEventTick); 2352 } 2353 2354 /* 2355 * re-add addrRanges to bus bridges 2356 */ 2357 if (pioInterface) { 2358 pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 2359 pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); 2360 } 2361} 2362 2363Tick 2364NSGigE::cacheAccess(MemReqPtr &req) 2365{ 2366 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2367 req->paddr, req->paddr - addr); 2368 return curTick + pioLatency; 2369} 2370 2371BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2372 2373 SimObjectParam<EtherInt *> peer; 2374 SimObjectParam<NSGigE *> device; 2375 2376END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2377 2378BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2379 2380 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2381 INIT_PARAM(device, "Ethernet device of this interface") 2382 2383END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2384 2385CREATE_SIM_OBJECT(NSGigEInt) 2386{ 2387 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2388 2389 EtherInt *p = (EtherInt *)peer; 2390 if (p) { 2391 dev_int->setPeer(p); 2392 p->setPeer(dev_int); 2393 } 2394 2395 return dev_int; 2396} 2397 2398REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2399 2400 2401BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2402 2403 Param<Tick> tx_delay; 2404 Param<Tick> rx_delay; 2405 Param<Tick> intr_delay; 2406 SimObjectParam<MemoryController *> mmu; 2407 SimObjectParam<PhysicalMemory *> physmem; 2408 Param<bool> rx_filter; 2409 Param<string> hardware_address; 2410 SimObjectParam<Bus*> header_bus; 2411 SimObjectParam<Bus*> payload_bus; 2412 SimObjectParam<HierParams *> hier; 2413 Param<Tick> pio_latency; 2414 Param<bool> dma_desc_free; 2415 Param<bool> dma_data_free; 2416 Param<Tick> dma_read_delay; 2417 Param<Tick> dma_write_delay; 2418 Param<Tick> dma_read_factor; 2419 Param<Tick> dma_write_factor; 2420 SimObjectParam<PciConfigAll *> configspace; 2421 SimObjectParam<PciConfigData *> configdata; 2422 SimObjectParam<Platform *> platform; 2423 Param<uint32_t> pci_bus; 2424 Param<uint32_t> pci_dev; 2425 Param<uint32_t> pci_func; 2426 Param<uint32_t> tx_fifo_size; 2427 Param<uint32_t> rx_fifo_size; 2428 2429END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2430 2431BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2432 2433 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2434 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2435 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2436 INIT_PARAM(mmu, "Memory Controller"), 2437 INIT_PARAM(physmem, "Physical Memory"), 2438 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2439 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2440 "00:99:00:00:00:01"), 2441 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2442 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2443 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2444 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2445 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2446 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2447 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2448 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2449 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2450 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2451 INIT_PARAM(configspace, "PCI Configspace"), 2452 INIT_PARAM(configdata, "PCI Config data"), 2453 INIT_PARAM(platform, "Platform"), 2454 INIT_PARAM(pci_bus, "PCI bus"), 2455 INIT_PARAM(pci_dev, "PCI device number"), 2456 INIT_PARAM(pci_func, "PCI function code"), 2457 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2458 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) 2459 2460END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2461 2462 2463CREATE_SIM_OBJECT(NSGigE) 2464{ 2465 NSGigE::Params *params = new NSGigE::Params; 2466 2467 params->name = getInstanceName(); 2468 params->mmu = mmu; 2469 params->configSpace = configspace; 2470 params->configData = configdata; 2471 params->plat = platform; 2472 params->busNum = pci_bus; 2473 params->deviceNum = pci_dev; 2474 params->functionNum = pci_func; 2475 2476 params->intr_delay = intr_delay; 2477 params->pmem = physmem; 2478 params->tx_delay = tx_delay; 2479 params->rx_delay = rx_delay; 2480 params->hier = hier; 2481 params->header_bus = header_bus; 2482 params->payload_bus = payload_bus; 2483 params->pio_latency = pio_latency; 2484 params->dma_desc_free = dma_desc_free; 2485 params->dma_data_free = dma_data_free; 2486 params->dma_read_delay = dma_read_delay; 2487 params->dma_write_delay = dma_write_delay; 2488 params->dma_read_factor = dma_read_factor; 2489 params->dma_write_factor = dma_write_factor; 2490 params->rx_filter = rx_filter; 2491 params->eaddr = hardware_address; 2492 params->tx_fifo_size = tx_fifo_size; 2493 params->rx_fifo_size = rx_fifo_size; 2494 return new NSGigE(params); 2495} 2496 2497REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2498