i8254xGBe.cc revision 5783
12SN/A/* 29608Sandreas.hansson@arm.com * Copyright (c) 2006 The Regents of The University of Michigan 38707Sandreas.hansson@arm.com * All rights reserved. 48707Sandreas.hansson@arm.com * 58707Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 68707Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 78707Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 88707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 98707Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 108707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 118707Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 128707Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 138707Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 141762SN/A * this software without specific prior written permission. 157897Shestness@cs.utexas.edu * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272SN/A * 282SN/A * Authors: Ali Saidi 292SN/A */ 302SN/A 312SN/A/* @file 322SN/A * Device model for Intel's 8254x line of gigabit ethernet controllers. 332SN/A * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the 342SN/A * fewest workarounds in the driver. It will probably work with most of the 352SN/A * other MACs with slight modifications. 362SN/A */ 372SN/A 382SN/A 392SN/A/* 402665Ssaidi@eecs.umich.edu * @todo really there are multiple dma engines.. we should implement them. 412665Ssaidi@eecs.umich.edu */ 422665Ssaidi@eecs.umich.edu 437897Shestness@cs.utexas.edu#include <algorithm> 442SN/A 452SN/A#include "base/inet.hh" 461717SN/A#include "base/trace.hh" 471717SN/A#include "dev/i8254xGBe.hh" 482SN/A#include "mem/packet.hh" 492SN/A#include "mem/packet_access.hh" 502SN/A#include "params/IGbE.hh" 519850Sandreas.hansson@arm.com#include "sim/stats.hh" 529850Sandreas.hansson@arm.com#include "sim/system.hh" 539850Sandreas.hansson@arm.com 549850Sandreas.hansson@arm.comusing namespace iGbReg; 559850Sandreas.hansson@arm.comusing namespace Net; 569850Sandreas.hansson@arm.com 578745Sgblack@eecs.umich.eduIGbE::IGbE(const Params *p) 584182Sgblack@eecs.umich.edu : EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control), 595664Sgblack@eecs.umich.edu rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), 60707SN/A txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0), 618229Snate@binkert.org fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), 6256SN/A fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), 638779Sgblack@eecs.umich.edu rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay), 644776Sgblack@eecs.umich.edu rdtrEvent(this), radvEvent(this), 6510464SAndreas.Sandberg@ARM.com tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this), 669814Sandreas.hansson@arm.com rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), 672SN/A txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), 688901Sandreas.hansson@arm.com clock(p->clock), lastInterrupt(0) 692315SN/A{ 702680Sktlim@umich.edu etherInt = new IGbEInt(name() + ".int", this); 712SN/A 722356SN/A // Initialized internal registers per Intel documentation 732356SN/A // All registers intialized to 0 by per register constructor 742356SN/A regs.ctrl.fd(1); 756144Sksewell@umich.edu regs.ctrl.lrst(1); 762356SN/A regs.ctrl.speed(2); 772356SN/A regs.ctrl.frcspd(1); 786144Sksewell@umich.edu regs.sts.speed(3); // Say we're 1000Mbps 792356SN/A regs.sts.fd(1); // full duplex 802356SN/A regs.sts.lu(1); // link up 816144Sksewell@umich.edu regs.eecd.fwe(1); 822356SN/A regs.eecd.ee_type(1); 832356SN/A regs.imr = 0; 842356SN/A regs.iam = 0; 856144Sksewell@umich.edu regs.rxdctl.gran(1); 866144Sksewell@umich.edu regs.rxdctl.wthresh(1); 876144Sksewell@umich.edu regs.fcrth(1); 886144Sksewell@umich.edu regs.tdwba = 0; 896144Sksewell@umich.edu regs.rlpml = 0; 905336Shines@cs.fsu.edu regs.sw_fw_sync = 0; 912356SN/A 922356SN/A regs.pba.rxa(0x30); 932856Srdreslin@umich.edu regs.pba.txa(0x10); 942SN/A 951634SN/A eeOpBits = 0; 969157Sandreas.hansson@arm.com eeAddrBits = 0; 973814Ssaidi@eecs.umich.edu eeDataBits = 0; 983814Ssaidi@eecs.umich.edu eeOpcode = 0; 995712Shsul@eecs.umich.edu 1005712Shsul@eecs.umich.edu // clear all 64 16 bit words of the eeprom 1015715Shsul@eecs.umich.edu memset(&flash, 0, EEPROM_SIZE*2); 1025712Shsul@eecs.umich.edu 1035712Shsul@eecs.umich.edu // Set the MAC address 1041634SN/A memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN); 10510190Sakash.bagdia@arm.com for (int x = 0; x < ETH_ADDR_LEN/2; x++) 10610190Sakash.bagdia@arm.com flash[x] = htobe(flash[x]); 10710190Sakash.bagdia@arm.com 10810190Sakash.bagdia@arm.com uint16_t csum = 0; 10910190Sakash.bagdia@arm.com for (int x = 0; x < EEPROM_SIZE; x++) 11010190Sakash.bagdia@arm.com csum += htobe(flash[x]); 11110190Sakash.bagdia@arm.com 1128832SAli.Saidi@ARM.com 1138832SAli.Saidi@ARM.com // Magic happy checksum value 1148832SAli.Saidi@ARM.com flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); 1158832SAli.Saidi@ARM.com 1168832SAli.Saidi@ARM.com rxFifo.clear(); 1178832SAli.Saidi@ARM.com txFifo.clear(); 1189332Sdam.sunwoo@arm.com} 1199332Sdam.sunwoo@arm.com 1209332Sdam.sunwoo@arm.comEtherInt* 1219332Sdam.sunwoo@arm.comIGbE::getEthPort(const std::string &if_name, int idx) 1229332Sdam.sunwoo@arm.com{ 1239332Sdam.sunwoo@arm.com 1249332Sdam.sunwoo@arm.com if (if_name == "interface") { 1259332Sdam.sunwoo@arm.com if (etherInt->getPeer()) 1269332Sdam.sunwoo@arm.com panic("Port already connected to\n"); 1279332Sdam.sunwoo@arm.com return etherInt; 1289332Sdam.sunwoo@arm.com } 1299430SAndreas.Sandberg@ARM.com return NULL; 1309430SAndreas.Sandberg@ARM.com} 1319430SAndreas.Sandberg@ARM.com 1329814Sandreas.hansson@arm.comTick 1339814Sandreas.hansson@arm.comIGbE::writeConfig(PacketPtr pkt) 1349814Sandreas.hansson@arm.com{ 1351634SN/A int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1368850Sandreas.hansson@arm.com if (offset < PCI_DEVICE_SPECIFIC) 1378850Sandreas.hansson@arm.com PciDev::writeConfig(pkt); 1388850Sandreas.hansson@arm.com else 1398850Sandreas.hansson@arm.com panic("Device specific PCI config space not implemented.\n"); 1408850Sandreas.hansson@arm.com 1418850Sandreas.hansson@arm.com /// 1428850Sandreas.hansson@arm.com /// Some work may need to be done here based for the pci COMMAND bits. 1439608Sandreas.hansson@arm.com /// 1448850Sandreas.hansson@arm.com 1458850Sandreas.hansson@arm.com return pioDelay; 1468850Sandreas.hansson@arm.com} 1478850Sandreas.hansson@arm.com 1488850Sandreas.hansson@arm.comTick 1498850Sandreas.hansson@arm.comIGbE::read(PacketPtr pkt) 1508850Sandreas.hansson@arm.com{ 1519608Sandreas.hansson@arm.com int bar; 1528850Sandreas.hansson@arm.com Addr daddr; 1535712Shsul@eecs.umich.edu 15410110Sandreas.hansson@arm.com if (!getBAR(pkt->getAddr(), bar, daddr)) 1555712Shsul@eecs.umich.edu panic("Invalid PCI memory access to unmapped memory.\n"); 15610190Sakash.bagdia@arm.com 15710190Sakash.bagdia@arm.com // Only Memory register BAR is allowed 15810190Sakash.bagdia@arm.com assert(bar == 0); 1598832SAli.Saidi@ARM.com 1608832SAli.Saidi@ARM.com // Only 32bit accesses allowed 1618832SAli.Saidi@ARM.com assert(pkt->getSize() == 4); 1628832SAli.Saidi@ARM.com 1638832SAli.Saidi@ARM.com DPRINTF(Ethernet, "Read device register %#X\n", daddr); 1648850Sandreas.hansson@arm.com 1658926Sandreas.hansson@arm.com pkt->allocate(); 1668926Sandreas.hansson@arm.com 1678926Sandreas.hansson@arm.com /// 1688850Sandreas.hansson@arm.com /// Handle read of register here 1698850Sandreas.hansson@arm.com /// 1708850Sandreas.hansson@arm.com 1718850Sandreas.hansson@arm.com 1728922Swilliam.wang@arm.com switch (daddr) { 1738850Sandreas.hansson@arm.com case REG_CTRL: 1749294Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.ctrl()); 1759294Sandreas.hansson@arm.com break; 1768850Sandreas.hansson@arm.com case REG_STATUS: 1779332Sdam.sunwoo@arm.com pkt->set<uint32_t>(regs.sts()); 1789332Sdam.sunwoo@arm.com break; 1799332Sdam.sunwoo@arm.com case REG_EECD: 1809332Sdam.sunwoo@arm.com pkt->set<uint32_t>(regs.eecd()); 1819332Sdam.sunwoo@arm.com break; 1829332Sdam.sunwoo@arm.com case REG_EERD: 1839332Sdam.sunwoo@arm.com pkt->set<uint32_t>(regs.eerd()); 1849332Sdam.sunwoo@arm.com break; 1857914SBrad.Beckmann@amd.com case REG_CTRL_EXT: 1867914SBrad.Beckmann@amd.com pkt->set<uint32_t>(regs.ctrl_ext()); 1873814Ssaidi@eecs.umich.edu break; 1883814Ssaidi@eecs.umich.edu case REG_MDIC: 1891634SN/A pkt->set<uint32_t>(regs.mdic()); 1905664Sgblack@eecs.umich.edu break; 1915664Sgblack@eecs.umich.edu case REG_ICR: 1922SN/A DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(), 1935704Snate@binkert.org regs.imr, regs.iam, regs.ctrl_ext.iame()); 1942SN/A pkt->set<uint32_t>(regs.icr()); 1952SN/A if (regs.icr.int_assert() || regs.imr == 0) { 1965645Sgblack@eecs.umich.edu regs.icr = regs.icr() & ~mask(30); 1975645Sgblack@eecs.umich.edu DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr()); 1985645Sgblack@eecs.umich.edu } 1995647Sgblack@eecs.umich.edu if (regs.ctrl_ext.iame() && regs.icr.int_assert()) 2005645Sgblack@eecs.umich.edu regs.imr &= ~regs.iam; 2015645Sgblack@eecs.umich.edu chkInterrupt(); 2025807Snate@binkert.org break; 2035807Snate@binkert.org case REG_EICR: 2045807Snate@binkert.org // This is only useful for MSI, but the driver reads it every time 2055807Snate@binkert.org // Just don't do anything 2065807Snate@binkert.org pkt->set<uint32_t>(0); 2075807Snate@binkert.org break; 2088779Sgblack@eecs.umich.edu case REG_ITR: 2098779Sgblack@eecs.umich.edu pkt->set<uint32_t>(regs.itr()); 2105807Snate@binkert.org break; 2115807Snate@binkert.org case REG_RCTL: 2125807Snate@binkert.org pkt->set<uint32_t>(regs.rctl()); 2135807Snate@binkert.org break; 2145807Snate@binkert.org case REG_FCTTV: 2155807Snate@binkert.org pkt->set<uint32_t>(regs.fcttv()); 2165807Snate@binkert.org break; 2175807Snate@binkert.org case REG_TCTL: 2185807Snate@binkert.org pkt->set<uint32_t>(regs.tctl()); 2195807Snate@binkert.org break; 2205807Snate@binkert.org case REG_PBA: 2215807Snate@binkert.org pkt->set<uint32_t>(regs.pba()); 2225807Snate@binkert.org break; 2232SN/A case REG_WUC: 2245704Snate@binkert.org case REG_LEDCTL: 2255704Snate@binkert.org pkt->set<uint32_t>(0); // We don't care, so just return 0 2265704Snate@binkert.org break; 2278793Sgblack@eecs.umich.edu case REG_FCRTL: 2285704Snate@binkert.org pkt->set<uint32_t>(regs.fcrtl()); 2291917SN/A break; 2301917SN/A case REG_FCRTH: 2311917SN/A pkt->set<uint32_t>(regs.fcrth()); 2321917SN/A break; 2331917SN/A case REG_RDBAL: 2345536Srstrong@hp.com pkt->set<uint32_t>(regs.rdba.rdbal()); 2351917SN/A break; 2361917SN/A case REG_RDBAH: 2375536Srstrong@hp.com pkt->set<uint32_t>(regs.rdba.rdbah()); 2381917SN/A break; 2391917SN/A case REG_RDLEN: 2401917SN/A pkt->set<uint32_t>(regs.rdlen()); 2412SN/A break; 2422SN/A case REG_SRRCTL: 2432680Sktlim@umich.edu pkt->set<uint32_t>(regs.srrctl()); 2442SN/A break; 2454776Sgblack@eecs.umich.edu case REG_RDH: 2464776Sgblack@eecs.umich.edu pkt->set<uint32_t>(regs.rdh()); 2472SN/A break; 248393SN/A case REG_RDT: 2497764Sgblack@eecs.umich.edu pkt->set<uint32_t>(regs.rdt()); 2507764Sgblack@eecs.umich.edu break; 2517764Sgblack@eecs.umich.edu case REG_RDTR: 2524776Sgblack@eecs.umich.edu pkt->set<uint32_t>(regs.rdtr()); 2534776Sgblack@eecs.umich.edu if (regs.rdtr.fpd()) { 2544776Sgblack@eecs.umich.edu rxDescCache.writeback(0); 25510407Smitch.hayenga@arm.com DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n"); 25610407Smitch.hayenga@arm.com postInterrupt(IT_RXT); 257393SN/A regs.rdtr.fpd(0); 258393SN/A } 2598737Skoansin.tan@gmail.com break; 260393SN/A case REG_RXDCTL: 261393SN/A pkt->set<uint32_t>(regs.rxdctl()); 2628737Skoansin.tan@gmail.com break; 2632SN/A case REG_RADV: 2644000Ssaidi@eecs.umich.edu pkt->set<uint32_t>(regs.radv()); 2654000Ssaidi@eecs.umich.edu break; 2664000Ssaidi@eecs.umich.edu case REG_TDBAL: 2674000Ssaidi@eecs.umich.edu pkt->set<uint32_t>(regs.tdba.tdbal()); 2689652SAndreas.Sandberg@ARM.com break; 2694000Ssaidi@eecs.umich.edu case REG_TDBAH: 27010030SAli.Saidi@ARM.com pkt->set<uint32_t>(regs.tdba.tdbah()); 27110030SAli.Saidi@ARM.com break; 27210030SAli.Saidi@ARM.com case REG_TDLEN: 2732SN/A pkt->set<uint32_t>(regs.tdlen()); 2745529Snate@binkert.org break; 2755529Snate@binkert.org case REG_TDH: 2765529Snate@binkert.org pkt->set<uint32_t>(regs.tdh()); 2778876Sandreas.hansson@arm.com break; 2781191SN/A case REG_TXDCA_CTL: 2792SN/A pkt->set<uint32_t>(regs.txdca_ctl()); 2801129SN/A break; 2811917SN/A case REG_TDT: 2822SN/A pkt->set<uint32_t>(regs.tdt()); 2832SN/A break; 28410464SAndreas.Sandberg@ARM.com case REG_TIDV: 28510464SAndreas.Sandberg@ARM.com pkt->set<uint32_t>(regs.tidv()); 2862680Sktlim@umich.edu break; 287180SN/A case REG_TXDCTL: 2889254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.txdctl()); 2899254SAndreas.Sandberg@arm.com break; 2909254SAndreas.Sandberg@arm.com case REG_TADV: 2919254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.tadv()); 2929254SAndreas.Sandberg@arm.com break; 2939254SAndreas.Sandberg@arm.com case REG_TDWBAL: 2949254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.tdwba & mask(32)); 2952798Sktlim@umich.edu break; 296180SN/A case REG_TDWBAH: 2979254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.tdwba >> 32); 2989254SAndreas.Sandberg@arm.com break; 2999254SAndreas.Sandberg@arm.com case REG_RXCSUM: 3009254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.rxcsum()); 3019254SAndreas.Sandberg@arm.com break; 3029254SAndreas.Sandberg@arm.com case REG_RLPML: 3039254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.rlpml); 3049254SAndreas.Sandberg@arm.com break; 3059254SAndreas.Sandberg@arm.com case REG_RFCTL: 3069254SAndreas.Sandberg@arm.com pkt->set<uint32_t>(regs.rfctl()); 3079254SAndreas.Sandberg@arm.com break; 3089254SAndreas.Sandberg@arm.com case REG_MANC: 309180SN/A pkt->set<uint32_t>(regs.manc()); 310124SN/A break; 3119446SAndreas.Sandberg@ARM.com case REG_SWSM: 3129446SAndreas.Sandberg@ARM.com pkt->set<uint32_t>(regs.swsm()); 3139446SAndreas.Sandberg@ARM.com regs.swsm.smbi(1); 3149446SAndreas.Sandberg@ARM.com break; 3159446SAndreas.Sandberg@ARM.com case REG_FWSM: 3169446SAndreas.Sandberg@ARM.com pkt->set<uint32_t>(regs.fwsm()); 3179446SAndreas.Sandberg@ARM.com break; 3189446SAndreas.Sandberg@ARM.com case REG_SWFWSYNC: 3199446SAndreas.Sandberg@ARM.com pkt->set<uint32_t>(regs.sw_fw_sync); 3209446SAndreas.Sandberg@ARM.com break; 3219446SAndreas.Sandberg@ARM.com default: 3229430SAndreas.Sandberg@ARM.com if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && 3239430SAndreas.Sandberg@ARM.com !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && 3249430SAndreas.Sandberg@ARM.com !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) && 3259430SAndreas.Sandberg@ARM.com !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE))) 3269430SAndreas.Sandberg@ARM.com panic("Read request to unknown register number: %#x\n", daddr); 3279430SAndreas.Sandberg@ARM.com else 3289430SAndreas.Sandberg@ARM.com pkt->set<uint32_t>(0); 3299523SAndreas.Sandberg@ARM.com }; 3309523SAndreas.Sandberg@ARM.com 3319523SAndreas.Sandberg@ARM.com pkt->makeAtomicResponse(); 3329523SAndreas.Sandberg@ARM.com return pioDelay; 3339523SAndreas.Sandberg@ARM.com} 3349523SAndreas.Sandberg@ARM.com 3359523SAndreas.Sandberg@ARM.comTick 3369523SAndreas.Sandberg@ARM.comIGbE::write(PacketPtr pkt) 3379523SAndreas.Sandberg@ARM.com{ 3389523SAndreas.Sandberg@ARM.com int bar; 3399523SAndreas.Sandberg@ARM.com Addr daddr; 340124SN/A 341124SN/A 342124SN/A if (!getBAR(pkt->getAddr(), bar, daddr)) 3436221Snate@binkert.org panic("Invalid PCI memory access to unmapped memory.\n"); 3442SN/A 345124SN/A // Only Memory register BAR is allowed 346124SN/A assert(bar == 0); 347124SN/A 348124SN/A // Only 32bit accesses allowed 349124SN/A assert(pkt->getSize() == sizeof(uint32_t)); 350503SN/A 3512SN/A DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>()); 352124SN/A 353124SN/A /// 354124SN/A /// Handle write of register here 355124SN/A /// 356124SN/A uint32_t val = pkt->get<uint32_t>(); 357124SN/A 358124SN/A Regs::RCTL oldrctl; 3592SN/A Regs::TCTL oldtctl; 360921SN/A 361921SN/A switch (daddr) { 3629814Sandreas.hansson@arm.com case REG_CTRL: 3639814Sandreas.hansson@arm.com regs.ctrl = val; 3649814Sandreas.hansson@arm.com if (regs.ctrl.tfce()) 3659814Sandreas.hansson@arm.com warn("TX Flow control enabled, should implement\n"); 3669814Sandreas.hansson@arm.com if (regs.ctrl.rfce()) 367921SN/A warn("RX Flow control enabled, should implement\n"); 3689448SAndreas.Sandberg@ARM.com break; 3699448SAndreas.Sandberg@ARM.com case REG_CTRL_EXT: 3709448SAndreas.Sandberg@ARM.com regs.ctrl_ext = val; 3719448SAndreas.Sandberg@ARM.com break; 3729448SAndreas.Sandberg@ARM.com case REG_STATUS: 3739448SAndreas.Sandberg@ARM.com regs.sts = val; 374921SN/A break; 375921SN/A case REG_EECD: 376921SN/A int oldClk; 377921SN/A oldClk = regs.eecd.sk(); 378921SN/A regs.eecd = val; 379921SN/A // See if this is a eeprom access and emulate accordingly 3809448SAndreas.Sandberg@ARM.com if (!oldClk && regs.eecd.sk()) { 3819448SAndreas.Sandberg@ARM.com if (eeOpBits < 8) { 3829448SAndreas.Sandberg@ARM.com eeOpcode = eeOpcode << 1 | regs.eecd.din(); 3839448SAndreas.Sandberg@ARM.com eeOpBits++; 3849448SAndreas.Sandberg@ARM.com } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 3859448SAndreas.Sandberg@ARM.com eeAddr = eeAddr << 1 | regs.eecd.din(); 386921SN/A eeAddrBits++; 3879448SAndreas.Sandberg@ARM.com } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 388921SN/A assert(eeAddr>>1 < EEPROM_SIZE); 389921SN/A DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", 390921SN/A flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); 391124SN/A regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1); 3929448SAndreas.Sandberg@ARM.com eeDataBits++; 3939448SAndreas.Sandberg@ARM.com } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { 3949448SAndreas.Sandberg@ARM.com regs.eecd.dout(0); 3959448SAndreas.Sandberg@ARM.com eeDataBits++; 3969448SAndreas.Sandberg@ARM.com } else 3979448SAndreas.Sandberg@ARM.com panic("What's going on with eeprom interface? opcode:" 3989448SAndreas.Sandberg@ARM.com " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, 3999448SAndreas.Sandberg@ARM.com (uint32_t)eeOpBits, (uint32_t)eeAddr, 4009448SAndreas.Sandberg@ARM.com (uint32_t)eeAddrBits, (uint32_t)eeDataBits); 4019448SAndreas.Sandberg@ARM.com 4029448SAndreas.Sandberg@ARM.com // Reset everything for the next command 4039448SAndreas.Sandberg@ARM.com if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || 4049448SAndreas.Sandberg@ARM.com (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { 4059448SAndreas.Sandberg@ARM.com eeOpBits = 0; 4069448SAndreas.Sandberg@ARM.com eeAddrBits = 0; 4079448SAndreas.Sandberg@ARM.com eeDataBits = 0; 4089448SAndreas.Sandberg@ARM.com eeOpcode = 0; 4098834Satgutier@umich.edu eeAddr = 0; 4108834Satgutier@umich.edu } 4118834Satgutier@umich.edu 412707SN/A DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", 4139749Sandreas@sandberg.pp.se (uint32_t)eeOpcode, (uint32_t) eeOpBits, 4149749Sandreas@sandberg.pp.se (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); 4159749Sandreas@sandberg.pp.se if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || 4169749Sandreas@sandberg.pp.se eeOpcode == EEPROM_RDSR_OPCODE_SPI )) 4179749Sandreas@sandberg.pp.se panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, 4189749Sandreas@sandberg.pp.se (uint32_t)eeOpBits); 4199749Sandreas@sandberg.pp.se 4209749Sandreas@sandberg.pp.se 4219749Sandreas@sandberg.pp.se } 4229749Sandreas@sandberg.pp.se // If driver requests eeprom access, immediately give it to it 4239749Sandreas@sandberg.pp.se regs.eecd.ee_gnt(regs.eecd.ee_req()); 4249749Sandreas@sandberg.pp.se break; 4259749Sandreas@sandberg.pp.se case REG_EERD: 4269749Sandreas@sandberg.pp.se regs.eerd = val; 4279749Sandreas@sandberg.pp.se if (regs.eerd.start()) { 4289749Sandreas@sandberg.pp.se regs.eerd.done(1); 4299749Sandreas@sandberg.pp.se assert(regs.eerd.addr() < EEPROM_SIZE); 4309749Sandreas@sandberg.pp.se regs.eerd.data(flash[regs.eerd.addr()]); 4319749Sandreas@sandberg.pp.se regs.eerd.start(0); 4329749Sandreas@sandberg.pp.se DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n", 4339749Sandreas@sandberg.pp.se regs.eerd.addr(), regs.eerd.data()); 4349749Sandreas@sandberg.pp.se } 4359749Sandreas@sandberg.pp.se break; 4369749Sandreas@sandberg.pp.se case REG_MDIC: 4379749Sandreas@sandberg.pp.se regs.mdic = val; 4389749Sandreas@sandberg.pp.se if (regs.mdic.i()) 4399749Sandreas@sandberg.pp.se panic("No support for interrupt on mdic complete\n"); 4409749Sandreas@sandberg.pp.se if (regs.mdic.phyadd() != 1) 4419749Sandreas@sandberg.pp.se panic("No support for reading anything but phy\n"); 4429749Sandreas@sandberg.pp.se DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing" 44310464SAndreas.Sandberg@ARM.com : "Reading", regs.mdic.regadd()); 44410464SAndreas.Sandberg@ARM.com switch (regs.mdic.regadd()) { 44510464SAndreas.Sandberg@ARM.com case PHY_PSTATUS: 44610464SAndreas.Sandberg@ARM.com regs.mdic.data(0x796D); // link up 44710464SAndreas.Sandberg@ARM.com break; 44810464SAndreas.Sandberg@ARM.com case PHY_PID: 44910464SAndreas.Sandberg@ARM.com regs.mdic.data(params()->phy_pid); 45010464SAndreas.Sandberg@ARM.com break; 45110464SAndreas.Sandberg@ARM.com case PHY_EPID: 45210464SAndreas.Sandberg@ARM.com regs.mdic.data(params()->phy_epid); 45310464SAndreas.Sandberg@ARM.com break; 45410464SAndreas.Sandberg@ARM.com case PHY_GSTATUS: 45510464SAndreas.Sandberg@ARM.com regs.mdic.data(0x7C00); 45610464SAndreas.Sandberg@ARM.com break; 45710464SAndreas.Sandberg@ARM.com case PHY_EPSTATUS: 45810464SAndreas.Sandberg@ARM.com regs.mdic.data(0x3000); 45910464SAndreas.Sandberg@ARM.com break; 46010464SAndreas.Sandberg@ARM.com case PHY_AGC: 46110464SAndreas.Sandberg@ARM.com regs.mdic.data(0x180); // some random length 46210464SAndreas.Sandberg@ARM.com break; 46310464SAndreas.Sandberg@ARM.com default: 46410464SAndreas.Sandberg@ARM.com regs.mdic.data(0); 46510464SAndreas.Sandberg@ARM.com } 46610464SAndreas.Sandberg@ARM.com regs.mdic.r(1); 46710464SAndreas.Sandberg@ARM.com break; 46810464SAndreas.Sandberg@ARM.com case REG_ICR: 46910464SAndreas.Sandberg@ARM.com DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(), 47010464SAndreas.Sandberg@ARM.com regs.imr, regs.iam, regs.ctrl_ext.iame()); 47110464SAndreas.Sandberg@ARM.com if (regs.ctrl_ext.iame()) 47210464SAndreas.Sandberg@ARM.com regs.imr &= ~regs.iam; 47310464SAndreas.Sandberg@ARM.com regs.icr = ~bits(val,30,0) & regs.icr(); 47410464SAndreas.Sandberg@ARM.com chkInterrupt(); 47510464SAndreas.Sandberg@ARM.com break; 47610464SAndreas.Sandberg@ARM.com case REG_ITR: 47710464SAndreas.Sandberg@ARM.com regs.itr = val; 47810464SAndreas.Sandberg@ARM.com break; 47910464SAndreas.Sandberg@ARM.com case REG_ICS: 48010464SAndreas.Sandberg@ARM.com DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n"); 48110464SAndreas.Sandberg@ARM.com postInterrupt((IntTypes)val); 48210464SAndreas.Sandberg@ARM.com break; 48310464SAndreas.Sandberg@ARM.com case REG_IMS: 48410464SAndreas.Sandberg@ARM.com regs.imr |= val; 48510464SAndreas.Sandberg@ARM.com chkInterrupt(); 48610464SAndreas.Sandberg@ARM.com break; 48710464SAndreas.Sandberg@ARM.com case REG_IMC: 48810464SAndreas.Sandberg@ARM.com regs.imr &= ~val; 48910464SAndreas.Sandberg@ARM.com chkInterrupt(); 49010464SAndreas.Sandberg@ARM.com break; 4911191SN/A case REG_IAM: 4921191SN/A regs.iam = val; 4931191SN/A break; 4941191SN/A case REG_RCTL: 4951191SN/A oldrctl = regs.rctl; 4961191SN/A regs.rctl = val; 4971191SN/A if (regs.rctl.rst()) { 4981191SN/A rxDescCache.reset(); 4991191SN/A DPRINTF(EthernetSM, "RXS: Got RESET!\n"); 5001191SN/A rxFifo.clear(); 5018662SAli.Saidi@ARM.com regs.rctl.rst(0); 5028662SAli.Saidi@ARM.com } 5038662SAli.Saidi@ARM.com if (regs.rctl.en()) 5048662SAli.Saidi@ARM.com rxTick = true; 5051191SN/A restartClock(); 5061191SN/A break; 5071191SN/A case REG_FCTTV: 5081191SN/A regs.fcttv = val; 5091191SN/A break; 5101191SN/A case REG_TCTL: 5112SN/A regs.tctl = val; 5128834Satgutier@umich.edu oldtctl = regs.tctl; 513707SN/A regs.tctl = val; 514707SN/A if (regs.tctl.en()) 515707SN/A txTick = true; 516707SN/A restartClock(); 517707SN/A if (regs.tctl.en() && !oldtctl.en()) { 5188834Satgutier@umich.edu txDescCache.reset(); 5198834Satgutier@umich.edu } 5208834Satgutier@umich.edu break; 5218834Satgutier@umich.edu case REG_PBA: 5228834Satgutier@umich.edu regs.pba.rxa(val); 5238834Satgutier@umich.edu regs.pba.txa(64 - regs.pba.rxa()); 5248834Satgutier@umich.edu break; 5258834Satgutier@umich.edu case REG_WUC: 5268834Satgutier@umich.edu case REG_LEDCTL: 5278834Satgutier@umich.edu case REG_FCAL: 5288834Satgutier@umich.edu case REG_FCAH: 5298834Satgutier@umich.edu case REG_FCT: 530707SN/A case REG_VET: 531707SN/A case REG_AIFS: 532707SN/A case REG_TIPG: 533707SN/A ; // We don't care, so don't store anything 534707SN/A break; 535707SN/A case REG_IVAR0: 5365999Snate@binkert.org warn("Writing to IVAR0, ignoring...\n"); 5377914SBrad.Beckmann@amd.com break; 5387914SBrad.Beckmann@amd.com case REG_FCRTL: 5392SN/A regs.fcrtl = val; 5402SN/A break; 5419850Sandreas.hansson@arm.com case REG_FCRTH: 5429850Sandreas.hansson@arm.com regs.fcrth = val; 5431717SN/A break; 544 case REG_RDBAL: 545 regs.rdba.rdbal( val & ~mask(4)); 546 rxDescCache.areaChanged(); 547 break; 548 case REG_RDBAH: 549 regs.rdba.rdbah(val); 550 rxDescCache.areaChanged(); 551 break; 552 case REG_RDLEN: 553 regs.rdlen = val & ~mask(7); 554 rxDescCache.areaChanged(); 555 break; 556 case REG_SRRCTL: 557 regs.srrctl = val; 558 break; 559 case REG_RDH: 560 regs.rdh = val; 561 rxDescCache.areaChanged(); 562 break; 563 case REG_RDT: 564 regs.rdt = val; 565 DPRINTF(EthernetSM, "RXS: RDT Updated.\n"); 566 if (getState() == SimObject::Running) { 567 DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n"); 568 rxDescCache.fetchDescriptors(); 569 } else { 570 DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n"); 571 } 572 break; 573 case REG_RDTR: 574 regs.rdtr = val; 575 break; 576 case REG_RADV: 577 regs.radv = val; 578 break; 579 case REG_RXDCTL: 580 regs.rxdctl = val; 581 break; 582 case REG_TDBAL: 583 regs.tdba.tdbal( val & ~mask(4)); 584 txDescCache.areaChanged(); 585 break; 586 case REG_TDBAH: 587 regs.tdba.tdbah(val); 588 txDescCache.areaChanged(); 589 break; 590 case REG_TDLEN: 591 regs.tdlen = val & ~mask(7); 592 txDescCache.areaChanged(); 593 break; 594 case REG_TDH: 595 regs.tdh = val; 596 txDescCache.areaChanged(); 597 break; 598 case REG_TXDCA_CTL: 599 regs.txdca_ctl = val; 600 if (regs.txdca_ctl.enabled()) 601 panic("No support for DCA\n"); 602 break; 603 case REG_TDT: 604 regs.tdt = val; 605 DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n"); 606 if (getState() == SimObject::Running) { 607 DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n"); 608 txDescCache.fetchDescriptors(); 609 } else { 610 DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n"); 611 } 612 break; 613 case REG_TIDV: 614 regs.tidv = val; 615 break; 616 case REG_TXDCTL: 617 regs.txdctl = val; 618 break; 619 case REG_TADV: 620 regs.tadv = val; 621 break; 622 case REG_TDWBAL: 623 regs.tdwba &= ~mask(32); 624 regs.tdwba |= val; 625 txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1)); 626 break; 627 case REG_TDWBAH: 628 regs.tdwba &= mask(32); 629 regs.tdwba |= (uint64_t)val << 32; 630 txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1)); 631 break; 632 case REG_RXCSUM: 633 regs.rxcsum = val; 634 break; 635 case REG_RLPML: 636 regs.rlpml = val; 637 break; 638 case REG_RFCTL: 639 regs.rfctl = val; 640 if (regs.rfctl.exsten()) 641 panic("Extended RX descriptors not implemented\n"); 642 break; 643 case REG_MANC: 644 regs.manc = val; 645 break; 646 case REG_SWSM: 647 regs.swsm = val; 648 if (regs.fwsm.eep_fw_semaphore()) 649 regs.swsm.swesmbi(0); 650 break; 651 case REG_SWFWSYNC: 652 regs.sw_fw_sync = val; 653 break; 654 default: 655 if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && 656 !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && 657 !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4))) 658 panic("Write request to unknown register number: %#x\n", daddr); 659 }; 660 661 pkt->makeAtomicResponse(); 662 return pioDelay; 663} 664 665void 666IGbE::postInterrupt(IntTypes t, bool now) 667{ 668 assert(t); 669 670 // Interrupt is already pending 671 if (t & regs.icr() && !now) 672 return; 673 674 regs.icr = regs.icr() | t; 675 676 Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval(); 677 DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n", 678 curTick, regs.itr.interval(), itr_interval); 679 680 if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) { 681 if (interEvent.scheduled()) { 682 deschedule(interEvent); 683 } 684 cpuPostInt(); 685 } else { 686 Tick int_time = lastInterrupt + itr_interval; 687 assert(int_time > 0); 688 DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n", 689 int_time); 690 if (!interEvent.scheduled()) { 691 schedule(interEvent, int_time); 692 } 693 } 694} 695 696void 697IGbE::delayIntEvent() 698{ 699 cpuPostInt(); 700} 701 702 703void 704IGbE::cpuPostInt() 705{ 706 707 postedInterrupts++; 708 709 if (!(regs.icr() & regs.imr)) { 710 DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n"); 711 return; 712 } 713 714 DPRINTF(Ethernet, "Posting Interrupt\n"); 715 716 717 if (interEvent.scheduled()) { 718 deschedule(interEvent); 719 } 720 721 if (rdtrEvent.scheduled()) { 722 regs.icr.rxt0(1); 723 deschedule(rdtrEvent); 724 } 725 if (radvEvent.scheduled()) { 726 regs.icr.rxt0(1); 727 deschedule(radvEvent); 728 } 729 if (tadvEvent.scheduled()) { 730 regs.icr.txdw(1); 731 deschedule(tadvEvent); 732 } 733 if (tidvEvent.scheduled()) { 734 regs.icr.txdw(1); 735 deschedule(tidvEvent); 736 } 737 738 regs.icr.int_assert(1); 739 DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n", 740 regs.icr()); 741 742 intrPost(); 743 744 lastInterrupt = curTick; 745} 746 747void 748IGbE::cpuClearInt() 749{ 750 if (regs.icr.int_assert()) { 751 regs.icr.int_assert(0); 752 DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n", 753 regs.icr()); 754 intrClear(); 755 } 756} 757 758void 759IGbE::chkInterrupt() 760{ 761 DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(), 762 regs.imr); 763 // Check if we need to clear the cpu interrupt 764 if (!(regs.icr() & regs.imr)) { 765 DPRINTF(Ethernet, "Mask cleaned all interrupts\n"); 766 if (interEvent.scheduled()) 767 deschedule(interEvent); 768 if (regs.icr.int_assert()) 769 cpuClearInt(); 770 } 771 DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval()); 772 773 if (regs.icr() & regs.imr) { 774 if (regs.itr.interval() == 0) { 775 cpuPostInt(); 776 } else { 777 DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n"); 778 if (!interEvent.scheduled()) { 779 DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns 780 * 256 * regs.itr.interval()); 781 schedule(interEvent, 782 curTick + Clock::Int::ns * 256 * regs.itr.interval()); 783 } 784 } 785 } 786 787 788} 789 790 791IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) 792 : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0), 793 pktEvent(this), pktHdrEvent(this), pktDataEvent(this) 794 795{ 796} 797 798void 799IGbE::RxDescCache::pktSplitDone() 800{ 801 splitCount++; 802 DPRINTF(EthernetDesc, "Part of split packet done: splitcount now %d\n", splitCount); 803 assert(splitCount <= 2); 804 if (splitCount != 2) 805 return; 806 splitCount = 0; 807 DPRINTF(EthernetDesc, "Part of split packet done: calling pktComplete()\n"); 808 pktComplete(); 809} 810 811int 812IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset) 813{ 814 assert(unusedCache.size()); 815 //if (!unusedCache.size()) 816 // return false; 817 818 pktPtr = packet; 819 pktDone = false; 820 int buf_len, hdr_len; 821 822 RxDesc *desc = unusedCache.front(); 823 switch (igbe->regs.srrctl.desctype()) { 824 case RXDT_LEGACY: 825 assert(pkt_offset == 0); 826 bytesCopied = packet->length; 827 DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n", 828 packet->length, igbe->regs.rctl.descSize()); 829 assert(packet->length < igbe->regs.rctl.descSize()); 830 igbe->dmaWrite(igbe->platform->pciToDma(desc->legacy.buf), packet->length, &pktEvent, 831 packet->data, igbe->rxWriteDelay); 832 break; 833 case RXDT_ADV_ONEBUF: 834 assert(pkt_offset == 0); 835 bytesCopied = packet->length; 836 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : 837 igbe->regs.rctl.descSize(); 838 DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n", 839 packet->length, igbe->regs.srrctl(), buf_len); 840 assert(packet->length < buf_len); 841 igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), packet->length, &pktEvent, 842 packet->data, igbe->rxWriteDelay); 843 desc->adv_wb.header_len = htole(0); 844 desc->adv_wb.sph = htole(0); 845 desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length)); 846 break; 847 case RXDT_ADV_SPLIT_A: 848 int split_point; 849 850 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : 851 igbe->regs.rctl.descSize(); 852 hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0; 853 DPRINTF(EthernetDesc, "lpe: %d Packet Length: %d offset: %d srrctl: %#x hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n", 854 igbe->regs.rctl.lpe(), packet->length, pkt_offset, igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, desc->adv_read.pkt, buf_len); 855 856 split_point = hsplit(pktPtr); 857 858 if (packet->length <= hdr_len) { 859 bytesCopied = packet->length; 860 assert(pkt_offset == 0); 861 DPRINTF(EthernetDesc, "Header Splitting: Entire packet being placed in header\n"); 862 igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), packet->length, &pktEvent, 863 packet->data, igbe->rxWriteDelay); 864 desc->adv_wb.header_len = htole((uint16_t)packet->length); 865 desc->adv_wb.sph = htole(0); 866 desc->adv_wb.pkt_len = htole(0); 867 } else if (split_point) { 868 if (pkt_offset) { 869 // we are only copying some data, header/data has already been 870 // copied 871 int max_to_copy = std::min(packet->length - pkt_offset, buf_len); 872 bytesCopied += max_to_copy; 873 DPRINTF(EthernetDesc, "Header Splitting: Continuing data buffer copy\n"); 874 igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),max_to_copy, &pktEvent, 875 packet->data + pkt_offset, igbe->rxWriteDelay); 876 desc->adv_wb.header_len = htole(0); 877 desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy); 878 desc->adv_wb.sph = htole(0); 879 } else { 880 int max_to_copy = std::min(packet->length - split_point, buf_len); 881 bytesCopied += max_to_copy + split_point; 882 883 DPRINTF(EthernetDesc, "Header Splitting: splitting at %d\n", 884 split_point); 885 igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), split_point, &pktHdrEvent, 886 packet->data, igbe->rxWriteDelay); 887 igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), 888 max_to_copy, &pktDataEvent, packet->data + split_point, igbe->rxWriteDelay); 889 desc->adv_wb.header_len = htole(split_point); 890 desc->adv_wb.sph = 1; 891 desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy)); 892 } 893 } else { 894 panic("Header split not fitting within header buffer or undecodable" 895 " packet not fitting in header unsupported\n"); 896 } 897 break; 898 default: 899 panic("Unimplemnted RX receive buffer type: %d\n", 900 igbe->regs.srrctl.desctype()); 901 } 902 return bytesCopied; 903 904} 905 906void 907IGbE::RxDescCache::pktComplete() 908{ 909 assert(unusedCache.size()); 910 RxDesc *desc; 911 desc = unusedCache.front(); 912 913 uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ; 914 DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d stripcrc offset: %d value written: %d %d\n", 915 pktPtr->length, bytesCopied, crcfixup, 916 htole((uint16_t)(pktPtr->length + crcfixup)), 917 (uint16_t)(pktPtr->length + crcfixup)); 918 919 // no support for anything but starting at 0 920 assert(igbe->regs.rxcsum.pcss() == 0); 921 922 DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n"); 923 924 uint16_t status = RXDS_DD; 925 uint8_t err = 0; 926 uint16_t ext_err = 0; 927 uint16_t csum = 0; 928 uint16_t ptype = 0; 929 uint16_t ip_id = 0; 930 931 assert(bytesCopied <= pktPtr->length); 932 if (bytesCopied == pktPtr->length) 933 status |= RXDS_EOP; 934 935 IpPtr ip(pktPtr); 936 937 if (ip) { 938 DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); 939 ptype |= RXDP_IPV4; 940 ip_id = ip->id(); 941 942 if (igbe->regs.rxcsum.ipofld()) { 943 DPRINTF(EthernetDesc, "Checking IP checksum\n"); 944 status |= RXDS_IPCS; 945 csum = htole(cksum(ip)); 946 igbe->rxIpChecksums++; 947 if (cksum(ip) != 0) { 948 err |= RXDE_IPE; 949 ext_err |= RXDEE_IPE; 950 DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 951 } 952 } 953 TcpPtr tcp(ip); 954 if (tcp && igbe->regs.rxcsum.tuofld()) { 955 DPRINTF(EthernetDesc, "Checking TCP checksum\n"); 956 status |= RXDS_TCPCS; 957 ptype |= RXDP_TCP; 958 csum = htole(cksum(tcp)); 959 igbe->rxTcpChecksums++; 960 if (cksum(tcp) != 0) { 961 DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 962 err |= RXDE_TCPE; 963 ext_err |= RXDEE_TCPE; 964 } 965 } 966 967 UdpPtr udp(ip); 968 if (udp && igbe->regs.rxcsum.tuofld()) { 969 DPRINTF(EthernetDesc, "Checking UDP checksum\n"); 970 status |= RXDS_UDPCS; 971 ptype |= RXDP_UDP; 972 csum = htole(cksum(udp)); 973 igbe->rxUdpChecksums++; 974 if (cksum(udp) != 0) { 975 DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 976 ext_err |= RXDEE_TCPE; 977 err |= RXDE_TCPE; 978 } 979 } 980 } else { // if ip 981 DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); 982 } 983 984 switch (igbe->regs.srrctl.desctype()) { 985 case RXDT_LEGACY: 986 desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup)); 987 desc->legacy.status = htole(status); 988 desc->legacy.errors = htole(err); 989 // No vlan support at this point... just set it to 0 990 desc->legacy.vlan = 0; 991 break; 992 case RXDT_ADV_SPLIT_A: 993 case RXDT_ADV_ONEBUF: 994 desc->adv_wb.rss_type = htole(0); 995 desc->adv_wb.pkt_type = htole(ptype); 996 if (igbe->regs.rxcsum.pcsd()) { 997 // no rss support right now 998 desc->adv_wb.rss_hash = htole(0); 999 } else { 1000 desc->adv_wb.id = htole(ip_id); 1001 desc->adv_wb.csum = htole(csum); 1002 } 1003 desc->adv_wb.status = htole(status); 1004 desc->adv_wb.errors = htole(ext_err); 1005 // no vlan support 1006 desc->adv_wb.vlan_tag = htole(0); 1007 break; 1008 default: 1009 panic("Unimplemnted RX receive buffer type %d\n", 1010 igbe->regs.srrctl.desctype()); 1011 } 1012 1013 DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n", 1014 desc->adv_read.pkt, desc->adv_read.hdr); 1015 1016 if (bytesCopied == pktPtr->length) { 1017 DPRINTF(EthernetDesc, "Packet completely written to descriptor buffers\n"); 1018 // Deal with the rx timer interrupts 1019 if (igbe->regs.rdtr.delay()) { 1020 DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", 1021 igbe->regs.rdtr.delay() * igbe->intClock()); 1022 igbe->reschedule(igbe->rdtrEvent, 1023 curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true); 1024 } 1025 1026 if (igbe->regs.radv.idv()) { 1027 DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", 1028 igbe->regs.radv.idv() * igbe->intClock()); 1029 if (!igbe->radvEvent.scheduled()) { 1030 igbe->schedule(igbe->radvEvent, 1031 curTick + igbe->regs.radv.idv() * igbe->intClock()); 1032 } 1033 } 1034 1035 // if neither radv or rdtr, maybe itr is set... 1036 if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) { 1037 DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); 1038 igbe->postInterrupt(IT_RXT); 1039 } 1040 1041 // If the packet is small enough, interrupt appropriately 1042 // I wonder if this is delayed or not?! 1043 if (pktPtr->length <= igbe->regs.rsrpd.idv()) { 1044 DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); 1045 igbe->postInterrupt(IT_SRPD); 1046 } 1047 bytesCopied = 0; 1048 } 1049 1050 pktPtr = NULL; 1051 igbe->checkDrain(); 1052 enableSm(); 1053 pktDone = true; 1054 1055 DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); 1056 unusedCache.pop_front(); 1057 usedCache.push_back(desc); 1058} 1059 1060void 1061IGbE::RxDescCache::enableSm() 1062{ 1063 if (!igbe->drainEvent) { 1064 igbe->rxTick = true; 1065 igbe->restartClock(); 1066 } 1067} 1068 1069bool 1070IGbE::RxDescCache::packetDone() 1071{ 1072 if (pktDone) { 1073 pktDone = false; 1074 return true; 1075 } 1076 return false; 1077} 1078 1079bool 1080IGbE::RxDescCache::hasOutstandingEvents() 1081{ 1082 return pktEvent.scheduled() || wbEvent.scheduled() || 1083 fetchEvent.scheduled() || pktHdrEvent.scheduled() || 1084 pktDataEvent.scheduled(); 1085 1086} 1087 1088void 1089IGbE::RxDescCache::serialize(std::ostream &os) 1090{ 1091 DescCache<RxDesc>::serialize(os); 1092 SERIALIZE_SCALAR(pktDone); 1093 SERIALIZE_SCALAR(splitCount); 1094 SERIALIZE_SCALAR(bytesCopied); 1095} 1096 1097void 1098IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion) 1099{ 1100 DescCache<RxDesc>::unserialize(cp, section); 1101 UNSERIALIZE_SCALAR(pktDone); 1102 UNSERIALIZE_SCALAR(splitCount); 1103 UNSERIALIZE_SCALAR(bytesCopied); 1104} 1105 1106 1107///////////////////////////////////// IGbE::TxDesc ///////////////////////////////// 1108 1109IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) 1110 : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false), 1111 useTso(false), pktEvent(this), headerEvent(this), nullEvent(this) 1112 1113{ 1114} 1115 1116void 1117IGbE::TxDescCache::processContextDesc() 1118{ 1119 assert(unusedCache.size()); 1120 TxDesc *desc; 1121 1122 DPRINTF(EthernetDesc, "Checking and processing context descriptors\n"); 1123 1124 while (!useTso && unusedCache.size() && TxdOp::isContext(unusedCache.front())) { 1125 DPRINTF(EthernetDesc, "Got context descriptor type...\n"); 1126 1127 desc = unusedCache.front(); 1128 DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", 1129 desc->d1, desc->d2); 1130 1131 1132 // is this going to be a tcp or udp packet? 1133 isTcp = TxdOp::tcp(desc) ? true : false; 1134 1135 // setup all the TSO variables, they'll be ignored if we don't use 1136 // tso for this connection 1137 tsoHeaderLen = TxdOp::hdrlen(desc); 1138 tsoMss = TxdOp::mss(desc); 1139 1140 if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) { 1141 DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n", 1142 TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc)); 1143 useTso = true; 1144 tsoTotalLen = TxdOp::getLen(desc); 1145 tsoLoadedHeader = false; 1146 tsoDescBytesUsed = 0; 1147 tsoUsedLen = 0; 1148 tsoPrevSeq = 0; 1149 tsoPktHasHeader = false; 1150 tsoPkts = 0; 1151 1152 } 1153 1154 TxdOp::setDd(desc); 1155 unusedCache.pop_front(); 1156 usedCache.push_back(desc); 1157 } 1158 1159 if (!unusedCache.size()) 1160 return; 1161 1162 desc = unusedCache.front(); 1163 if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) { 1164 DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n", 1165 tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc)); 1166 useTso = true; 1167 tsoTotalLen = TxdOp::getTsoLen(desc); 1168 tsoLoadedHeader = false; 1169 tsoDescBytesUsed = 0; 1170 tsoUsedLen = 0; 1171 tsoPrevSeq = 0; 1172 tsoPktHasHeader = false; 1173 tsoPkts = 0; 1174 } 1175 1176 if (useTso && !tsoLoadedHeader) { 1177 // we need to fetch a header 1178 DPRINTF(EthernetDesc, "Starting DMA of TSO header\n"); 1179 assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen); 1180 pktWaiting = true; 1181 assert(tsoHeaderLen <= 256); 1182 igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), 1183 tsoHeaderLen, &headerEvent, tsoHeader, 0); 1184 } 1185} 1186 1187void 1188IGbE::TxDescCache::headerComplete() 1189{ 1190 DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n"); 1191 pktWaiting = false; 1192 1193 assert(unusedCache.size()); 1194 TxDesc *desc = unusedCache.front(); 1195 DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n", 1196 TxdOp::getLen(desc), tsoHeaderLen); 1197 1198 if (TxdOp::getLen(desc) == tsoHeaderLen) { 1199 tsoDescBytesUsed = 0; 1200 tsoLoadedHeader = true; 1201 unusedCache.pop_front(); 1202 usedCache.push_back(desc); 1203 } else { 1204 // I don't think this case happens, I think the headrer is always 1205 // it's own packet, if it wasn't it might be as simple as just 1206 // incrementing descBytesUsed by the header length, but I'm not 1207 // completely sure 1208 panic("TSO header part of bigger packet, not implemented\n"); 1209 } 1210 enableSm(); 1211 igbe->checkDrain(); 1212} 1213 1214int 1215IGbE::TxDescCache::getPacketSize(EthPacketPtr p) 1216{ 1217 TxDesc *desc; 1218 1219 1220 if (!unusedCache.size()) 1221 return -1; 1222 1223 DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); 1224 1225 assert(!useTso || tsoLoadedHeader); 1226 desc = unusedCache.front(); 1227 1228 1229 if (useTso) { 1230 DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 1231 DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n", 1232 useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader); 1233 DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d this descLen: %d\n", 1234 tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc)); 1235 DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader); 1236 1237 if (tsoPktHasHeader) 1238 tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length, TxdOp::getLen(desc) - tsoDescBytesUsed); 1239 else 1240 tsoCopyBytes = std::min(tsoMss, TxdOp::getLen(desc) - tsoDescBytesUsed); 1241 Addr pkt_size = tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen); 1242 DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size); 1243 return pkt_size; 1244 } 1245 1246 DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", 1247 TxdOp::getLen(unusedCache.front())); 1248 return TxdOp::getLen(desc); 1249} 1250 1251void 1252IGbE::TxDescCache::getPacketData(EthPacketPtr p) 1253{ 1254 assert(unusedCache.size()); 1255 1256 TxDesc *desc; 1257 desc = unusedCache.front(); 1258 1259 DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 1260 assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); 1261 1262 pktPtr = p; 1263 1264 pktWaiting = true; 1265 1266 DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); 1267 1268 if (useTso) { 1269 assert(tsoLoadedHeader); 1270 if (!tsoPktHasHeader) { 1271 DPRINTF(EthernetDesc, "Loading TSO header (%d bytes) into start of packet\n", 1272 tsoHeaderLen); 1273 memcpy(p->data, &tsoHeader,tsoHeaderLen); 1274 p->length +=tsoHeaderLen; 1275 tsoPktHasHeader = true; 1276 } 1277 } 1278 1279 if (useTso) { 1280 tsoDescBytesUsed += tsoCopyBytes; 1281 assert(tsoDescBytesUsed <= TxdOp::getLen(desc)); 1282 DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d length: %d\n", 1283 p->length, tsoCopyBytes); 1284 igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)) + tsoDescBytesUsed, 1285 tsoCopyBytes, &pktEvent, p->data + p->length, igbe->txReadDelay); 1286 } else { 1287 igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), 1288 TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay); 1289 } 1290} 1291 1292void 1293IGbE::TxDescCache::pktComplete() 1294{ 1295 1296 TxDesc *desc; 1297 assert(unusedCache.size()); 1298 assert(pktPtr); 1299 1300 DPRINTF(EthernetDesc, "DMA of packet complete\n"); 1301 1302 1303 desc = unusedCache.front(); 1304 assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); 1305 1306 DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 1307 DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n", 1308 useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader); 1309 1310 // Set the length of the data in the EtherPacket 1311 if (useTso) { 1312 pktPtr->length += tsoCopyBytes; 1313 tsoUsedLen += tsoCopyBytes; 1314 } else 1315 pktPtr->length += TxdOp::getLen(desc); 1316 1317 DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n", 1318 tsoDescBytesUsed, tsoCopyBytes); 1319 1320 1321 if ((!TxdOp::eop(desc) && !useTso) || 1322 (pktPtr->length < ( tsoMss + tsoHeaderLen) && tsoTotalLen != tsoUsedLen)) { 1323 assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc))); 1324 unusedCache.pop_front(); 1325 usedCache.push_back(desc); 1326 1327 tsoDescBytesUsed = 0; 1328 pktDone = true; 1329 pktWaiting = false; 1330 pktMultiDesc = true; 1331 1332 DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n", 1333 pktPtr->length); 1334 pktPtr = NULL; 1335 1336 enableSm(); 1337 igbe->checkDrain(); 1338 return; 1339 } 1340 1341 1342 pktMultiDesc = false; 1343 // no support for vlans 1344 assert(!TxdOp::vle(desc)); 1345 1346 // we only support single packet descriptors at this point 1347 if (!useTso) 1348 assert(TxdOp::eop(desc)); 1349 1350 // set that this packet is done 1351 if (TxdOp::rs(desc)) 1352 TxdOp::setDd(desc); 1353 1354 DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 1355 1356 if (useTso) { 1357 IpPtr ip(pktPtr); 1358 if (ip) { 1359 DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n", 1360 tsoPkts); 1361 ip->id(ip->id() + tsoPkts++); 1362 ip->len(pktPtr->length - EthPtr(pktPtr)->size()); 1363 1364 TcpPtr tcp(ip); 1365 if (tcp) { 1366 DPRINTF(EthernetDesc, "TSO: Modifying TCP header. old seq %d + %d\n", 1367 tcp->seq(), tsoPrevSeq); 1368 tcp->seq(tcp->seq() + tsoPrevSeq); 1369 if (tsoUsedLen != tsoTotalLen) 1370 tcp->flags(tcp->flags() & ~9); // clear fin & psh 1371 } 1372 UdpPtr udp(ip); 1373 if (udp) { 1374 DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n"); 1375 udp->len(pktPtr->length - EthPtr(pktPtr)->size()); 1376 } 1377 } 1378 tsoPrevSeq = tsoUsedLen; 1379 } 1380 1381 if (DTRACE(EthernetDesc)) { 1382 IpPtr ip(pktPtr); 1383 if (ip) 1384 DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", 1385 ip->id()); 1386 else 1387 DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); 1388 } 1389 1390 // Checksums are only ofloaded for new descriptor types 1391 if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { 1392 DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); 1393 IpPtr ip(pktPtr); 1394 assert(ip); 1395 if (TxdOp::ixsm(desc)) { 1396 ip->sum(0); 1397 ip->sum(cksum(ip)); 1398 igbe->txIpChecksums++; 1399 DPRINTF(EthernetDesc, "Calculated IP checksum\n"); 1400 } 1401 if (TxdOp::txsm(desc)) { 1402 TcpPtr tcp(ip); 1403 UdpPtr udp(ip); 1404 if (tcp) { 1405 tcp->sum(0); 1406 tcp->sum(cksum(tcp)); 1407 igbe->txTcpChecksums++; 1408 DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); 1409 } else if (udp) { 1410 assert(udp); 1411 udp->sum(0); 1412 udp->sum(cksum(udp)); 1413 igbe->txUdpChecksums++; 1414 DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); 1415 } else { 1416 panic("Told to checksum, but don't know how\n"); 1417 } 1418 } 1419 } 1420 1421 if (TxdOp::ide(desc)) { 1422 // Deal with the rx timer interrupts 1423 DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); 1424 if (igbe->regs.tidv.idv()) { 1425 DPRINTF(EthernetDesc, "setting tidv\n"); 1426 igbe->reschedule(igbe->tidvEvent, 1427 curTick + igbe->regs.tidv.idv() * igbe->intClock(), true); 1428 } 1429 1430 if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { 1431 DPRINTF(EthernetDesc, "setting tadv\n"); 1432 if (!igbe->tadvEvent.scheduled()) { 1433 igbe->schedule(igbe->tadvEvent, 1434 curTick + igbe->regs.tadv.idv() * igbe->intClock()); 1435 } 1436 } 1437 } 1438 1439 1440 if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) { 1441 DPRINTF(EthernetDesc, "Descriptor Done\n"); 1442 unusedCache.pop_front(); 1443 usedCache.push_back(desc); 1444 tsoDescBytesUsed = 0; 1445 } 1446 1447 if (useTso && tsoUsedLen == tsoTotalLen) 1448 useTso = false; 1449 1450 1451 DPRINTF(EthernetDesc, "------Packet of %d bytes ready for transmission-------\n", 1452 pktPtr->length); 1453 pktDone = true; 1454 pktWaiting = false; 1455 pktPtr = NULL; 1456 tsoPktHasHeader = false; 1457 1458 if (igbe->regs.txdctl.wthresh() == 0) { 1459 DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); 1460 writeback(0); 1461 } else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >= 1462 descInBlock(usedCache.size())) { 1463 DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); 1464 writeback((igbe->cacheBlockSize()-1)>>4); 1465 } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) { 1466 DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); 1467 writeback((igbe->cacheBlockSize()-1)>>4); 1468 } 1469 1470 enableSm(); 1471 igbe->checkDrain(); 1472} 1473 1474void 1475IGbE::TxDescCache::actionAfterWb() 1476{ 1477 DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n", 1478 completionEnabled); 1479 igbe->postInterrupt(iGbReg::IT_TXDW); 1480 if (completionEnabled) { 1481 descEnd = igbe->regs.tdh(); 1482 DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd, 1483 completionAddress); 1484 igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)), 1485 sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0); 1486 } 1487} 1488 1489void 1490IGbE::TxDescCache::serialize(std::ostream &os) 1491{ 1492 DescCache<TxDesc>::serialize(os); 1493 SERIALIZE_SCALAR(pktDone); 1494 SERIALIZE_SCALAR(isTcp); 1495 SERIALIZE_SCALAR(pktWaiting); 1496 SERIALIZE_SCALAR(pktMultiDesc); 1497 1498 SERIALIZE_SCALAR(useTso); 1499 SERIALIZE_SCALAR(tsoHeaderLen); 1500 SERIALIZE_SCALAR(tsoMss); 1501 SERIALIZE_SCALAR(tsoTotalLen); 1502 SERIALIZE_SCALAR(tsoUsedLen); 1503 SERIALIZE_SCALAR(tsoPrevSeq);; 1504 SERIALIZE_SCALAR(tsoPktPayloadBytes); 1505 SERIALIZE_SCALAR(tsoLoadedHeader); 1506 SERIALIZE_SCALAR(tsoPktHasHeader); 1507 SERIALIZE_ARRAY(tsoHeader, 256); 1508 SERIALIZE_SCALAR(tsoDescBytesUsed); 1509 SERIALIZE_SCALAR(tsoCopyBytes); 1510 SERIALIZE_SCALAR(tsoPkts); 1511 1512 SERIALIZE_SCALAR(completionAddress); 1513 SERIALIZE_SCALAR(completionEnabled); 1514 SERIALIZE_SCALAR(descEnd); 1515} 1516 1517void 1518IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion) 1519{ 1520 DescCache<TxDesc>::unserialize(cp, section); 1521 UNSERIALIZE_SCALAR(pktDone); 1522 UNSERIALIZE_SCALAR(isTcp); 1523 UNSERIALIZE_SCALAR(pktWaiting); 1524 UNSERIALIZE_SCALAR(pktMultiDesc); 1525 1526 UNSERIALIZE_SCALAR(useTso); 1527 UNSERIALIZE_SCALAR(tsoHeaderLen); 1528 UNSERIALIZE_SCALAR(tsoMss); 1529 UNSERIALIZE_SCALAR(tsoTotalLen); 1530 UNSERIALIZE_SCALAR(tsoUsedLen); 1531 UNSERIALIZE_SCALAR(tsoPrevSeq);; 1532 UNSERIALIZE_SCALAR(tsoPktPayloadBytes); 1533 UNSERIALIZE_SCALAR(tsoLoadedHeader); 1534 UNSERIALIZE_SCALAR(tsoPktHasHeader); 1535 UNSERIALIZE_ARRAY(tsoHeader, 256); 1536 UNSERIALIZE_SCALAR(tsoDescBytesUsed); 1537 UNSERIALIZE_SCALAR(tsoCopyBytes); 1538 UNSERIALIZE_SCALAR(tsoPkts); 1539 1540 UNSERIALIZE_SCALAR(completionAddress); 1541 UNSERIALIZE_SCALAR(completionEnabled); 1542 UNSERIALIZE_SCALAR(descEnd); 1543} 1544 1545bool 1546IGbE::TxDescCache::packetAvailable() 1547{ 1548 if (pktDone) { 1549 pktDone = false; 1550 return true; 1551 } 1552 return false; 1553} 1554 1555void 1556IGbE::TxDescCache::enableSm() 1557{ 1558 if (!igbe->drainEvent) { 1559 igbe->txTick = true; 1560 igbe->restartClock(); 1561 } 1562} 1563 1564bool 1565IGbE::TxDescCache::hasOutstandingEvents() 1566{ 1567 return pktEvent.scheduled() || wbEvent.scheduled() || 1568 fetchEvent.scheduled(); 1569} 1570 1571 1572///////////////////////////////////// IGbE ///////////////////////////////// 1573 1574void 1575IGbE::restartClock() 1576{ 1577 if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && 1578 getState() == SimObject::Running) 1579 schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1)); 1580} 1581 1582unsigned int 1583IGbE::drain(Event *de) 1584{ 1585 unsigned int count; 1586 count = pioPort->drain(de) + dmaPort->drain(de); 1587 if (rxDescCache.hasOutstandingEvents() || 1588 txDescCache.hasOutstandingEvents()) { 1589 count++; 1590 drainEvent = de; 1591 } 1592 1593 txFifoTick = false; 1594 txTick = false; 1595 rxTick = false; 1596 1597 if (tickEvent.scheduled()) 1598 deschedule(tickEvent); 1599 1600 if (count) 1601 changeState(Draining); 1602 else 1603 changeState(Drained); 1604 1605 return count; 1606} 1607 1608void 1609IGbE::resume() 1610{ 1611 SimObject::resume(); 1612 1613 txFifoTick = true; 1614 txTick = true; 1615 rxTick = true; 1616 1617 restartClock(); 1618} 1619 1620void 1621IGbE::checkDrain() 1622{ 1623 if (!drainEvent) 1624 return; 1625 1626 txFifoTick = false; 1627 txTick = false; 1628 rxTick = false; 1629 if (!rxDescCache.hasOutstandingEvents() && 1630 !txDescCache.hasOutstandingEvents()) { 1631 drainEvent->process(); 1632 drainEvent = NULL; 1633 } 1634} 1635 1636void 1637IGbE::txStateMachine() 1638{ 1639 if (!regs.tctl.en()) { 1640 txTick = false; 1641 DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n"); 1642 return; 1643 } 1644 1645 // If we have a packet available and it's length is not 0 (meaning it's not 1646 // a multidescriptor packet) put it in the fifo, otherwise an the next 1647 // iteration we'll get the rest of the data 1648 if (txPacket && txDescCache.packetAvailable() 1649 && !txDescCache.packetMultiDesc() && txPacket->length) { 1650 bool success; 1651 1652 DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); 1653 success = txFifo.push(txPacket); 1654 txFifoTick = true && !drainEvent; 1655 assert(success); 1656 txPacket = NULL; 1657 txDescCache.writeback((cacheBlockSize()-1)>>4); 1658 return; 1659 } 1660 1661 // Only support descriptor granularity 1662 if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) { 1663 DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n"); 1664 postInterrupt(IT_TXDLOW); 1665 } 1666 1667 if (!txPacket) { 1668 txPacket = new EthPacketData(16384); 1669 } 1670 1671 if (!txDescCache.packetWaiting()) { 1672 if (txDescCache.descLeft() == 0) { 1673 postInterrupt(IT_TXQE); 1674 txDescCache.writeback(0); 1675 txDescCache.fetchDescriptors(); 1676 DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing " 1677 "writeback stopping ticking and posting TXQE\n"); 1678 txTick = false; 1679 return; 1680 } 1681 1682 1683 if (!(txDescCache.descUnused())) { 1684 txDescCache.fetchDescriptors(); 1685 DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n"); 1686 txTick = false; 1687 return; 1688 } 1689 1690 1691 txDescCache.processContextDesc(); 1692 if (txDescCache.packetWaiting()) { 1693 DPRINTF(EthernetSM, "TXS: Fetching TSO header, stopping ticking\n"); 1694 txTick = false; 1695 return; 1696 } 1697 1698 int size; 1699 size = txDescCache.getPacketSize(txPacket); 1700 if (size > 0 && txFifo.avail() > size) { 1701 DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining " 1702 "DMA of next packet\n", size); 1703 txFifo.reserve(size); 1704 txDescCache.getPacketData(txPacket); 1705 } else if (size <= 0) { 1706 DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size); 1707 DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); 1708 txDescCache.writeback(0); 1709 } else { 1710 DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " 1711 "available in FIFO\n"); 1712 txTick = false; 1713 } 1714 1715 1716 return; 1717 } 1718 DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n"); 1719 txTick = false; 1720} 1721 1722bool 1723IGbE::ethRxPkt(EthPacketPtr pkt) 1724{ 1725 rxBytes += pkt->length; 1726 rxPackets++; 1727 1728 DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); 1729 1730 if (!regs.rctl.en()) { 1731 DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n"); 1732 return true; 1733 } 1734 1735 // restart the state machines if they are stopped 1736 rxTick = true && !drainEvent; 1737 if ((rxTick || txTick) && !tickEvent.scheduled()) { 1738 DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n"); 1739 restartClock(); 1740 } 1741 1742 if (!rxFifo.push(pkt)) { 1743 DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n"); 1744 postInterrupt(IT_RXO, true); 1745 return false; 1746 } 1747 1748 return true; 1749} 1750 1751 1752void 1753IGbE::rxStateMachine() 1754{ 1755 if (!regs.rctl.en()) { 1756 rxTick = false; 1757 DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n"); 1758 return; 1759 } 1760 1761 // If the packet is done check for interrupts/descriptors/etc 1762 if (rxDescCache.packetDone()) { 1763 rxDmaPacket = false; 1764 DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); 1765 int descLeft = rxDescCache.descLeft(); 1766 DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n", 1767 descLeft, regs.rctl.rdmts(), regs.rdlen()); 1768 switch (regs.rctl.rdmts()) { 1769 case 2: if (descLeft > .125 * regs.rdlen()) break; 1770 case 1: if (descLeft > .250 * regs.rdlen()) break; 1771 case 0: if (descLeft > .500 * regs.rdlen()) break; 1772 DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n"); 1773 postInterrupt(IT_RXDMT); 1774 break; 1775 } 1776 1777 if (rxFifo.empty()) 1778 rxDescCache.writeback(0); 1779 1780 if (descLeft == 0) { 1781 rxDescCache.writeback(0); 1782 DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" 1783 " writeback and stopping ticking\n"); 1784 rxTick = false; 1785 } 1786 1787 // only support descriptor granulaties 1788 assert(regs.rxdctl.gran()); 1789 1790 if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) { 1791 DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n"); 1792 if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4)) 1793 rxDescCache.writeback(regs.rxdctl.wthresh()-1); 1794 else 1795 rxDescCache.writeback((cacheBlockSize()-1)>>4); 1796 } 1797 1798 if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) && 1799 ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) { 1800 DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n"); 1801 rxDescCache.fetchDescriptors(); 1802 } 1803 1804 if (rxDescCache.descUnused() == 0) { 1805 rxDescCache.fetchDescriptors(); 1806 DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " 1807 "fetching descriptors and stopping ticking\n"); 1808 rxTick = false; 1809 } 1810 return; 1811 } 1812 1813 if (rxDmaPacket) { 1814 DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); 1815 rxTick = false; 1816 return; 1817 } 1818 1819 if (!rxDescCache.descUnused()) { 1820 rxDescCache.fetchDescriptors(); 1821 DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); 1822 rxTick = false; 1823 DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); 1824 return; 1825 } 1826 1827 if (rxFifo.empty()) { 1828 DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n"); 1829 rxTick = false; 1830 return; 1831 } 1832 1833 EthPacketPtr pkt; 1834 pkt = rxFifo.front(); 1835 1836 1837 pktOffset = rxDescCache.writePacket(pkt, pktOffset); 1838 DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); 1839 if (pktOffset == pkt->length) { 1840 DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); 1841 pktOffset = 0; 1842 rxFifo.pop(); 1843 } 1844 1845 DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); 1846 rxTick = false; 1847 rxDmaPacket = true; 1848} 1849 1850void 1851IGbE::txWire() 1852{ 1853 if (txFifo.empty()) { 1854 txFifoTick = false; 1855 return; 1856 } 1857 1858 1859 if (etherInt->sendPacket(txFifo.front())) { 1860 if (DTRACE(EthernetSM)) { 1861 IpPtr ip(txFifo.front()); 1862 if (ip) 1863 DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n", 1864 ip->id()); 1865 else 1866 DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n"); 1867 } 1868 DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n", 1869 txFifo.avail()); 1870 1871 txBytes += txFifo.front()->length; 1872 txPackets++; 1873 txFifoTick = false; 1874 1875 txFifo.pop(); 1876 } else { 1877 // We'll get woken up when the packet ethTxDone() gets called 1878 txFifoTick = false; 1879 } 1880} 1881 1882void 1883IGbE::tick() 1884{ 1885 DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n"); 1886 1887 if (rxTick) 1888 rxStateMachine(); 1889 1890 if (txTick) 1891 txStateMachine(); 1892 1893 if (txFifoTick) 1894 txWire(); 1895 1896 1897 if (rxTick || txTick || txFifoTick) 1898 schedule(tickEvent, curTick + ticks(1)); 1899} 1900 1901void 1902IGbE::ethTxDone() 1903{ 1904 // restart the tx state machines if they are stopped 1905 // fifo to send another packet 1906 // tx sm to put more data into the fifo 1907 txFifoTick = true && !drainEvent; 1908 if (txDescCache.descLeft() != 0 && !drainEvent) 1909 txTick = true; 1910 1911 restartClock(); 1912 txWire(); 1913 DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n"); 1914} 1915 1916void 1917IGbE::serialize(std::ostream &os) 1918{ 1919 PciDev::serialize(os); 1920 1921 regs.serialize(os); 1922 SERIALIZE_SCALAR(eeOpBits); 1923 SERIALIZE_SCALAR(eeAddrBits); 1924 SERIALIZE_SCALAR(eeDataBits); 1925 SERIALIZE_SCALAR(eeOpcode); 1926 SERIALIZE_SCALAR(eeAddr); 1927 SERIALIZE_SCALAR(lastInterrupt); 1928 SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); 1929 1930 rxFifo.serialize("rxfifo", os); 1931 txFifo.serialize("txfifo", os); 1932 1933 bool txPktExists = txPacket; 1934 SERIALIZE_SCALAR(txPktExists); 1935 if (txPktExists) 1936 txPacket->serialize("txpacket", os); 1937 1938 Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0, 1939 inter_time = 0; 1940 1941 if (rdtrEvent.scheduled()) 1942 rdtr_time = rdtrEvent.when(); 1943 SERIALIZE_SCALAR(rdtr_time); 1944 1945 if (radvEvent.scheduled()) 1946 radv_time = radvEvent.when(); 1947 SERIALIZE_SCALAR(radv_time); 1948 1949 if (tidvEvent.scheduled()) 1950 tidv_time = tidvEvent.when(); 1951 SERIALIZE_SCALAR(tidv_time); 1952 1953 if (tadvEvent.scheduled()) 1954 tadv_time = tadvEvent.when(); 1955 SERIALIZE_SCALAR(tadv_time); 1956 1957 if (interEvent.scheduled()) 1958 inter_time = interEvent.when(); 1959 SERIALIZE_SCALAR(inter_time); 1960 1961 SERIALIZE_SCALAR(pktOffset); 1962 1963 nameOut(os, csprintf("%s.TxDescCache", name())); 1964 txDescCache.serialize(os); 1965 1966 nameOut(os, csprintf("%s.RxDescCache", name())); 1967 rxDescCache.serialize(os); 1968} 1969 1970void 1971IGbE::unserialize(Checkpoint *cp, const std::string §ion) 1972{ 1973 PciDev::unserialize(cp, section); 1974 1975 regs.unserialize(cp, section); 1976 UNSERIALIZE_SCALAR(eeOpBits); 1977 UNSERIALIZE_SCALAR(eeAddrBits); 1978 UNSERIALIZE_SCALAR(eeDataBits); 1979 UNSERIALIZE_SCALAR(eeOpcode); 1980 UNSERIALIZE_SCALAR(eeAddr); 1981 UNSERIALIZE_SCALAR(lastInterrupt); 1982 UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); 1983 1984 rxFifo.unserialize("rxfifo", cp, section); 1985 txFifo.unserialize("txfifo", cp, section); 1986 1987 bool txPktExists; 1988 UNSERIALIZE_SCALAR(txPktExists); 1989 if (txPktExists) { 1990 txPacket = new EthPacketData(16384); 1991 txPacket->unserialize("txpacket", cp, section); 1992 } 1993 1994 rxTick = true; 1995 txTick = true; 1996 txFifoTick = true; 1997 1998 Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time; 1999 UNSERIALIZE_SCALAR(rdtr_time); 2000 UNSERIALIZE_SCALAR(radv_time); 2001 UNSERIALIZE_SCALAR(tidv_time); 2002 UNSERIALIZE_SCALAR(tadv_time); 2003 UNSERIALIZE_SCALAR(inter_time); 2004 2005 if (rdtr_time) 2006 schedule(rdtrEvent, rdtr_time); 2007 2008 if (radv_time) 2009 schedule(radvEvent, radv_time); 2010 2011 if (tidv_time) 2012 schedule(tidvEvent, tidv_time); 2013 2014 if (tadv_time) 2015 schedule(tadvEvent, tadv_time); 2016 2017 if (inter_time) 2018 schedule(interEvent, inter_time); 2019 2020 UNSERIALIZE_SCALAR(pktOffset); 2021 2022 txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section)); 2023 2024 rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section)); 2025} 2026 2027IGbE * 2028IGbEParams::create() 2029{ 2030 return new IGbE(this); 2031} 2032