ns_gige.cc revision 1224
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> 369364Snilay@cs.wisc.edu 377055Snate@binkert.org#include "base/inet.hh" 386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh" 396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh" 408191SLisa.Hsu@amd.com#include "dev/dma.hh" 416882SBrad.Beckmann@amd.com#include "dev/etherlink.hh" 426882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 439102SNuwan.Jayasena@amd.com#include "dev/pciconfigall.hh" 449366Snilay@cs.wisc.edu#include "mem/bus/bus.hh" 459366Snilay@cs.wisc.edu#include "mem/bus/dma_interface.hh" 466882SBrad.Beckmann@amd.com#include "mem/bus/pio_interface.hh" 476882SBrad.Beckmann@amd.com#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" 516657Snate@binkert.org#include "sim/debug.hh" 526657Snate@binkert.org#include "sim/host.hh" 539366Snilay@cs.wisc.edu#include "sim/stats.hh" 547839Snilay@cs.wisc.edu#include "targetarch/vtophys.hh" 556657Snate@binkert.org 566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] = 576882SBrad.Beckmann@amd.com{ 586882SBrad.Beckmann@amd.com "rxIdle", 596882SBrad.Beckmann@amd.com "rxDescRefr", 606882SBrad.Beckmann@amd.com "rxDescRead", 616882SBrad.Beckmann@amd.com "rxFifoBlock", 626657Snate@binkert.org "rxFragWrite", 639366Snilay@cs.wisc.edu "rxDescWrite", 649366Snilay@cs.wisc.edu "rxAdvance" 656657Snate@binkert.org}; 666657Snate@binkert.org 676657Snate@binkert.orgconst char *NsTxStateStrings[] = 686657Snate@binkert.org{ 699104Shestness@cs.utexas.edu "txIdle", 706657Snate@binkert.org "txDescRefr", 716657Snate@binkert.org "txDescRead", 726657Snate@binkert.org "txFifoBlock", 736657Snate@binkert.org "txFragRead", 747839Snilay@cs.wisc.edu "txDescWrite", 757839Snilay@cs.wisc.edu "txAdvance" 769366Snilay@cs.wisc.edu}; 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 906657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 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), 966779SBrad.Beckmann@amd.com 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), 1069104Shestness@cs.utexas.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1079104Shestness@cs.utexas.edu rxKickTick(0), txKickTick(0), 1089104Shestness@cs.utexas.edu txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), 1099104Shestness@cs.utexas.edu 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) { 1156657Snate@binkert.org pioInterface = newPioInterface(name(), p->hier, 1166657Snate@binkert.org p->header_bus, this, 1176657Snate@binkert.org &NSGigE::cacheAccess); 1186657Snate@binkert.org 1196657Snate@binkert.org pioLatency = p->pio_latency * p->header_bus->clockRatio; 1206657Snate@binkert.org 1216657Snate@binkert.org if (p->payload_bus) 1226657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1236657Snate@binkert.org p->header_bus, 1246657Snate@binkert.org 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) { 1307839Snilay@cs.wisc.edu pioInterface = newPioInterface(name(), p->hier, 1317839Snilay@cs.wisc.edu p->payload_bus, this, 1327839Snilay@cs.wisc.edu &NSGigE::cacheAccess); 1337839Snilay@cs.wisc.edu 1347839Snilay@cs.wisc.edu pioLatency = p->pio_latency * p->payload_bus->clockRatio; 1357839Snilay@cs.wisc.edu 1367839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1377839Snilay@cs.wisc.edu p->payload_bus, 1387839Snilay@cs.wisc.edu p->payload_bus, 1); 1397839Snilay@cs.wisc.edu } 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") 1616657Snate@binkert.org .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) 1686657Snate@binkert.org ; 1696657Snate@binkert.org 1709219Spower.jg@gmail.com txPackets 1716877Ssteve.reinhardt@amd.com .name(name() + ".txPackets") 1726657Snate@binkert.org .desc("Number of Packets Transmitted") 1739219Spower.jg@gmail.com .prereq(txBytes) 1746657Snate@binkert.org ; 1759219Spower.jg@gmail.com 1766657Snate@binkert.org rxPackets 1776657Snate@binkert.org .name(name() + ".rxPackets") 1787542SBrad.Beckmann@amd.com .desc("Number of Packets Received") 1797542SBrad.Beckmann@amd.com .prereq(rxBytes) 1806657Snate@binkert.org ; 1816877Ssteve.reinhardt@amd.com 1826999Snate@binkert.org 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") 1926877Ssteve.reinhardt@amd.com .precision(0) 1939338SAndreas.Sandberg@arm.com .prereq(rxBytes) 1946877Ssteve.reinhardt@amd.com ; 1956877Ssteve.reinhardt@amd.com 1966877Ssteve.reinhardt@amd.com txTcpChecksums 1976877Ssteve.reinhardt@amd.com .name(name() + ".txTcpChecksums") 1986877Ssteve.reinhardt@amd.com .desc("Number of tx TCP Checksums done by device") 1996877Ssteve.reinhardt@amd.com .precision(0) 2006882SBrad.Beckmann@amd.com .prereq(txBytes) 2016882SBrad.Beckmann@amd.com ; 2026882SBrad.Beckmann@amd.com 2036882SBrad.Beckmann@amd.com rxTcpChecksums 2046882SBrad.Beckmann@amd.com .name(name() + ".rxTcpChecksums") 2056882SBrad.Beckmann@amd.com .desc("Number of rx TCP Checksums done by device") 2066882SBrad.Beckmann@amd.com .precision(0) 2076877Ssteve.reinhardt@amd.com .prereq(rxBytes) 2086877Ssteve.reinhardt@amd.com ; 2096877Ssteve.reinhardt@amd.com 2106877Ssteve.reinhardt@amd.com txUdpChecksums 2116657Snate@binkert.org .name(name() + ".txUdpChecksums") 2126657Snate@binkert.org .desc("Number of tx UDP Checksums done by device") 2136999Snate@binkert.org .precision(0) 2146657Snate@binkert.org .prereq(txBytes) 2156657Snate@binkert.org ; 2166657Snate@binkert.org 2176657Snate@binkert.org rxUdpChecksums 2186657Snate@binkert.org .name(name() + ".rxUdpChecksums") 2196657Snate@binkert.org .desc("Number of rx UDP Checksums done by device") 2207007Snate@binkert.org .precision(0) 2216657Snate@binkert.org .prereq(rxBytes) 2226657Snate@binkert.org ; 2236657Snate@binkert.org 2246657Snate@binkert.org descDmaReads 2256657Snate@binkert.org .name(name() + ".descDMAReads") 2267007Snate@binkert.org .desc("Number of descriptors the device read w/ DMA") 2277007Snate@binkert.org .precision(0) 2286657Snate@binkert.org ; 2297002Snate@binkert.org 2307002Snate@binkert.org descDmaWrites 2317002Snate@binkert.org .name(name() + ".descDMAWrites") 2327002Snate@binkert.org .desc("Number of descriptors the device wrote w/ DMA") 2338229Snate@binkert.org .precision(0) 2348229Snate@binkert.org ; 2356657Snate@binkert.org 2366657Snate@binkert.org descDmaRdBytes 2378229Snate@binkert.org .name(name() + ".descDmaReadBytes") 2388229Snate@binkert.org .desc("number of descriptor bytes read w/ DMA") 2398229Snate@binkert.org .precision(0) 2408229Snate@binkert.org ; 2416657Snate@binkert.org 2426657Snate@binkert.org descDmaWrBytes 2436657Snate@binkert.org .name(name() + ".descDmaWriteBytes") 2446657Snate@binkert.org .desc("number of descriptor bytes write w/ DMA") 2456793SBrad.Beckmann@amd.com .precision(0) 2466657Snate@binkert.org ; 2476657Snate@binkert.org 2486657Snate@binkert.org 2496657Snate@binkert.org txBandwidth 2506657Snate@binkert.org .name(name() + ".txBandwidth") 2517002Snate@binkert.org .desc("Transmit Bandwidth (bits/s)") 2526657Snate@binkert.org .precision(0) 2537007Snate@binkert.org .prereq(txBytes) 2547007Snate@binkert.org ; 2559271Snilay@cs.wisc.edu 2566877Ssteve.reinhardt@amd.com rxBandwidth 2576877Ssteve.reinhardt@amd.com .name(name() + ".rxBandwidth") 2586657Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 2596877Ssteve.reinhardt@amd.com .precision(0) 2606657Snate@binkert.org .prereq(rxBytes) 2616657Snate@binkert.org ; 2627002Snate@binkert.org 2637002Snate@binkert.org txPacketRate 2647567SBrad.Beckmann@amd.com .name(name() + ".txPPS") 2657567SBrad.Beckmann@amd.com .desc("Packet Tranmission Rate (packets/s)") 2667922SBrad.Beckmann@amd.com .precision(0) 2676881SBrad.Beckmann@amd.com .prereq(txBytes) 2687002Snate@binkert.org ; 2696657Snate@binkert.org 2707002Snate@binkert.org rxPacketRate 2716902SBrad.Beckmann@amd.com .name(name() + ".rxPPS") 2726863Sdrh5@cs.wisc.edu .desc("Packet Reception Rate (packets/s)") 2736863Sdrh5@cs.wisc.edu .precision(0) 2748683Snilay@cs.wisc.edu .prereq(rxBytes) 2758683Snilay@cs.wisc.edu ; 2767007Snate@binkert.org 2779302Snilay@cs.wisc.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2789302Snilay@cs.wisc.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2799302Snilay@cs.wisc.edu txPacketRate = txPackets / simSeconds; 2806657Snate@binkert.org rxPacketRate = rxPackets / simSeconds; 2816657Snate@binkert.org} 2826657Snate@binkert.org 2836657Snate@binkert.org/** 2846657Snate@binkert.org * This is to read the PCI general configuration registers 2856657Snate@binkert.org */ 2866882SBrad.Beckmann@amd.comvoid 2876882SBrad.Beckmann@amd.comNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2886882SBrad.Beckmann@amd.com{ 2896882SBrad.Beckmann@amd.com if (offset < PCI_DEVICE_SPECIFIC) 2906657Snate@binkert.org PciDev::ReadConfig(offset, size, data); 2916657Snate@binkert.org else 2927007Snate@binkert.org 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 2997839Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 3007839Snilay@cs.wisc.edu{ 3017839Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 3027839Snilay@cs.wisc.edu PciDev::WriteConfig(offset, size, data); 3037839Snilay@cs.wisc.edu else 3047839Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 3057007Snate@binkert.org 3067007Snate@binkert.org // Need to catch writes to BARs to update the PIO interface 3077007Snate@binkert.org switch (offset) { 3087007Snate@binkert.org // seems to work fine without all these PCI settings, but i 3097007Snate@binkert.org // 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; 3167839Snilay@cs.wisc.edu 3177839Snilay@cs.wisc.edu#if 0 3187839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_BME) { 3197839Snilay@cs.wisc.edu bmEnabled = true; 3207839Snilay@cs.wisc.edu } 3217839Snilay@cs.wisc.edu else { 3227007Snate@binkert.org bmEnabled = false; 3237007Snate@binkert.org } 3247542SBrad.Beckmann@amd.com 3257542SBrad.Beckmann@amd.com if (config.data[offset] & PCI_CMD_MSE) { 3266657Snate@binkert.org memEnable = true; 3277007Snate@binkert.org } 3286657Snate@binkert.org else { 3296657Snate@binkert.org memEnable = false; 3306657Snate@binkert.org } 3316657Snate@binkert.org#endif 3326657Snate@binkert.org break; 3336657Snate@binkert.org 3346657Snate@binkert.org case PCI0_BASE_ADDR0: 3356657Snate@binkert.org if (BARAddrs[0] != 0) { 3367839Snilay@cs.wisc.edu if (pioInterface) 3377839Snilay@cs.wisc.edu pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 3387839Snilay@cs.wisc.edu 3397839Snilay@cs.wisc.edu BARAddrs[0] &= EV5::PAddrUncachedMask; 3407839Snilay@cs.wisc.edu } 3417839Snilay@cs.wisc.edu break; 3427839Snilay@cs.wisc.edu case PCI0_BASE_ADDR1: 3437839Snilay@cs.wisc.edu if (BARAddrs[1] != 0) { 3447839Snilay@cs.wisc.edu 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 } 3517839Snilay@cs.wisc.edu} 3526657Snate@binkert.org 3536657Snate@binkert.org/** 3546657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820 3556657Snate@binkert.org * 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 3637839Snilay@cs.wisc.edu Addr daddr = req->paddr & 0xfff; 3647839Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3657839Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 3667839Snilay@cs.wisc.edu 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"); 3726657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 3736657Snate@binkert.org ReadConfig(daddr & 0xff, req->size, data); 3746657Snate@binkert.org return No_Fault; 3756657Snate@binkert.org } else if (daddr >= MIB_START && daddr <= MIB_END) { 3767007Snate@binkert.org // don't implement all the MIB's. hopefully the kernel 3776657Snate@binkert.org // doesn't actually DEPEND upon their values 3786657Snate@binkert.org // MIB are just hardware stats keepers 3799273Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *) data; 3806657Snate@binkert.org reg = 0; 3816657Snate@binkert.org return No_Fault; 3826657Snate@binkert.org } 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 3909219Spower.jg@gmail.com switch (daddr) { 3916657Snate@binkert.org case CR: 3926657Snate@binkert.org reg = regs.command; 3936999Snate@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; 4048946Sandreas.hansson@arm.com 4058946Sandreas.hansson@arm.com case PTSCR: 4068946Sandreas.hansson@arm.com reg = regs.ptscr; 4077832Snate@binkert.org break; 4087002Snate@binkert.org 4097002Snate@binkert.org case ISR: 4107002Snate@binkert.org reg = regs.isr; 4118641Snate@binkert.org devIntrClear(ISR_ALL); 4127056Snate@binkert.org break; 4138232Snate@binkert.org 4148232Snate@binkert.org case IMR: 4156657Snate@binkert.org reg = regs.imr; 4168229Snate@binkert.org break; 4176657Snate@binkert.org 4186657Snate@binkert.org case IER: 4197056Snate@binkert.org reg = regs.ier; 4206657Snate@binkert.org break; 4219219Spower.jg@gmail.com 4229219Spower.jg@gmail.com case IHR: 4239219Spower.jg@gmail.com reg = regs.ihr; 4249219Spower.jg@gmail.com break; 4259219Spower.jg@gmail.com 4267002Snate@binkert.org case TXDP: 4277002Snate@binkert.org reg = regs.txdp; 4286657Snate@binkert.org break; 4296657Snate@binkert.org 4306657Snate@binkert.org case TXDP_HI: 4316657Snate@binkert.org reg = regs.txdp_hi; 4326657Snate@binkert.org break; 4336793SBrad.Beckmann@amd.com 4346657Snate@binkert.org case TXCFG: 4356657Snate@binkert.org reg = regs.txcfg; 4366657Snate@binkert.org break; 4376657Snate@binkert.org 4386877Ssteve.reinhardt@amd.com 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; 4446657Snate@binkert.org break; 4457542SBrad.Beckmann@amd.com 4466657Snate@binkert.org case RXDP_HI: 4477007Snate@binkert.org reg = regs.rxdp_hi; 4486657Snate@binkert.org break; 4496657Snate@binkert.org 4507007Snate@binkert.org case RXCFG: 4516657Snate@binkert.org reg = regs.rxcfg; 4526877Ssteve.reinhardt@amd.com break; 4536877Ssteve.reinhardt@amd.com 4546657Snate@binkert.org case PQCR: 4558532SLisa.Hsu@amd.com reg = regs.pqcr; 4566657Snate@binkert.org break; 4577567SBrad.Beckmann@amd.com 4587567SBrad.Beckmann@amd.com case WCSR: 4597567SBrad.Beckmann@amd.com reg = regs.wcsr; 4607567SBrad.Beckmann@amd.com break; 4617567SBrad.Beckmann@amd.com 4627567SBrad.Beckmann@amd.com case PCR: 4636657Snate@binkert.org reg = regs.pcr; 4646882SBrad.Beckmann@amd.com break; 4656882SBrad.Beckmann@amd.com 4666882SBrad.Beckmann@amd.com // see the spec sheet for how RFCR and RFDR work 4676882SBrad.Beckmann@amd.com // basically, you write to RFCR to tell the machine 4686882SBrad.Beckmann@amd.com // what you want to do next, then you act upon RFDR, 4696882SBrad.Beckmann@amd.com // and the device will be prepared b/c of what you 4706882SBrad.Beckmann@amd.com // wrote to RFCR 4718189SLisa.Hsu@amd.com case RFCR: 4728189SLisa.Hsu@amd.com reg = regs.rfcr; 4736877Ssteve.reinhardt@amd.com break; 4748189SLisa.Hsu@amd.com 4758189SLisa.Hsu@amd.com case RFDR: 4768189SLisa.Hsu@amd.com switch (regs.rfcr & RFCR_RFADDR) { 4778189SLisa.Hsu@amd.com case 0x000: 4786882SBrad.Beckmann@amd.com reg = rom.perfectMatch[1]; 4796882SBrad.Beckmann@amd.com reg = reg << 8; 4806882SBrad.Beckmann@amd.com reg += rom.perfectMatch[0]; 4816882SBrad.Beckmann@amd.com break; 4826882SBrad.Beckmann@amd.com case 0x002: 4836882SBrad.Beckmann@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; 4888189SLisa.Hsu@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"); 4928189SLisa.Hsu@amd.com // didn't implement other RFDR functionality b/c 4938189SLisa.Hsu@amd.com // driver didn't use it 4948189SLisa.Hsu@amd.com } 4958189SLisa.Hsu@amd.com break; 4968938SLisa.Hsu@amd.com 4978938SLisa.Hsu@amd.com case SRR: 4988938SLisa.Hsu@amd.com reg = regs.srr; 4998938SLisa.Hsu@amd.com break; 5008938SLisa.Hsu@amd.com 5018938SLisa.Hsu@amd.com case MIBC: 5028938SLisa.Hsu@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: 5076888SBrad.Beckmann@amd.com reg = regs.vrcr; 5088189SLisa.Hsu@amd.com break; 5096888SBrad.Beckmann@amd.com 5106888SBrad.Beckmann@amd.com case VTCR: 5116657Snate@binkert.org reg = regs.vtcr; 5126888SBrad.Beckmann@amd.com break; 5136888SBrad.Beckmann@amd.com 5146888SBrad.Beckmann@amd.com case VDR: 5156888SBrad.Beckmann@amd.com 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; 5246657Snate@binkert.org break; 5257007Snate@binkert.org 5267007Snate@binkert.org case TBISR: 5276657Snate@binkert.org reg = regs.tbisr; 5287007Snate@binkert.org break; 5297007Snate@binkert.org 5307007Snate@binkert.org case TANAR: 5316657Snate@binkert.org reg = regs.tanar; 5326657Snate@binkert.org break; 5336657Snate@binkert.org 5347007Snate@binkert.org case TANLPAR: 5357542SBrad.Beckmann@amd.com reg = regs.tanlpar; 5367542SBrad.Beckmann@amd.com break; 5377007Snate@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: 5569273Snilay@cs.wisc.edu panic("accessing register with invalid size: addr=%#x, size=%d", 5576657Snate@binkert.org daddr, req->size); 5586657Snate@binkert.org } 5596657Snate@binkert.org 5609364Snilay@cs.wisc.edu return No_Fault; 5617007Snate@binkert.org} 5626657Snate@binkert.org 5636657Snate@binkert.orgFault 5646657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data) 5656657Snate@binkert.org{ 5667007Snate@binkert.org assert(ioEnable); 5676657Snate@binkert.org 5687007Snate@binkert.org Addr daddr = req->paddr & 0xfff; 5697007Snate@binkert.org DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5706657Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 5716657Snate@binkert.org 5726657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 5736657Snate@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) { 5857566SBrad.Beckmann@amd.com case CR: 5866657Snate@binkert.org regs.command = reg; 5876657Snate@binkert.org if (reg & CR_TXD) { 5886657Snate@binkert.org txEnable = false; 5896657Snate@binkert.org } else if (reg & CR_TXE) { 5906657Snate@binkert.org txEnable = true; 5918308Stushar@csail.mit.edu 5926657Snate@binkert.org // the kernel is enabling the transmit machine 5936657Snate@binkert.org if (txState == txIdle) 5946657Snate@binkert.org txKick(); 5957007Snate@binkert.org } 5967007Snate@binkert.org 5978308Stushar@csail.mit.edu if (reg & CR_RXD) { 5986657Snate@binkert.org rxEnable = false; 5996657Snate@binkert.org } else if (reg & CR_RXE) { 6006657Snate@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) 6108187SLisa.Hsu@amd.com rxReset(); 6116657Snate@binkert.org 6126657Snate@binkert.org if (reg & CR_SWI) 6136657Snate@binkert.org 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(); 6207454Snate@binkert.org } 6216657Snate@binkert.org break; 6226657Snate@binkert.org 6236657Snate@binkert.org case CFG: 6246657Snate@binkert.org if (reg & CFG_LNKSTS || 6257007Snate@binkert.org reg & CFG_SPDSTS || 6267056Snate@binkert.org reg & CFG_DUPSTS || 6277007Snate@binkert.org reg & CFG_RESERVED || 6287007Snate@binkert.org reg & CFG_T64ADDR || 6296657Snate@binkert.org reg & CFG_PCI64_DET) 6307566SBrad.Beckmann@amd.com panic("writing to read-only or reserved CFG bits!\n"); 6317566SBrad.Beckmann@amd.com 6327566SBrad.Beckmann@amd.com 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 6369366Snilay@cs.wisc.edu// have these implemented. if there is a problem relating to one of 6379366Snilay@cs.wisc.edu// these, you may need to add functionality in. 6389366Snilay@cs.wisc.edu#if 0 6399366Snilay@cs.wisc.edu if (reg & CFG_TBI_EN) ; 6407566SBrad.Beckmann@amd.com if (reg & CFG_MODE_1000) ; 6416657Snate@binkert.org#endif 6427672Snate@binkert.org 6436657Snate@binkert.org if (reg & CFG_AUTO_1000) 6446657Snate@binkert.org panic("CFG_AUTO_1000 not implemented!\n"); 6456657Snate@binkert.org 6466657Snate@binkert.org#if 0 6477672Snate@binkert.org if (reg & CFG_PINT_DUPSTS || 6486657Snate@binkert.org reg & CFG_PINT_LNKSTS || 6497056Snate@binkert.org reg & CFG_PINT_SPDSTS) 6506657Snate@binkert.org ; 6516657Snate@binkert.org 6527672Snate@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) ; 6636657Snate@binkert.org if (reg & CFG_M64ADDR) ; 6647542SBrad.Beckmann@amd.com 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) ; 6798683Snilay@cs.wisc.edu if (reg & CFG_BROM_DIS) ; 6808683Snilay@cs.wisc.edu if (reg & CFG_EXT_125) ; 6818683Snilay@cs.wisc.edu if (reg & CFG_BEM) ; 6828683Snilay@cs.wisc.edu#endif 6838683Snilay@cs.wisc.edu break; 6848683Snilay@cs.wisc.edu 6856657Snate@binkert.org case MEAR: 6867007Snate@binkert.org regs.mear = reg; 6877007Snate@binkert.org // since phy is completely faked, MEAR_MD* don't matter 6887007Snate@binkert.org // and since the driver never uses MEAR_EE*, they don't 6896657Snate@binkert.org // matter 6906657Snate@binkert.org#if 0 6916657Snate@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) ; 6947007Snate@binkert.org if (reg & MEAR_EESEL) ; 6956657Snate@binkert.org if (reg & MEAR_MDIO) ; 6966657Snate@binkert.org if (reg & MEAR_MDDIR) ; 6976657Snate@binkert.org if (reg & MEAR_MDC) ; 6988683Snilay@cs.wisc.edu#endif 6998683Snilay@cs.wisc.edu break; 7008683Snilay@cs.wisc.edu 7018683Snilay@cs.wisc.edu case PTSCR: 7028683Snilay@cs.wisc.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 7038683Snilay@cs.wisc.edu // 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) 7067007Snate@binkert.org regs.ptscr |= PTSCR_RBIST_DONE; 7076657Snate@binkert.org if (reg & PTSCR_EEBIST_EN) 7086657Snate@binkert.org regs.ptscr &= ~PTSCR_EEBIST_EN; 7096657Snate@binkert.org if (reg & PTSCR_EELOAD_EN) 7107007Snate@binkert.org regs.ptscr &= ~PTSCR_EELOAD_EN; 7117007Snate@binkert.org break; 7127007Snate@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"); 7156657Snate@binkert.org 7167007Snate@binkert.org case IMR: 7177007Snate@binkert.org regs.imr = reg; 7187007Snate@binkert.org devIntrChangeMask(); 7196657Snate@binkert.org break; 7206657Snate@binkert.org 7217007Snate@binkert.org case IER: 7227007Snate@binkert.org 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; 7297567SBrad.Beckmann@amd.com 7307567SBrad.Beckmann@amd.com case TXDP: 7317567SBrad.Beckmann@amd.com regs.txdp = (reg & 0xFFFFFFFC); 7327567SBrad.Beckmann@amd.com assert(txState == txIdle); 7337567SBrad.Beckmann@amd.com CTDD = false; 7347567SBrad.Beckmann@amd.com break; 7357567SBrad.Beckmann@amd.com 7368155Snilay@cs.wisc.edu case TXDP_HI: 7378155Snilay@cs.wisc.edu regs.txdp_hi = reg; 7388155Snilay@cs.wisc.edu break; 7398155Snilay@cs.wisc.edu 7408155Snilay@cs.wisc.edu case TXCFG: 7418155Snilay@cs.wisc.edu regs.txcfg = reg; 7428155Snilay@cs.wisc.edu#if 0 7438155Snilay@cs.wisc.edu if (reg & TXCFG_CSI) ; 7448155Snilay@cs.wisc.edu if (reg & TXCFG_HBI) ; 7458155Snilay@cs.wisc.edu if (reg & TXCFG_MLB) ; 7468155Snilay@cs.wisc.edu if (reg & TXCFG_ATP) ; 7477567SBrad.Beckmann@amd.com if (reg & TXCFG_ECRETRY) { 7488155Snilay@cs.wisc.edu /* 7498155Snilay@cs.wisc.edu * this could easily be implemented, but considering 7507567SBrad.Beckmann@amd.com * the network is just a fake pipe, wouldn't make 7517567SBrad.Beckmann@amd.com * sense to do this 7527567SBrad.Beckmann@amd.com */ 7537567SBrad.Beckmann@amd.com } 7547922SBrad.Beckmann@amd.com 7557922SBrad.Beckmann@amd.com if (reg & TXCFG_BRST_DIS) ; 7567922SBrad.Beckmann@amd.com#endif 7577922SBrad.Beckmann@amd.com 7587922SBrad.Beckmann@amd.com#if 0 7597922SBrad.Beckmann@amd.com /* we handle our own DMA, ignore the kernel's exhortations */ 7607922SBrad.Beckmann@amd.com if (reg & TXCFG_MXDMA) ; 7617922SBrad.Beckmann@amd.com#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: 7768154Snilay@cs.wisc.edu regs.rxdp = reg; 7778154Snilay@cs.wisc.edu CRDD = false; 7788154Snilay@cs.wisc.edu break; 7798154Snilay@cs.wisc.edu 7808154Snilay@cs.wisc.edu case RXDP_HI: 7818154Snilay@cs.wisc.edu regs.rxdp_hi = reg; 7828154Snilay@cs.wisc.edu break; 7837922SBrad.Beckmann@amd.com 7847922SBrad.Beckmann@amd.com case RXCFG: 7857922SBrad.Beckmann@amd.com regs.rxcfg = reg; 7867922SBrad.Beckmann@amd.com#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) ; 7927007Snate@binkert.org if (reg & RXCFG_AIRL) ; 7937007Snate@binkert.org 7947007Snate@binkert.org /* we handle our own DMA, ignore what kernel says about it */ 7957007Snate@binkert.org if (reg & RXCFG_MXDMA) ; 7966863Sdrh5@cs.wisc.edu 7976863Sdrh5@cs.wisc.edu //also, we currently don't care about fill/drain thresholds 7986863Sdrh5@cs.wisc.edu //though this may change in the future with more realistic 7996863Sdrh5@cs.wisc.edu //networks or a driver which changes it according to feedback 8006863Sdrh5@cs.wisc.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 8016863Sdrh5@cs.wisc.edu#endif 8027007Snate@binkert.org break; 8037007Snate@binkert.org 8047007Snate@binkert.org case PQCR: 8057007Snate@binkert.org /* there is no priority queueing used in the linux 2.6 driver */ 8067007Snate@binkert.org regs.pqcr = reg; 8076657Snate@binkert.org break; 8087007Snate@binkert.org 8097007Snate@binkert.org case WCSR: 8107007Snate@binkert.org /* not going to implement wake on LAN */ 8116902SBrad.Beckmann@amd.com regs.wcsr = reg; 8126902SBrad.Beckmann@amd.com break; 8136902SBrad.Beckmann@amd.com 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; 8187025SBrad.Beckmann@amd.com 8196902SBrad.Beckmann@amd.com case RFCR: 8206902SBrad.Beckmann@amd.com regs.rfcr = reg; 8216902SBrad.Beckmann@amd.com 8226902SBrad.Beckmann@amd.com rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8236902SBrad.Beckmann@amd.com acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8247542SBrad.Beckmann@amd.com acceptMulticast = (reg & RFCR_AAM) ? true : false; 8257542SBrad.Beckmann@amd.com acceptUnicast = (reg & RFCR_AAU) ? true : false; 8267542SBrad.Beckmann@amd.com acceptPerfect = (reg & RFCR_APM) ? true : false; 8276902SBrad.Beckmann@amd.com acceptArp = (reg & RFCR_AARP) ? true : false; 8286902SBrad.Beckmann@amd.com 8296902SBrad.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 8427542SBrad.Beckmann@amd.com case RFDR: 8436902SBrad.Beckmann@amd.com panic("the driver never writes to RFDR, something is wrong!\n"); 8447839Snilay@cs.wisc.edu 8457839Snilay@cs.wisc.edu case BRAR: 8467839Snilay@cs.wisc.edu 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; 8647839Snilay@cs.wisc.edu 8657839Snilay@cs.wisc.edu case VDR: 8667839Snilay@cs.wisc.edu panic("the driver never uses VDR, something is wrong!\n"); 8677839Snilay@cs.wisc.edu break; 8687839Snilay@cs.wisc.edu 8697839Snilay@cs.wisc.edu case CCSR: 8707839Snilay@cs.wisc.edu /* not going to implement clockrun stuff */ 8717839Snilay@cs.wisc.edu regs.ccsr = reg; 8727839Snilay@cs.wisc.edu 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; 8816902SBrad.Beckmann@amd.com regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8828683Snilay@cs.wisc.edu } 8838683Snilay@cs.wisc.edu 8848683Snilay@cs.wisc.edu#if 0 8858683Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 8868683Snilay@cs.wisc.edu#endif 8878683Snilay@cs.wisc.edu 8888683Snilay@cs.wisc.edu break; 8898683Snilay@cs.wisc.edu 8908683Snilay@cs.wisc.edu case TBISR: 8918683Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 8928683Snilay@cs.wisc.edu 8938683Snilay@cs.wisc.edu case TANAR: 8948683Snilay@cs.wisc.edu regs.tanar = reg; 8958683Snilay@cs.wisc.edu if (reg & TANAR_PS2) 8968683Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8978683Snilay@cs.wisc.edu 8988683Snilay@cs.wisc.edu if (reg & TANAR_PS1) 8996657Snate@binkert.org 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 9056657Snate@binkert.org case TANER: 9067839Snilay@cs.wisc.edu panic("TANER is read only register!\n"); 9077839Snilay@cs.wisc.edu 9087839Snilay@cs.wisc.edu case TESR: 9097839Snilay@cs.wisc.edu regs.tesr = reg; 9107839Snilay@cs.wisc.edu break; 9118055Sksewell@umich.edu 9127839Snilay@cs.wisc.edu default: 9137839Snilay@cs.wisc.edu panic("invalid register access daddr=%#x", daddr); 9146657Snate@binkert.org } 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} 9217839Snilay@cs.wisc.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) 9268055Sksewell@umich.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", 9367839Snilay@cs.wisc.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)) 9418055Sksewell@umich.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 9477839Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts) 9487839Snilay@cs.wisc.edu{ 9497839Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 9507839Snilay@cs.wisc.edu panic("Cannot clear a reserved interrupt"); 9517839Snilay@cs.wisc.edu 9526657Snate@binkert.org interrupts &= ~ISR_NOIMPL; 9537007Snate@binkert.org regs.isr &= ~interrupts; 9547007Snate@binkert.org 9556657Snate@binkert.org DPRINTF(EthernetIntr, 9568055Sksewell@umich.edu "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(); 9618478Snilay@cs.wisc.edu} 9628478Snilay@cs.wisc.edu 9638478Snilay@cs.wisc.eduvoid 9649302Snilay@cs.wisc.eduNSGigE::devIntrChangeMask() 9659302Snilay@cs.wisc.edu{ 9669302Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9679302Snilay@cs.wisc.edu regs.isr, regs.imr, regs.isr & regs.imr); 9689302Snilay@cs.wisc.edu 9699302Snilay@cs.wisc.edu if (regs.isr & regs.imr) 9709302Snilay@cs.wisc.edu cpuIntrPost(curTick); 9719302Snilay@cs.wisc.edu else 9729302Snilay@cs.wisc.edu cpuIntrClear(); 9739302Snilay@cs.wisc.edu} 9749302Snilay@cs.wisc.edu 9759302Snilay@cs.wisc.eduvoid 9769302Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when) 9779302Snilay@cs.wisc.edu{ 9789302Snilay@cs.wisc.edu // If the interrupt you want to post is later than an interrupt 9799302Snilay@cs.wisc.edu // already scheduled, just let it post in the coming one and don't 9809302Snilay@cs.wisc.edu // schedule another. 9819302Snilay@cs.wisc.edu // HOWEVER, must be sure that the scheduled intrTick is in the 9829302Snilay@cs.wisc.edu // future (this was formerly the source of a bug) 9839302Snilay@cs.wisc.edu /** 9849302Snilay@cs.wisc.edu * @todo this warning should be removed and the intrTick code should 9859302Snilay@cs.wisc.edu * be fixed. 9869302Snilay@cs.wisc.edu */ 9879302Snilay@cs.wisc.edu assert(when >= curTick); 9889302Snilay@cs.wisc.edu assert(intrTick >= curTick || intrTick == 0); 9899302Snilay@cs.wisc.edu if (when > intrTick && intrTick != 0) { 9909302Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9919302Snilay@cs.wisc.edu intrTick); 9929302Snilay@cs.wisc.edu return; 9939302Snilay@cs.wisc.edu } 9949302Snilay@cs.wisc.edu 9959302Snilay@cs.wisc.edu intrTick = when; 9969302Snilay@cs.wisc.edu if (intrTick < curTick) { 9976657Snate@binkert.org debug_break(); 9986657Snate@binkert.org intrTick = curTick; 9999219Spower.jg@gmail.com } 10006657Snate@binkert.org 10016657Snate@binkert.org DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 10026999Snate@binkert.org intrTick); 10036657Snate@binkert.org 10046657Snate@binkert.org if (intrEvent) 10059104Shestness@cs.utexas.edu intrEvent->squash(); 10069104Shestness@cs.utexas.edu intrEvent = new IntrEvent(this, true); 10079104Shestness@cs.utexas.edu intrEvent->schedule(intrTick); 10089104Shestness@cs.utexas.edu} 10096657Snate@binkert.org 10106657Snate@binkert.orgvoid 10116657Snate@binkert.orgNSGigE::cpuInterrupt() 10126657Snate@binkert.org{ 10138946Sandreas.hansson@arm.com assert(intrTick == curTick); 10148946Sandreas.hansson@arm.com 10158946Sandreas.hansson@arm.com // Whether or not there's a pending interrupt, we don't care about 10167832Snate@binkert.org // it anymore 10177832Snate@binkert.org intrEvent = 0; 10187007Snate@binkert.org intrTick = 0; 10198232Snate@binkert.org 10208229Snate@binkert.org // Don't send an interrupt if there's already one 10218229Snate@binkert.org if (cpuPendingIntr) { 10228229Snate@binkert.org DPRINTF(EthernetIntr, 10239104Shestness@cs.utexas.edu "would send an interrupt now, but there's already pending\n"); 10249104Shestness@cs.utexas.edu } else { 10259104Shestness@cs.utexas.edu // Send interrupt 10269104Shestness@cs.utexas.edu cpuPendingIntr = true; 10279104Shestness@cs.utexas.edu 10289104Shestness@cs.utexas.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 10298229Snate@binkert.org intrPost(); 10306657Snate@binkert.org } 10316657Snate@binkert.org} 10329219Spower.jg@gmail.com 10339219Spower.jg@gmail.comvoid 10349219Spower.jg@gmail.comNSGigE::cpuIntrClear() 10359219Spower.jg@gmail.com{ 10369219Spower.jg@gmail.com if (!cpuPendingIntr) 10379219Spower.jg@gmail.com return; 10389219Spower.jg@gmail.com 10396657Snate@binkert.org if (intrEvent) { 10407055Snate@binkert.org intrEvent->squash(); 10417055Snate@binkert.org intrEvent = 0; 10427007Snate@binkert.org } 10437007Snate@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(); 10507007Snate@binkert.org} 10517007Snate@binkert.org 10527007Snate@binkert.orgbool 10537007Snate@binkert.orgNSGigE::cpuIntrPending() const 10549230Snilay@cs.wisc.edu{ return cpuPendingIntr; } 10556657Snate@binkert.org 10566657Snate@binkert.orgvoid 10576657Snate@binkert.orgNSGigE::txReset() 10586657Snate@binkert.org{ 10596657Snate@binkert.org 10606657Snate@binkert.org DPRINTF(Ethernet, "transmit reset\n"); 10616657Snate@binkert.org 10626657Snate@binkert.org CTDD = false; 10636657Snate@binkert.org txEnable = false;; 10646657Snate@binkert.org txFragPtr = 0; 10656657Snate@binkert.org assert(txDescCnt == 0); 10666657Snate@binkert.org txFifo.clear(); 10677567SBrad.Beckmann@amd.com txState = txIdle; 10687567SBrad.Beckmann@amd.com assert(txDmaState == dmaIdle); 10697567SBrad.Beckmann@amd.com} 10707567SBrad.Beckmann@amd.com 10716657Snate@binkert.orgvoid 10726657Snate@binkert.orgNSGigE::rxReset() 10736657Snate@binkert.org{ 10746657Snate@binkert.org DPRINTF(Ethernet, "receive reset\n"); 10756657Snate@binkert.org 10766657Snate@binkert.org CRDD = false; 10776657Snate@binkert.org assert(rxPktBytes == 0); 10786657Snate@binkert.org rxEnable = false; 10796657Snate@binkert.org rxFragPtr = 0; 10806657Snate@binkert.org assert(rxDescCnt == 0); 10816657Snate@binkert.org assert(rxDmaState == dmaIdle); 10826657Snate@binkert.org rxFifo.clear(); 10836657Snate@binkert.org rxState = rxIdle; 10846657Snate@binkert.org} 10856657Snate@binkert.org 10866657Snate@binkert.orgvoid 10876657Snate@binkert.orgNSGigE::regsReset() 10886657Snate@binkert.org{ 10896999Snate@binkert.org memset(®s, 0, sizeof(regs)); 10906657Snate@binkert.org regs.config = CFG_LNKSTS; 10916657Snate@binkert.org regs.mear = MEAR_MDDIR | MEAR_EEDO; 10926657Snate@binkert.org regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 10936657Snate@binkert.org // fill threshold to 32 bytes 10946657Snate@binkert.org regs.rxcfg = 0x4; // set drain threshold to 16 bytes 10956657Snate@binkert.org regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 10967832Snate@binkert.org regs.mibc = MIBC_FRZ; 10977832Snate@binkert.org regs.vdr = 0x81; // set the vlan tag type to 802.1q 10987805Snilay@cs.wisc.edu regs.tesr = 0xc000; // TBI capable of both full and half duplex 10997832Snate@binkert.org 11008232Snate@binkert.org extstsEnable = false; 11018232Snate@binkert.org acceptBroadcast = false; 11028229Snate@binkert.org acceptMulticast = false; 11038229Snate@binkert.org acceptUnicast = false; 11048229Snate@binkert.org acceptPerfect = false; 11058229Snate@binkert.org acceptArp = false; 11066657Snate@binkert.org} 11076657Snate@binkert.org 11086657Snate@binkert.orgvoid 11096657Snate@binkert.orgNSGigE::rxDmaReadCopy() 11106657Snate@binkert.org{ 11116657Snate@binkert.org assert(rxDmaState == dmaReading); 11126657Snate@binkert.org 11136657Snate@binkert.org physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); 11147007Snate@binkert.org rxDmaState = dmaIdle; 11157007Snate@binkert.org 11167839Snilay@cs.wisc.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 11177839Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 11187839Snilay@cs.wisc.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11197839Snilay@cs.wisc.edu} 11207839Snilay@cs.wisc.edu 11217839Snilay@cs.wisc.edubool 11227839Snilay@cs.wisc.eduNSGigE::doRxDmaRead() 11237839Snilay@cs.wisc.edu{ 11247839Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 11257839Snilay@cs.wisc.edu rxDmaState = dmaReading; 11267007Snate@binkert.org 11276657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 11287839Snilay@cs.wisc.edu if (dmaInterface->busy()) 11297839Snilay@cs.wisc.edu rxDmaState = dmaReadWaiting; 11308337Snilay@cs.wisc.edu else 11317839Snilay@cs.wisc.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 11328337Snilay@cs.wisc.edu &rxDmaReadEvent, true); 11337839Snilay@cs.wisc.edu return true; 11348337Snilay@cs.wisc.edu } 11357839Snilay@cs.wisc.edu 11368337Snilay@cs.wisc.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 11377839Snilay@cs.wisc.edu rxDmaReadCopy(); 11387839Snilay@cs.wisc.edu return false; 11396657Snate@binkert.org } 11406657Snate@binkert.org 11417780Snilay@cs.wisc.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 11429171Snilay@cs.wisc.edu Tick start = curTick + dmaReadDelay + factor; 11439171Snilay@cs.wisc.edu rxDmaReadEvent.schedule(start); 11446657Snate@binkert.org return true; 11457007Snate@binkert.org} 11467839Snilay@cs.wisc.edu 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) 11556657Snate@binkert.org txKick(); 11567839Snilay@cs.wisc.edu 11576657Snate@binkert.org rxKick(); 11587780Snilay@cs.wisc.edu} 11597780Snilay@cs.wisc.edu 11607542SBrad.Beckmann@amd.comvoid 11618266Sksewell@umich.eduNSGigE::rxDmaWriteCopy() 11628266Sksewell@umich.edu{ 11638266Sksewell@umich.edu assert(rxDmaState == dmaWriting); 11648266Sksewell@umich.edu 11658266Sksewell@umich.edu physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 11668266Sksewell@umich.edu rxDmaState = dmaIdle; 11676657Snate@binkert.org 11687832Snate@binkert.org DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11697839Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 11707839Snilay@cs.wisc.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11718337Snilay@cs.wisc.edu} 11728341Snilay@cs.wisc.edu 11737839Snilay@cs.wisc.edubool 11748337Snilay@cs.wisc.eduNSGigE::doRxDmaWrite() 11758341Snilay@cs.wisc.edu{ 11767839Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11778337Snilay@cs.wisc.edu rxDmaState = dmaWriting; 11788341Snilay@cs.wisc.edu 11797839Snilay@cs.wisc.edu if (dmaInterface && !rxDmaFree) { 11808337Snilay@cs.wisc.edu if (dmaInterface->busy()) 11818341Snilay@cs.wisc.edu rxDmaState = dmaWriteWaiting; 11827839Snilay@cs.wisc.edu else 11837839Snilay@cs.wisc.edu dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 11846657Snate@binkert.org &rxDmaWriteEvent, true); 11858266Sksewell@umich.edu return true; 11868266Sksewell@umich.edu } 11878266Sksewell@umich.edu 11888266Sksewell@umich.edu if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 11898266Sksewell@umich.edu rxDmaWriteCopy(); 11908266Sksewell@umich.edu return false; 11916657Snate@binkert.org } 11927780Snilay@cs.wisc.edu 11938266Sksewell@umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 11948266Sksewell@umich.edu Tick start = curTick + dmaWriteDelay + factor; 11958266Sksewell@umich.edu rxDmaWriteEvent.schedule(start); 11968266Sksewell@umich.edu return true; 11978266Sksewell@umich.edu} 11988266Sksewell@umich.edu 11996657Snate@binkert.orgvoid 12006657Snate@binkert.orgNSGigE::rxDmaWriteDone() 12016657Snate@binkert.org{ 12026657Snate@binkert.org assert(rxDmaState == dmaWriting); 12036657Snate@binkert.org rxDmaWriteCopy(); 12047007Snate@binkert.org 12057007Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 12067007Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12077007Snate@binkert.org 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 12187839Snilay@cs.wisc.edu if (rxKickTick > curTick) { 12197007Snate@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: 12316999Snate@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 12389104Shestness@cs.utexas.edu // see state machine from spec for details 12396657Snate@binkert.org // the way this works is, if you finish work on one state and can 12406657Snate@binkert.org // go directly to another, you do that through jumping to the 12416657Snate@binkert.org // 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) { 12467007Snate@binkert.org case rxIdle: 12476657Snate@binkert.org if (!rxEnable) { 12486657Snate@binkert.org DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 12496657Snate@binkert.org goto exit; 12506657Snate@binkert.org } 12519105SBrad.Beckmann@amd.com 12529105SBrad.Beckmann@amd.com if (CRDD) { 12539105SBrad.Beckmann@amd.com rxState = rxDescRefr; 12549105SBrad.Beckmann@amd.com 12559105SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 12569105SBrad.Beckmann@amd.com rxDmaData = &rxDescCache + offsetof(ns_desc, link); 12579105SBrad.Beckmann@amd.com rxDmaLen = sizeof(rxDescCache.link); 12589105SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 12596657Snate@binkert.org 12606657Snate@binkert.org descDmaReads++; 12616657Snate@binkert.org descDmaRdBytes += rxDmaLen; 12626657Snate@binkert.org 12636657Snate@binkert.org if (doRxDmaRead()) 12646657Snate@binkert.org goto exit; 12656657Snate@binkert.org } else { 12669104Shestness@cs.utexas.edu rxState = rxDescRead; 12679104Shestness@cs.utexas.edu 12689104Shestness@cs.utexas.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 12699104Shestness@cs.utexas.edu rxDmaData = &rxDescCache; 12706657Snate@binkert.org rxDmaLen = sizeof(ns_desc); 12716657Snate@binkert.org rxDmaFree = dmaDescFree; 12726657Snate@binkert.org 12736657Snate@binkert.org descDmaReads++; 12746657Snate@binkert.org descDmaRdBytes += rxDmaLen; 12756657Snate@binkert.org 12766657Snate@binkert.org if (doRxDmaRead()) 12776657Snate@binkert.org goto exit; 12786657Snate@binkert.org } 12796657Snate@binkert.org break; 12807839Snilay@cs.wisc.edu 12817839Snilay@cs.wisc.edu case rxDescRefr: 12827839Snilay@cs.wisc.edu if (rxDmaState != dmaIdle) 12837839Snilay@cs.wisc.edu goto exit; 12847839Snilay@cs.wisc.edu 12857839Snilay@cs.wisc.edu rxState = rxAdvance; 12867839Snilay@cs.wisc.edu break; 12877839Snilay@cs.wisc.edu 12887839Snilay@cs.wisc.edu case rxDescRead: 12897839Snilay@cs.wisc.edu if (rxDmaState != dmaIdle) 12907839Snilay@cs.wisc.edu goto exit; 12917839Snilay@cs.wisc.edu 12926657Snate@binkert.org DPRINTF(EthernetDesc, 12936657Snate@binkert.org "rxDescCache: addr=%08x read descriptor\n", 12946657Snate@binkert.org regs.rxdp & 0x3fffffff); 12956657Snate@binkert.org DPRINTF(EthernetDesc, 12966657Snate@binkert.org "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 12976657Snate@binkert.org rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 12986657Snate@binkert.org rxDescCache.extsts); 12996657Snate@binkert.org 13006657Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_OWN) { 13016657Snate@binkert.org devIntrPost(ISR_RXIDLE); 13026657Snate@binkert.org rxState = rxIdle; 13036657Snate@binkert.org goto exit; 13046657Snate@binkert.org } else { 13056657Snate@binkert.org rxState = rxFifoBlock; 13066657Snate@binkert.org rxFragPtr = rxDescCache.bufptr; 13076657Snate@binkert.org rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 13086657Snate@binkert.org } 13096657Snate@binkert.org break; 13106657Snate@binkert.org 13116657Snate@binkert.org case rxFifoBlock: 13126657Snate@binkert.org if (!rxPacket) { 13137805Snilay@cs.wisc.edu /** 13148159SBrad.Beckmann@amd.com * @todo in reality, we should be able to start processing 13159171Snilay@cs.wisc.edu * the packet as it arrives, and not have to wait for the 13166657Snate@binkert.org * full packet ot be in the receive fifo. 13176657Snate@binkert.org */ 13186657Snate@binkert.org if (rxFifo.empty()) 13196657Snate@binkert.org goto exit; 13206657Snate@binkert.org 13216657Snate@binkert.org 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()); 13337832Snate@binkert.org 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()); 13378229Snate@binkert.org } 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); 13447542SBrad.Beckmann@amd.com rxFifo.pop(); 13457542SBrad.Beckmann@amd.com } 13467542SBrad.Beckmann@amd.com 13477542SBrad.Beckmann@amd.com 13487542SBrad.Beckmann@amd.com // dont' need the && rxDescCnt > 0 if driver sanity check 13497542SBrad.Beckmann@amd.com // above holds 13507542SBrad.Beckmann@amd.com if (rxPktBytes > 0) { 13517542SBrad.Beckmann@amd.com rxState = rxFragWrite; 13527542SBrad.Beckmann@amd.com // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 13537542SBrad.Beckmann@amd.com // check holds 13547542SBrad.Beckmann@amd.com rxXferLen = rxPktBytes; 13557542SBrad.Beckmann@amd.com 13567542SBrad.Beckmann@amd.com rxDmaAddr = rxFragPtr & 0x3fffffff; 13577542SBrad.Beckmann@amd.com rxDmaData = rxPacketBufPtr; 13587542SBrad.Beckmann@amd.com rxDmaLen = rxXferLen; 13597542SBrad.Beckmann@amd.com rxDmaFree = dmaDataFree; 13607542SBrad.Beckmann@amd.com 13617542SBrad.Beckmann@amd.com if (doRxDmaWrite()) 13627542SBrad.Beckmann@amd.com goto exit; 13637542SBrad.Beckmann@amd.com 13647542SBrad.Beckmann@amd.com } else { 13657542SBrad.Beckmann@amd.com rxState = rxDescWrite; 13667542SBrad.Beckmann@amd.com 13677542SBrad.Beckmann@amd.com //if (rxPktBytes == 0) { /* packet is done */ 13687542SBrad.Beckmann@amd.com 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; 13727542SBrad.Beckmann@amd.com rxDescCache.cmdsts &= ~CMDSTS_MORE; 13737542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_OK; 13747542SBrad.Beckmann@amd.com rxDescCache.cmdsts &= 0xffff0000; 13757542SBrad.Beckmann@amd.com rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 13767542SBrad.Beckmann@amd.com 13777542SBrad.Beckmann@amd.com#if 0 13787542SBrad.Beckmann@amd.com /* 13797542SBrad.Beckmann@amd.com * all the driver uses these are for its own stats keeping 13807542SBrad.Beckmann@amd.com * which we don't care about, aren't necessary for 13817542SBrad.Beckmann@amd.com * functionality and doing this would just slow us down. 13827542SBrad.Beckmann@amd.com * if they end up using this in a later version for 13837542SBrad.Beckmann@amd.com * functional purposes, just undef 13847542SBrad.Beckmann@amd.com */ 13857542SBrad.Beckmann@amd.com if (rxFilterEnable) { 13867542SBrad.Beckmann@amd.com rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 13877542SBrad.Beckmann@amd.com const EthAddr &dst = rxFifoFront()->dst(); 13887542SBrad.Beckmann@amd.com if (dst->unicast()) 13897542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 13907542SBrad.Beckmann@amd.com if (dst->multicast()) 13917542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 13927542SBrad.Beckmann@amd.com if (dst->broadcast()) 13937542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 13947542SBrad.Beckmann@amd.com } 13957542SBrad.Beckmann@amd.com#endif 13967542SBrad.Beckmann@amd.com 13977542SBrad.Beckmann@amd.com IpPtr ip(rxPacket); 13987542SBrad.Beckmann@amd.com if (extstsEnable && ip) { 13997542SBrad.Beckmann@amd.com rxDescCache.extsts |= EXTSTS_IPPKT; 14007542SBrad.Beckmann@amd.com rxIpChecksums++; 14017542SBrad.Beckmann@amd.com if (cksum(ip) != 0) { 14027542SBrad.Beckmann@amd.com DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 14037542SBrad.Beckmann@amd.com rxDescCache.extsts |= EXTSTS_IPERR; 14047542SBrad.Beckmann@amd.com } 14057542SBrad.Beckmann@amd.com TcpPtr tcp(ip); 14067542SBrad.Beckmann@amd.com UdpPtr udp(ip); 14077542SBrad.Beckmann@amd.com if (tcp) { 14087542SBrad.Beckmann@amd.com rxDescCache.extsts |= EXTSTS_TCPPKT; 14097542SBrad.Beckmann@amd.com rxTcpChecksums++; 14107542SBrad.Beckmann@amd.com if (cksum(tcp) != 0) { 14117542SBrad.Beckmann@amd.com DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 14127542SBrad.Beckmann@amd.com rxDescCache.extsts |= EXTSTS_TCPERR; 14137542SBrad.Beckmann@amd.com 14147542SBrad.Beckmann@amd.com } 14157542SBrad.Beckmann@amd.com } else if (udp) { 14167542SBrad.Beckmann@amd.com rxDescCache.extsts |= EXTSTS_UDPPKT; 14177542SBrad.Beckmann@amd.com rxUdpChecksums++; 14186657Snate@binkert.org if (cksum(udp) != 0) { 14196999Snate@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 14267542SBrad.Beckmann@amd.com /* 14277542SBrad.Beckmann@amd.com * the driver seems to always receive into desc buffers 14286657Snate@binkert.org * of size 1514, so you never have a pkt that is split 14297832Snate@binkert.org * into multiple descriptors on the receive side, so 14307002Snate@binkert.org * i don't implement that case, hence the assert above. 14317002Snate@binkert.org */ 14328229Snate@binkert.org 14338229Snate@binkert.org DPRINTF(EthernetDesc, 14348608Snilay@cs.wisc.edu "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", 14386657Snate@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; 14426657Snate@binkert.org rxDmaData = &(rxDescCache.cmdsts); 14437542SBrad.Beckmann@amd.com rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 14447542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 14457542SBrad.Beckmann@amd.com 14466657Snate@binkert.org descDmaWrites++; 14476657Snate@binkert.org descDmaWrBytes += rxDmaLen; 14486657Snate@binkert.org 14496657Snate@binkert.org if (doRxDmaWrite()) 14506657Snate@binkert.org goto exit; 14516657Snate@binkert.org } 14526657Snate@binkert.org break; 14536657Snate@binkert.org 14546657Snate@binkert.org case rxFragWrite: 14557007Snate@binkert.org if (rxDmaState != dmaIdle) 14566657Snate@binkert.org goto exit; 14576657Snate@binkert.org 14586657Snate@binkert.org rxPacketBufPtr += rxXferLen; 14596657Snate@binkert.org rxFragPtr += rxXferLen; 14606999Snate@binkert.org rxPktBytes -= rxXferLen; 14616657Snate@binkert.org 14626657Snate@binkert.org rxState = rxFifoBlock; 14636657Snate@binkert.org break; 14646657Snate@binkert.org 14656657Snate@binkert.org case rxDescWrite: 14666657Snate@binkert.org if (rxDmaState != dmaIdle) 14677832Snate@binkert.org goto exit; 14687832Snate@binkert.org 14696657Snate@binkert.org assert(rxDescCache.cmdsts & CMDSTS_OWN); 14706657Snate@binkert.org 14716657Snate@binkert.org assert(rxPacket == 0); 14726657Snate@binkert.org devIntrPost(ISR_RXOK); 14736657Snate@binkert.org 14746657Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_INTR) 14756657Snate@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; 14837007Snate@binkert.org break; 14847007Snate@binkert.org 14857007Snate@binkert.org case rxAdvance: 14866657Snate@binkert.org if (rxDescCache.link == 0) { 14876657Snate@binkert.org devIntrPost(ISR_RXIDLE); 14886657Snate@binkert.org rxState = rxIdle; 14897007Snate@binkert.org CRDD = true; 14907007Snate@binkert.org goto exit; 14917007Snate@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; 15037007Snate@binkert.org } 15047007Snate@binkert.org break; 15056657Snate@binkert.org 15066657Snate@binkert.org default: 15076657Snate@binkert.org panic("Invalid rxState!"); 15086657Snate@binkert.org } 15096657Snate@binkert.org 15107007Snate@binkert.org DPRINTF(EthernetSM, "entering next rxState=%s\n", 15117007Snate@binkert.org NsRxStateStrings[rxState]); 15127007Snate@binkert.org 15136657Snate@binkert.org goto next; 15146657Snate@binkert.org 15156657Snate@binkert.org exit: 15167007Snate@binkert.org /** 15177542SBrad.Beckmann@amd.com * @todo do we want to schedule a future kick? 15187542SBrad.Beckmann@amd.com */ 15196657Snate@binkert.org DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 15207542SBrad.Beckmann@amd.com NsRxStateStrings[rxState]); 15217542SBrad.Beckmann@amd.com} 15227002Snate@binkert.org 15237542SBrad.Beckmann@amd.comvoid 15247542SBrad.Beckmann@amd.comNSGigE::transmit() 15257542SBrad.Beckmann@amd.com{ 15267542SBrad.Beckmann@amd.com if (txFifo.empty()) { 15276657Snate@binkert.org DPRINTF(Ethernet, "nothing to transmit\n"); 15287542SBrad.Beckmann@amd.com return; 15297542SBrad.Beckmann@amd.com } 15307542SBrad.Beckmann@amd.com 15317542SBrad.Beckmann@amd.com DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 15327542SBrad.Beckmann@amd.com txFifo.size()); 15337542SBrad.Beckmann@amd.com if (interface->sendPacket(txFifo.front())) { 15347542SBrad.Beckmann@amd.com#if TRACING_ON 15357542SBrad.Beckmann@amd.com 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", 15427007Snate@binkert.org tcp->sport(), tcp->dport()); 15436999Snate@binkert.org } 15447007Snate@binkert.org } 15457007Snate@binkert.org } 15467007Snate@binkert.org#endif 15477007Snate@binkert.org 15487007Snate@binkert.org DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 15497007Snate@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; 15796999Snate@binkert.org 15806657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 15816657Snate@binkert.org txDmaAddr, txDmaLen); 15827007Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 15837007Snate@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; 15986657Snate@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; 16066657Snate@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(); 16226657Snate@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()) 16456657Snate@binkert.org txDmaState = dmaWriteWaiting; 16466657Snate@binkert.org else 16476657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 16486657Snate@binkert.org &txDmaWriteEvent, true); 16496657Snate@binkert.org return true; 16506657Snate@binkert.org } 16516657Snate@binkert.org 16526657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 16536657Snate@binkert.org txDmaWriteCopy(); 16546657Snate@binkert.org return false; 16556657Snate@binkert.org } 16566657Snate@binkert.org 16576657Snate@binkert.org Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 16586657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 16596657Snate@binkert.org txDmaWriteEvent.schedule(start); 16606657Snate@binkert.org return true; 16616657Snate@binkert.org} 16626657Snate@binkert.org 16636657Snate@binkert.orgvoid 16646657Snate@binkert.orgNSGigE::txDmaWriteDone() 16656657Snate@binkert.org{ 16666657Snate@binkert.org assert(txDmaState == dmaWriting); 16676657Snate@binkert.org txDmaWriteCopy(); 16686657Snate@binkert.org 16696657Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 16706657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 16716657Snate@binkert.org rxKick(); 16727007Snate@binkert.org 16736657Snate@binkert.org txKick(); 16746657Snate@binkert.org} 16756657Snate@binkert.org 16766657Snate@binkert.orgvoid 16776657Snate@binkert.orgNSGigE::txKick() 16786657Snate@binkert.org{ 16796657Snate@binkert.org DPRINTF(EthernetSM, "transmit kick txState=%s\n", 16807007Snate@binkert.org NsTxStateStrings[txState]); 16816657Snate@binkert.org 16826657Snate@binkert.org if (txKickTick > curTick) { 16836657Snate@binkert.org DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 16846657Snate@binkert.org txKickTick); 16856657Snate@binkert.org 16866657Snate@binkert.org return; 16876657Snate@binkert.org } 16886657Snate@binkert.org 16896657Snate@binkert.org next: 16906657Snate@binkert.org switch(txDmaState) { 16916657Snate@binkert.org case dmaReadWaiting: 16926657Snate@binkert.org if (doTxDmaRead()) 16936657Snate@binkert.org goto exit; 16946657Snate@binkert.org break; 16956657Snate@binkert.org case dmaWriteWaiting: 16967007Snate@binkert.org if (doTxDmaWrite()) 16976657Snate@binkert.org goto exit; 16986657Snate@binkert.org break; 16996657Snate@binkert.org default: 17006657Snate@binkert.org break; 17016657Snate@binkert.org } 17026657Snate@binkert.org 17036657Snate@binkert.org switch (txState) { 17046657Snate@binkert.org case txIdle: 17056657Snate@binkert.org if (!txEnable) { 17066657Snate@binkert.org DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 17076657Snate@binkert.org goto exit; 17086657Snate@binkert.org } 17096657Snate@binkert.org 17106657Snate@binkert.org if (CTDD) { 17116657Snate@binkert.org txState = txDescRefr; 17126657Snate@binkert.org 17136657Snate@binkert.org txDmaAddr = regs.txdp & 0x3fffffff; 17146657Snate@binkert.org txDmaData = &txDescCache + offsetof(ns_desc, link); 17156657Snate@binkert.org txDmaLen = sizeof(txDescCache.link); 17166657Snate@binkert.org txDmaFree = dmaDescFree; 17176657Snate@binkert.org 17186657Snate@binkert.org 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(rxFragPtr); 2170 SERIALIZE_SCALAR(rxDescCnt); 2171 int rxDmaState = this->rxDmaState; 2172 SERIALIZE_SCALAR(rxDmaState); 2173 2174 SERIALIZE_SCALAR(extstsEnable); 2175 2176 /* 2177 * If there's a pending transmit, store the time so we can 2178 * reschedule it later 2179 */ 2180 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2181 SERIALIZE_SCALAR(transmitTick); 2182 2183 /* 2184 * receive address filter settings 2185 */ 2186 SERIALIZE_SCALAR(rxFilterEnable); 2187 SERIALIZE_SCALAR(acceptBroadcast); 2188 SERIALIZE_SCALAR(acceptMulticast); 2189 SERIALIZE_SCALAR(acceptUnicast); 2190 SERIALIZE_SCALAR(acceptPerfect); 2191 SERIALIZE_SCALAR(acceptArp); 2192 2193 /* 2194 * Keep track of pending interrupt status. 2195 */ 2196 SERIALIZE_SCALAR(intrTick); 2197 SERIALIZE_SCALAR(cpuPendingIntr); 2198 Tick intrEventTick = 0; 2199 if (intrEvent) 2200 intrEventTick = intrEvent->when(); 2201 SERIALIZE_SCALAR(intrEventTick); 2202 2203} 2204 2205void 2206NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2207{ 2208 // Unserialize the PciDev base class 2209 PciDev::unserialize(cp, section); 2210 2211 UNSERIALIZE_SCALAR(regs.command); 2212 UNSERIALIZE_SCALAR(regs.config); 2213 UNSERIALIZE_SCALAR(regs.mear); 2214 UNSERIALIZE_SCALAR(regs.ptscr); 2215 UNSERIALIZE_SCALAR(regs.isr); 2216 UNSERIALIZE_SCALAR(regs.imr); 2217 UNSERIALIZE_SCALAR(regs.ier); 2218 UNSERIALIZE_SCALAR(regs.ihr); 2219 UNSERIALIZE_SCALAR(regs.txdp); 2220 UNSERIALIZE_SCALAR(regs.txdp_hi); 2221 UNSERIALIZE_SCALAR(regs.txcfg); 2222 UNSERIALIZE_SCALAR(regs.gpior); 2223 UNSERIALIZE_SCALAR(regs.rxdp); 2224 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2225 UNSERIALIZE_SCALAR(regs.rxcfg); 2226 UNSERIALIZE_SCALAR(regs.pqcr); 2227 UNSERIALIZE_SCALAR(regs.wcsr); 2228 UNSERIALIZE_SCALAR(regs.pcr); 2229 UNSERIALIZE_SCALAR(regs.rfcr); 2230 UNSERIALIZE_SCALAR(regs.rfdr); 2231 UNSERIALIZE_SCALAR(regs.srr); 2232 UNSERIALIZE_SCALAR(regs.mibc); 2233 UNSERIALIZE_SCALAR(regs.vrcr); 2234 UNSERIALIZE_SCALAR(regs.vtcr); 2235 UNSERIALIZE_SCALAR(regs.vdr); 2236 UNSERIALIZE_SCALAR(regs.ccsr); 2237 UNSERIALIZE_SCALAR(regs.tbicr); 2238 UNSERIALIZE_SCALAR(regs.tbisr); 2239 UNSERIALIZE_SCALAR(regs.tanar); 2240 UNSERIALIZE_SCALAR(regs.tanlpar); 2241 UNSERIALIZE_SCALAR(regs.taner); 2242 UNSERIALIZE_SCALAR(regs.tesr); 2243 2244 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2245 2246 UNSERIALIZE_SCALAR(ioEnable); 2247 2248 /* 2249 * unserialize the data fifos 2250 */ 2251 rxFifo.unserialize("rxFifo", cp, section); 2252 txFifo.unserialize("txFifo", cp, section); 2253 2254 /* 2255 * unserialize the various helper variables 2256 */ 2257 bool txPacketExists; 2258 UNSERIALIZE_SCALAR(txPacketExists); 2259 if (txPacketExists) { 2260 txPacket = new PacketData; 2261 txPacket->unserialize("txPacket", cp, section); 2262 uint32_t txPktBufPtr; 2263 UNSERIALIZE_SCALAR(txPktBufPtr); 2264 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2265 } else 2266 txPacket = 0; 2267 2268 bool rxPacketExists; 2269 UNSERIALIZE_SCALAR(rxPacketExists); 2270 rxPacket = 0; 2271 if (rxPacketExists) { 2272 rxPacket = new PacketData; 2273 rxPacket->unserialize("rxPacket", cp, section); 2274 uint32_t rxPktBufPtr; 2275 UNSERIALIZE_SCALAR(rxPktBufPtr); 2276 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2277 } else 2278 rxPacket = 0; 2279 2280 UNSERIALIZE_SCALAR(txXferLen); 2281 UNSERIALIZE_SCALAR(rxXferLen); 2282 2283 /* 2284 * Unserialize DescCaches 2285 */ 2286 UNSERIALIZE_SCALAR(txDescCache.link); 2287 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2288 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2289 UNSERIALIZE_SCALAR(txDescCache.extsts); 2290 UNSERIALIZE_SCALAR(rxDescCache.link); 2291 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2292 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2293 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2294 2295 /* 2296 * unserialize tx state machine 2297 */ 2298 int txState; 2299 UNSERIALIZE_SCALAR(txState); 2300 this->txState = (TxState) txState; 2301 UNSERIALIZE_SCALAR(txEnable); 2302 UNSERIALIZE_SCALAR(CTDD); 2303 UNSERIALIZE_SCALAR(txFragPtr); 2304 UNSERIALIZE_SCALAR(txDescCnt); 2305 int txDmaState; 2306 UNSERIALIZE_SCALAR(txDmaState); 2307 this->txDmaState = (DmaState) txDmaState; 2308 2309 /* 2310 * unserialize rx state machine 2311 */ 2312 int rxState; 2313 UNSERIALIZE_SCALAR(rxState); 2314 this->rxState = (RxState) rxState; 2315 UNSERIALIZE_SCALAR(rxEnable); 2316 UNSERIALIZE_SCALAR(CRDD); 2317 UNSERIALIZE_SCALAR(rxPktBytes); 2318 UNSERIALIZE_SCALAR(rxFragPtr); 2319 UNSERIALIZE_SCALAR(rxDescCnt); 2320 int rxDmaState; 2321 UNSERIALIZE_SCALAR(rxDmaState); 2322 this->rxDmaState = (DmaState) rxDmaState; 2323 2324 UNSERIALIZE_SCALAR(extstsEnable); 2325 2326 /* 2327 * If there's a pending transmit, reschedule it now 2328 */ 2329 Tick transmitTick; 2330 UNSERIALIZE_SCALAR(transmitTick); 2331 if (transmitTick) 2332 txEvent.schedule(curTick + transmitTick); 2333 2334 /* 2335 * unserialize receive address filter settings 2336 */ 2337 UNSERIALIZE_SCALAR(rxFilterEnable); 2338 UNSERIALIZE_SCALAR(acceptBroadcast); 2339 UNSERIALIZE_SCALAR(acceptMulticast); 2340 UNSERIALIZE_SCALAR(acceptUnicast); 2341 UNSERIALIZE_SCALAR(acceptPerfect); 2342 UNSERIALIZE_SCALAR(acceptArp); 2343 2344 /* 2345 * Keep track of pending interrupt status. 2346 */ 2347 UNSERIALIZE_SCALAR(intrTick); 2348 UNSERIALIZE_SCALAR(cpuPendingIntr); 2349 Tick intrEventTick; 2350 UNSERIALIZE_SCALAR(intrEventTick); 2351 if (intrEventTick) { 2352 intrEvent = new IntrEvent(this, true); 2353 intrEvent->schedule(intrEventTick); 2354 } 2355 2356 /* 2357 * re-add addrRanges to bus bridges 2358 */ 2359 if (pioInterface) { 2360 pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 2361 pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); 2362 } 2363} 2364 2365Tick 2366NSGigE::cacheAccess(MemReqPtr &req) 2367{ 2368 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2369 req->paddr, req->paddr - addr); 2370 return curTick + pioLatency; 2371} 2372 2373BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2374 2375 SimObjectParam<EtherInt *> peer; 2376 SimObjectParam<NSGigE *> device; 2377 2378END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2379 2380BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2381 2382 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2383 INIT_PARAM(device, "Ethernet device of this interface") 2384 2385END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2386 2387CREATE_SIM_OBJECT(NSGigEInt) 2388{ 2389 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2390 2391 EtherInt *p = (EtherInt *)peer; 2392 if (p) { 2393 dev_int->setPeer(p); 2394 p->setPeer(dev_int); 2395 } 2396 2397 return dev_int; 2398} 2399 2400REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2401 2402 2403BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2404 2405 Param<Tick> tx_delay; 2406 Param<Tick> rx_delay; 2407 Param<Tick> intr_delay; 2408 SimObjectParam<MemoryController *> mmu; 2409 SimObjectParam<PhysicalMemory *> physmem; 2410 Param<bool> rx_filter; 2411 Param<string> hardware_address; 2412 SimObjectParam<Bus*> header_bus; 2413 SimObjectParam<Bus*> payload_bus; 2414 SimObjectParam<HierParams *> hier; 2415 Param<Tick> pio_latency; 2416 Param<bool> dma_desc_free; 2417 Param<bool> dma_data_free; 2418 Param<Tick> dma_read_delay; 2419 Param<Tick> dma_write_delay; 2420 Param<Tick> dma_read_factor; 2421 Param<Tick> dma_write_factor; 2422 SimObjectParam<PciConfigAll *> configspace; 2423 SimObjectParam<PciConfigData *> configdata; 2424 SimObjectParam<Platform *> platform; 2425 Param<uint32_t> pci_bus; 2426 Param<uint32_t> pci_dev; 2427 Param<uint32_t> pci_func; 2428 Param<uint32_t> tx_fifo_size; 2429 Param<uint32_t> rx_fifo_size; 2430 2431END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2432 2433BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2434 2435 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2436 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2437 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2438 INIT_PARAM(mmu, "Memory Controller"), 2439 INIT_PARAM(physmem, "Physical Memory"), 2440 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2441 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2442 "00:99:00:00:00:01"), 2443 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2444 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2445 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2446 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2447 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2448 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2449 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2450 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2451 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2452 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2453 INIT_PARAM(configspace, "PCI Configspace"), 2454 INIT_PARAM(configdata, "PCI Config data"), 2455 INIT_PARAM(platform, "Platform"), 2456 INIT_PARAM(pci_bus, "PCI bus"), 2457 INIT_PARAM(pci_dev, "PCI device number"), 2458 INIT_PARAM(pci_func, "PCI function code"), 2459 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2460 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) 2461 2462END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2463 2464 2465CREATE_SIM_OBJECT(NSGigE) 2466{ 2467 NSGigE::Params *params = new NSGigE::Params; 2468 2469 params->name = getInstanceName(); 2470 params->mmu = mmu; 2471 params->configSpace = configspace; 2472 params->configData = configdata; 2473 params->plat = platform; 2474 params->busNum = pci_bus; 2475 params->deviceNum = pci_dev; 2476 params->functionNum = pci_func; 2477 2478 params->intr_delay = intr_delay; 2479 params->pmem = physmem; 2480 params->tx_delay = tx_delay; 2481 params->rx_delay = rx_delay; 2482 params->hier = hier; 2483 params->header_bus = header_bus; 2484 params->payload_bus = payload_bus; 2485 params->pio_latency = pio_latency; 2486 params->dma_desc_free = dma_desc_free; 2487 params->dma_data_free = dma_data_free; 2488 params->dma_read_delay = dma_read_delay; 2489 params->dma_write_delay = dma_write_delay; 2490 params->dma_read_factor = dma_read_factor; 2491 params->dma_write_factor = dma_write_factor; 2492 params->rx_filter = rx_filter; 2493 params->eaddr = hardware_address; 2494 params->tx_fifo_size = tx_fifo_size; 2495 params->rx_fifo_size = rx_fifo_size; 2496 return new NSGigE(params); 2497} 2498 2499REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2500