ns_gige.cc revision 881
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2003 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 */ 336657Snate@binkert.org#include <cstdio> 346882SBrad.Beckmann@amd.com#include <deque> 356882SBrad.Beckmann@amd.com#include <string> 366882SBrad.Beckmann@amd.com 376882SBrad.Beckmann@amd.com#include "base/inet.hh" 386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh" 396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh" 406882SBrad.Beckmann@amd.com#include "dev/dma.hh" 416888SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 426882SBrad.Beckmann@amd.com#include "dev/etherlink.hh" 436882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh" 446657Snate@binkert.org#include "mem/bus/dma_interface.hh" 456657Snate@binkert.org#include "mem/bus/pio_interface.hh" 466657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh" 476657Snate@binkert.org#include "mem/functional_mem/memory_control.hh" 486657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh" 496657Snate@binkert.org#include "sim/builder.hh" 506882SBrad.Beckmann@amd.com#include "sim/host.hh" 516882SBrad.Beckmann@amd.com#include "sim/sim_stats.hh" 526882SBrad.Beckmann@amd.com#include "targetarch/vtophys.hh" 536882SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh" 546882SBrad.Beckmann@amd.com#include "dev/tsunami_cchip.hh" 556882SBrad.Beckmann@amd.com 566657Snate@binkert.orgconst char *NsRxStateStrings[] = 576657Snate@binkert.org{ 586657Snate@binkert.org "rxIdle", 596657Snate@binkert.org "rxDescRefr", 606657Snate@binkert.org "rxDescRead", 616657Snate@binkert.org "rxFifoBlock", 626657Snate@binkert.org "rxFragWrite", 636657Snate@binkert.org "rxDescWrite", 646657Snate@binkert.org "rxAdvance" 656657Snate@binkert.org}; 666657Snate@binkert.org 676657Snate@binkert.orgconst char *NsTxStateStrings[] = 686657Snate@binkert.org{ 696657Snate@binkert.org "txIdle", 706657Snate@binkert.org "txDescRefr", 716657Snate@binkert.org "txDescRead", 726657Snate@binkert.org "txFifoBlock", 736657Snate@binkert.org "txFragRead", 746657Snate@binkert.org "txDescWrite", 756657Snate@binkert.org "txAdvance" 766657Snate@binkert.org}; 776657Snate@binkert.org 786657Snate@binkert.orgconst char *NsDmaState[] = 796657Snate@binkert.org{ 806657Snate@binkert.org "dmaIdle", 816657Snate@binkert.org "dmaReading", 826657Snate@binkert.org "dmaWriting", 836657Snate@binkert.org "dmaReadWaiting", 846657Snate@binkert.org "dmaWriteWaiting" 856779SBrad.Beckmann@amd.com}; 866657Snate@binkert.org 876657Snate@binkert.orgusing namespace std; 886657Snate@binkert.org 896657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 906657Snate@binkert.org// 916657Snate@binkert.org// NSGigE PCI Device 926657Snate@binkert.org// 936657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 946657Snate@binkert.org PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 956657Snate@binkert.org MemoryController *mmu, HierParams *hier, Bus *header_bus, 966657Snate@binkert.org Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 976657Snate@binkert.org bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 986657Snate@binkert.org Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 996657Snate@binkert.org PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1006657Snate@binkert.org uint32_t func, bool rx_filter, const int eaddr[6], Addr addr) 1016657Snate@binkert.org : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), 1026657Snate@binkert.org addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1036657Snate@binkert.org txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false), 1046657Snate@binkert.org txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), 1056657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1066657Snate@binkert.org CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 1076657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1086657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1096657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1106657Snate@binkert.org dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1116657Snate@binkert.org txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1126657Snate@binkert.org txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1136657Snate@binkert.org acceptMulticast(false), acceptUnicast(false), 1146657Snate@binkert.org acceptPerfect(false), acceptArp(false), 1156657Snate@binkert.org physmem(pmem), intctrl(i), intrTick(0), 1166657Snate@binkert.org cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency) 1176657Snate@binkert.org{ 1186657Snate@binkert.org mmu->add_child(this, Range<Addr>(addr, addr + size)); 1196657Snate@binkert.org tsunami->ethernet = this; 1206657Snate@binkert.org 1216657Snate@binkert.org if (header_bus) { 1226657Snate@binkert.org pioInterface = newPioInterface(name, hier, header_bus, this, 1236657Snate@binkert.org &NSGigE::cacheAccess); 1246657Snate@binkert.org pioInterface->addAddrRange(addr, addr + size - 1); 1256657Snate@binkert.org if (payload_bus) 1266657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", 1276657Snate@binkert.org header_bus, payload_bus, 1); 1286657Snate@binkert.org else 1296657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", 1306657Snate@binkert.org header_bus, header_bus, 1); 1316657Snate@binkert.org } else if (payload_bus) { 1326657Snate@binkert.org pioInterface = newPioInterface(name, hier, payload_bus, this, 1336657Snate@binkert.org &NSGigE::cacheAccess); 1346657Snate@binkert.org pioInterface->addAddrRange(addr, addr + size - 1); 1356657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", 1366657Snate@binkert.org payload_bus, payload_bus, 1); 1376657Snate@binkert.org 1386657Snate@binkert.org } 1396657Snate@binkert.org 1406657Snate@binkert.org 1416877Ssteve.reinhardt@amd.com intrDelay = US2Ticks(intr_delay); 1426657Snate@binkert.org dmaReadDelay = dma_read_delay; 1436657Snate@binkert.org dmaWriteDelay = dma_write_delay; 1446657Snate@binkert.org dmaReadFactor = dma_read_factor; 1456657Snate@binkert.org dmaWriteFactor = dma_write_factor; 1466657Snate@binkert.org 1476657Snate@binkert.org memset(®s, 0, sizeof(regs)); 1486657Snate@binkert.org regsReset(); 1496657Snate@binkert.org rom.perfectMatch[0] = eaddr[0]; 1506657Snate@binkert.org rom.perfectMatch[1] = eaddr[1]; 1516657Snate@binkert.org rom.perfectMatch[2] = eaddr[2]; 1526877Ssteve.reinhardt@amd.com rom.perfectMatch[3] = eaddr[3]; 1536999Snate@binkert.org rom.perfectMatch[4] = eaddr[4]; 1546877Ssteve.reinhardt@amd.com rom.perfectMatch[5] = eaddr[5]; 1556877Ssteve.reinhardt@amd.com} 1566877Ssteve.reinhardt@amd.com 1576877Ssteve.reinhardt@amd.comNSGigE::~NSGigE() 1586877Ssteve.reinhardt@amd.com{} 1596877Ssteve.reinhardt@amd.com 1606877Ssteve.reinhardt@amd.comvoid 1616877Ssteve.reinhardt@amd.comNSGigE::regStats() 1626877Ssteve.reinhardt@amd.com{ 1636877Ssteve.reinhardt@amd.com txBytes 1646877Ssteve.reinhardt@amd.com .name(name() + ".txBytes") 1656877Ssteve.reinhardt@amd.com .desc("Bytes Transmitted") 1666877Ssteve.reinhardt@amd.com .prereq(txBytes) 1676877Ssteve.reinhardt@amd.com ; 1686877Ssteve.reinhardt@amd.com 1696877Ssteve.reinhardt@amd.com rxBytes 1706882SBrad.Beckmann@amd.com .name(name() + ".rxBytes") 1716882SBrad.Beckmann@amd.com .desc("Bytes Received") 1726882SBrad.Beckmann@amd.com .prereq(rxBytes) 1736882SBrad.Beckmann@amd.com ; 1746882SBrad.Beckmann@amd.com 1756882SBrad.Beckmann@amd.com txPackets 1766882SBrad.Beckmann@amd.com .name(name() + ".txPackets") 1776877Ssteve.reinhardt@amd.com .desc("Number of Packets Transmitted") 1786877Ssteve.reinhardt@amd.com .prereq(txBytes) 1796877Ssteve.reinhardt@amd.com ; 1806877Ssteve.reinhardt@amd.com 1816657Snate@binkert.org rxPackets 1826657Snate@binkert.org .name(name() + ".rxPackets") 1836999Snate@binkert.org .desc("Number of Packets Received") 1846657Snate@binkert.org .prereq(rxBytes) 1856657Snate@binkert.org ; 1866657Snate@binkert.org 1876657Snate@binkert.org txBandwidth 1886657Snate@binkert.org .name(name() + ".txBandwidth") 1896657Snate@binkert.org .desc("Transmit Bandwidth (bits/s)") 1906657Snate@binkert.org .precision(0) 1916657Snate@binkert.org .prereq(txBytes) 1926657Snate@binkert.org ; 1936657Snate@binkert.org 1946657Snate@binkert.org rxBandwidth 1956657Snate@binkert.org .name(name() + ".rxBandwidth") 1966657Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 1976657Snate@binkert.org .precision(0) 1986657Snate@binkert.org .prereq(rxBytes) 1997002Snate@binkert.org ; 2007002Snate@binkert.org 2017002Snate@binkert.org txPacketRate 2027002Snate@binkert.org .name(name() + ".txPPS") 2036877Ssteve.reinhardt@amd.com .desc("Packet Tranmission Rate (packets/s)") 2046877Ssteve.reinhardt@amd.com .precision(0) 2056657Snate@binkert.org .prereq(txBytes) 2066657Snate@binkert.org ; 2076657Snate@binkert.org 2086657Snate@binkert.org rxPacketRate 2096657Snate@binkert.org .name(name() + ".rxPPS") 2106657Snate@binkert.org .desc("Packet Reception Rate (packets/s)") 2116657Snate@binkert.org .precision(0) 2126657Snate@binkert.org .prereq(rxBytes) 2136657Snate@binkert.org ; 2146657Snate@binkert.org 2156793SBrad.Beckmann@amd.com txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2166657Snate@binkert.org rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2176657Snate@binkert.org txPacketRate = txPackets / simSeconds; 2186657Snate@binkert.org rxPacketRate = rxPackets / simSeconds; 2196657Snate@binkert.org} 2206657Snate@binkert.org 2217002Snate@binkert.org/** 2226657Snate@binkert.org * This is to read the PCI general configuration registers 2236657Snate@binkert.org */ 2246657Snate@binkert.orgvoid 2256657Snate@binkert.orgNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2266657Snate@binkert.org{ 2276877Ssteve.reinhardt@amd.com if (offset < PCI_DEVICE_SPECIFIC) 2286877Ssteve.reinhardt@amd.com PciDev::ReadConfig(offset, size, data); 2296657Snate@binkert.org else { 2306877Ssteve.reinhardt@amd.com panic("need to do this\n"); 2316657Snate@binkert.org } 2326657Snate@binkert.org} 2337002Snate@binkert.org 2347002Snate@binkert.org/** 2356657Snate@binkert.org * This is to write to the PCI general configuration registers 2366881SBrad.Beckmann@amd.com */ 2377002Snate@binkert.orgvoid 2387002Snate@binkert.orgNSGigE::WriteConfig(int offset, int size, uint32_t data) 2396657Snate@binkert.org{ 2407002Snate@binkert.org if (offset < PCI_DEVICE_SPECIFIC) 2416902SBrad.Beckmann@amd.com PciDev::WriteConfig(offset, size, data); 2426863Sdrh5@cs.wisc.edu else 2436863Sdrh5@cs.wisc.edu panic("Need to do that\n"); 2446657Snate@binkert.org} 2456657Snate@binkert.org 2466657Snate@binkert.org/** 2476657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820 2486657Snate@binkert.org * spec sheet 2496657Snate@binkert.org */ 2506882SBrad.Beckmann@amd.comFault 2516882SBrad.Beckmann@amd.comNSGigE::read(MemReqPtr &req, uint8_t *data) 2526882SBrad.Beckmann@amd.com{ 2536882SBrad.Beckmann@amd.com //The mask is to give you only the offset into the device register file 2546657Snate@binkert.org Addr daddr = req->paddr & 0xfff; 2556657Snate@binkert.org DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 2566657Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 2576657Snate@binkert.org 2586657Snate@binkert.org 2596657Snate@binkert.org //there are some reserved registers, you can see ns_gige_reg.h and 2607002Snate@binkert.org //the spec sheet for details 2616657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 2626657Snate@binkert.org panic("Accessing reserved register"); 2636657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 2647002Snate@binkert.org ReadConfig(daddr & 0xff, req->size, data); 2656657Snate@binkert.org return No_Fault; 2666657Snate@binkert.org } else if (daddr >= MIB_START && daddr <= MIB_END) { 2676657Snate@binkert.org // don't implement all the MIB's. hopefully the kernel 2686863Sdrh5@cs.wisc.edu // doesn't actually DEPEND upon their values 2696863Sdrh5@cs.wisc.edu // MIB are just hardware stats keepers 2706657Snate@binkert.org uint32_t ® = *(uint32_t *) data; 2716657Snate@binkert.org reg = 0; 2726657Snate@binkert.org return No_Fault; 2736657Snate@binkert.org } else if (daddr > 0x3FC) 2746657Snate@binkert.org panic("Something is messed up!\n"); 2756657Snate@binkert.org 2766657Snate@binkert.org switch (req->size) { 2776657Snate@binkert.org case sizeof(uint32_t): 2786657Snate@binkert.org { 2796657Snate@binkert.org uint32_t ® = *(uint32_t *)data; 2806657Snate@binkert.org 2816657Snate@binkert.org switch (daddr) { 2826657Snate@binkert.org case CR: 2836657Snate@binkert.org reg = regs.command; 2846657Snate@binkert.org //these are supposed to be cleared on a read 2856657Snate@binkert.org reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2866657Snate@binkert.org break; 2876657Snate@binkert.org 2886657Snate@binkert.org case CFG: 2896657Snate@binkert.org reg = regs.config; 2906657Snate@binkert.org break; 2916657Snate@binkert.org 2926657Snate@binkert.org case MEAR: 2936657Snate@binkert.org reg = regs.mear; 2946657Snate@binkert.org break; 2956657Snate@binkert.org 2966657Snate@binkert.org case PTSCR: 2976657Snate@binkert.org reg = regs.ptscr; 2986657Snate@binkert.org break; 2996657Snate@binkert.org 3006657Snate@binkert.org case ISR: 3016657Snate@binkert.org reg = regs.isr; 3026657Snate@binkert.org devIntrClear(ISR_ALL); 3036657Snate@binkert.org break; 3046657Snate@binkert.org 3056657Snate@binkert.org case IMR: 3066657Snate@binkert.org reg = regs.imr; 3076657Snate@binkert.org break; 3086999Snate@binkert.org 3096657Snate@binkert.org case IER: 3106657Snate@binkert.org reg = regs.ier; 3116657Snate@binkert.org break; 3126657Snate@binkert.org 3136657Snate@binkert.org case IHR: 3146657Snate@binkert.org reg = regs.ihr; 3156657Snate@binkert.org break; 3166657Snate@binkert.org 3176657Snate@binkert.org case TXDP: 3186657Snate@binkert.org reg = regs.txdp; 3197002Snate@binkert.org break; 3207002Snate@binkert.org 3217002Snate@binkert.org case TXDP_HI: 3226657Snate@binkert.org reg = regs.txdp_hi; 3236657Snate@binkert.org break; 3246657Snate@binkert.org 3256657Snate@binkert.org case TXCFG: 3266657Snate@binkert.org reg = regs.txcfg; 3276657Snate@binkert.org break; 3286657Snate@binkert.org 3297002Snate@binkert.org case GPIOR: 3307002Snate@binkert.org reg = regs.gpior; 3316657Snate@binkert.org break; 3326657Snate@binkert.org 3336657Snate@binkert.org case RXDP: 3346657Snate@binkert.org reg = regs.rxdp; 3356657Snate@binkert.org break; 3366793SBrad.Beckmann@amd.com 3376657Snate@binkert.org case RXDP_HI: 3386657Snate@binkert.org reg = regs.rxdp_hi; 3396657Snate@binkert.org break; 3406657Snate@binkert.org 3416877Ssteve.reinhardt@amd.com case RXCFG: 3426877Ssteve.reinhardt@amd.com reg = regs.rxcfg; 3436877Ssteve.reinhardt@amd.com break; 3446877Ssteve.reinhardt@amd.com 3456877Ssteve.reinhardt@amd.com case PQCR: 3466877Ssteve.reinhardt@amd.com reg = regs.pqcr; 3476877Ssteve.reinhardt@amd.com break; 3486657Snate@binkert.org 3496657Snate@binkert.org case WCSR: 3506657Snate@binkert.org reg = regs.wcsr; 3516657Snate@binkert.org break; 3526657Snate@binkert.org 3536877Ssteve.reinhardt@amd.com case PCR: 3546877Ssteve.reinhardt@amd.com reg = regs.pcr; 3556657Snate@binkert.org break; 3566877Ssteve.reinhardt@amd.com 3576877Ssteve.reinhardt@amd.com //see the spec sheet for how RFCR and RFDR work 3586877Ssteve.reinhardt@amd.com //basically, you write to RFCR to tell the machine what you want to do next 3596877Ssteve.reinhardt@amd.com //then you act upon RFDR, and the device will be prepared b/c 3606877Ssteve.reinhardt@amd.com //of what you wrote to RFCR 3616969SBrad.Beckmann@amd.com case RFCR: 3626657Snate@binkert.org reg = regs.rfcr; 3636657Snate@binkert.org break; 3646882SBrad.Beckmann@amd.com 3656882SBrad.Beckmann@amd.com case RFDR: 3666882SBrad.Beckmann@amd.com switch (regs.rfcr & RFCR_RFADDR) { 3676882SBrad.Beckmann@amd.com case 0x000: 3686882SBrad.Beckmann@amd.com reg = rom.perfectMatch[1]; 3696882SBrad.Beckmann@amd.com reg = reg << 8; 3706882SBrad.Beckmann@amd.com reg += rom.perfectMatch[0]; 3716882SBrad.Beckmann@amd.com break; 3726877Ssteve.reinhardt@amd.com case 0x002: 3736888SBrad.Beckmann@amd.com reg = rom.perfectMatch[3] << 8; 3746882SBrad.Beckmann@amd.com reg += rom.perfectMatch[2]; 3756882SBrad.Beckmann@amd.com break; 3766882SBrad.Beckmann@amd.com case 0x004: 3776882SBrad.Beckmann@amd.com reg = rom.perfectMatch[5] << 8; 3786882SBrad.Beckmann@amd.com reg += rom.perfectMatch[4]; 3796882SBrad.Beckmann@amd.com break; 3806882SBrad.Beckmann@amd.com default: 3816882SBrad.Beckmann@amd.com panic("reading from RFDR for something for other than PMATCH!\n"); 3826882SBrad.Beckmann@amd.com //didn't implement other RFDR functionality b/c driver didn't use 3836882SBrad.Beckmann@amd.com } 3846882SBrad.Beckmann@amd.com break; 3856882SBrad.Beckmann@amd.com 3866882SBrad.Beckmann@amd.com case SRR: 3876882SBrad.Beckmann@amd.com reg = regs.srr; 3886882SBrad.Beckmann@amd.com break; 3896882SBrad.Beckmann@amd.com 3906882SBrad.Beckmann@amd.com case MIBC: 3916882SBrad.Beckmann@amd.com reg = regs.mibc; 3926888SBrad.Beckmann@amd.com reg &= ~(MIBC_MIBS | MIBC_ACLR); 3936888SBrad.Beckmann@amd.com break; 3946888SBrad.Beckmann@amd.com 3956888SBrad.Beckmann@amd.com case VRCR: 3966888SBrad.Beckmann@amd.com reg = regs.vrcr; 3976888SBrad.Beckmann@amd.com break; 3986888SBrad.Beckmann@amd.com 3996888SBrad.Beckmann@amd.com case VTCR: 4006657Snate@binkert.org reg = regs.vtcr; 4016888SBrad.Beckmann@amd.com break; 4026888SBrad.Beckmann@amd.com 4036888SBrad.Beckmann@amd.com case VDR: 4046888SBrad.Beckmann@amd.com reg = regs.vdr; 4056657Snate@binkert.org break; 4066657Snate@binkert.org 4076657Snate@binkert.org case CCSR: 4086657Snate@binkert.org reg = regs.ccsr; 4096657Snate@binkert.org break; 4106657Snate@binkert.org 4116657Snate@binkert.org case TBICR: 4126657Snate@binkert.org reg = regs.tbicr; 4136657Snate@binkert.org break; 4146877Ssteve.reinhardt@amd.com 4156657Snate@binkert.org case TBISR: 4166657Snate@binkert.org reg = regs.tbisr; 4176657Snate@binkert.org break; 4186657Snate@binkert.org 4196657Snate@binkert.org case TANAR: 4206657Snate@binkert.org reg = regs.tanar; 4216657Snate@binkert.org break; 4226657Snate@binkert.org 4236657Snate@binkert.org case TANLPAR: 4246657Snate@binkert.org reg = regs.tanlpar; 4256657Snate@binkert.org break; 4266657Snate@binkert.org 4276657Snate@binkert.org case TANER: 4286657Snate@binkert.org reg = regs.taner; 4296657Snate@binkert.org break; 4306657Snate@binkert.org 4316657Snate@binkert.org case TESR: 4326657Snate@binkert.org reg = regs.tesr; 4336657Snate@binkert.org break; 4346657Snate@binkert.org 4356657Snate@binkert.org default: 4366657Snate@binkert.org panic("reading unimplemented register: addr = %#x", daddr); 4376657Snate@binkert.org } 4386657Snate@binkert.org 4396657Snate@binkert.org DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 4406657Snate@binkert.org daddr, reg, reg); 4416657Snate@binkert.org } 4426657Snate@binkert.org break; 4436657Snate@binkert.org 4446657Snate@binkert.org default: 4456657Snate@binkert.org panic("accessing register with invalid size: addr=%#x, size=%d", 4466657Snate@binkert.org daddr, req->size); 4476657Snate@binkert.org } 4486657Snate@binkert.org 4496657Snate@binkert.org return No_Fault; 4506657Snate@binkert.org} 4516657Snate@binkert.org 4526657Snate@binkert.orgFault 4536657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data) 4546657Snate@binkert.org{ 4556657Snate@binkert.org Addr daddr = req->paddr & 0xfff; 4566657Snate@binkert.org DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 4576657Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 4586657Snate@binkert.org 4596657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 4606657Snate@binkert.org panic("Accessing reserved register"); 4616657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 4626657Snate@binkert.org WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 4636657Snate@binkert.org return No_Fault; 4646657Snate@binkert.org } else if (daddr > 0x3FC) 4656657Snate@binkert.org panic("Something is messed up!\n"); 4666657Snate@binkert.org 4676657Snate@binkert.org if (req->size == sizeof(uint32_t)) { 4686657Snate@binkert.org uint32_t reg = *(uint32_t *)data; 4696657Snate@binkert.org DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4706657Snate@binkert.org 4716657Snate@binkert.org switch (daddr) { 4726657Snate@binkert.org case CR: 4736657Snate@binkert.org regs.command = reg; 4746657Snate@binkert.org if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 4756657Snate@binkert.org txHalt = true; 4766657Snate@binkert.org } else if (reg & CR_TXE) { 4776657Snate@binkert.org //the kernel is enabling the transmit machine 4786657Snate@binkert.org if (txState == txIdle) 4796657Snate@binkert.org txKick(); 4806657Snate@binkert.org } else if (reg & CR_TXD) { 4816657Snate@binkert.org txHalt = true; 4826657Snate@binkert.org } 4836657Snate@binkert.org 4846657Snate@binkert.org if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 4856657Snate@binkert.org rxHalt = true; 4866657Snate@binkert.org } else if (reg & CR_RXE) { 4876657Snate@binkert.org if (rxState == rxIdle) { 4886657Snate@binkert.org rxKick(); 4896657Snate@binkert.org } 4906657Snate@binkert.org } else if (reg & CR_RXD) { 4916657Snate@binkert.org rxHalt = true; 4926657Snate@binkert.org } 4936657Snate@binkert.org 4946657Snate@binkert.org if (reg & CR_TXR) 4956657Snate@binkert.org txReset(); 4966657Snate@binkert.org 4976657Snate@binkert.org if (reg & CR_RXR) 4986657Snate@binkert.org rxReset(); 4996657Snate@binkert.org 5006657Snate@binkert.org if (reg & CR_SWI) 5016657Snate@binkert.org devIntrPost(ISR_SWI); 5026657Snate@binkert.org 5036657Snate@binkert.org if (reg & CR_RST) { 5046657Snate@binkert.org txReset(); 5056657Snate@binkert.org rxReset(); 5066657Snate@binkert.org 5076657Snate@binkert.org regsReset(); 5086657Snate@binkert.org } 5096657Snate@binkert.org break; 5106657Snate@binkert.org 5116657Snate@binkert.org case CFG: 5126657Snate@binkert.org if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS 5136657Snate@binkert.org || reg & CFG_RESERVED || reg & CFG_T64ADDR 5146657Snate@binkert.org || reg & CFG_PCI64_DET) 5156657Snate@binkert.org panic("writing to read-only or reserved CFG bits!\n"); 5166657Snate@binkert.org 5176657Snate@binkert.org regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED | 5186657Snate@binkert.org CFG_T64ADDR | CFG_PCI64_DET); 5196657Snate@binkert.org 5206657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to have these implemented 5216657Snate@binkert.org// if there is a problem relating to one of these, you may need to add functionality in 5226657Snate@binkert.org#if 0 5236657Snate@binkert.org if (reg & CFG_TBI_EN) ; 5246657Snate@binkert.org if (reg & CFG_MODE_1000) ; 5256657Snate@binkert.org#endif 5266657Snate@binkert.org 5276657Snate@binkert.org if (reg & CFG_AUTO_1000) 5286657Snate@binkert.org panic("CFG_AUTO_1000 not implemented!\n"); 5296657Snate@binkert.org 5306657Snate@binkert.org#if 0 5316657Snate@binkert.org if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; 5326657Snate@binkert.org if (reg & CFG_TMRTEST) ; 5336657Snate@binkert.org if (reg & CFG_MRM_DIS) ; 5346657Snate@binkert.org if (reg & CFG_MWI_DIS) ; 5356657Snate@binkert.org 5366657Snate@binkert.org if (reg & CFG_T64ADDR) 5376657Snate@binkert.org panic("CFG_T64ADDR is read only register!\n"); 5386657Snate@binkert.org 5396657Snate@binkert.org if (reg & CFG_PCI64_DET) 5406657Snate@binkert.org panic("CFG_PCI64_DET is read only register!\n"); 5416657Snate@binkert.org 5426657Snate@binkert.org if (reg & CFG_DATA64_EN) ; 5436657Snate@binkert.org if (reg & CFG_M64ADDR) ; 5446657Snate@binkert.org if (reg & CFG_PHY_RST) ; 5456657Snate@binkert.org if (reg & CFG_PHY_DIS) ; 5466657Snate@binkert.org#endif 5476657Snate@binkert.org 5486657Snate@binkert.org if (reg & CFG_EXTSTS_EN) 5496657Snate@binkert.org extstsEnable = true; 5506657Snate@binkert.org else 5516657Snate@binkert.org extstsEnable = false; 5526657Snate@binkert.org 5536657Snate@binkert.org#if 0 5546657Snate@binkert.org if (reg & CFG_REQALG) ; 5556657Snate@binkert.org if (reg & CFG_SB) ; 5566657Snate@binkert.org if (reg & CFG_POW) ; 5576657Snate@binkert.org if (reg & CFG_EXD) ; 5586657Snate@binkert.org if (reg & CFG_PESEL) ; 5596657Snate@binkert.org if (reg & CFG_BROM_DIS) ; 5606657Snate@binkert.org if (reg & CFG_EXT_125) ; 5616657Snate@binkert.org if (reg & CFG_BEM) ; 5626657Snate@binkert.org#endif 5636657Snate@binkert.org break; 5646657Snate@binkert.org 5656657Snate@binkert.org case MEAR: 5666657Snate@binkert.org regs.mear = reg; 5676657Snate@binkert.org /* since phy is completely faked, MEAR_MD* don't matter 5686657Snate@binkert.org and since the driver never uses MEAR_EE*, they don't matter */ 5696657Snate@binkert.org#if 0 5706657Snate@binkert.org if (reg & MEAR_EEDI) ; 5716657Snate@binkert.org if (reg & MEAR_EEDO) ; //this one is read only 5726657Snate@binkert.org if (reg & MEAR_EECLK) ; 5736657Snate@binkert.org if (reg & MEAR_EESEL) ; 5746657Snate@binkert.org if (reg & MEAR_MDIO) ; 5756657Snate@binkert.org if (reg & MEAR_MDDIR) ; 5766657Snate@binkert.org if (reg & MEAR_MDC) ; 5776657Snate@binkert.org#endif 5786657Snate@binkert.org break; 5796863Sdrh5@cs.wisc.edu 5806863Sdrh5@cs.wisc.edu case PTSCR: 5816863Sdrh5@cs.wisc.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5826863Sdrh5@cs.wisc.edu /* these control BISTs for various parts of chip - we don't care or do 5836863Sdrh5@cs.wisc.edu just fake that the BIST is done */ 5846863Sdrh5@cs.wisc.edu if (reg & PTSCR_RBIST_EN) 5856863Sdrh5@cs.wisc.edu regs.ptscr |= PTSCR_RBIST_DONE; 5866863Sdrh5@cs.wisc.edu if (reg & PTSCR_EEBIST_EN) 5876863Sdrh5@cs.wisc.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5886863Sdrh5@cs.wisc.edu if (reg & PTSCR_EELOAD_EN) 5896863Sdrh5@cs.wisc.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 5906657Snate@binkert.org break; 5916657Snate@binkert.org 5926657Snate@binkert.org case ISR: /* writing to the ISR has no effect */ 5936657Snate@binkert.org panic("ISR is a read only register!\n"); 5946657Snate@binkert.org 5956657Snate@binkert.org case IMR: 5966657Snate@binkert.org regs.imr = reg; 5976657Snate@binkert.org devIntrChangeMask(); 5986657Snate@binkert.org break; 5996657Snate@binkert.org 6006902SBrad.Beckmann@amd.com case IER: 6016902SBrad.Beckmann@amd.com regs.ier = reg; 6026902SBrad.Beckmann@amd.com break; 6036902SBrad.Beckmann@amd.com 6046902SBrad.Beckmann@amd.com case IHR: 6056902SBrad.Beckmann@amd.com regs.ihr = reg; 6066902SBrad.Beckmann@amd.com /* not going to implement real interrupt holdoff */ 6076902SBrad.Beckmann@amd.com break; 6086902SBrad.Beckmann@amd.com 6096902SBrad.Beckmann@amd.com case TXDP: 6106902SBrad.Beckmann@amd.com regs.txdp = (reg & 0xFFFFFFFC); 6116902SBrad.Beckmann@amd.com assert(txState == txIdle); 6126902SBrad.Beckmann@amd.com CTDD = false; 6136902SBrad.Beckmann@amd.com break; 6146902SBrad.Beckmann@amd.com 6156902SBrad.Beckmann@amd.com case TXDP_HI: 6166902SBrad.Beckmann@amd.com regs.txdp_hi = reg; 6176902SBrad.Beckmann@amd.com break; 6186902SBrad.Beckmann@amd.com 6196902SBrad.Beckmann@amd.com case TXCFG: 6206902SBrad.Beckmann@amd.com regs.txcfg = reg; 6216902SBrad.Beckmann@amd.com#if 0 6226902SBrad.Beckmann@amd.com if (reg & TXCFG_CSI) ; 6236902SBrad.Beckmann@amd.com if (reg & TXCFG_HBI) ; 6246902SBrad.Beckmann@amd.com if (reg & TXCFG_MLB) ; 6256902SBrad.Beckmann@amd.com if (reg & TXCFG_ATP) ; 6266902SBrad.Beckmann@amd.com if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but 6276902SBrad.Beckmann@amd.com considering the network is just a fake 6286902SBrad.Beckmann@amd.com pipe, wouldn't make sense to do this */ 6296902SBrad.Beckmann@amd.com 6306902SBrad.Beckmann@amd.com if (reg & TXCFG_BRST_DIS) ; 6316902SBrad.Beckmann@amd.com#endif 6326657Snate@binkert.org 6336657Snate@binkert.org 6346657Snate@binkert.org /* we handle our own DMA, ignore the kernel's exhortations */ 6356657Snate@binkert.org if (reg & TXCFG_MXDMA) ; 6366657Snate@binkert.org 6376657Snate@binkert.org break; 6386657Snate@binkert.org 6396657Snate@binkert.org case GPIOR: 6406657Snate@binkert.org regs.gpior = reg; 6416657Snate@binkert.org /* these just control general purpose i/o pins, don't matter */ 6426657Snate@binkert.org break; 6436657Snate@binkert.org 6446657Snate@binkert.org case RXDP: 6456657Snate@binkert.org regs.rxdp = reg; 6466657Snate@binkert.org break; 6476657Snate@binkert.org 6486657Snate@binkert.org case RXDP_HI: 6496657Snate@binkert.org regs.rxdp_hi = reg; 6506657Snate@binkert.org break; 6516657Snate@binkert.org 6526657Snate@binkert.org case RXCFG: 6536999Snate@binkert.org regs.rxcfg = reg; 6546657Snate@binkert.org#if 0 6556657Snate@binkert.org if (reg & RXCFG_AEP) ; 6566657Snate@binkert.org if (reg & RXCFG_ARP) ; 6576657Snate@binkert.org if (reg & RXCFG_STRIPCRC) ; 6586657Snate@binkert.org if (reg & RXCFG_RX_RD) ; 6596657Snate@binkert.org if (reg & RXCFG_ALP) ; 6606657Snate@binkert.org if (reg & RXCFG_AIRL) ; 6616657Snate@binkert.org#endif 6626657Snate@binkert.org 6636657Snate@binkert.org /* we handle our own DMA, ignore what kernel says about it */ 6646657Snate@binkert.org if (reg & RXCFG_MXDMA) ; 6656657Snate@binkert.org 6666657Snate@binkert.org#if 0 6676657Snate@binkert.org if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 6686657Snate@binkert.org#endif 6696657Snate@binkert.org break; 6706657Snate@binkert.org 6716657Snate@binkert.org case PQCR: 6726657Snate@binkert.org /* there is no priority queueing used in the linux 2.6 driver */ 6736657Snate@binkert.org regs.pqcr = reg; 6746657Snate@binkert.org break; 6756657Snate@binkert.org 6766657Snate@binkert.org case WCSR: 6776657Snate@binkert.org /* not going to implement wake on LAN */ 6786657Snate@binkert.org regs.wcsr = reg; 6796657Snate@binkert.org break; 6806657Snate@binkert.org 6816657Snate@binkert.org case PCR: 6826657Snate@binkert.org /* not going to implement pause control */ 6836657Snate@binkert.org regs.pcr = reg; 6846657Snate@binkert.org break; 6856657Snate@binkert.org 6866657Snate@binkert.org case RFCR: 6876657Snate@binkert.org regs.rfcr = reg; 6886657Snate@binkert.org 6896657Snate@binkert.org rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6906657Snate@binkert.org 6916657Snate@binkert.org acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6926657Snate@binkert.org 6936657Snate@binkert.org acceptMulticast = (reg & RFCR_AAM) ? true : false; 6946657Snate@binkert.org 6956657Snate@binkert.org acceptUnicast = (reg & RFCR_AAU) ? true : false; 6966657Snate@binkert.org 6976657Snate@binkert.org acceptPerfect = (reg & RFCR_APM) ? true : false; 6986657Snate@binkert.org 6996657Snate@binkert.org acceptArp = (reg & RFCR_AARP) ? true : false; 7006657Snate@binkert.org 7016657Snate@binkert.org if (reg & RFCR_APAT) ; 7026657Snate@binkert.org// panic("RFCR_APAT not implemented!\n"); 7036657Snate@binkert.org 7046657Snate@binkert.org if (reg & RFCR_MHEN || reg & RFCR_UHEN) 7056657Snate@binkert.org panic("hash filtering not implemented!\n"); 7066657Snate@binkert.org 7076657Snate@binkert.org if (reg & RFCR_ULM) 7086999Snate@binkert.org panic("RFCR_ULM not implemented!\n"); 7096657Snate@binkert.org 7106657Snate@binkert.org break; 7116657Snate@binkert.org 7126657Snate@binkert.org case RFDR: 7136657Snate@binkert.org panic("the driver never writes to RFDR, something is wrong!\n"); 7146657Snate@binkert.org 7156657Snate@binkert.org case BRAR: 7166657Snate@binkert.org panic("the driver never uses BRAR, something is wrong!\n"); 7176657Snate@binkert.org 7186657Snate@binkert.org case BRDR: 7196657Snate@binkert.org panic("the driver never uses BRDR, something is wrong!\n"); 7206657Snate@binkert.org 7216657Snate@binkert.org case SRR: 7226657Snate@binkert.org panic("SRR is read only register!\n"); 7236657Snate@binkert.org 7246657Snate@binkert.org case MIBC: 7256657Snate@binkert.org panic("the driver never uses MIBC, something is wrong!\n"); 7266657Snate@binkert.org 7276657Snate@binkert.org case VRCR: 7286657Snate@binkert.org regs.vrcr = reg; 7296657Snate@binkert.org break; 7306657Snate@binkert.org 7316657Snate@binkert.org case VTCR: 7326657Snate@binkert.org regs.vtcr = reg; 7336657Snate@binkert.org break; 7346657Snate@binkert.org 7356657Snate@binkert.org case VDR: 7366657Snate@binkert.org panic("the driver never uses VDR, something is wrong!\n"); 7376657Snate@binkert.org break; 7386657Snate@binkert.org 7396657Snate@binkert.org case CCSR: 7406657Snate@binkert.org /* not going to implement clockrun stuff */ 7416657Snate@binkert.org regs.ccsr = reg; 7426657Snate@binkert.org break; 7436657Snate@binkert.org 7446657Snate@binkert.org case TBICR: 7456657Snate@binkert.org regs.tbicr = reg; 7466657Snate@binkert.org if (reg & TBICR_MR_LOOPBACK) 7476657Snate@binkert.org panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7486657Snate@binkert.org 7496657Snate@binkert.org if (reg & TBICR_MR_AN_ENABLE) { 7506657Snate@binkert.org regs.tanlpar = regs.tanar; 7516657Snate@binkert.org regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7526657Snate@binkert.org } 7536657Snate@binkert.org 7546657Snate@binkert.org#if 0 7556657Snate@binkert.org if (reg & TBICR_MR_RESTART_AN) ; 7566657Snate@binkert.org#endif 7576657Snate@binkert.org 7586657Snate@binkert.org break; 7596657Snate@binkert.org 7606657Snate@binkert.org case TBISR: 7616657Snate@binkert.org panic("TBISR is read only register!\n"); 7626657Snate@binkert.org 7636657Snate@binkert.org case TANAR: 7646657Snate@binkert.org regs.tanar = reg; 7656657Snate@binkert.org if (reg & TANAR_PS2) 7666657Snate@binkert.org panic("this isn't used in driver, something wrong!\n"); 7676657Snate@binkert.org 7686657Snate@binkert.org if (reg & TANAR_PS1) 7696657Snate@binkert.org panic("this isn't used in driver, something wrong!\n"); 7706657Snate@binkert.org break; 7716657Snate@binkert.org 7726657Snate@binkert.org case TANLPAR: 7736657Snate@binkert.org panic("this should only be written to by the fake phy!\n"); 7746657Snate@binkert.org 7756657Snate@binkert.org case TANER: 7766657Snate@binkert.org panic("TANER is read only register!\n"); 7776657Snate@binkert.org 7786657Snate@binkert.org case TESR: 7796657Snate@binkert.org regs.tesr = reg; 7806657Snate@binkert.org break; 7816657Snate@binkert.org 7826657Snate@binkert.org default: 7836657Snate@binkert.org panic("thought i covered all the register, what is this? addr=%#x", 7846657Snate@binkert.org daddr); 7856657Snate@binkert.org } 7866657Snate@binkert.org } else 7876657Snate@binkert.org panic("Invalid Request Size"); 7886657Snate@binkert.org 7896657Snate@binkert.org return No_Fault; 7906999Snate@binkert.org} 7916657Snate@binkert.org 7926657Snate@binkert.orgvoid 7936657Snate@binkert.orgNSGigE::devIntrPost(uint32_t interrupts) 7946657Snate@binkert.org{ 7956657Snate@binkert.org bool delay = false; 7966657Snate@binkert.org 7976657Snate@binkert.org if (interrupts & ISR_RESERVE) 7986657Snate@binkert.org panic("Cannot set a reserved interrupt"); 7996657Snate@binkert.org 8006657Snate@binkert.org if (interrupts & ISR_TXRCMP) 8016657Snate@binkert.org regs.isr |= ISR_TXRCMP; 8026657Snate@binkert.org 8036657Snate@binkert.org if (interrupts & ISR_RXRCMP) 8046657Snate@binkert.org regs.isr |= ISR_RXRCMP; 8056657Snate@binkert.org 8066657Snate@binkert.org//ISR_DPERR not implemented 8076657Snate@binkert.org//ISR_SSERR not implemented 8086657Snate@binkert.org//ISR_RMABT not implemented 8096657Snate@binkert.org//ISR_RXSOVR not implemented 8106657Snate@binkert.org//ISR_HIBINT not implemented 8116657Snate@binkert.org//ISR_PHY not implemented 8126657Snate@binkert.org//ISR_PME not implemented 8136657Snate@binkert.org 8146657Snate@binkert.org if (interrupts & ISR_SWI) 8156657Snate@binkert.org regs.isr |= ISR_SWI; 8166657Snate@binkert.org 8176657Snate@binkert.org//ISR_MIB not implemented 8186657Snate@binkert.org//ISR_TXURN not implemented 8196657Snate@binkert.org 8206657Snate@binkert.org if (interrupts & ISR_TXIDLE) 8216657Snate@binkert.org regs.isr |= ISR_TXIDLE; 8226657Snate@binkert.org 8236657Snate@binkert.org if (interrupts & ISR_TXERR) 8246657Snate@binkert.org regs.isr |= ISR_TXERR; 8256657Snate@binkert.org 8266657Snate@binkert.org if (interrupts & ISR_TXDESC) 8276657Snate@binkert.org regs.isr |= ISR_TXDESC; 8286657Snate@binkert.org 8296657Snate@binkert.org if (interrupts & ISR_TXOK) { 8306657Snate@binkert.org regs.isr |= ISR_TXOK; 8316657Snate@binkert.org delay = true; 8326657Snate@binkert.org } 8336657Snate@binkert.org 8346657Snate@binkert.org if (interrupts & ISR_RXORN) 8356657Snate@binkert.org regs.isr |= ISR_RXORN; 8366657Snate@binkert.org 8376657Snate@binkert.org if (interrupts & ISR_RXIDLE) 8386657Snate@binkert.org regs.isr |= ISR_RXIDLE; 8396657Snate@binkert.org 8406657Snate@binkert.org//ISR_RXEARLY not implemented 8416657Snate@binkert.org 8426657Snate@binkert.org if (interrupts & ISR_RXERR) 8436657Snate@binkert.org regs.isr |= ISR_RXERR; 8446657Snate@binkert.org 8456657Snate@binkert.org if (interrupts & ISR_RXDESC) 8466657Snate@binkert.org regs.isr |= ISR_RXDESC; 8476657Snate@binkert.org 8486657Snate@binkert.org if (interrupts & ISR_RXOK) { 8496657Snate@binkert.org delay = true; 8506657Snate@binkert.org regs.isr |= ISR_RXOK; 8516657Snate@binkert.org } 8526657Snate@binkert.org 8536657Snate@binkert.org if ((regs.isr & regs.imr)) { 8546657Snate@binkert.org Tick when = curTick; 8556657Snate@binkert.org if (delay) 8566657Snate@binkert.org when += intrDelay; 8576657Snate@binkert.org cpuIntrPost(when); 8586657Snate@binkert.org } 8596657Snate@binkert.org 8606657Snate@binkert.org DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n", 8616657Snate@binkert.org interrupts, regs.isr, regs.imr); 8626657Snate@binkert.org} 8636657Snate@binkert.org 8646657Snate@binkert.orgvoid 8656999Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts) 8666657Snate@binkert.org{ 8676657Snate@binkert.org if (interrupts & ISR_RESERVE) 8686657Snate@binkert.org panic("Cannot clear a reserved interrupt"); 8696657Snate@binkert.org 8706657Snate@binkert.org if (interrupts & ISR_TXRCMP) 8716657Snate@binkert.org regs.isr &= ~ISR_TXRCMP; 8726657Snate@binkert.org 8736657Snate@binkert.org if (interrupts & ISR_RXRCMP) 8746657Snate@binkert.org regs.isr &= ~ISR_RXRCMP; 8757002Snate@binkert.org 8767002Snate@binkert.org//ISR_DPERR not implemented 8776657Snate@binkert.org//ISR_SSERR not implemented 8786657Snate@binkert.org//ISR_RMABT not implemented 8796657Snate@binkert.org//ISR_RXSOVR not implemented 8806657Snate@binkert.org//ISR_HIBINT not implemented 8816657Snate@binkert.org//ISR_PHY not implemented 8826657Snate@binkert.org//ISR_PME not implemented 8836657Snate@binkert.org 8846657Snate@binkert.org if (interrupts & ISR_SWI) 8856657Snate@binkert.org regs.isr &= ~ISR_SWI; 8866657Snate@binkert.org 8877002Snate@binkert.org//ISR_MIB not implemented 8886657Snate@binkert.org//ISR_TXURN not implemented 8896657Snate@binkert.org 8906657Snate@binkert.org if (interrupts & ISR_TXIDLE) 8916657Snate@binkert.org regs.isr &= ~ISR_TXIDLE; 8926657Snate@binkert.org 8936657Snate@binkert.org if (interrupts & ISR_TXERR) 8946657Snate@binkert.org regs.isr &= ~ISR_TXERR; 8956657Snate@binkert.org 8966657Snate@binkert.org if (interrupts & ISR_TXDESC) 8976657Snate@binkert.org regs.isr &= ~ISR_TXDESC; 8986657Snate@binkert.org 8996657Snate@binkert.org if (interrupts & ISR_TXOK) 9006657Snate@binkert.org regs.isr &= ~ISR_TXOK; 9016657Snate@binkert.org 9026999Snate@binkert.org if (interrupts & ISR_RXORN) 9036657Snate@binkert.org regs.isr &= ~ISR_RXORN; 9046657Snate@binkert.org 9056657Snate@binkert.org if (interrupts & ISR_RXIDLE) 9066657Snate@binkert.org regs.isr &= ~ISR_RXIDLE; 9076657Snate@binkert.org 9086657Snate@binkert.org//ISR_RXEARLY not implemented 9096657Snate@binkert.org 9106657Snate@binkert.org if (interrupts & ISR_RXERR) 9116657Snate@binkert.org regs.isr &= ~ISR_RXERR; 9126657Snate@binkert.org 9136657Snate@binkert.org if (interrupts & ISR_RXDESC) 9146657Snate@binkert.org regs.isr &= ~ISR_RXDESC; 9156657Snate@binkert.org 9166657Snate@binkert.org if (interrupts & ISR_RXOK) 9176657Snate@binkert.org regs.isr &= ~ISR_RXOK; 9186657Snate@binkert.org 9196657Snate@binkert.org if (!(regs.isr & regs.imr)) 9206657Snate@binkert.org cpuIntrClear(); 9216657Snate@binkert.org 9226657Snate@binkert.org DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n", 9236657Snate@binkert.org interrupts, regs.isr, regs.imr); 9246657Snate@binkert.org} 9256657Snate@binkert.org 9266657Snate@binkert.orgvoid 9276657Snate@binkert.orgNSGigE::devIntrChangeMask() 9286657Snate@binkert.org{ 9296657Snate@binkert.org DPRINTF(Ethernet, "interrupt mask changed\n"); 9306657Snate@binkert.org 9316657Snate@binkert.org if (regs.isr & regs.imr) 9326657Snate@binkert.org cpuIntrPost(curTick); 9336657Snate@binkert.org else 9346657Snate@binkert.org cpuIntrClear(); 9356657Snate@binkert.org} 9366657Snate@binkert.org 9376657Snate@binkert.orgvoid 9386657Snate@binkert.orgNSGigE::cpuIntrPost(Tick when) 9396657Snate@binkert.org{ 9406657Snate@binkert.org if (when > intrTick && intrTick != 0) 9416657Snate@binkert.org return; 9426657Snate@binkert.org 9436657Snate@binkert.org intrTick = when; 9446657Snate@binkert.org 9456657Snate@binkert.org if (intrEvent) { 9466657Snate@binkert.org intrEvent->squash(); 9476657Snate@binkert.org intrEvent = 0; 9486657Snate@binkert.org } 9497002Snate@binkert.org 9506657Snate@binkert.org if (when < curTick) { 9517002Snate@binkert.org cpuInterrupt(); 9527002Snate@binkert.org } else { 9536657Snate@binkert.org intrEvent = new IntrEvent(this, true); 9546657Snate@binkert.org intrEvent->schedule(intrTick); 9556657Snate@binkert.org } 9566657Snate@binkert.org} 9576657Snate@binkert.org 9586657Snate@binkert.orgvoid 9596657Snate@binkert.orgNSGigE::cpuInterrupt() 9606657Snate@binkert.org{ 9616657Snate@binkert.org // Don't send an interrupt if there's already one 9626657Snate@binkert.org if (cpuPendingIntr) 9636657Snate@binkert.org return; 9646657Snate@binkert.org 9656657Snate@binkert.org // Don't send an interrupt if it's supposed to be delayed 9666657Snate@binkert.org if (intrTick > curTick) 9676657Snate@binkert.org return; 9686657Snate@binkert.org 9696657Snate@binkert.org // Whether or not there's a pending interrupt, we don't care about 9706657Snate@binkert.org // it anymore 9716657Snate@binkert.org intrEvent = 0; 9726657Snate@binkert.org intrTick = 0; 9736657Snate@binkert.org 9746657Snate@binkert.org // Send interrupt 9756657Snate@binkert.org cpuPendingIntr = true; 9766657Snate@binkert.org /** @todo rework the intctrl to be tsunami ok */ 9776657Snate@binkert.org //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 9786657Snate@binkert.org tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 9796657Snate@binkert.org} 9806657Snate@binkert.org 9816657Snate@binkert.orgvoid 9826657Snate@binkert.orgNSGigE::cpuIntrClear() 9836999Snate@binkert.org{ 9846657Snate@binkert.org if (cpuPendingIntr) { 9856657Snate@binkert.org cpuPendingIntr = false; 9866657Snate@binkert.org /** @todo rework the intctrl to be tsunami ok */ 9876657Snate@binkert.org //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 9886657Snate@binkert.org tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 9896657Snate@binkert.org } 9906657Snate@binkert.org} 9916657Snate@binkert.org 9926657Snate@binkert.orgbool 9936657Snate@binkert.orgNSGigE::cpuIntrPending() const 9946657Snate@binkert.org{ return cpuPendingIntr; } 9956657Snate@binkert.org 9966657Snate@binkert.orgvoid 9976657Snate@binkert.orgNSGigE::txReset() 9986657Snate@binkert.org{ 9996657Snate@binkert.org 10006657Snate@binkert.org DPRINTF(Ethernet, "transmit reset\n"); 10016657Snate@binkert.org 10026657Snate@binkert.org CTDD = false; 10036657Snate@binkert.org txFifoCnt = 0; 10046657Snate@binkert.org txFifoAvail = MAX_TX_FIFO_SIZE; 10056657Snate@binkert.org txHalt = false; 10066657Snate@binkert.org txFragPtr = 0; 10076657Snate@binkert.org assert(txDescCnt == 0); 10086657Snate@binkert.org txFifo.clear(); 10096657Snate@binkert.org regs.command &= ~CR_TXE; 10106657Snate@binkert.org txState = txIdle; 10116657Snate@binkert.org assert(txDmaState == dmaIdle); 10126657Snate@binkert.org} 10136657Snate@binkert.org 10146999Snate@binkert.orgvoid 10156657Snate@binkert.orgNSGigE::rxReset() 10166657Snate@binkert.org{ 10176657Snate@binkert.org DPRINTF(Ethernet, "receive reset\n"); 10186657Snate@binkert.org 10196657Snate@binkert.org CRDD = false; 10206657Snate@binkert.org assert(rxPktBytes == 0); 10216657Snate@binkert.org rxFifoCnt = 0; 10226657Snate@binkert.org rxHalt = false; 10236657Snate@binkert.org rxFragPtr = 0; 10246657Snate@binkert.org assert(rxDescCnt == 0); 10256657Snate@binkert.org assert(rxDmaState == dmaIdle); 10266657Snate@binkert.org rxFifo.clear(); 10276657Snate@binkert.org regs.command &= ~CR_RXE; 10286657Snate@binkert.org rxState = rxIdle; 10296657Snate@binkert.org} 10306657Snate@binkert.org 10316657Snate@binkert.orgvoid 10326657Snate@binkert.orgNSGigE::rxDmaReadCopy() 10336657Snate@binkert.org{ 10346657Snate@binkert.org assert(rxDmaState == dmaReading); 10356657Snate@binkert.org 10366657Snate@binkert.org memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 10376657Snate@binkert.org rxDmaState = dmaIdle; 10386657Snate@binkert.org 10396657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 10406657Snate@binkert.org rxDmaAddr, rxDmaLen); 10416657Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10426657Snate@binkert.org} 10436657Snate@binkert.org 10446657Snate@binkert.orgbool 10456657Snate@binkert.orgNSGigE::doRxDmaRead() 10466657Snate@binkert.org{ 10476657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 10486657Snate@binkert.org rxDmaState = dmaReading; 10496657Snate@binkert.org 10506657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 10516657Snate@binkert.org if (dmaInterface->busy()) 10526657Snate@binkert.org rxDmaState = dmaReadWaiting; 10536657Snate@binkert.org else 10546657Snate@binkert.org dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 10556657Snate@binkert.org &rxDmaReadEvent); 10566657Snate@binkert.org return true; 10576657Snate@binkert.org } 10586657Snate@binkert.org 10596657Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0) { 10606657Snate@binkert.org rxDmaReadCopy(); 10616657Snate@binkert.org return false; 10626657Snate@binkert.org } 10636657Snate@binkert.org 10646657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 10656657Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 10666657Snate@binkert.org rxDmaReadEvent.schedule(start); 10676657Snate@binkert.org return true; 10686657Snate@binkert.org} 10696657Snate@binkert.org 10706657Snate@binkert.orgvoid 10716657Snate@binkert.orgNSGigE::rxDmaReadDone() 10726657Snate@binkert.org{ 10736657Snate@binkert.org assert(rxDmaState == dmaReading); 10746657Snate@binkert.org rxDmaReadCopy(); 10756657Snate@binkert.org 10766657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 10776657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10786657Snate@binkert.org txKick(); 10796657Snate@binkert.org 10806657Snate@binkert.org rxKick(); 10816657Snate@binkert.org} 10826657Snate@binkert.org 10836657Snate@binkert.orgvoid 10846657Snate@binkert.orgNSGigE::rxDmaWriteCopy() 10856657Snate@binkert.org{ 10866657Snate@binkert.org assert(rxDmaState == dmaWriting); 10876657Snate@binkert.org 10886657Snate@binkert.org memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 10896657Snate@binkert.org rxDmaState = dmaIdle; 10906657Snate@binkert.org 10916657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 10926657Snate@binkert.org rxDmaAddr, rxDmaLen); 10936657Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10946657Snate@binkert.org} 10956657Snate@binkert.org 10966657Snate@binkert.orgbool 10976657Snate@binkert.orgNSGigE::doRxDmaWrite() 10986657Snate@binkert.org{ 10996657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11006657Snate@binkert.org rxDmaState = dmaWriting; 11016657Snate@binkert.org 11026657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 11036657Snate@binkert.org if (dmaInterface->busy()) 11046657Snate@binkert.org rxDmaState = dmaWriteWaiting; 11056657Snate@binkert.org else 11066657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 11076657Snate@binkert.org &rxDmaWriteEvent); 11086657Snate@binkert.org return true; 11096657Snate@binkert.org } 11106657Snate@binkert.org 11116657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 11126657Snate@binkert.org rxDmaWriteCopy(); 11136657Snate@binkert.org return false; 11146657Snate@binkert.org } 11156657Snate@binkert.org 11166657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 11176657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 11186657Snate@binkert.org rxDmaWriteEvent.schedule(start); 11196657Snate@binkert.org return true; 11206657Snate@binkert.org} 11216657Snate@binkert.org 11226657Snate@binkert.orgvoid 11236657Snate@binkert.orgNSGigE::rxDmaWriteDone() 11246657Snate@binkert.org{ 11256657Snate@binkert.org assert(rxDmaState == dmaWriting); 11266657Snate@binkert.org rxDmaWriteCopy(); 11276657Snate@binkert.org 11286657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 11296657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11306657Snate@binkert.org txKick(); 11316657Snate@binkert.org 11326657Snate@binkert.org rxKick(); 11336657Snate@binkert.org} 11346657Snate@binkert.org 11356657Snate@binkert.orgvoid 11366657Snate@binkert.orgNSGigE::rxKick() 11376657Snate@binkert.org{ 11386657Snate@binkert.org DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n", 11396657Snate@binkert.org NsRxStateStrings[rxState], rxFifo.size()); 11406657Snate@binkert.org 11416657Snate@binkert.org if (rxKickTick > curTick) { 11426657Snate@binkert.org DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", 11436657Snate@binkert.org rxKickTick); 11446657Snate@binkert.org return; 11456657Snate@binkert.org } 11466657Snate@binkert.org 11476657Snate@binkert.org next: 11486657Snate@binkert.org switch(rxDmaState) { 11496657Snate@binkert.org case dmaReadWaiting: 11506657Snate@binkert.org if (doRxDmaRead()) 11516657Snate@binkert.org goto exit; 11526657Snate@binkert.org break; 11536657Snate@binkert.org case dmaWriteWaiting: 1154 if (doRxDmaWrite()) 1155 goto exit; 1156 break; 1157 default: 1158 break; 1159 } 1160 1161 // see state machine from spec for details 1162 // the way this works is, if you finish work on one state and can go directly to 1163 // another, you do that through jumping to the label "next". however, if you have 1164 // intermediate work, like DMA so that you can't go to the next state yet, you go to 1165 // exit and exit the loop. however, when the DMA is done it will trigger an 1166 // event and come back to this loop. 1167 switch (rxState) { 1168 case rxIdle: 1169 if (!regs.command & CR_RXE) { 1170 DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n"); 1171 goto exit; 1172 } 1173 1174 if (CRDD) { 1175 rxState = rxDescRefr; 1176 1177 rxDmaAddr = regs.rxdp & 0x3fffffff; 1178 rxDmaData = &rxDescCache + offsetof(ns_desc, link); 1179 rxDmaLen = sizeof(rxDescCache.link); 1180 rxDmaFree = dmaDescFree; 1181 1182 if (doRxDmaRead()) 1183 goto exit; 1184 } else { 1185 rxState = rxDescRead; 1186 1187 rxDmaAddr = regs.rxdp & 0x3fffffff; 1188 rxDmaData = &rxDescCache; 1189 rxDmaLen = sizeof(ns_desc); 1190 rxDmaFree = dmaDescFree; 1191 1192 if (doRxDmaRead()) 1193 goto exit; 1194 } 1195 break; 1196 1197 case rxDescRefr: 1198 if (rxDmaState != dmaIdle) 1199 goto exit; 1200 1201 rxState = rxAdvance; 1202 break; 1203 1204 case rxDescRead: 1205 if (rxDmaState != dmaIdle) 1206 goto exit; 1207 1208 DPRINTF(Ethernet, 1209 "rxDescCache:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n" 1210 ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 1211 rxDescCache.extsts); 1212 1213 if (rxDescCache.cmdsts & CMDSTS_OWN) { 1214 rxState = rxIdle; 1215 } else { 1216 rxState = rxFifoBlock; 1217 rxFragPtr = rxDescCache.bufptr; 1218 rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 1219 } 1220 break; 1221 1222 case rxFifoBlock: 1223 if (!rxPacket) { 1224 /** 1225 * @todo in reality, we should be able to start processing 1226 * the packet as it arrives, and not have to wait for the 1227 * full packet ot be in the receive fifo. 1228 */ 1229 if (rxFifo.empty()) 1230 goto exit; 1231 1232 // If we don't have a packet, grab a new one from the fifo. 1233 rxPacket = rxFifo.front(); 1234 rxPktBytes = rxPacket->length; 1235 rxPacketBufPtr = rxPacket->data; 1236 1237 // sanity check - i think the driver behaves like this 1238 assert(rxDescCnt >= rxPktBytes); 1239 1240 // Must clear the value before popping to decrement the 1241 // reference count 1242 rxFifo.front() = NULL; 1243 rxFifo.pop_front(); 1244 } 1245 1246 1247 // dont' need the && rxDescCnt > 0 if driver sanity check above holds 1248 if (rxPktBytes > 0) { 1249 rxState = rxFragWrite; 1250 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds 1251 rxXferLen = rxPktBytes; 1252 1253 rxDmaAddr = rxFragPtr & 0x3fffffff; 1254 rxDmaData = rxPacketBufPtr; 1255 rxDmaLen = rxXferLen; 1256 rxDmaFree = dmaDataFree; 1257 1258 if (doRxDmaWrite()) 1259 goto exit; 1260 1261 } else { 1262 rxState = rxDescWrite; 1263 1264 //if (rxPktBytes == 0) { /* packet is done */ 1265 assert(rxPktBytes == 0); 1266 1267 rxDescCache.cmdsts |= CMDSTS_OWN; 1268 rxDescCache.cmdsts &= ~CMDSTS_MORE; 1269 rxDescCache.cmdsts |= CMDSTS_OK; 1270 rxDescCache.cmdsts &= 0xffff0000; 1271 rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1272 1273#if 0 1274 /* all the driver uses these are for its own stats keeping 1275 which we don't care about, aren't necessary for functionality 1276 and doing this would just slow us down. if they end up using 1277 this in a later version for functional purposes, just undef 1278 */ 1279 if (rxFilterEnable) { 1280 rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 1281 if (rxFifo.front()->IsUnicast()) 1282 rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 1283 if (rxFifo.front()->IsMulticast()) 1284 rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 1285 if (rxFifo.front()->IsBroadcast()) 1286 rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 1287 } 1288#endif 1289 1290 eth_header *eth = (eth_header *) rxPacket->data; 1291 // eth->type 0x800 indicated that it's an ip packet. 1292 if (eth->type == 0x800 && extstsEnable) { 1293 rxDescCache.extsts |= EXTSTS_IPPKT; 1294 if (!ipChecksum(rxPacket, false)) 1295 rxDescCache.extsts |= EXTSTS_IPERR; 1296 ip_header *ip = rxFifo.front()->getIpHdr(); 1297 1298 if (ip->protocol == 6) { 1299 rxDescCache.extsts |= EXTSTS_TCPPKT; 1300 if (!tcpChecksum(rxPacket, false)) 1301 rxDescCache.extsts |= EXTSTS_TCPERR; 1302 } else if (ip->protocol == 17) { 1303 rxDescCache.extsts |= EXTSTS_UDPPKT; 1304 if (!udpChecksum(rxPacket, false)) 1305 rxDescCache.extsts |= EXTSTS_UDPERR; 1306 } 1307 } 1308 1309 rxFifoCnt -= rxPacket->length; 1310 rxPacket = 0; 1311 1312 /* the driver seems to always receive into desc buffers 1313 of size 1514, so you never have a pkt that is split 1314 into multiple descriptors on the receive side, so 1315 i don't implement that case, hence the assert above. 1316 */ 1317 1318 DPRINTF(Ethernet, "rxDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n", 1319 rxDescCache.cmdsts, rxDescCache.extsts); 1320 1321 rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1322 rxDmaData = &(rxDescCache.cmdsts); 1323 rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 1324 rxDmaFree = dmaDescFree; 1325 1326 if (doRxDmaWrite()) 1327 goto exit; 1328 } 1329 break; 1330 1331 case rxFragWrite: 1332 if (rxDmaState != dmaIdle) 1333 goto exit; 1334 1335 rxPacketBufPtr += rxXferLen; 1336 rxFragPtr += rxXferLen; 1337 rxPktBytes -= rxXferLen; 1338 1339 rxState = rxFifoBlock; 1340 break; 1341 1342 case rxDescWrite: 1343 if (rxDmaState != dmaIdle) 1344 goto exit; 1345 1346 assert(rxDescCache.cmdsts & CMDSTS_OWN); 1347 1348 assert(rxPacket == 0); 1349 devIntrPost(ISR_RXOK); 1350 1351 if (rxDescCache.cmdsts & CMDSTS_INTR) 1352 devIntrPost(ISR_RXDESC); 1353 1354 if (rxHalt) { 1355 rxState = rxIdle; 1356 rxHalt = false; 1357 } else 1358 rxState = rxAdvance; 1359 break; 1360 1361 case rxAdvance: 1362 if (rxDescCache.link == 0) { 1363 rxState = rxIdle; 1364 return; 1365 } else { 1366 rxState = rxDescRead; 1367 regs.rxdp = rxDescCache.link; 1368 CRDD = false; 1369 1370 rxDmaAddr = regs.rxdp & 0x3fffffff; 1371 rxDmaData = &rxDescCache; 1372 rxDmaLen = sizeof(ns_desc); 1373 rxDmaFree = dmaDescFree; 1374 1375 if (doRxDmaRead()) 1376 goto exit; 1377 } 1378 break; 1379 1380 default: 1381 panic("Invalid rxState!"); 1382 } 1383 1384 1385 DPRINTF(Ethernet, "entering next rx state = %s\n", 1386 NsRxStateStrings[rxState]); 1387 1388 if (rxState == rxIdle) { 1389 regs.command &= ~CR_RXE; 1390 devIntrPost(ISR_RXIDLE); 1391 return; 1392 } 1393 1394 goto next; 1395 1396 exit: 1397 /** 1398 * @todo do we want to schedule a future kick? 1399 */ 1400 DPRINTF(Ethernet, "rx state machine exited state=%s\n", 1401 NsRxStateStrings[rxState]); 1402} 1403 1404void 1405NSGigE::transmit() 1406{ 1407 if (txFifo.empty()) { 1408 DPRINTF(Ethernet, "nothing to transmit\n"); 1409 return; 1410 } 1411 1412 if (interface->sendPacket(txFifo.front())) { 1413 DPRINTF(Ethernet, "transmit packet\n"); 1414 DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 1415 txBytes += txFifo.front()->length; 1416 txPackets++; 1417 1418 txFifoCnt -= (txFifo.front()->length - txPktXmitted); 1419 txPktXmitted = 0; 1420 txFifo.front() = NULL; 1421 txFifo.pop_front(); 1422 1423 /* normally do a writeback of the descriptor here, and ONLY after that is 1424 done, send this interrupt. but since our stuff never actually fails, 1425 just do this interrupt here, otherwise the code has to stray from this 1426 nice format. besides, it's functionally the same. 1427 */ 1428 devIntrPost(ISR_TXOK); 1429 } 1430 1431 if (!txFifo.empty() && !txEvent.scheduled()) { 1432 DPRINTF(Ethernet, "reschedule transmit\n"); 1433 txEvent.schedule(curTick + 1000); 1434 } 1435} 1436 1437void 1438NSGigE::txDmaReadCopy() 1439{ 1440 assert(txDmaState == dmaReading); 1441 1442 memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); 1443 txDmaState = dmaIdle; 1444 1445 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1446 txDmaAddr, txDmaLen); 1447 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1448} 1449 1450bool 1451NSGigE::doTxDmaRead() 1452{ 1453 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1454 txDmaState = dmaReading; 1455 1456 if (dmaInterface && !txDmaFree) { 1457 if (dmaInterface->busy()) 1458 txDmaState = dmaReadWaiting; 1459 else 1460 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1461 &txDmaReadEvent); 1462 return true; 1463 } 1464 1465 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1466 txDmaReadCopy(); 1467 return false; 1468 } 1469 1470 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1471 Tick start = curTick + dmaReadDelay + factor; 1472 txDmaReadEvent.schedule(start); 1473 return true; 1474} 1475 1476void 1477NSGigE::txDmaReadDone() 1478{ 1479 assert(txDmaState == dmaReading); 1480 txDmaReadCopy(); 1481 1482 // If the receive state machine has a pending DMA, let it go first 1483 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1484 rxKick(); 1485 1486 txKick(); 1487} 1488 1489void 1490NSGigE::txDmaWriteCopy() 1491{ 1492 assert(txDmaState == dmaWriting); 1493 1494 memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); 1495 txDmaState = dmaIdle; 1496 1497 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1498 txDmaAddr, txDmaLen); 1499 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1500} 1501 1502bool 1503NSGigE::doTxDmaWrite() 1504{ 1505 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1506 txDmaState = dmaWriting; 1507 1508 if (dmaInterface && !txDmaFree) { 1509 if (dmaInterface->busy()) 1510 txDmaState = dmaWriteWaiting; 1511 else 1512 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1513 &txDmaWriteEvent); 1514 return true; 1515 } 1516 1517 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1518 txDmaWriteCopy(); 1519 return false; 1520 } 1521 1522 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1523 Tick start = curTick + dmaWriteDelay + factor; 1524 txDmaWriteEvent.schedule(start); 1525 return true; 1526} 1527 1528void 1529NSGigE::txDmaWriteDone() 1530{ 1531 assert(txDmaState == dmaWriting); 1532 txDmaWriteCopy(); 1533 1534 // If the receive state machine has a pending DMA, let it go first 1535 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1536 rxKick(); 1537 1538 txKick(); 1539} 1540 1541void 1542NSGigE::txKick() 1543{ 1544 DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]); 1545 1546 if (rxKickTick > curTick) { 1547 DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", 1548 rxKickTick); 1549 1550 return; 1551 } 1552 1553 next: 1554 switch(txDmaState) { 1555 case dmaReadWaiting: 1556 if (doTxDmaRead()) 1557 goto exit; 1558 break; 1559 case dmaWriteWaiting: 1560 if (doTxDmaWrite()) 1561 goto exit; 1562 break; 1563 default: 1564 break; 1565 } 1566 1567 switch (txState) { 1568 case txIdle: 1569 if (!regs.command & CR_TXE) { 1570 DPRINTF(Ethernet, "Transmit disabled. Nothing to do.\n"); 1571 goto exit; 1572 } 1573 1574 if (CTDD) { 1575 txState = txDescRefr; 1576 1577 txDmaAddr = regs.txdp & 0x3fffffff; 1578 txDmaData = &txDescCache + offsetof(ns_desc, link); 1579 txDmaLen = sizeof(txDescCache.link); 1580 txDmaFree = dmaDescFree; 1581 1582 if (doTxDmaRead()) 1583 goto exit; 1584 1585 } else { 1586 txState = txDescRead; 1587 1588 txDmaAddr = regs.txdp & 0x3fffffff; 1589 txDmaData = &txDescCache; 1590 txDmaLen = sizeof(ns_desc); 1591 txDmaFree = dmaDescFree; 1592 1593 if (doTxDmaRead()) 1594 goto exit; 1595 } 1596 break; 1597 1598 case txDescRefr: 1599 if (txDmaState != dmaIdle) 1600 goto exit; 1601 1602 txState = txAdvance; 1603 break; 1604 1605 case txDescRead: 1606 if (txDmaState != dmaIdle) 1607 goto exit; 1608 1609 DPRINTF(Ethernet, 1610 "txDescCache data:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n" 1611 ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1612 txDescCache.extsts); 1613 1614 if (txDescCache.cmdsts & CMDSTS_OWN) { 1615 txState = txFifoBlock; 1616 txFragPtr = txDescCache.bufptr; 1617 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1618 } else { 1619 txState = txIdle; 1620 } 1621 break; 1622 1623 case txFifoBlock: 1624 if (!txPacket) { 1625 DPRINTF(Ethernet, "starting the tx of a new packet\n"); 1626 txPacket = new EtherPacket; 1627 txPacket->data = new uint8_t[16384]; 1628 txPacketBufPtr = txPacket->data; 1629 } 1630 1631 if (txDescCnt == 0) { 1632 DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n"); 1633 if (txDescCache.cmdsts & CMDSTS_MORE) { 1634 DPRINTF(Ethernet, "there are more descriptors to come\n"); 1635 txState = txDescWrite; 1636 1637 txDescCache.cmdsts &= ~CMDSTS_OWN; 1638 1639 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1640 txDmaData = &(txDescCache.cmdsts); 1641 txDmaLen = sizeof(txDescCache.cmdsts); 1642 txDmaFree = dmaDescFree; 1643 1644 if (doTxDmaWrite()) 1645 goto exit; 1646 1647 } else { /* this packet is totally done */ 1648 DPRINTF(Ethernet, "This packet is done, let's wrap it up\n"); 1649 /* deal with the the packet that just finished */ 1650 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1651 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1652 udpChecksum(txPacket, true); 1653 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1654 tcpChecksum(txPacket, true); 1655 } else if (txDescCache.extsts & EXTSTS_IPPKT) { 1656 ipChecksum(txPacket, true); 1657 } 1658 } 1659 1660 txPacket->length = txPacketBufPtr - txPacket->data; 1661 /* this is just because the receive can't handle a packet bigger 1662 want to make sure */ 1663 assert(txPacket->length <= 1514); 1664 txFifo.push_back(txPacket); 1665 1666 1667 /* this following section is not to spec, but functionally shouldn't 1668 be any different. normally, the chip will wait til the transmit has 1669 occurred before writing back the descriptor because it has to wait 1670 to see that it was successfully transmitted to decide whether to set 1671 CMDSTS_OK or not. however, in the simulator since it is always 1672 successfully transmitted, and writing it exactly to spec would 1673 complicate the code, we just do it here 1674 */ 1675 txDescCache.cmdsts &= ~CMDSTS_OWN; 1676 txDescCache.cmdsts |= CMDSTS_OK; 1677 1678 DPRINTF(Ethernet, 1679 "txDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n", 1680 txDescCache.cmdsts, txDescCache.extsts); 1681 1682 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1683 txDmaData = &(txDescCache.cmdsts); 1684 txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts); 1685 txDmaFree = dmaDescFree; 1686 1687 if (doTxDmaWrite()) 1688 goto exit; 1689 1690 txPacket = 0; 1691 transmit(); 1692 1693 if (txHalt) { 1694 txState = txIdle; 1695 txHalt = false; 1696 } else 1697 txState = txAdvance; 1698 } 1699 } else { 1700 DPRINTF(Ethernet, "this descriptor isn't done yet\n"); 1701 /* the fill thresh is in units of 32 bytes, shift right by 8 to get the 1702 value, shift left by 5 to get the real number of bytes */ 1703 if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) { 1704 DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n", 1705 txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK); 1706 goto exit; 1707 } 1708 1709 txState = txFragRead; 1710 1711 /* The number of bytes transferred is either whatever is left 1712 in the descriptor (txDescCnt), or if there is not enough 1713 room in the fifo, just whatever room is left in the fifo 1714 */ 1715 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1716 1717 txDmaAddr = txFragPtr & 0x3fffffff; 1718 txDmaData = txPacketBufPtr; 1719 txDmaLen = txXferLen; 1720 txDmaFree = dmaDataFree; 1721 1722 if (doTxDmaRead()) 1723 goto exit; 1724 } 1725 break; 1726 1727 case txFragRead: 1728 if (txDmaState != dmaIdle) 1729 goto exit; 1730 1731 txPacketBufPtr += txXferLen; 1732 txFragPtr += txXferLen; 1733 txFifoCnt += txXferLen; 1734 txDescCnt -= txXferLen; 1735 1736 txState = txFifoBlock; 1737 break; 1738 1739 case txDescWrite: 1740 if (txDmaState != dmaIdle) 1741 goto exit; 1742 1743 if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) { 1744 if (txFifo.empty()) { 1745 uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted); 1746 txFifoCnt -= xmitted; 1747 txPktXmitted += xmitted; 1748 } else { 1749 transmit(); 1750 } 1751 } 1752 1753 if (txDescCache.cmdsts & CMDSTS_INTR) { 1754 devIntrPost(ISR_TXDESC); 1755 } 1756 1757 txState = txAdvance; 1758 break; 1759 1760 case txAdvance: 1761 if (txDescCache.link == 0) { 1762 txState = txIdle; 1763 } else { 1764 txState = txDescRead; 1765 regs.txdp = txDescCache.link; 1766 CTDD = false; 1767 1768 txDmaAddr = txDescCache.link & 0x3fffffff; 1769 txDmaData = &txDescCache; 1770 txDmaLen = sizeof(ns_desc); 1771 txDmaFree = dmaDescFree; 1772 1773 if (doTxDmaRead()) 1774 goto exit; 1775 } 1776 break; 1777 1778 default: 1779 panic("invalid state"); 1780 } 1781 1782 DPRINTF(Ethernet, "entering next tx state=%s\n", 1783 NsTxStateStrings[txState]); 1784 1785 if (txState == txIdle) { 1786 regs.command &= ~CR_TXE; 1787 devIntrPost(ISR_TXIDLE); 1788 return; 1789 } 1790 1791 goto next; 1792 1793 exit: 1794 /** 1795 * @todo do we want to schedule a future kick? 1796 */ 1797 DPRINTF(Ethernet, "tx state machine exited state=%s\n", 1798 NsTxStateStrings[txState]); 1799} 1800 1801void 1802NSGigE::transferDone() 1803{ 1804 if (txFifo.empty()) 1805 return; 1806 1807 DPRINTF(Ethernet, "schedule transmit\n"); 1808 1809 if (txEvent.scheduled()) 1810 txEvent.reschedule(curTick + 1); 1811 else 1812 txEvent.schedule(curTick + 1); 1813} 1814 1815bool 1816NSGigE::rxFilter(PacketPtr packet) 1817{ 1818 bool drop = true; 1819 string type; 1820 1821 if (packet->IsUnicast()) { 1822 type = "unicast"; 1823 1824 // If we're accepting all unicast addresses 1825 if (acceptUnicast) 1826 drop = false; 1827 1828 // If we make a perfect match 1829 if ((acceptPerfect) 1830 && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0)) 1831 drop = false; 1832 1833 eth_header *eth = (eth_header *) packet->data; 1834 if ((acceptArp) && (eth->type == 0x806)) 1835 drop = false; 1836 1837 } else if (packet->IsBroadcast()) { 1838 type = "broadcast"; 1839 1840 // if we're accepting broadcasts 1841 if (acceptBroadcast) 1842 drop = false; 1843 1844 } else if (packet->IsMulticast()) { 1845 type = "multicast"; 1846 1847 // if we're accepting all multicasts 1848 if (acceptMulticast) 1849 drop = false; 1850 1851 } else { 1852 type = "unknown"; 1853 1854 // oh well, punt on this one 1855 } 1856 1857 if (drop) { 1858 DPRINTF(Ethernet, "rxFilter drop\n"); 1859 DDUMP(EthernetData, packet->data, packet->length); 1860 } 1861 1862 return drop; 1863} 1864 1865bool 1866NSGigE::recvPacket(PacketPtr packet) 1867{ 1868 rxBytes += packet->length; 1869 rxPackets++; 1870 1871 if (rxState == rxIdle) { 1872 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1873 interface->recvDone(); 1874 return true; 1875 } 1876 1877 if (rxFilterEnable && rxFilter(packet)) { 1878 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1879 interface->recvDone(); 1880 return true; 1881 } 1882 1883 if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) { 1884 DPRINTF(Ethernet, 1885 "packet will not fit in receive buffer...packet dropped\n"); 1886 devIntrPost(ISR_RXORN); 1887 return false; 1888 } 1889 1890 rxFifo.push_back(packet); 1891 rxFifoCnt += packet->length; 1892 interface->recvDone(); 1893 1894 rxKick(); 1895 return true; 1896} 1897 1898/** 1899 * does a udp checksum. if gen is true, then it generates it and puts it in the right place 1900 * else, it just checks what it calculates against the value in the header in packet 1901 */ 1902bool 1903NSGigE::udpChecksum(PacketPtr packet, bool gen) 1904{ 1905 udp_header *hdr = (udp_header *) packet->getTransportHdr(); 1906 1907 ip_header *ip = packet->getIpHdr(); 1908 1909 pseudo_header *pseudo = new pseudo_header; 1910 1911 pseudo->src_ip_addr = ip->src_ip_addr; 1912 pseudo->dest_ip_addr = ip->dest_ip_addr; 1913 pseudo->protocol = ip->protocol; 1914 pseudo->len = hdr->len; 1915 1916 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 1917 (uint32_t) hdr->len); 1918 1919 delete pseudo; 1920 if (gen) 1921 hdr->chksum = cksum; 1922 else 1923 if (cksum != 0) 1924 return false; 1925 1926 return true; 1927} 1928 1929bool 1930NSGigE::tcpChecksum(PacketPtr packet, bool gen) 1931{ 1932 tcp_header *hdr = (tcp_header *) packet->getTransportHdr(); 1933 1934 ip_header *ip = packet->getIpHdr(); 1935 1936 pseudo_header *pseudo = new pseudo_header; 1937 1938 pseudo->src_ip_addr = ip->src_ip_addr; 1939 pseudo->dest_ip_addr = ip->dest_ip_addr; 1940 pseudo->protocol = ip->protocol; 1941 pseudo->len = ip->dgram_len - (ip->vers_len & 0xf); 1942 1943 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 1944 (uint32_t) pseudo->len); 1945 1946 delete pseudo; 1947 if (gen) 1948 hdr->chksum = cksum; 1949 else 1950 if (cksum != 0) 1951 return false; 1952 1953 return true; 1954} 1955 1956bool 1957NSGigE::ipChecksum(PacketPtr packet, bool gen) 1958{ 1959 ip_header *hdr = packet->getIpHdr(); 1960 1961 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)); 1962 1963 if (gen) 1964 hdr->hdr_chksum = cksum; 1965 else 1966 if (cksum != 0) 1967 return false; 1968 1969 return true; 1970} 1971 1972uint16_t 1973NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 1974{ 1975 uint32_t sum = 0; 1976 1977 uint16_t last_pad = 0; 1978 if (len & 1) { 1979 last_pad = buf[len/2] & 0xff; 1980 len--; 1981 sum += last_pad; 1982 } 1983 1984 if (pseudo) { 1985 sum = pseudo[0] + pseudo[1] + pseudo[2] + 1986 pseudo[3] + pseudo[4] + pseudo[5]; 1987 } 1988 1989 for (int i=0; i < (len/2); ++i) { 1990 sum += buf[i]; 1991 } 1992 1993 while (sum >> 16) 1994 sum = (sum >> 16) + (sum & 0xffff); 1995 1996 return ~sum; 1997} 1998 1999//===================================================================== 2000// 2001// 2002void 2003NSGigE::serialize(ostream &os) 2004{ 2005 /* 2006 * Finalize any DMA events now. 2007 */ 2008 if (rxDmaReadEvent.scheduled()) 2009 rxDmaReadCopy(); 2010 if (rxDmaWriteEvent.scheduled()) 2011 rxDmaWriteCopy(); 2012 if (txDmaReadEvent.scheduled()) 2013 txDmaReadCopy(); 2014 if (txDmaWriteEvent.scheduled()) 2015 txDmaWriteCopy(); 2016 2017 /* 2018 * Serialize the device registers 2019 */ 2020 SERIALIZE_SCALAR(regs.command); 2021 SERIALIZE_SCALAR(regs.config); 2022 SERIALIZE_SCALAR(regs.mear); 2023 SERIALIZE_SCALAR(regs.ptscr); 2024 SERIALIZE_SCALAR(regs.isr); 2025 SERIALIZE_SCALAR(regs.imr); 2026 SERIALIZE_SCALAR(regs.ier); 2027 SERIALIZE_SCALAR(regs.ihr); 2028 SERIALIZE_SCALAR(regs.txdp); 2029 SERIALIZE_SCALAR(regs.txdp_hi); 2030 SERIALIZE_SCALAR(regs.txcfg); 2031 SERIALIZE_SCALAR(regs.gpior); 2032 SERIALIZE_SCALAR(regs.rxdp); 2033 SERIALIZE_SCALAR(regs.rxdp_hi); 2034 SERIALIZE_SCALAR(regs.rxcfg); 2035 SERIALIZE_SCALAR(regs.pqcr); 2036 SERIALIZE_SCALAR(regs.wcsr); 2037 SERIALIZE_SCALAR(regs.pcr); 2038 SERIALIZE_SCALAR(regs.rfcr); 2039 SERIALIZE_SCALAR(regs.rfdr); 2040 SERIALIZE_SCALAR(regs.srr); 2041 SERIALIZE_SCALAR(regs.mibc); 2042 SERIALIZE_SCALAR(regs.vrcr); 2043 SERIALIZE_SCALAR(regs.vtcr); 2044 SERIALIZE_SCALAR(regs.vdr); 2045 SERIALIZE_SCALAR(regs.ccsr); 2046 SERIALIZE_SCALAR(regs.tbicr); 2047 SERIALIZE_SCALAR(regs.tbisr); 2048 SERIALIZE_SCALAR(regs.tanar); 2049 SERIALIZE_SCALAR(regs.tanlpar); 2050 SERIALIZE_SCALAR(regs.taner); 2051 SERIALIZE_SCALAR(regs.tesr); 2052 2053 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2054 2055 /* 2056 * Serialize the various helper variables 2057 */ 2058 uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr; 2059 SERIALIZE_SCALAR(txPktBufPtr); 2060 uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr; 2061 SERIALIZE_SCALAR(rxPktBufPtr); 2062 SERIALIZE_SCALAR(txXferLen); 2063 SERIALIZE_SCALAR(rxXferLen); 2064 SERIALIZE_SCALAR(txPktXmitted); 2065 2066 bool txPacketExists = txPacket; 2067 SERIALIZE_SCALAR(txPacketExists); 2068 bool rxPacketExists = rxPacket; 2069 SERIALIZE_SCALAR(rxPacketExists); 2070 2071 /* 2072 * Serialize DescCaches 2073 */ 2074 SERIALIZE_SCALAR(txDescCache.link); 2075 SERIALIZE_SCALAR(txDescCache.bufptr); 2076 SERIALIZE_SCALAR(txDescCache.cmdsts); 2077 SERIALIZE_SCALAR(txDescCache.extsts); 2078 SERIALIZE_SCALAR(rxDescCache.link); 2079 SERIALIZE_SCALAR(rxDescCache.bufptr); 2080 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2081 SERIALIZE_SCALAR(rxDescCache.extsts); 2082 2083 /* 2084 * Serialize tx state machine 2085 */ 2086 int txNumPkts = txFifo.size(); 2087 SERIALIZE_SCALAR(txNumPkts); 2088 int txState = this->txState; 2089 SERIALIZE_SCALAR(txState); 2090 SERIALIZE_SCALAR(CTDD); 2091 SERIALIZE_SCALAR(txFifoCnt); 2092 SERIALIZE_SCALAR(txFifoAvail); 2093 SERIALIZE_SCALAR(txHalt); 2094 SERIALIZE_SCALAR(txFragPtr); 2095 SERIALIZE_SCALAR(txDescCnt); 2096 int txDmaState = this->txDmaState; 2097 SERIALIZE_SCALAR(txDmaState); 2098 2099 /* 2100 * Serialize rx state machine 2101 */ 2102 int rxNumPkts = rxFifo.size(); 2103 SERIALIZE_SCALAR(rxNumPkts); 2104 int rxState = this->rxState; 2105 SERIALIZE_SCALAR(rxState); 2106 SERIALIZE_SCALAR(CRDD); 2107 SERIALIZE_SCALAR(rxPktBytes); 2108 SERIALIZE_SCALAR(rxFifoCnt); 2109 SERIALIZE_SCALAR(rxHalt); 2110 SERIALIZE_SCALAR(rxDescCnt); 2111 int rxDmaState = this->rxDmaState; 2112 SERIALIZE_SCALAR(rxDmaState); 2113 2114 SERIALIZE_SCALAR(extstsEnable); 2115 2116 /* 2117 * If there's a pending transmit, store the time so we can 2118 * reschedule it later 2119 */ 2120 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2121 SERIALIZE_SCALAR(transmitTick); 2122 2123 /* 2124 * Keep track of pending interrupt status. 2125 */ 2126 SERIALIZE_SCALAR(intrTick); 2127 SERIALIZE_SCALAR(cpuPendingIntr); 2128 Tick intrEventTick = 0; 2129 if (intrEvent) 2130 intrEventTick = intrEvent->when(); 2131 SERIALIZE_SCALAR(intrEventTick); 2132 2133 int i = 0; 2134 for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) { 2135 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2136 (*p)->serialize(os); 2137 } 2138 if (rxPacketExists) { 2139 nameOut(os, csprintf("%s.rxPacket", name())); 2140 rxPacket->serialize(os); 2141 } 2142 i = 0; 2143 for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) { 2144 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2145 (*p)->serialize(os); 2146 } 2147 if (txPacketExists) { 2148 nameOut(os, csprintf("%s.txPacket", name())); 2149 txPacket->serialize(os); 2150 } 2151} 2152 2153void 2154NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2155{ 2156 UNSERIALIZE_SCALAR(regs.command); 2157 UNSERIALIZE_SCALAR(regs.config); 2158 UNSERIALIZE_SCALAR(regs.mear); 2159 UNSERIALIZE_SCALAR(regs.ptscr); 2160 UNSERIALIZE_SCALAR(regs.isr); 2161 UNSERIALIZE_SCALAR(regs.imr); 2162 UNSERIALIZE_SCALAR(regs.ier); 2163 UNSERIALIZE_SCALAR(regs.ihr); 2164 UNSERIALIZE_SCALAR(regs.txdp); 2165 UNSERIALIZE_SCALAR(regs.txdp_hi); 2166 UNSERIALIZE_SCALAR(regs.txcfg); 2167 UNSERIALIZE_SCALAR(regs.gpior); 2168 UNSERIALIZE_SCALAR(regs.rxdp); 2169 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2170 UNSERIALIZE_SCALAR(regs.rxcfg); 2171 UNSERIALIZE_SCALAR(regs.pqcr); 2172 UNSERIALIZE_SCALAR(regs.wcsr); 2173 UNSERIALIZE_SCALAR(regs.pcr); 2174 UNSERIALIZE_SCALAR(regs.rfcr); 2175 UNSERIALIZE_SCALAR(regs.rfdr); 2176 UNSERIALIZE_SCALAR(regs.srr); 2177 UNSERIALIZE_SCALAR(regs.mibc); 2178 UNSERIALIZE_SCALAR(regs.vrcr); 2179 UNSERIALIZE_SCALAR(regs.vtcr); 2180 UNSERIALIZE_SCALAR(regs.vdr); 2181 UNSERIALIZE_SCALAR(regs.ccsr); 2182 UNSERIALIZE_SCALAR(regs.tbicr); 2183 UNSERIALIZE_SCALAR(regs.tbisr); 2184 UNSERIALIZE_SCALAR(regs.tanar); 2185 UNSERIALIZE_SCALAR(regs.tanlpar); 2186 UNSERIALIZE_SCALAR(regs.taner); 2187 UNSERIALIZE_SCALAR(regs.tesr); 2188 2189 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2190 2191 /* 2192 * unserialize the various helper variables 2193 */ 2194 uint32_t txPktBufPtr; 2195 UNSERIALIZE_SCALAR(txPktBufPtr); 2196 txPacketBufPtr = (uint8_t *) txPktBufPtr; 2197 uint32_t rxPktBufPtr; 2198 UNSERIALIZE_SCALAR(rxPktBufPtr); 2199 rxPacketBufPtr = (uint8_t *) rxPktBufPtr; 2200 UNSERIALIZE_SCALAR(txXferLen); 2201 UNSERIALIZE_SCALAR(rxXferLen); 2202 UNSERIALIZE_SCALAR(txPktXmitted); 2203 2204 bool txPacketExists; 2205 UNSERIALIZE_SCALAR(txPacketExists); 2206 bool rxPacketExists; 2207 UNSERIALIZE_SCALAR(rxPacketExists); 2208 2209 /* 2210 * Unserialize DescCaches 2211 */ 2212 UNSERIALIZE_SCALAR(txDescCache.link); 2213 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2214 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2215 UNSERIALIZE_SCALAR(txDescCache.extsts); 2216 UNSERIALIZE_SCALAR(rxDescCache.link); 2217 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2218 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2219 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2220 2221 /* 2222 * unserialize tx state machine 2223 */ 2224 int txNumPkts; 2225 UNSERIALIZE_SCALAR(txNumPkts); 2226 int txState; 2227 UNSERIALIZE_SCALAR(txState); 2228 this->txState = (TxState) txState; 2229 UNSERIALIZE_SCALAR(CTDD); 2230 UNSERIALIZE_SCALAR(txFifoCnt); 2231 UNSERIALIZE_SCALAR(txFifoAvail); 2232 UNSERIALIZE_SCALAR(txHalt); 2233 UNSERIALIZE_SCALAR(txFragPtr); 2234 UNSERIALIZE_SCALAR(txDescCnt); 2235 int txDmaState; 2236 UNSERIALIZE_SCALAR(txDmaState); 2237 this->txDmaState = (DmaState) txDmaState; 2238 2239 /* 2240 * unserialize rx state machine 2241 */ 2242 int rxNumPkts; 2243 UNSERIALIZE_SCALAR(rxNumPkts); 2244 int rxState; 2245 UNSERIALIZE_SCALAR(rxState); 2246 this->rxState = (RxState) rxState; 2247 UNSERIALIZE_SCALAR(CRDD); 2248 UNSERIALIZE_SCALAR(rxPktBytes); 2249 UNSERIALIZE_SCALAR(rxFifoCnt); 2250 UNSERIALIZE_SCALAR(rxHalt); 2251 UNSERIALIZE_SCALAR(rxDescCnt); 2252 int rxDmaState; 2253 UNSERIALIZE_SCALAR(rxDmaState); 2254 this->rxDmaState = (DmaState) rxDmaState; 2255 2256 UNSERIALIZE_SCALAR(extstsEnable); 2257 2258 /* 2259 * If there's a pending transmit, store the time so we can 2260 * reschedule it later 2261 */ 2262 Tick transmitTick; 2263 UNSERIALIZE_SCALAR(transmitTick); 2264 if (transmitTick) 2265 txEvent.schedule(curTick + transmitTick); 2266 2267 /* 2268 * Keep track of pending interrupt status. 2269 */ 2270 UNSERIALIZE_SCALAR(intrTick); 2271 UNSERIALIZE_SCALAR(cpuPendingIntr); 2272 Tick intrEventTick; 2273 UNSERIALIZE_SCALAR(intrEventTick); 2274 if (intrEventTick) { 2275 intrEvent = new IntrEvent(this, true); 2276 intrEvent->schedule(intrEventTick); 2277 } 2278 2279 for (int i = 0; i < rxNumPkts; ++i) { 2280 PacketPtr p = new EtherPacket; 2281 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2282 rxFifo.push_back(p); 2283 } 2284 rxPacket = NULL; 2285 if (rxPacketExists) { 2286 rxPacket = new EtherPacket; 2287 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2288 } 2289 for (int i = 0; i < txNumPkts; ++i) { 2290 PacketPtr p = new EtherPacket; 2291 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2292 txFifo.push_back(p); 2293 } 2294 if (txPacketExists) { 2295 txPacket = new EtherPacket; 2296 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2297 } 2298} 2299 2300 2301Tick 2302NSGigE::cacheAccess(MemReqPtr &req) 2303{ 2304 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2305 req->paddr, req->paddr - addr); 2306 return curTick + pioLatency; 2307} 2308//===================================================================== 2309 2310 2311BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2312 2313 SimObjectParam<EtherInt *> peer; 2314 SimObjectParam<NSGigE *> device; 2315 2316END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2317 2318BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2319 2320 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2321 INIT_PARAM(device, "Ethernet device of this interface") 2322 2323END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2324 2325CREATE_SIM_OBJECT(NSGigEInt) 2326{ 2327 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2328 2329 EtherInt *p = (EtherInt *)peer; 2330 if (p) { 2331 dev_int->setPeer(p); 2332 p->setPeer(dev_int); 2333 } 2334 2335 return dev_int; 2336} 2337 2338REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2339 2340 2341BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2342 2343 Param<Tick> tx_delay; 2344 Param<Tick> rx_delay; 2345 SimObjectParam<IntrControl *> intr_ctrl; 2346 Param<Tick> intr_delay; 2347 SimObjectParam<MemoryController *> mmu; 2348 SimObjectParam<PhysicalMemory *> physmem; 2349 Param<Addr> addr; 2350 Param<bool> rx_filter; 2351 Param<string> hardware_address; 2352 SimObjectParam<Bus*> header_bus; 2353 SimObjectParam<Bus*> payload_bus; 2354 SimObjectParam<HierParams *> hier; 2355 Param<Tick> pio_latency; 2356 Param<bool> dma_desc_free; 2357 Param<bool> dma_data_free; 2358 Param<Tick> dma_read_delay; 2359 Param<Tick> dma_write_delay; 2360 Param<Tick> dma_read_factor; 2361 Param<Tick> dma_write_factor; 2362 SimObjectParam<PciConfigAll *> configspace; 2363 SimObjectParam<PciConfigData *> configdata; 2364 SimObjectParam<Tsunami *> tsunami; 2365 Param<uint32_t> pci_bus; 2366 Param<uint32_t> pci_dev; 2367 Param<uint32_t> pci_func; 2368 2369END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2370 2371BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2372 2373 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2374 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2375 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2376 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2377 INIT_PARAM(mmu, "Memory Controller"), 2378 INIT_PARAM(physmem, "Physical Memory"), 2379 INIT_PARAM(addr, "Device Address"), 2380 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2381 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2382 "00:99:00:00:00:01"), 2383 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2384 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2385 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2386 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), 2387 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2388 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2389 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2390 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2391 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2392 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2393 INIT_PARAM(configspace, "PCI Configspace"), 2394 INIT_PARAM(configdata, "PCI Config data"), 2395 INIT_PARAM(tsunami, "Tsunami"), 2396 INIT_PARAM(pci_bus, "PCI bus"), 2397 INIT_PARAM(pci_dev, "PCI device number"), 2398 INIT_PARAM(pci_func, "PCI function code") 2399 2400END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2401 2402 2403CREATE_SIM_OBJECT(NSGigE) 2404{ 2405 int eaddr[6]; 2406 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2407 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2408 2409 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2410 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2411 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2412 dma_read_delay, dma_write_delay, dma_read_factor, 2413 dma_write_factor, configspace, configdata, 2414 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, 2415 addr); 2416} 2417 2418REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2419