i8254xGBe.cc revision 8984
114060Stiago.muck@arm.com/* 28999Suri.wiener@arm.com * Copyright (c) 2006 The Regents of The University of Michigan 38999Suri.wiener@arm.com * All rights reserved. 48999Suri.wiener@arm.com * 58999Suri.wiener@arm.com * Redistribution and use in source and binary forms, with or without 68999Suri.wiener@arm.com * modification, are permitted provided that the following conditions are 78999Suri.wiener@arm.com * met: redistributions of source code must retain the above copyright 88999Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer; 98999Suri.wiener@arm.com * redistributions in binary form must reproduce the above copyright 108999Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer in the 118999Suri.wiener@arm.com * documentation and/or other materials provided with the distribution; 128999Suri.wiener@arm.com * neither the name of the copyright holders nor the names of its 138999Suri.wiener@arm.com * contributors may be used to endorse or promote products derived from 148999Suri.wiener@arm.com * this software without specific prior written permission. 158999Suri.wiener@arm.com * 168999Suri.wiener@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 178999Suri.wiener@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 188999Suri.wiener@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 198999Suri.wiener@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 208999Suri.wiener@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 218999Suri.wiener@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 228999Suri.wiener@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 238999Suri.wiener@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 248999Suri.wiener@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258999Suri.wiener@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 268999Suri.wiener@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278999Suri.wiener@arm.com * 288999Suri.wiener@arm.com * Authors: Ali Saidi 298999Suri.wiener@arm.com */ 308999Suri.wiener@arm.com 318999Suri.wiener@arm.com/* @file 328999Suri.wiener@arm.com * Device model for Intel's 8254x line of gigabit ethernet controllers. 338999Suri.wiener@arm.com * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the 348999Suri.wiener@arm.com * fewest workarounds in the driver. It will probably work with most of the 358999Suri.wiener@arm.com * other MACs with slight modifications. 368999Suri.wiener@arm.com */ 378999Suri.wiener@arm.com 3811418Ssascha.bischoff@arm.com 398999Suri.wiener@arm.com/* 408999Suri.wiener@arm.com * @todo really there are multiple dma engines.. we should implement them. 418999Suri.wiener@arm.com */ 428999Suri.wiener@arm.com 438999Suri.wiener@arm.com#include <algorithm> 448999Suri.wiener@arm.com 459852Sandreas.hansson@arm.com#include "base/inet.hh" 469852Sandreas.hansson@arm.com#include "base/trace.hh" 479852Sandreas.hansson@arm.com#include "debug/EthernetAll.hh" 489852Sandreas.hansson@arm.com#include "dev/i8254xGBe.hh" 499852Sandreas.hansson@arm.com#include "mem/packet.hh" 509852Sandreas.hansson@arm.com#include "mem/packet_access.hh" 519852Sandreas.hansson@arm.com#include "params/IGbE.hh" 529852Sandreas.hansson@arm.com#include "sim/stats.hh" 539852Sandreas.hansson@arm.com#include "sim/system.hh" 549852Sandreas.hansson@arm.com 558999Suri.wiener@arm.comusing namespace iGbReg; 568999Suri.wiener@arm.comusing namespace Net; 578999Suri.wiener@arm.com 588999Suri.wiener@arm.comIGbE::IGbE(const Params *p) 598999Suri.wiener@arm.com : EtherDevice(p), etherInt(NULL), drainEvent(NULL), 6013714Sandreas.sandberg@arm.com useFlowControl(p->use_flow_control), 6113714Sandreas.sandberg@arm.com rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), 6213714Sandreas.sandberg@arm.com txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0), 638999Suri.wiener@arm.com fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), 648999Suri.wiener@arm.com fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), 6512202Sgabeblack@google.com rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay), 669528Ssascha.bischoff@arm.com rdtrEvent(this), radvEvent(this), 678999Suri.wiener@arm.com tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this), 688999Suri.wiener@arm.com rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), 698999Suri.wiener@arm.com txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), 708999Suri.wiener@arm.com clock(p->clock), lastInterrupt(0) 718999Suri.wiener@arm.com{ 7212202Sgabeblack@google.com etherInt = new IGbEInt(name() + ".int", this); 7313709Sandreas.sandberg@arm.com 7412202Sgabeblack@google.com // Initialized internal registers per Intel documentation 7512202Sgabeblack@google.com // All registers intialized to 0 by per register constructor 7612202Sgabeblack@google.com regs.ctrl.fd(1); 7712202Sgabeblack@google.com regs.ctrl.lrst(1); 7812202Sgabeblack@google.com regs.ctrl.speed(2); 7912202Sgabeblack@google.com regs.ctrl.frcspd(1); 8012202Sgabeblack@google.com regs.sts.speed(3); // Say we're 1000Mbps 8112202Sgabeblack@google.com regs.sts.fd(1); // full duplex 8212202Sgabeblack@google.com regs.sts.lu(1); // link up 838999Suri.wiener@arm.com regs.eecd.fwe(1); 848999Suri.wiener@arm.com regs.eecd.ee_type(1); 858999Suri.wiener@arm.com regs.imr = 0; 868999Suri.wiener@arm.com regs.iam = 0; 878999Suri.wiener@arm.com regs.rxdctl.gran(1); 888999Suri.wiener@arm.com regs.rxdctl.wthresh(1); 898999Suri.wiener@arm.com regs.fcrth(1); 909852Sandreas.hansson@arm.com regs.tdwba = 0; 919852Sandreas.hansson@arm.com regs.rlpml = 0; 928999Suri.wiener@arm.com regs.sw_fw_sync = 0; 938999Suri.wiener@arm.com 948999Suri.wiener@arm.com regs.pba.rxa(0x30); 958999Suri.wiener@arm.com regs.pba.txa(0x10); 968999Suri.wiener@arm.com 978999Suri.wiener@arm.com eeOpBits = 0; 988999Suri.wiener@arm.com eeAddrBits = 0; 998999Suri.wiener@arm.com eeDataBits = 0; 1008999Suri.wiener@arm.com eeOpcode = 0; 1018999Suri.wiener@arm.com 1028999Suri.wiener@arm.com // clear all 64 16 bit words of the eeprom 1038999Suri.wiener@arm.com memset(&flash, 0, EEPROM_SIZE*2); 1048999Suri.wiener@arm.com 10512202Sgabeblack@google.com // Set the MAC address 10612202Sgabeblack@google.com memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN); 1078999Suri.wiener@arm.com for (int x = 0; x < ETH_ADDR_LEN/2; x++) 1088999Suri.wiener@arm.com flash[x] = htobe(flash[x]); 1098999Suri.wiener@arm.com 1108999Suri.wiener@arm.com uint16_t csum = 0; 1118999Suri.wiener@arm.com for (int x = 0; x < EEPROM_SIZE; x++) 1128999Suri.wiener@arm.com csum += htobe(flash[x]); 1138999Suri.wiener@arm.com 1148999Suri.wiener@arm.com 1158999Suri.wiener@arm.com // Magic happy checksum value 1168999Suri.wiener@arm.com flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); 1178999Suri.wiener@arm.com 1188999Suri.wiener@arm.com // Store the MAC address as queue ID 11910176Ssascha.bischoff@arm.com macAddr = p->hardware_address; 1208999Suri.wiener@arm.com 1218999Suri.wiener@arm.com rxFifo.clear(); 1228999Suri.wiener@arm.com txFifo.clear(); 1238999Suri.wiener@arm.com} 1248999Suri.wiener@arm.com 1258999Suri.wiener@arm.comvoid 12612202Sgabeblack@google.comIGbE::init() 12712202Sgabeblack@google.com{ 1288999Suri.wiener@arm.com cpa = CPA::cpa(); 12913870Sgabeblack@google.com PciDev::init(); 13013870Sgabeblack@google.com} 13113870Sgabeblack@google.com 13213870Sgabeblack@google.comEtherInt* 13313870Sgabeblack@google.comIGbE::getEthPort(const std::string &if_name, int idx) 13413870Sgabeblack@google.com{ 13513870Sgabeblack@google.com 13613870Sgabeblack@google.com if (if_name == "interface") { 13713870Sgabeblack@google.com if (etherInt->getPeer()) 13813870Sgabeblack@google.com panic("Port already connected to\n"); 13913870Sgabeblack@google.com return etherInt; 14013870Sgabeblack@google.com } 14113870Sgabeblack@google.com return NULL; 14213870Sgabeblack@google.com} 14313870Sgabeblack@google.com 14413870Sgabeblack@google.comTick 14513870Sgabeblack@google.comIGbE::writeConfig(PacketPtr pkt) 1468999Suri.wiener@arm.com{ 1478999Suri.wiener@arm.com int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1489854Sandreas.hansson@arm.com if (offset < PCI_DEVICE_SPECIFIC) 1499854Sandreas.hansson@arm.com PciDev::writeConfig(pkt); 1509854Sandreas.hansson@arm.com else 1519854Sandreas.hansson@arm.com panic("Device specific PCI config space not implemented.\n"); 1529854Sandreas.hansson@arm.com 1539854Sandreas.hansson@arm.com // 1549854Sandreas.hansson@arm.com // Some work may need to be done here based for the pci COMMAND bits. 1559854Sandreas.hansson@arm.com // 1569854Sandreas.hansson@arm.com 15714060Stiago.muck@arm.com return pioDelay; 1589854Sandreas.hansson@arm.com} 1598999Suri.wiener@arm.com 1608999Suri.wiener@arm.com// Handy macro for range-testing register access addresses 1618999Suri.wiener@arm.com#define IN_RANGE(val, base, len) (val >= base && val < (base + len)) 1628999Suri.wiener@arm.com 1639854Sandreas.hansson@arm.comTick 1648999Suri.wiener@arm.comIGbE::read(PacketPtr pkt) 1658999Suri.wiener@arm.com{ 1669853Sandreas.hansson@arm.com int bar; 1678999Suri.wiener@arm.com Addr daddr; 1688999Suri.wiener@arm.com 1698999Suri.wiener@arm.com if (!getBAR(pkt->getAddr(), bar, daddr)) 1708999Suri.wiener@arm.com panic("Invalid PCI memory access to unmapped memory.\n"); 1718999Suri.wiener@arm.com 1728999Suri.wiener@arm.com // Only Memory register BAR is allowed 1738999Suri.wiener@arm.com assert(bar == 0); 1748999Suri.wiener@arm.com 1758999Suri.wiener@arm.com // Only 32bit accesses allowed 1768999Suri.wiener@arm.com assert(pkt->getSize() == 4); 1778999Suri.wiener@arm.com 1788999Suri.wiener@arm.com DPRINTF(Ethernet, "Read device register %#X\n", daddr); 1799853Sandreas.hansson@arm.com 1808999Suri.wiener@arm.com pkt->allocate(); 1818999Suri.wiener@arm.com 1828999Suri.wiener@arm.com // 1838999Suri.wiener@arm.com // Handle read of register here 1848999Suri.wiener@arm.com // 1859853Sandreas.hansson@arm.com 1869853Sandreas.hansson@arm.com 1879853Sandreas.hansson@arm.com switch (daddr) { 1889853Sandreas.hansson@arm.com case REG_CTRL: 1899853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.ctrl()); 1909853Sandreas.hansson@arm.com break; 19110405Sandreas.hansson@arm.com case REG_STATUS: 1929853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.sts()); 1939853Sandreas.hansson@arm.com break; 1949853Sandreas.hansson@arm.com case REG_EECD: 1959853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.eecd()); 1969853Sandreas.hansson@arm.com break; 1979853Sandreas.hansson@arm.com case REG_EERD: 1989853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.eerd()); 1999853Sandreas.hansson@arm.com break; 2009853Sandreas.hansson@arm.com case REG_CTRL_EXT: 2019853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.ctrl_ext()); 2029853Sandreas.hansson@arm.com break; 2039853Sandreas.hansson@arm.com case REG_MDIC: 2049853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.mdic()); 2059853Sandreas.hansson@arm.com break; 2069853Sandreas.hansson@arm.com case REG_ICR: 2079853Sandreas.hansson@arm.com DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", 20810405Sandreas.hansson@arm.com regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame()); 20910405Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.icr()); 2109853Sandreas.hansson@arm.com if (regs.icr.int_assert() || regs.imr == 0) { 2119853Sandreas.hansson@arm.com regs.icr = regs.icr() & ~mask(30); 2129853Sandreas.hansson@arm.com DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr()); 2139853Sandreas.hansson@arm.com } 2149853Sandreas.hansson@arm.com if (regs.ctrl_ext.iame() && regs.icr.int_assert()) 2159853Sandreas.hansson@arm.com regs.imr &= ~regs.iam; 2169853Sandreas.hansson@arm.com chkInterrupt(); 2179853Sandreas.hansson@arm.com break; 2189853Sandreas.hansson@arm.com case REG_EICR: 2199853Sandreas.hansson@arm.com // This is only useful for MSI, but the driver reads it every time 2209853Sandreas.hansson@arm.com // Just don't do anything 2219853Sandreas.hansson@arm.com pkt->set<uint32_t>(0); 2229853Sandreas.hansson@arm.com break; 22310405Sandreas.hansson@arm.com case REG_ITR: 2249853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.itr()); 2259853Sandreas.hansson@arm.com break; 2269853Sandreas.hansson@arm.com case REG_RCTL: 2279853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rctl()); 2289853Sandreas.hansson@arm.com break; 2299853Sandreas.hansson@arm.com case REG_FCTTV: 2309853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.fcttv()); 2319853Sandreas.hansson@arm.com break; 2329853Sandreas.hansson@arm.com case REG_TCTL: 2339853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.tctl()); 2349853Sandreas.hansson@arm.com break; 2359853Sandreas.hansson@arm.com case REG_PBA: 2369853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.pba()); 2379853Sandreas.hansson@arm.com break; 2389853Sandreas.hansson@arm.com case REG_WUC: 2399853Sandreas.hansson@arm.com case REG_LEDCTL: 2409853Sandreas.hansson@arm.com pkt->set<uint32_t>(0); // We don't care, so just return 0 2419853Sandreas.hansson@arm.com break; 2429853Sandreas.hansson@arm.com case REG_FCRTL: 2439853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.fcrtl()); 2449853Sandreas.hansson@arm.com break; 2459853Sandreas.hansson@arm.com case REG_FCRTH: 2469853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.fcrth()); 2479853Sandreas.hansson@arm.com break; 2489853Sandreas.hansson@arm.com case REG_RDBAL: 2499853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rdba.rdbal()); 2509853Sandreas.hansson@arm.com break; 2519853Sandreas.hansson@arm.com case REG_RDBAH: 2529853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rdba.rdbah()); 2539853Sandreas.hansson@arm.com break; 2549853Sandreas.hansson@arm.com case REG_RDLEN: 2559853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rdlen()); 2569853Sandreas.hansson@arm.com break; 2579853Sandreas.hansson@arm.com case REG_SRRCTL: 2589853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.srrctl()); 2599853Sandreas.hansson@arm.com break; 2609853Sandreas.hansson@arm.com case REG_RDH: 2619853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rdh()); 2629853Sandreas.hansson@arm.com break; 2639853Sandreas.hansson@arm.com case REG_RDT: 2649853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rdt()); 2659853Sandreas.hansson@arm.com break; 2669853Sandreas.hansson@arm.com case REG_RDTR: 2679853Sandreas.hansson@arm.com pkt->set<uint32_t>(regs.rdtr()); 2688999Suri.wiener@arm.com if (regs.rdtr.fpd()) { 2699852Sandreas.hansson@arm.com rxDescCache.writeback(0); 2709852Sandreas.hansson@arm.com DPRINTF(EthernetIntr, 2719852Sandreas.hansson@arm.com "Posting interrupt because of RDTR.FPD write\n"); 2728999Suri.wiener@arm.com postInterrupt(IT_RXT); 2738999Suri.wiener@arm.com regs.rdtr.fpd(0); 27411418Ssascha.bischoff@arm.com } 27511418Ssascha.bischoff@arm.com break; 27611418Ssascha.bischoff@arm.com case REG_RXDCTL: 27711418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.rxdctl()); 27811418Ssascha.bischoff@arm.com break; 27911418Ssascha.bischoff@arm.com case REG_RADV: 28011418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.radv()); 28111418Ssascha.bischoff@arm.com break; 28211418Ssascha.bischoff@arm.com case REG_TDBAL: 28311418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdba.tdbal()); 28411418Ssascha.bischoff@arm.com break; 28511418Ssascha.bischoff@arm.com case REG_TDBAH: 28611418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdba.tdbah()); 28711418Ssascha.bischoff@arm.com break; 28811418Ssascha.bischoff@arm.com case REG_TDLEN: 28911418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdlen()); 29011418Ssascha.bischoff@arm.com break; 29111418Ssascha.bischoff@arm.com case REG_TDH: 29211418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdh()); 29311418Ssascha.bischoff@arm.com break; 29411418Ssascha.bischoff@arm.com case REG_TXDCA_CTL: 29511418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.txdca_ctl()); 29611418Ssascha.bischoff@arm.com break; 29711418Ssascha.bischoff@arm.com case REG_TDT: 29811418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdt()); 29911418Ssascha.bischoff@arm.com break; 30011418Ssascha.bischoff@arm.com case REG_TIDV: 30111418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tidv()); 30211418Ssascha.bischoff@arm.com break; 30311418Ssascha.bischoff@arm.com case REG_TXDCTL: 30411418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.txdctl()); 30511418Ssascha.bischoff@arm.com break; 30611418Ssascha.bischoff@arm.com case REG_TADV: 30711418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tadv()); 30811418Ssascha.bischoff@arm.com break; 30911418Ssascha.bischoff@arm.com case REG_TDWBAL: 31011418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdwba & mask(32)); 31111418Ssascha.bischoff@arm.com break; 31211418Ssascha.bischoff@arm.com case REG_TDWBAH: 31311418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.tdwba >> 32); 31411418Ssascha.bischoff@arm.com break; 31511418Ssascha.bischoff@arm.com case REG_RXCSUM: 31612202Sgabeblack@google.com pkt->set<uint32_t>(regs.rxcsum()); 31712202Sgabeblack@google.com break; 31812202Sgabeblack@google.com case REG_RLPML: 31912202Sgabeblack@google.com pkt->set<uint32_t>(regs.rlpml); 32012202Sgabeblack@google.com break; 32112202Sgabeblack@google.com case REG_RFCTL: 32212202Sgabeblack@google.com pkt->set<uint32_t>(regs.rfctl()); 32312202Sgabeblack@google.com break; 32412202Sgabeblack@google.com case REG_MANC: 32511418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.manc()); 32612202Sgabeblack@google.com break; 32712202Sgabeblack@google.com case REG_SWSM: 32812202Sgabeblack@google.com pkt->set<uint32_t>(regs.swsm()); 32912202Sgabeblack@google.com regs.swsm.smbi(1); 33012202Sgabeblack@google.com break; 33112202Sgabeblack@google.com case REG_FWSM: 33211418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.fwsm()); 33312202Sgabeblack@google.com break; 33412202Sgabeblack@google.com case REG_SWFWSYNC: 33511418Ssascha.bischoff@arm.com pkt->set<uint32_t>(regs.sw_fw_sync); 33611418Ssascha.bischoff@arm.com break; 33711418Ssascha.bischoff@arm.com default: 33811418Ssascha.bischoff@arm.com if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) && 33911418Ssascha.bischoff@arm.com !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) && 34011418Ssascha.bischoff@arm.com !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) && 3418999Suri.wiener@arm.com !IN_RANGE(daddr, REG_CRCERRS, STATS_REGS_SIZE)) 3428999Suri.wiener@arm.com panic("Read request to unknown register number: %#x\n", daddr); 3438999Suri.wiener@arm.com else 3449852Sandreas.hansson@arm.com pkt->set<uint32_t>(0); 3459852Sandreas.hansson@arm.com }; 3469852Sandreas.hansson@arm.com 3479852Sandreas.hansson@arm.com pkt->makeAtomicResponse(); 3489852Sandreas.hansson@arm.com return pioDelay; 3498999Suri.wiener@arm.com} 3508999Suri.wiener@arm.com 3518999Suri.wiener@arm.comTick 3528999Suri.wiener@arm.comIGbE::write(PacketPtr pkt) 3538999Suri.wiener@arm.com{ 3548999Suri.wiener@arm.com int bar; 3558999Suri.wiener@arm.com Addr daddr; 3569852Sandreas.hansson@arm.com 3578999Suri.wiener@arm.com 3588999Suri.wiener@arm.com if (!getBAR(pkt->getAddr(), bar, daddr)) 3599853Sandreas.hansson@arm.com panic("Invalid PCI memory access to unmapped memory.\n"); 36011418Ssascha.bischoff@arm.com 36111418Ssascha.bischoff@arm.com // Only Memory register BAR is allowed 36211418Ssascha.bischoff@arm.com assert(bar == 0); 36311418Ssascha.bischoff@arm.com 36411431Ssascha.bischoff@arm.com // Only 32bit accesses allowed 36511431Ssascha.bischoff@arm.com assert(pkt->getSize() == sizeof(uint32_t)); 36611431Ssascha.bischoff@arm.com 36711431Ssascha.bischoff@arm.com DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", 36811431Ssascha.bischoff@arm.com daddr, pkt->get<uint32_t>()); 36911431Ssascha.bischoff@arm.com 37011431Ssascha.bischoff@arm.com // 37111431Ssascha.bischoff@arm.com // Handle write of register here 37211431Ssascha.bischoff@arm.com // 37311431Ssascha.bischoff@arm.com uint32_t val = pkt->get<uint32_t>(); 37411431Ssascha.bischoff@arm.com 37511431Ssascha.bischoff@arm.com Regs::RCTL oldrctl; 37611431Ssascha.bischoff@arm.com Regs::TCTL oldtctl; 37711418Ssascha.bischoff@arm.com 37811418Ssascha.bischoff@arm.com switch (daddr) { 37911418Ssascha.bischoff@arm.com case REG_CTRL: 38011418Ssascha.bischoff@arm.com regs.ctrl = val; 38111418Ssascha.bischoff@arm.com if (regs.ctrl.tfce()) 38211418Ssascha.bischoff@arm.com warn("TX Flow control enabled, should implement\n"); 38311418Ssascha.bischoff@arm.com if (regs.ctrl.rfce()) 384 warn("RX Flow control enabled, should implement\n"); 385 break; 386 case REG_CTRL_EXT: 387 regs.ctrl_ext = val; 388 break; 389 case REG_STATUS: 390 regs.sts = val; 391 break; 392 case REG_EECD: 393 int oldClk; 394 oldClk = regs.eecd.sk(); 395 regs.eecd = val; 396 // See if this is a eeprom access and emulate accordingly 397 if (!oldClk && regs.eecd.sk()) { 398 if (eeOpBits < 8) { 399 eeOpcode = eeOpcode << 1 | regs.eecd.din(); 400 eeOpBits++; 401 } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 402 eeAddr = eeAddr << 1 | regs.eecd.din(); 403 eeAddrBits++; 404 } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 405 assert(eeAddr>>1 < EEPROM_SIZE); 406 DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", 407 flash[eeAddr>>1] >> eeDataBits & 0x1, 408 flash[eeAddr>>1]); 409 regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1); 410 eeDataBits++; 411 } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { 412 regs.eecd.dout(0); 413 eeDataBits++; 414 } else 415 panic("What's going on with eeprom interface? opcode:" 416 " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, 417 (uint32_t)eeOpBits, (uint32_t)eeAddr, 418 (uint32_t)eeAddrBits, (uint32_t)eeDataBits); 419 420 // Reset everything for the next command 421 if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || 422 (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { 423 eeOpBits = 0; 424 eeAddrBits = 0; 425 eeDataBits = 0; 426 eeOpcode = 0; 427 eeAddr = 0; 428 } 429 430 DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", 431 (uint32_t)eeOpcode, (uint32_t) eeOpBits, 432 (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); 433 if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || 434 eeOpcode == EEPROM_RDSR_OPCODE_SPI )) 435 panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, 436 (uint32_t)eeOpBits); 437 438 439 } 440 // If driver requests eeprom access, immediately give it to it 441 regs.eecd.ee_gnt(regs.eecd.ee_req()); 442 break; 443 case REG_EERD: 444 regs.eerd = val; 445 if (regs.eerd.start()) { 446 regs.eerd.done(1); 447 assert(regs.eerd.addr() < EEPROM_SIZE); 448 regs.eerd.data(flash[regs.eerd.addr()]); 449 regs.eerd.start(0); 450 DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n", 451 regs.eerd.addr(), regs.eerd.data()); 452 } 453 break; 454 case REG_MDIC: 455 regs.mdic = val; 456 if (regs.mdic.i()) 457 panic("No support for interrupt on mdic complete\n"); 458 if (regs.mdic.phyadd() != 1) 459 panic("No support for reading anything but phy\n"); 460 DPRINTF(Ethernet, "%s phy address %x\n", 461 regs.mdic.op() == 1 ? "Writing" : "Reading", 462 regs.mdic.regadd()); 463 switch (regs.mdic.regadd()) { 464 case PHY_PSTATUS: 465 regs.mdic.data(0x796D); // link up 466 break; 467 case PHY_PID: 468 regs.mdic.data(params()->phy_pid); 469 break; 470 case PHY_EPID: 471 regs.mdic.data(params()->phy_epid); 472 break; 473 case PHY_GSTATUS: 474 regs.mdic.data(0x7C00); 475 break; 476 case PHY_EPSTATUS: 477 regs.mdic.data(0x3000); 478 break; 479 case PHY_AGC: 480 regs.mdic.data(0x180); // some random length 481 break; 482 default: 483 regs.mdic.data(0); 484 } 485 regs.mdic.r(1); 486 break; 487 case REG_ICR: 488 DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", 489 regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame()); 490 if (regs.ctrl_ext.iame()) 491 regs.imr &= ~regs.iam; 492 regs.icr = ~bits(val,30,0) & regs.icr(); 493 chkInterrupt(); 494 break; 495 case REG_ITR: 496 regs.itr = val; 497 break; 498 case REG_ICS: 499 DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n"); 500 postInterrupt((IntTypes)val); 501 break; 502 case REG_IMS: 503 regs.imr |= val; 504 chkInterrupt(); 505 break; 506 case REG_IMC: 507 regs.imr &= ~val; 508 chkInterrupt(); 509 break; 510 case REG_IAM: 511 regs.iam = val; 512 break; 513 case REG_RCTL: 514 oldrctl = regs.rctl; 515 regs.rctl = val; 516 if (regs.rctl.rst()) { 517 rxDescCache.reset(); 518 DPRINTF(EthernetSM, "RXS: Got RESET!\n"); 519 rxFifo.clear(); 520 regs.rctl.rst(0); 521 } 522 if (regs.rctl.en()) 523 rxTick = true; 524 restartClock(); 525 break; 526 case REG_FCTTV: 527 regs.fcttv = val; 528 break; 529 case REG_TCTL: 530 regs.tctl = val; 531 oldtctl = regs.tctl; 532 regs.tctl = val; 533 if (regs.tctl.en()) 534 txTick = true; 535 restartClock(); 536 if (regs.tctl.en() && !oldtctl.en()) { 537 txDescCache.reset(); 538 } 539 break; 540 case REG_PBA: 541 regs.pba.rxa(val); 542 regs.pba.txa(64 - regs.pba.rxa()); 543 break; 544 case REG_WUC: 545 case REG_LEDCTL: 546 case REG_FCAL: 547 case REG_FCAH: 548 case REG_FCT: 549 case REG_VET: 550 case REG_AIFS: 551 case REG_TIPG: 552 ; // We don't care, so don't store anything 553 break; 554 case REG_IVAR0: 555 warn("Writing to IVAR0, ignoring...\n"); 556 break; 557 case REG_FCRTL: 558 regs.fcrtl = val; 559 break; 560 case REG_FCRTH: 561 regs.fcrth = val; 562 break; 563 case REG_RDBAL: 564 regs.rdba.rdbal( val & ~mask(4)); 565 rxDescCache.areaChanged(); 566 break; 567 case REG_RDBAH: 568 regs.rdba.rdbah(val); 569 rxDescCache.areaChanged(); 570 break; 571 case REG_RDLEN: 572 regs.rdlen = val & ~mask(7); 573 rxDescCache.areaChanged(); 574 break; 575 case REG_SRRCTL: 576 regs.srrctl = val; 577 break; 578 case REG_RDH: 579 regs.rdh = val; 580 rxDescCache.areaChanged(); 581 break; 582 case REG_RDT: 583 regs.rdt = val; 584 DPRINTF(EthernetSM, "RXS: RDT Updated.\n"); 585 if (getState() == SimObject::Running) { 586 DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n"); 587 rxDescCache.fetchDescriptors(); 588 } else { 589 DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n"); 590 } 591 break; 592 case REG_RDTR: 593 regs.rdtr = val; 594 break; 595 case REG_RADV: 596 regs.radv = val; 597 break; 598 case REG_RXDCTL: 599 regs.rxdctl = val; 600 break; 601 case REG_TDBAL: 602 regs.tdba.tdbal( val & ~mask(4)); 603 txDescCache.areaChanged(); 604 break; 605 case REG_TDBAH: 606 regs.tdba.tdbah(val); 607 txDescCache.areaChanged(); 608 break; 609 case REG_TDLEN: 610 regs.tdlen = val & ~mask(7); 611 txDescCache.areaChanged(); 612 break; 613 case REG_TDH: 614 regs.tdh = val; 615 txDescCache.areaChanged(); 616 break; 617 case REG_TXDCA_CTL: 618 regs.txdca_ctl = val; 619 if (regs.txdca_ctl.enabled()) 620 panic("No support for DCA\n"); 621 break; 622 case REG_TDT: 623 regs.tdt = val; 624 DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n"); 625 if (getState() == SimObject::Running) { 626 DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n"); 627 txDescCache.fetchDescriptors(); 628 } else { 629 DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n"); 630 } 631 break; 632 case REG_TIDV: 633 regs.tidv = val; 634 break; 635 case REG_TXDCTL: 636 regs.txdctl = val; 637 break; 638 case REG_TADV: 639 regs.tadv = val; 640 break; 641 case REG_TDWBAL: 642 regs.tdwba &= ~mask(32); 643 regs.tdwba |= val; 644 txDescCache.completionWriteback(regs.tdwba & ~mask(1), 645 regs.tdwba & mask(1)); 646 break; 647 case REG_TDWBAH: 648 regs.tdwba &= mask(32); 649 regs.tdwba |= (uint64_t)val << 32; 650 txDescCache.completionWriteback(regs.tdwba & ~mask(1), 651 regs.tdwba & mask(1)); 652 break; 653 case REG_RXCSUM: 654 regs.rxcsum = val; 655 break; 656 case REG_RLPML: 657 regs.rlpml = val; 658 break; 659 case REG_RFCTL: 660 regs.rfctl = val; 661 if (regs.rfctl.exsten()) 662 panic("Extended RX descriptors not implemented\n"); 663 break; 664 case REG_MANC: 665 regs.manc = val; 666 break; 667 case REG_SWSM: 668 regs.swsm = val; 669 if (regs.fwsm.eep_fw_semaphore()) 670 regs.swsm.swesmbi(0); 671 break; 672 case REG_SWFWSYNC: 673 regs.sw_fw_sync = val; 674 break; 675 default: 676 if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) && 677 !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) && 678 !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4)) 679 panic("Write request to unknown register number: %#x\n", daddr); 680 }; 681 682 pkt->makeAtomicResponse(); 683 return pioDelay; 684} 685 686void 687IGbE::postInterrupt(IntTypes t, bool now) 688{ 689 assert(t); 690 691 // Interrupt is already pending 692 if (t & regs.icr() && !now) 693 return; 694 695 regs.icr = regs.icr() | t; 696 697 Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval(); 698 DPRINTF(EthernetIntr, 699 "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n", 700 curTick(), regs.itr.interval(), itr_interval); 701 702 if (regs.itr.interval() == 0 || now || 703 lastInterrupt + itr_interval <= curTick()) { 704 if (interEvent.scheduled()) { 705 deschedule(interEvent); 706 } 707 cpuPostInt(); 708 } else { 709 Tick int_time = lastInterrupt + itr_interval; 710 assert(int_time > 0); 711 DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n", 712 int_time); 713 if (!interEvent.scheduled()) { 714 schedule(interEvent, int_time); 715 } 716 } 717} 718 719void 720IGbE::delayIntEvent() 721{ 722 cpuPostInt(); 723} 724 725 726void 727IGbE::cpuPostInt() 728{ 729 730 postedInterrupts++; 731 732 if (!(regs.icr() & regs.imr)) { 733 DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n"); 734 return; 735 } 736 737 DPRINTF(Ethernet, "Posting Interrupt\n"); 738 739 740 if (interEvent.scheduled()) { 741 deschedule(interEvent); 742 } 743 744 if (rdtrEvent.scheduled()) { 745 regs.icr.rxt0(1); 746 deschedule(rdtrEvent); 747 } 748 if (radvEvent.scheduled()) { 749 regs.icr.rxt0(1); 750 deschedule(radvEvent); 751 } 752 if (tadvEvent.scheduled()) { 753 regs.icr.txdw(1); 754 deschedule(tadvEvent); 755 } 756 if (tidvEvent.scheduled()) { 757 regs.icr.txdw(1); 758 deschedule(tidvEvent); 759 } 760 761 regs.icr.int_assert(1); 762 DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n", 763 regs.icr()); 764 765 intrPost(); 766 767 lastInterrupt = curTick(); 768} 769 770void 771IGbE::cpuClearInt() 772{ 773 if (regs.icr.int_assert()) { 774 regs.icr.int_assert(0); 775 DPRINTF(EthernetIntr, 776 "EINT: Clearing interrupt to CPU now. Vector %#x\n", 777 regs.icr()); 778 intrClear(); 779 } 780} 781 782void 783IGbE::chkInterrupt() 784{ 785 DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(), 786 regs.imr); 787 // Check if we need to clear the cpu interrupt 788 if (!(regs.icr() & regs.imr)) { 789 DPRINTF(Ethernet, "Mask cleaned all interrupts\n"); 790 if (interEvent.scheduled()) 791 deschedule(interEvent); 792 if (regs.icr.int_assert()) 793 cpuClearInt(); 794 } 795 DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", 796 regs.itr(), regs.itr.interval()); 797 798 if (regs.icr() & regs.imr) { 799 if (regs.itr.interval() == 0) { 800 cpuPostInt(); 801 } else { 802 DPRINTF(Ethernet, 803 "Possibly scheduling interrupt because of imr write\n"); 804 if (!interEvent.scheduled()) { 805 Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval(); 806 DPRINTF(Ethernet, "Scheduling for %d\n", t); 807 schedule(interEvent, t); 808 } 809 } 810 } 811} 812 813 814///////////////////////////// IGbE::DescCache ////////////////////////////// 815 816template<class T> 817IGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s) 818 : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), 819 wbOut(0), pktPtr(NULL), wbDelayEvent(this), 820 fetchDelayEvent(this), fetchEvent(this), wbEvent(this) 821{ 822 fetchBuf = new T[size]; 823 wbBuf = new T[size]; 824} 825 826template<class T> 827IGbE::DescCache<T>::~DescCache() 828{ 829 reset(); 830} 831 832template<class T> 833void 834IGbE::DescCache<T>::areaChanged() 835{ 836 if (usedCache.size() > 0 || curFetching || wbOut) 837 panic("Descriptor Address, Length or Head changed. Bad\n"); 838 reset(); 839 840} 841 842template<class T> 843void 844IGbE::DescCache<T>::writeback(Addr aMask) 845{ 846 int curHead = descHead(); 847 int max_to_wb = usedCache.size(); 848 849 // Check if this writeback is less restrictive that the previous 850 // and if so setup another one immediately following it 851 if (wbOut) { 852 if (aMask < wbAlignment) { 853 moreToWb = true; 854 wbAlignment = aMask; 855 } 856 DPRINTF(EthernetDesc, 857 "Writing back already in process, returning\n"); 858 return; 859 } 860 861 moreToWb = false; 862 wbAlignment = aMask; 863 864 865 DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: " 866 "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n", 867 curHead, descTail(), descLen(), cachePnt, max_to_wb, 868 descLeft()); 869 870 if (max_to_wb + curHead >= descLen()) { 871 max_to_wb = descLen() - curHead; 872 moreToWb = true; 873 // this is by definition aligned correctly 874 } else if (wbAlignment != 0) { 875 // align the wb point to the mask 876 max_to_wb = max_to_wb & ~wbAlignment; 877 } 878 879 DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb); 880 881 if (max_to_wb <= 0) { 882 if (usedCache.size()) 883 igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT); 884 else 885 igbe->anWe(annSmWb, annUsedCacheQ); 886 return; 887 } 888 889 wbOut = max_to_wb; 890 891 assert(!wbDelayEvent.scheduled()); 892 igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay); 893 igbe->anBegin(annSmWb, "Prepare Writeback Desc"); 894} 895 896template<class T> 897void 898IGbE::DescCache<T>::writeback1() 899{ 900 // If we're draining delay issuing this DMA 901 if (igbe->getState() != SimObject::Running) { 902 igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay); 903 return; 904 } 905 906 DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut); 907 908 for (int x = 0; x < wbOut; x++) { 909 assert(usedCache.size()); 910 memcpy(&wbBuf[x], usedCache[x], sizeof(T)); 911 igbe->anPq(annSmWb, annUsedCacheQ); 912 igbe->anPq(annSmWb, annDescQ); 913 igbe->anQ(annSmWb, annUsedDescQ); 914 } 915 916 917 igbe->anBegin(annSmWb, "Writeback Desc DMA"); 918 919 assert(wbOut); 920 igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)), 921 wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf, 922 igbe->wbCompDelay); 923} 924 925template<class T> 926void 927IGbE::DescCache<T>::fetchDescriptors() 928{ 929 size_t max_to_fetch; 930 931 if (curFetching) { 932 DPRINTF(EthernetDesc, 933 "Currently fetching %d descriptors, returning\n", 934 curFetching); 935 return; 936 } 937 938 if (descTail() >= cachePnt) 939 max_to_fetch = descTail() - cachePnt; 940 else 941 max_to_fetch = descLen() - cachePnt; 942 943 size_t free_cache = size - usedCache.size() - unusedCache.size(); 944 945 if (!max_to_fetch) 946 igbe->anWe(annSmFetch, annUnusedDescQ); 947 else 948 igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch); 949 950 if (max_to_fetch) { 951 if (!free_cache) 952 igbe->anWf(annSmFetch, annDescQ); 953 else 954 igbe->anRq(annSmFetch, annDescQ, free_cache); 955 } 956 957 max_to_fetch = std::min(max_to_fetch, free_cache); 958 959 960 DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: " 961 "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n", 962 descHead(), descTail(), descLen(), cachePnt, 963 max_to_fetch, descLeft()); 964 965 // Nothing to do 966 if (max_to_fetch == 0) 967 return; 968 969 // So we don't have two descriptor fetches going on at once 970 curFetching = max_to_fetch; 971 972 assert(!fetchDelayEvent.scheduled()); 973 igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay); 974 igbe->anBegin(annSmFetch, "Prepare Fetch Desc"); 975} 976 977template<class T> 978void 979IGbE::DescCache<T>::fetchDescriptors1() 980{ 981 // If we're draining delay issuing this DMA 982 if (igbe->getState() != SimObject::Running) { 983 igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay); 984 return; 985 } 986 987 igbe->anBegin(annSmFetch, "Fetch Desc"); 988 989 DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n", 990 descBase() + cachePnt * sizeof(T), 991 pciToDma(descBase() + cachePnt * sizeof(T)), 992 curFetching * sizeof(T)); 993 assert(curFetching); 994 igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)), 995 curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf, 996 igbe->fetchCompDelay); 997} 998 999template<class T> 1000void 1001IGbE::DescCache<T>::fetchComplete() 1002{ 1003 T *newDesc; 1004 igbe->anBegin(annSmFetch, "Fetch Complete"); 1005 for (int x = 0; x < curFetching; x++) { 1006 newDesc = new T; 1007 memcpy(newDesc, &fetchBuf[x], sizeof(T)); 1008 unusedCache.push_back(newDesc); 1009 igbe->anDq(annSmFetch, annUnusedDescQ); 1010 igbe->anQ(annSmFetch, annUnusedCacheQ); 1011 igbe->anQ(annSmFetch, annDescQ); 1012 } 1013 1014 1015#ifndef NDEBUG 1016 int oldCp = cachePnt; 1017#endif 1018 1019 cachePnt += curFetching; 1020 assert(cachePnt <= descLen()); 1021 if (cachePnt == descLen()) 1022 cachePnt = 0; 1023 1024 curFetching = 0; 1025 1026 DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n", 1027 oldCp, cachePnt); 1028 1029 if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() - 1030 cachePnt)) == 0) 1031 { 1032 igbe->anWe(annSmFetch, annUnusedDescQ); 1033 } else if (!(size - usedCache.size() - unusedCache.size())) { 1034 igbe->anWf(annSmFetch, annDescQ); 1035 } else { 1036 igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT); 1037 } 1038 1039 enableSm(); 1040 igbe->checkDrain(); 1041} 1042 1043template<class T> 1044void 1045IGbE::DescCache<T>::wbComplete() 1046{ 1047 1048 igbe->anBegin(annSmWb, "Finish Writeback"); 1049 1050 long curHead = descHead(); 1051#ifndef NDEBUG 1052 long oldHead = curHead; 1053#endif 1054 1055 for (int x = 0; x < wbOut; x++) { 1056 assert(usedCache.size()); 1057 delete usedCache[0]; 1058 usedCache.pop_front(); 1059 1060 igbe->anDq(annSmWb, annUsedCacheQ); 1061 igbe->anDq(annSmWb, annDescQ); 1062 } 1063 1064 curHead += wbOut; 1065 wbOut = 0; 1066 1067 if (curHead >= descLen()) 1068 curHead -= descLen(); 1069 1070 // Update the head 1071 updateHead(curHead); 1072 1073 DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n", 1074 oldHead, curHead); 1075 1076 // If we still have more to wb, call wb now 1077 actionAfterWb(); 1078 if (moreToWb) { 1079 moreToWb = false; 1080 DPRINTF(EthernetDesc, "Writeback has more todo\n"); 1081 writeback(wbAlignment); 1082 } 1083 1084 if (!wbOut) { 1085 igbe->checkDrain(); 1086 if (usedCache.size()) 1087 igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT); 1088 else 1089 igbe->anWe(annSmWb, annUsedCacheQ); 1090 } 1091 fetchAfterWb(); 1092} 1093 1094template<class T> 1095void 1096IGbE::DescCache<T>::reset() 1097{ 1098 DPRINTF(EthernetDesc, "Reseting descriptor cache\n"); 1099 for (typename CacheType::size_type x = 0; x < usedCache.size(); x++) 1100 delete usedCache[x]; 1101 for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++) 1102 delete unusedCache[x]; 1103 1104 usedCache.clear(); 1105 unusedCache.clear(); 1106 1107 cachePnt = 0; 1108 1109} 1110 1111template<class T> 1112void 1113IGbE::DescCache<T>::serialize(std::ostream &os) 1114{ 1115 SERIALIZE_SCALAR(cachePnt); 1116 SERIALIZE_SCALAR(curFetching); 1117 SERIALIZE_SCALAR(wbOut); 1118 SERIALIZE_SCALAR(moreToWb); 1119 SERIALIZE_SCALAR(wbAlignment); 1120 1121 typename CacheType::size_type usedCacheSize = usedCache.size(); 1122 SERIALIZE_SCALAR(usedCacheSize); 1123 for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) { 1124 arrayParamOut(os, csprintf("usedCache_%d", x), 1125 (uint8_t*)usedCache[x],sizeof(T)); 1126 } 1127 1128 typename CacheType::size_type unusedCacheSize = unusedCache.size(); 1129 SERIALIZE_SCALAR(unusedCacheSize); 1130 for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) { 1131 arrayParamOut(os, csprintf("unusedCache_%d", x), 1132 (uint8_t*)unusedCache[x],sizeof(T)); 1133 } 1134 1135 Tick fetch_delay = 0, wb_delay = 0; 1136 if (fetchDelayEvent.scheduled()) 1137 fetch_delay = fetchDelayEvent.when(); 1138 SERIALIZE_SCALAR(fetch_delay); 1139 if (wbDelayEvent.scheduled()) 1140 wb_delay = wbDelayEvent.when(); 1141 SERIALIZE_SCALAR(wb_delay); 1142 1143 1144} 1145 1146template<class T> 1147void 1148IGbE::DescCache<T>::unserialize(Checkpoint *cp, const std::string §ion) 1149{ 1150 UNSERIALIZE_SCALAR(cachePnt); 1151 UNSERIALIZE_SCALAR(curFetching); 1152 UNSERIALIZE_SCALAR(wbOut); 1153 UNSERIALIZE_SCALAR(moreToWb); 1154 UNSERIALIZE_SCALAR(wbAlignment); 1155 1156 typename CacheType::size_type usedCacheSize; 1157 UNSERIALIZE_SCALAR(usedCacheSize); 1158 T *temp; 1159 for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) { 1160 temp = new T; 1161 arrayParamIn(cp, section, csprintf("usedCache_%d", x), 1162 (uint8_t*)temp,sizeof(T)); 1163 usedCache.push_back(temp); 1164 } 1165 1166 typename CacheType::size_type unusedCacheSize; 1167 UNSERIALIZE_SCALAR(unusedCacheSize); 1168 for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) { 1169 temp = new T; 1170 arrayParamIn(cp, section, csprintf("unusedCache_%d", x), 1171 (uint8_t*)temp,sizeof(T)); 1172 unusedCache.push_back(temp); 1173 } 1174 Tick fetch_delay = 0, wb_delay = 0; 1175 UNSERIALIZE_SCALAR(fetch_delay); 1176 UNSERIALIZE_SCALAR(wb_delay); 1177 if (fetch_delay) 1178 igbe->schedule(fetchDelayEvent, fetch_delay); 1179 if (wb_delay) 1180 igbe->schedule(wbDelayEvent, wb_delay); 1181 1182 1183} 1184 1185///////////////////////////// IGbE::RxDescCache ////////////////////////////// 1186 1187IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) 1188 : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0), 1189 pktEvent(this), pktHdrEvent(this), pktDataEvent(this) 1190 1191{ 1192 annSmFetch = "RX Desc Fetch"; 1193 annSmWb = "RX Desc Writeback"; 1194 annUnusedDescQ = "RX Unused Descriptors"; 1195 annUnusedCacheQ = "RX Unused Descriptor Cache"; 1196 annUsedCacheQ = "RX Used Descriptor Cache"; 1197 annUsedDescQ = "RX Used Descriptors"; 1198 annDescQ = "RX Descriptors"; 1199} 1200 1201void 1202IGbE::RxDescCache::pktSplitDone() 1203{ 1204 splitCount++; 1205 DPRINTF(EthernetDesc, 1206 "Part of split packet done: splitcount now %d\n", splitCount); 1207 assert(splitCount <= 2); 1208 if (splitCount != 2) 1209 return; 1210 splitCount = 0; 1211 DPRINTF(EthernetDesc, 1212 "Part of split packet done: calling pktComplete()\n"); 1213 pktComplete(); 1214} 1215 1216int 1217IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset) 1218{ 1219 assert(unusedCache.size()); 1220 //if (!unusedCache.size()) 1221 // return false; 1222 1223 pktPtr = packet; 1224 pktDone = false; 1225 unsigned buf_len, hdr_len; 1226 1227 RxDesc *desc = unusedCache.front(); 1228 switch (igbe->regs.srrctl.desctype()) { 1229 case RXDT_LEGACY: 1230 assert(pkt_offset == 0); 1231 bytesCopied = packet->length; 1232 DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n", 1233 packet->length, igbe->regs.rctl.descSize()); 1234 assert(packet->length < igbe->regs.rctl.descSize()); 1235 igbe->dmaWrite(pciToDma(desc->legacy.buf), 1236 packet->length, &pktEvent, packet->data, 1237 igbe->rxWriteDelay); 1238 break; 1239 case RXDT_ADV_ONEBUF: 1240 assert(pkt_offset == 0); 1241 bytesCopied = packet->length; 1242 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : 1243 igbe->regs.rctl.descSize(); 1244 DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n", 1245 packet->length, igbe->regs.srrctl(), buf_len); 1246 assert(packet->length < buf_len); 1247 igbe->dmaWrite(pciToDma(desc->adv_read.pkt), 1248 packet->length, &pktEvent, packet->data, 1249 igbe->rxWriteDelay); 1250 desc->adv_wb.header_len = htole(0); 1251 desc->adv_wb.sph = htole(0); 1252 desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length)); 1253 break; 1254 case RXDT_ADV_SPLIT_A: 1255 int split_point; 1256 1257 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : 1258 igbe->regs.rctl.descSize(); 1259 hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0; 1260 DPRINTF(EthernetDesc, 1261 "lpe: %d Packet Length: %d offset: %d srrctl: %#x " 1262 "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n", 1263 igbe->regs.rctl.lpe(), packet->length, pkt_offset, 1264 igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, 1265 desc->adv_read.pkt, buf_len); 1266 1267 split_point = hsplit(pktPtr); 1268 1269 if (packet->length <= hdr_len) { 1270 bytesCopied = packet->length; 1271 assert(pkt_offset == 0); 1272 DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n"); 1273 igbe->dmaWrite(pciToDma(desc->adv_read.hdr), 1274 packet->length, &pktEvent, packet->data, 1275 igbe->rxWriteDelay); 1276 desc->adv_wb.header_len = htole((uint16_t)packet->length); 1277 desc->adv_wb.sph = htole(0); 1278 desc->adv_wb.pkt_len = htole(0); 1279 } else if (split_point) { 1280 if (pkt_offset) { 1281 // we are only copying some data, header/data has already been 1282 // copied 1283 int max_to_copy = 1284 std::min(packet->length - pkt_offset, buf_len); 1285 bytesCopied += max_to_copy; 1286 DPRINTF(EthernetDesc, 1287 "Hdr split: Continuing data buffer copy\n"); 1288 igbe->dmaWrite(pciToDma(desc->adv_read.pkt), 1289 max_to_copy, &pktEvent, 1290 packet->data + pkt_offset, igbe->rxWriteDelay); 1291 desc->adv_wb.header_len = htole(0); 1292 desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy); 1293 desc->adv_wb.sph = htole(0); 1294 } else { 1295 int max_to_copy = 1296 std::min(packet->length - split_point, buf_len); 1297 bytesCopied += max_to_copy + split_point; 1298 1299 DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n", 1300 split_point); 1301 igbe->dmaWrite(pciToDma(desc->adv_read.hdr), 1302 split_point, &pktHdrEvent, 1303 packet->data, igbe->rxWriteDelay); 1304 igbe->dmaWrite(pciToDma(desc->adv_read.pkt), 1305 max_to_copy, &pktDataEvent, 1306 packet->data + split_point, igbe->rxWriteDelay); 1307 desc->adv_wb.header_len = htole(split_point); 1308 desc->adv_wb.sph = 1; 1309 desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy)); 1310 } 1311 } else { 1312 panic("Header split not fitting within header buffer or " 1313 "undecodable packet not fitting in header unsupported\n"); 1314 } 1315 break; 1316 default: 1317 panic("Unimplemnted RX receive buffer type: %d\n", 1318 igbe->regs.srrctl.desctype()); 1319 } 1320 return bytesCopied; 1321 1322} 1323 1324void 1325IGbE::RxDescCache::pktComplete() 1326{ 1327 assert(unusedCache.size()); 1328 RxDesc *desc; 1329 desc = unusedCache.front(); 1330 1331 igbe->anBegin("RXS", "Update Desc"); 1332 1333 uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ; 1334 DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d " 1335 "stripcrc offset: %d value written: %d %d\n", 1336 pktPtr->length, bytesCopied, crcfixup, 1337 htole((uint16_t)(pktPtr->length + crcfixup)), 1338 (uint16_t)(pktPtr->length + crcfixup)); 1339 1340 // no support for anything but starting at 0 1341 assert(igbe->regs.rxcsum.pcss() == 0); 1342 1343 DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n"); 1344 1345 uint16_t status = RXDS_DD; 1346 uint8_t err = 0; 1347 uint16_t ext_err = 0; 1348 uint16_t csum = 0; 1349 uint16_t ptype = 0; 1350 uint16_t ip_id = 0; 1351 1352 assert(bytesCopied <= pktPtr->length); 1353 if (bytesCopied == pktPtr->length) 1354 status |= RXDS_EOP; 1355 1356 IpPtr ip(pktPtr); 1357 1358 if (ip) { 1359 DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); 1360 ptype |= RXDP_IPV4; 1361 ip_id = ip->id(); 1362 1363 if (igbe->regs.rxcsum.ipofld()) { 1364 DPRINTF(EthernetDesc, "Checking IP checksum\n"); 1365 status |= RXDS_IPCS; 1366 csum = htole(cksum(ip)); 1367 igbe->rxIpChecksums++; 1368 if (cksum(ip) != 0) { 1369 err |= RXDE_IPE; 1370 ext_err |= RXDEE_IPE; 1371 DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 1372 } 1373 } 1374 TcpPtr tcp(ip); 1375 if (tcp && igbe->regs.rxcsum.tuofld()) { 1376 DPRINTF(EthernetDesc, "Checking TCP checksum\n"); 1377 status |= RXDS_TCPCS; 1378 ptype |= RXDP_TCP; 1379 csum = htole(cksum(tcp)); 1380 igbe->rxTcpChecksums++; 1381 if (cksum(tcp) != 0) { 1382 DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 1383 err |= RXDE_TCPE; 1384 ext_err |= RXDEE_TCPE; 1385 } 1386 } 1387 1388 UdpPtr udp(ip); 1389 if (udp && igbe->regs.rxcsum.tuofld()) { 1390 DPRINTF(EthernetDesc, "Checking UDP checksum\n"); 1391 status |= RXDS_UDPCS; 1392 ptype |= RXDP_UDP; 1393 csum = htole(cksum(udp)); 1394 igbe->rxUdpChecksums++; 1395 if (cksum(udp) != 0) { 1396 DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 1397 ext_err |= RXDEE_TCPE; 1398 err |= RXDE_TCPE; 1399 } 1400 } 1401 } else { // if ip 1402 DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); 1403 } 1404 1405 switch (igbe->regs.srrctl.desctype()) { 1406 case RXDT_LEGACY: 1407 desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup)); 1408 desc->legacy.status = htole(status); 1409 desc->legacy.errors = htole(err); 1410 // No vlan support at this point... just set it to 0 1411 desc->legacy.vlan = 0; 1412 break; 1413 case RXDT_ADV_SPLIT_A: 1414 case RXDT_ADV_ONEBUF: 1415 desc->adv_wb.rss_type = htole(0); 1416 desc->adv_wb.pkt_type = htole(ptype); 1417 if (igbe->regs.rxcsum.pcsd()) { 1418 // no rss support right now 1419 desc->adv_wb.rss_hash = htole(0); 1420 } else { 1421 desc->adv_wb.id = htole(ip_id); 1422 desc->adv_wb.csum = htole(csum); 1423 } 1424 desc->adv_wb.status = htole(status); 1425 desc->adv_wb.errors = htole(ext_err); 1426 // no vlan support 1427 desc->adv_wb.vlan_tag = htole(0); 1428 break; 1429 default: 1430 panic("Unimplemnted RX receive buffer type %d\n", 1431 igbe->regs.srrctl.desctype()); 1432 } 1433 1434 DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n", 1435 desc->adv_read.pkt, desc->adv_read.hdr); 1436 1437 if (bytesCopied == pktPtr->length) { 1438 DPRINTF(EthernetDesc, 1439 "Packet completely written to descriptor buffers\n"); 1440 // Deal with the rx timer interrupts 1441 if (igbe->regs.rdtr.delay()) { 1442 Tick delay = igbe->regs.rdtr.delay() * igbe->intClock(); 1443 DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay); 1444 igbe->reschedule(igbe->rdtrEvent, curTick() + delay); 1445 } 1446 1447 if (igbe->regs.radv.idv()) { 1448 Tick delay = igbe->regs.radv.idv() * igbe->intClock(); 1449 DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay); 1450 if (!igbe->radvEvent.scheduled()) { 1451 igbe->schedule(igbe->radvEvent, curTick() + delay); 1452 } 1453 } 1454 1455 // if neither radv or rdtr, maybe itr is set... 1456 if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) { 1457 DPRINTF(EthernetSM, 1458 "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); 1459 igbe->postInterrupt(IT_RXT); 1460 } 1461 1462 // If the packet is small enough, interrupt appropriately 1463 // I wonder if this is delayed or not?! 1464 if (pktPtr->length <= igbe->regs.rsrpd.idv()) { 1465 DPRINTF(EthernetSM, 1466 "RXS: Posting IT_SRPD beacuse small packet received\n"); 1467 igbe->postInterrupt(IT_SRPD); 1468 } 1469 bytesCopied = 0; 1470 } 1471 1472 pktPtr = NULL; 1473 igbe->checkDrain(); 1474 enableSm(); 1475 pktDone = true; 1476 1477 igbe->anBegin("RXS", "Done Updating Desc"); 1478 DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); 1479 igbe->anDq("RXS", annUnusedCacheQ); 1480 unusedCache.pop_front(); 1481 igbe->anQ("RXS", annUsedCacheQ); 1482 usedCache.push_back(desc); 1483} 1484 1485void 1486IGbE::RxDescCache::enableSm() 1487{ 1488 if (!igbe->drainEvent) { 1489 igbe->rxTick = true; 1490 igbe->restartClock(); 1491 } 1492} 1493 1494bool 1495IGbE::RxDescCache::packetDone() 1496{ 1497 if (pktDone) { 1498 pktDone = false; 1499 return true; 1500 } 1501 return false; 1502} 1503 1504bool 1505IGbE::RxDescCache::hasOutstandingEvents() 1506{ 1507 return pktEvent.scheduled() || wbEvent.scheduled() || 1508 fetchEvent.scheduled() || pktHdrEvent.scheduled() || 1509 pktDataEvent.scheduled(); 1510 1511} 1512 1513void 1514IGbE::RxDescCache::serialize(std::ostream &os) 1515{ 1516 DescCache<RxDesc>::serialize(os); 1517 SERIALIZE_SCALAR(pktDone); 1518 SERIALIZE_SCALAR(splitCount); 1519 SERIALIZE_SCALAR(bytesCopied); 1520} 1521 1522void 1523IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion) 1524{ 1525 DescCache<RxDesc>::unserialize(cp, section); 1526 UNSERIALIZE_SCALAR(pktDone); 1527 UNSERIALIZE_SCALAR(splitCount); 1528 UNSERIALIZE_SCALAR(bytesCopied); 1529} 1530 1531 1532///////////////////////////// IGbE::TxDescCache ////////////////////////////// 1533 1534IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) 1535 : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), 1536 pktWaiting(false), completionAddress(0), completionEnabled(false), 1537 useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0), 1538 tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false), 1539 tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0), 1540 pktEvent(this), headerEvent(this), nullEvent(this) 1541{ 1542 annSmFetch = "TX Desc Fetch"; 1543 annSmWb = "TX Desc Writeback"; 1544 annUnusedDescQ = "TX Unused Descriptors"; 1545 annUnusedCacheQ = "TX Unused Descriptor Cache"; 1546 annUsedCacheQ = "TX Used Descriptor Cache"; 1547 annUsedDescQ = "TX Used Descriptors"; 1548 annDescQ = "TX Descriptors"; 1549} 1550 1551void 1552IGbE::TxDescCache::processContextDesc() 1553{ 1554 assert(unusedCache.size()); 1555 TxDesc *desc; 1556 1557 DPRINTF(EthernetDesc, "Checking and processing context descriptors\n"); 1558 1559 while (!useTso && unusedCache.size() && 1560 TxdOp::isContext(unusedCache.front())) { 1561 DPRINTF(EthernetDesc, "Got context descriptor type...\n"); 1562 1563 desc = unusedCache.front(); 1564 DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", 1565 desc->d1, desc->d2); 1566 1567 1568 // is this going to be a tcp or udp packet? 1569 isTcp = TxdOp::tcp(desc) ? true : false; 1570 1571 // setup all the TSO variables, they'll be ignored if we don't use 1572 // tso for this connection 1573 tsoHeaderLen = TxdOp::hdrlen(desc); 1574 tsoMss = TxdOp::mss(desc); 1575 1576 if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) { 1577 DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: " 1578 "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc), 1579 TxdOp::mss(desc), TxdOp::getLen(desc)); 1580 useTso = true; 1581 tsoTotalLen = TxdOp::getLen(desc); 1582 tsoLoadedHeader = false; 1583 tsoDescBytesUsed = 0; 1584 tsoUsedLen = 0; 1585 tsoPrevSeq = 0; 1586 tsoPktHasHeader = false; 1587 tsoPkts = 0; 1588 tsoCopyBytes = 0; 1589 } 1590 1591 TxdOp::setDd(desc); 1592 unusedCache.pop_front(); 1593 igbe->anDq("TXS", annUnusedCacheQ); 1594 usedCache.push_back(desc); 1595 igbe->anQ("TXS", annUsedCacheQ); 1596 } 1597 1598 if (!unusedCache.size()) 1599 return; 1600 1601 desc = unusedCache.front(); 1602 if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && 1603 TxdOp::tse(desc)) { 1604 DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet " 1605 "hdrlen: %d mss: %d paylen %d\n", 1606 tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc)); 1607 useTso = true; 1608 tsoTotalLen = TxdOp::getTsoLen(desc); 1609 tsoLoadedHeader = false; 1610 tsoDescBytesUsed = 0; 1611 tsoUsedLen = 0; 1612 tsoPrevSeq = 0; 1613 tsoPktHasHeader = false; 1614 tsoPkts = 0; 1615 } 1616 1617 if (useTso && !tsoLoadedHeader) { 1618 // we need to fetch a header 1619 DPRINTF(EthernetDesc, "Starting DMA of TSO header\n"); 1620 assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen); 1621 pktWaiting = true; 1622 assert(tsoHeaderLen <= 256); 1623 igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)), 1624 tsoHeaderLen, &headerEvent, tsoHeader, 0); 1625 } 1626} 1627 1628void 1629IGbE::TxDescCache::headerComplete() 1630{ 1631 DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n"); 1632 pktWaiting = false; 1633 1634 assert(unusedCache.size()); 1635 TxDesc *desc = unusedCache.front(); 1636 DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n", 1637 TxdOp::getLen(desc), tsoHeaderLen); 1638 1639 if (TxdOp::getLen(desc) == tsoHeaderLen) { 1640 tsoDescBytesUsed = 0; 1641 tsoLoadedHeader = true; 1642 unusedCache.pop_front(); 1643 usedCache.push_back(desc); 1644 } else { 1645 // I don't think this case happens, I think the headrer is always 1646 // it's own packet, if it wasn't it might be as simple as just 1647 // incrementing descBytesUsed by the header length, but I'm not 1648 // completely sure 1649 panic("TSO header part of bigger packet, not implemented\n"); 1650 } 1651 enableSm(); 1652 igbe->checkDrain(); 1653} 1654 1655unsigned 1656IGbE::TxDescCache::getPacketSize(EthPacketPtr p) 1657{ 1658 if (!unusedCache.size()) 1659 return 0; 1660 1661 DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); 1662 1663 assert(!useTso || tsoLoadedHeader); 1664 TxDesc *desc = unusedCache.front(); 1665 1666 if (useTso) { 1667 DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data " 1668 "d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 1669 DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d " 1670 "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss, 1671 tsoTotalLen, tsoUsedLen, tsoLoadedHeader); 1672 1673 if (tsoPktHasHeader) 1674 tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length, 1675 TxdOp::getLen(desc) - tsoDescBytesUsed); 1676 else 1677 tsoCopyBytes = std::min(tsoMss, 1678 TxdOp::getLen(desc) - tsoDescBytesUsed); 1679 unsigned pkt_size = 1680 tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen); 1681 1682 DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d " 1683 "this descLen: %d\n", 1684 tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc)); 1685 DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader); 1686 DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size); 1687 return pkt_size; 1688 } 1689 1690 DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", 1691 TxdOp::getLen(unusedCache.front())); 1692 return TxdOp::getLen(desc); 1693} 1694 1695void 1696IGbE::TxDescCache::getPacketData(EthPacketPtr p) 1697{ 1698 assert(unusedCache.size()); 1699 1700 TxDesc *desc; 1701 desc = unusedCache.front(); 1702 1703 DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data " 1704 "d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 1705 assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && 1706 TxdOp::getLen(desc)); 1707 1708 pktPtr = p; 1709 1710 pktWaiting = true; 1711 1712 DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); 1713 1714 if (useTso) { 1715 assert(tsoLoadedHeader); 1716 if (!tsoPktHasHeader) { 1717 DPRINTF(EthernetDesc, 1718 "Loading TSO header (%d bytes) into start of packet\n", 1719 tsoHeaderLen); 1720 memcpy(p->data, &tsoHeader,tsoHeaderLen); 1721 p->length +=tsoHeaderLen; 1722 tsoPktHasHeader = true; 1723 } 1724 } 1725 1726 if (useTso) { 1727 DPRINTF(EthernetDesc, 1728 "Starting DMA of packet at offset %d length: %d\n", 1729 p->length, tsoCopyBytes); 1730 igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)) 1731 + tsoDescBytesUsed, 1732 tsoCopyBytes, &pktEvent, p->data + p->length, 1733 igbe->txReadDelay); 1734 tsoDescBytesUsed += tsoCopyBytes; 1735 assert(tsoDescBytesUsed <= TxdOp::getLen(desc)); 1736 } else { 1737 igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)), 1738 TxdOp::getLen(desc), &pktEvent, p->data + p->length, 1739 igbe->txReadDelay); 1740 } 1741} 1742 1743void 1744IGbE::TxDescCache::pktComplete() 1745{ 1746 1747 TxDesc *desc; 1748 assert(unusedCache.size()); 1749 assert(pktPtr); 1750 1751 igbe->anBegin("TXS", "Update Desc"); 1752 1753 DPRINTF(EthernetDesc, "DMA of packet complete\n"); 1754 1755 1756 desc = unusedCache.front(); 1757 assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && 1758 TxdOp::getLen(desc)); 1759 1760 DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", 1761 desc->d1, desc->d2); 1762 1763 // Set the length of the data in the EtherPacket 1764 if (useTso) { 1765 DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d " 1766 "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss, 1767 tsoTotalLen, tsoUsedLen, tsoLoadedHeader); 1768 pktPtr->length += tsoCopyBytes; 1769 tsoUsedLen += tsoCopyBytes; 1770 DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n", 1771 tsoDescBytesUsed, tsoCopyBytes); 1772 } else 1773 pktPtr->length += TxdOp::getLen(desc); 1774 1775 1776 1777 if ((!TxdOp::eop(desc) && !useTso) || 1778 (pktPtr->length < ( tsoMss + tsoHeaderLen) && 1779 tsoTotalLen != tsoUsedLen && useTso)) { 1780 assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc))); 1781 igbe->anDq("TXS", annUnusedCacheQ); 1782 unusedCache.pop_front(); 1783 igbe->anQ("TXS", annUsedCacheQ); 1784 usedCache.push_back(desc); 1785 1786 tsoDescBytesUsed = 0; 1787 pktDone = true; 1788 pktWaiting = false; 1789 pktMultiDesc = true; 1790 1791 DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n", 1792 pktPtr->length); 1793 pktPtr = NULL; 1794 1795 enableSm(); 1796 igbe->checkDrain(); 1797 return; 1798 } 1799 1800 1801 pktMultiDesc = false; 1802 // no support for vlans 1803 assert(!TxdOp::vle(desc)); 1804 1805 // we only support single packet descriptors at this point 1806 if (!useTso) 1807 assert(TxdOp::eop(desc)); 1808 1809 // set that this packet is done 1810 if (TxdOp::rs(desc)) 1811 TxdOp::setDd(desc); 1812 1813 DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", 1814 desc->d1, desc->d2); 1815 1816 if (useTso) { 1817 IpPtr ip(pktPtr); 1818 if (ip) { 1819 DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n", 1820 tsoPkts); 1821 ip->id(ip->id() + tsoPkts++); 1822 ip->len(pktPtr->length - EthPtr(pktPtr)->size()); 1823 1824 TcpPtr tcp(ip); 1825 if (tcp) { 1826 DPRINTF(EthernetDesc, 1827 "TSO: Modifying TCP header. old seq %d + %d\n", 1828 tcp->seq(), tsoPrevSeq); 1829 tcp->seq(tcp->seq() + tsoPrevSeq); 1830 if (tsoUsedLen != tsoTotalLen) 1831 tcp->flags(tcp->flags() & ~9); // clear fin & psh 1832 } 1833 UdpPtr udp(ip); 1834 if (udp) { 1835 DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n"); 1836 udp->len(pktPtr->length - EthPtr(pktPtr)->size()); 1837 } 1838 } 1839 tsoPrevSeq = tsoUsedLen; 1840 } 1841 1842 if (DTRACE(EthernetDesc)) { 1843 IpPtr ip(pktPtr); 1844 if (ip) 1845 DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", 1846 ip->id()); 1847 else 1848 DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); 1849 } 1850 1851 // Checksums are only ofloaded for new descriptor types 1852 if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { 1853 DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); 1854 IpPtr ip(pktPtr); 1855 assert(ip); 1856 if (TxdOp::ixsm(desc)) { 1857 ip->sum(0); 1858 ip->sum(cksum(ip)); 1859 igbe->txIpChecksums++; 1860 DPRINTF(EthernetDesc, "Calculated IP checksum\n"); 1861 } 1862 if (TxdOp::txsm(desc)) { 1863 TcpPtr tcp(ip); 1864 UdpPtr udp(ip); 1865 if (tcp) { 1866 tcp->sum(0); 1867 tcp->sum(cksum(tcp)); 1868 igbe->txTcpChecksums++; 1869 DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); 1870 } else if (udp) { 1871 assert(udp); 1872 udp->sum(0); 1873 udp->sum(cksum(udp)); 1874 igbe->txUdpChecksums++; 1875 DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); 1876 } else { 1877 panic("Told to checksum, but don't know how\n"); 1878 } 1879 } 1880 } 1881 1882 if (TxdOp::ide(desc)) { 1883 // Deal with the rx timer interrupts 1884 DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); 1885 if (igbe->regs.tidv.idv()) { 1886 Tick delay = igbe->regs.tidv.idv() * igbe->intClock(); 1887 DPRINTF(EthernetDesc, "setting tidv\n"); 1888 igbe->reschedule(igbe->tidvEvent, curTick() + delay, true); 1889 } 1890 1891 if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { 1892 Tick delay = igbe->regs.tadv.idv() * igbe->intClock(); 1893 DPRINTF(EthernetDesc, "setting tadv\n"); 1894 if (!igbe->tadvEvent.scheduled()) { 1895 igbe->schedule(igbe->tadvEvent, curTick() + delay); 1896 } 1897 } 1898 } 1899 1900 1901 if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) { 1902 DPRINTF(EthernetDesc, "Descriptor Done\n"); 1903 igbe->anDq("TXS", annUnusedCacheQ); 1904 unusedCache.pop_front(); 1905 igbe->anQ("TXS", annUsedCacheQ); 1906 usedCache.push_back(desc); 1907 tsoDescBytesUsed = 0; 1908 } 1909 1910 if (useTso && tsoUsedLen == tsoTotalLen) 1911 useTso = false; 1912 1913 1914 DPRINTF(EthernetDesc, 1915 "------Packet of %d bytes ready for transmission-------\n", 1916 pktPtr->length); 1917 pktDone = true; 1918 pktWaiting = false; 1919 pktPtr = NULL; 1920 tsoPktHasHeader = false; 1921 1922 if (igbe->regs.txdctl.wthresh() == 0) { 1923 igbe->anBegin("TXS", "Desc Writeback"); 1924 DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); 1925 writeback(0); 1926 } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <= 1927 descInBlock(usedCache.size())) { 1928 DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); 1929 igbe->anBegin("TXS", "Desc Writeback"); 1930 writeback((igbe->cacheBlockSize()-1)>>4); 1931 } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) { 1932 DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); 1933 igbe->anBegin("TXS", "Desc Writeback"); 1934 writeback((igbe->cacheBlockSize()-1)>>4); 1935 } 1936 1937 enableSm(); 1938 igbe->checkDrain(); 1939} 1940 1941void 1942IGbE::TxDescCache::actionAfterWb() 1943{ 1944 DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n", 1945 completionEnabled); 1946 igbe->postInterrupt(iGbReg::IT_TXDW); 1947 if (completionEnabled) { 1948 descEnd = igbe->regs.tdh(); 1949 DPRINTF(EthernetDesc, 1950 "Completion writing back value: %d to addr: %#x\n", descEnd, 1951 completionAddress); 1952 igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)), 1953 sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0); 1954 } 1955} 1956 1957void 1958IGbE::TxDescCache::serialize(std::ostream &os) 1959{ 1960 DescCache<TxDesc>::serialize(os); 1961 SERIALIZE_SCALAR(pktDone); 1962 SERIALIZE_SCALAR(isTcp); 1963 SERIALIZE_SCALAR(pktWaiting); 1964 SERIALIZE_SCALAR(pktMultiDesc); 1965 1966 SERIALIZE_SCALAR(useTso); 1967 SERIALIZE_SCALAR(tsoHeaderLen); 1968 SERIALIZE_SCALAR(tsoMss); 1969 SERIALIZE_SCALAR(tsoTotalLen); 1970 SERIALIZE_SCALAR(tsoUsedLen); 1971 SERIALIZE_SCALAR(tsoPrevSeq);; 1972 SERIALIZE_SCALAR(tsoPktPayloadBytes); 1973 SERIALIZE_SCALAR(tsoLoadedHeader); 1974 SERIALIZE_SCALAR(tsoPktHasHeader); 1975 SERIALIZE_ARRAY(tsoHeader, 256); 1976 SERIALIZE_SCALAR(tsoDescBytesUsed); 1977 SERIALIZE_SCALAR(tsoCopyBytes); 1978 SERIALIZE_SCALAR(tsoPkts); 1979 1980 SERIALIZE_SCALAR(completionAddress); 1981 SERIALIZE_SCALAR(completionEnabled); 1982 SERIALIZE_SCALAR(descEnd); 1983} 1984 1985void 1986IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion) 1987{ 1988 DescCache<TxDesc>::unserialize(cp, section); 1989 UNSERIALIZE_SCALAR(pktDone); 1990 UNSERIALIZE_SCALAR(isTcp); 1991 UNSERIALIZE_SCALAR(pktWaiting); 1992 UNSERIALIZE_SCALAR(pktMultiDesc); 1993 1994 UNSERIALIZE_SCALAR(useTso); 1995 UNSERIALIZE_SCALAR(tsoHeaderLen); 1996 UNSERIALIZE_SCALAR(tsoMss); 1997 UNSERIALIZE_SCALAR(tsoTotalLen); 1998 UNSERIALIZE_SCALAR(tsoUsedLen); 1999 UNSERIALIZE_SCALAR(tsoPrevSeq);; 2000 UNSERIALIZE_SCALAR(tsoPktPayloadBytes); 2001 UNSERIALIZE_SCALAR(tsoLoadedHeader); 2002 UNSERIALIZE_SCALAR(tsoPktHasHeader); 2003 UNSERIALIZE_ARRAY(tsoHeader, 256); 2004 UNSERIALIZE_SCALAR(tsoDescBytesUsed); 2005 UNSERIALIZE_SCALAR(tsoCopyBytes); 2006 UNSERIALIZE_SCALAR(tsoPkts); 2007 2008 UNSERIALIZE_SCALAR(completionAddress); 2009 UNSERIALIZE_SCALAR(completionEnabled); 2010 UNSERIALIZE_SCALAR(descEnd); 2011} 2012 2013bool 2014IGbE::TxDescCache::packetAvailable() 2015{ 2016 if (pktDone) { 2017 pktDone = false; 2018 return true; 2019 } 2020 return false; 2021} 2022 2023void 2024IGbE::TxDescCache::enableSm() 2025{ 2026 if (!igbe->drainEvent) { 2027 igbe->txTick = true; 2028 igbe->restartClock(); 2029 } 2030} 2031 2032bool 2033IGbE::TxDescCache::hasOutstandingEvents() 2034{ 2035 return pktEvent.scheduled() || wbEvent.scheduled() || 2036 fetchEvent.scheduled(); 2037} 2038 2039 2040///////////////////////////////////// IGbE ///////////////////////////////// 2041 2042void 2043IGbE::restartClock() 2044{ 2045 if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && 2046 getState() == SimObject::Running) 2047 schedule(tickEvent, (curTick() / ticks(1)) * ticks(1) + ticks(1)); 2048} 2049 2050unsigned int 2051IGbE::drain(Event *de) 2052{ 2053 unsigned int count; 2054 count = pioPort.drain(de) + dmaPort.drain(de); 2055 if (rxDescCache.hasOutstandingEvents() || 2056 txDescCache.hasOutstandingEvents()) { 2057 count++; 2058 drainEvent = de; 2059 } 2060 2061 txFifoTick = false; 2062 txTick = false; 2063 rxTick = false; 2064 2065 if (tickEvent.scheduled()) 2066 deschedule(tickEvent); 2067 2068 if (count) 2069 changeState(Draining); 2070 else 2071 changeState(Drained); 2072 2073 DPRINTF(EthernetSM, "got drain() returning %d", count); 2074 return count; 2075} 2076 2077void 2078IGbE::resume() 2079{ 2080 SimObject::resume(); 2081 2082 txFifoTick = true; 2083 txTick = true; 2084 rxTick = true; 2085 2086 restartClock(); 2087 DPRINTF(EthernetSM, "resuming from drain"); 2088} 2089 2090void 2091IGbE::checkDrain() 2092{ 2093 if (!drainEvent) 2094 return; 2095 2096 DPRINTF(EthernetSM, "checkDrain() in drain\n"); 2097 txFifoTick = false; 2098 txTick = false; 2099 rxTick = false; 2100 if (!rxDescCache.hasOutstandingEvents() && 2101 !txDescCache.hasOutstandingEvents()) { 2102 drainEvent->process(); 2103 drainEvent = NULL; 2104 } 2105} 2106 2107void 2108IGbE::txStateMachine() 2109{ 2110 if (!regs.tctl.en()) { 2111 txTick = false; 2112 DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n"); 2113 return; 2114 } 2115 2116 // If we have a packet available and it's length is not 0 (meaning it's not 2117 // a multidescriptor packet) put it in the fifo, otherwise an the next 2118 // iteration we'll get the rest of the data 2119 if (txPacket && txDescCache.packetAvailable() 2120 && !txDescCache.packetMultiDesc() && txPacket->length) { 2121 anQ("TXS", "TX FIFO Q"); 2122 DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); 2123#ifndef NDEBUG 2124 bool success = 2125#endif 2126 txFifo.push(txPacket); 2127 txFifoTick = true && !drainEvent; 2128 assert(success); 2129 txPacket = NULL; 2130 anBegin("TXS", "Desc Writeback"); 2131 txDescCache.writeback((cacheBlockSize()-1)>>4); 2132 return; 2133 } 2134 2135 // Only support descriptor granularity 2136 if (regs.txdctl.lwthresh() && 2137 txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) { 2138 DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n"); 2139 postInterrupt(IT_TXDLOW); 2140 } 2141 2142 if (!txPacket) { 2143 txPacket = new EthPacketData(16384); 2144 } 2145 2146 if (!txDescCache.packetWaiting()) { 2147 if (txDescCache.descLeft() == 0) { 2148 postInterrupt(IT_TXQE); 2149 anBegin("TXS", "Desc Writeback"); 2150 txDescCache.writeback(0); 2151 anBegin("TXS", "Desc Fetch"); 2152 anWe("TXS", txDescCache.annUnusedCacheQ); 2153 txDescCache.fetchDescriptors(); 2154 DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing " 2155 "writeback stopping ticking and posting TXQE\n"); 2156 txTick = false; 2157 return; 2158 } 2159 2160 2161 if (!(txDescCache.descUnused())) { 2162 anBegin("TXS", "Desc Fetch"); 2163 txDescCache.fetchDescriptors(); 2164 anWe("TXS", txDescCache.annUnusedCacheQ); 2165 DPRINTF(EthernetSM, "TXS: No descriptors available in cache, " 2166 "fetching and stopping ticking\n"); 2167 txTick = false; 2168 return; 2169 } 2170 anPq("TXS", txDescCache.annUnusedCacheQ); 2171 2172 2173 txDescCache.processContextDesc(); 2174 if (txDescCache.packetWaiting()) { 2175 DPRINTF(EthernetSM, 2176 "TXS: Fetching TSO header, stopping ticking\n"); 2177 txTick = false; 2178 return; 2179 } 2180 2181 unsigned size = txDescCache.getPacketSize(txPacket); 2182 if (size > 0 && txFifo.avail() > size) { 2183 anRq("TXS", "TX FIFO Q"); 2184 anBegin("TXS", "DMA Packet"); 2185 DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and " 2186 "beginning DMA of next packet\n", size); 2187 txFifo.reserve(size); 2188 txDescCache.getPacketData(txPacket); 2189 } else if (size == 0) { 2190 DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size); 2191 DPRINTF(EthernetSM, 2192 "TXS: No packets to get, writing back used descriptors\n"); 2193 anBegin("TXS", "Desc Writeback"); 2194 txDescCache.writeback(0); 2195 } else { 2196 anWf("TXS", "TX FIFO Q"); 2197 DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " 2198 "available in FIFO\n"); 2199 txTick = false; 2200 } 2201 2202 2203 return; 2204 } 2205 DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n"); 2206 txTick = false; 2207} 2208 2209bool 2210IGbE::ethRxPkt(EthPacketPtr pkt) 2211{ 2212 rxBytes += pkt->length; 2213 rxPackets++; 2214 2215 DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); 2216 anBegin("RXQ", "Wire Recv"); 2217 2218 2219 if (!regs.rctl.en()) { 2220 DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n"); 2221 anBegin("RXQ", "FIFO Drop", CPA::FL_BAD); 2222 return true; 2223 } 2224 2225 // restart the state machines if they are stopped 2226 rxTick = true && !drainEvent; 2227 if ((rxTick || txTick) && !tickEvent.scheduled()) { 2228 DPRINTF(EthernetSM, 2229 "RXS: received packet into fifo, starting ticking\n"); 2230 restartClock(); 2231 } 2232 2233 if (!rxFifo.push(pkt)) { 2234 DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n"); 2235 postInterrupt(IT_RXO, true); 2236 anBegin("RXQ", "FIFO Drop", CPA::FL_BAD); 2237 return false; 2238 } 2239 2240 if (CPA::available() && cpa->enabled()) { 2241 assert(sys->numSystemsRunning <= 2); 2242 System *other_sys; 2243 if (sys->systemList[0] == sys) 2244 other_sys = sys->systemList[1]; 2245 else 2246 other_sys = sys->systemList[0]; 2247 2248 cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys); 2249 anQ("RXQ", "RX FIFO Q"); 2250 cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys); 2251 } 2252 2253 return true; 2254} 2255 2256 2257void 2258IGbE::rxStateMachine() 2259{ 2260 if (!regs.rctl.en()) { 2261 rxTick = false; 2262 DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n"); 2263 return; 2264 } 2265 2266 // If the packet is done check for interrupts/descriptors/etc 2267 if (rxDescCache.packetDone()) { 2268 rxDmaPacket = false; 2269 DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); 2270 int descLeft = rxDescCache.descLeft(); 2271 DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n", 2272 descLeft, regs.rctl.rdmts(), regs.rdlen()); 2273 switch (regs.rctl.rdmts()) { 2274 case 2: if (descLeft > .125 * regs.rdlen()) break; 2275 case 1: if (descLeft > .250 * regs.rdlen()) break; 2276 case 0: if (descLeft > .500 * regs.rdlen()) break; 2277 DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) " 2278 "because of descriptors left\n"); 2279 postInterrupt(IT_RXDMT); 2280 break; 2281 } 2282 2283 if (rxFifo.empty()) 2284 rxDescCache.writeback(0); 2285 2286 if (descLeft == 0) { 2287 anBegin("RXS", "Writeback Descriptors"); 2288 rxDescCache.writeback(0); 2289 DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" 2290 " writeback and stopping ticking\n"); 2291 rxTick = false; 2292 } 2293 2294 // only support descriptor granulaties 2295 assert(regs.rxdctl.gran()); 2296 2297 if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) { 2298 DPRINTF(EthernetSM, 2299 "RXS: Writing back because WTHRESH >= descUsed\n"); 2300 anBegin("RXS", "Writeback Descriptors"); 2301 if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4)) 2302 rxDescCache.writeback(regs.rxdctl.wthresh()-1); 2303 else 2304 rxDescCache.writeback((cacheBlockSize()-1)>>4); 2305 } 2306 2307 if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) && 2308 ((rxDescCache.descLeft() - rxDescCache.descUnused()) > 2309 regs.rxdctl.hthresh())) { 2310 DPRINTF(EthernetSM, "RXS: Fetching descriptors because " 2311 "descUnused < PTHRESH\n"); 2312 anBegin("RXS", "Fetch Descriptors"); 2313 rxDescCache.fetchDescriptors(); 2314 } 2315 2316 if (rxDescCache.descUnused() == 0) { 2317 anBegin("RXS", "Fetch Descriptors"); 2318 rxDescCache.fetchDescriptors(); 2319 anWe("RXS", rxDescCache.annUnusedCacheQ); 2320 DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " 2321 "fetching descriptors and stopping ticking\n"); 2322 rxTick = false; 2323 } 2324 return; 2325 } 2326 2327 if (rxDmaPacket) { 2328 DPRINTF(EthernetSM, 2329 "RXS: stopping ticking until packet DMA completes\n"); 2330 rxTick = false; 2331 return; 2332 } 2333 2334 if (!rxDescCache.descUnused()) { 2335 anBegin("RXS", "Fetch Descriptors"); 2336 rxDescCache.fetchDescriptors(); 2337 anWe("RXS", rxDescCache.annUnusedCacheQ); 2338 DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " 2339 "stopping ticking\n"); 2340 rxTick = false; 2341 DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); 2342 return; 2343 } 2344 anPq("RXS", rxDescCache.annUnusedCacheQ); 2345 2346 if (rxFifo.empty()) { 2347 anWe("RXS", "RX FIFO Q"); 2348 DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n"); 2349 rxTick = false; 2350 return; 2351 } 2352 anPq("RXS", "RX FIFO Q"); 2353 anBegin("RXS", "Get Desc"); 2354 2355 EthPacketPtr pkt; 2356 pkt = rxFifo.front(); 2357 2358 2359 pktOffset = rxDescCache.writePacket(pkt, pktOffset); 2360 DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); 2361 if (pktOffset == pkt->length) { 2362 anBegin( "RXS", "FIFO Dequeue"); 2363 DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); 2364 pktOffset = 0; 2365 anDq("RXS", "RX FIFO Q"); 2366 rxFifo.pop(); 2367 } 2368 2369 DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); 2370 rxTick = false; 2371 rxDmaPacket = true; 2372 anBegin("RXS", "DMA Packet"); 2373} 2374 2375void 2376IGbE::txWire() 2377{ 2378 if (txFifo.empty()) { 2379 anWe("TXQ", "TX FIFO Q"); 2380 txFifoTick = false; 2381 return; 2382 } 2383 2384 2385 anPq("TXQ", "TX FIFO Q"); 2386 if (etherInt->sendPacket(txFifo.front())) { 2387 cpa->hwQ(CPA::FL_NONE, sys, macAddr, "TXQ", "WireQ", 0); 2388 if (DTRACE(EthernetSM)) { 2389 IpPtr ip(txFifo.front()); 2390 if (ip) 2391 DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n", 2392 ip->id()); 2393 else 2394 DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n"); 2395 } 2396 anDq("TXQ", "TX FIFO Q"); 2397 anBegin("TXQ", "Wire Send"); 2398 DPRINTF(EthernetSM, 2399 "TxFIFO: Successful transmit, bytes available in fifo: %d\n", 2400 txFifo.avail()); 2401 2402 txBytes += txFifo.front()->length; 2403 txPackets++; 2404 txFifoTick = false; 2405 2406 txFifo.pop(); 2407 } else { 2408 // We'll get woken up when the packet ethTxDone() gets called 2409 txFifoTick = false; 2410 } 2411} 2412 2413void 2414IGbE::tick() 2415{ 2416 DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n"); 2417 2418 if (rxTick) 2419 rxStateMachine(); 2420 2421 if (txTick) 2422 txStateMachine(); 2423 2424 if (txFifoTick) 2425 txWire(); 2426 2427 2428 if (rxTick || txTick || txFifoTick) 2429 schedule(tickEvent, curTick() + ticks(1)); 2430} 2431 2432void 2433IGbE::ethTxDone() 2434{ 2435 anBegin("TXQ", "Send Done"); 2436 // restart the tx state machines if they are stopped 2437 // fifo to send another packet 2438 // tx sm to put more data into the fifo 2439 txFifoTick = true && !drainEvent; 2440 if (txDescCache.descLeft() != 0 && !drainEvent) 2441 txTick = true; 2442 2443 restartClock(); 2444 txWire(); 2445 DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n"); 2446} 2447 2448void 2449IGbE::serialize(std::ostream &os) 2450{ 2451 PciDev::serialize(os); 2452 2453 regs.serialize(os); 2454 SERIALIZE_SCALAR(eeOpBits); 2455 SERIALIZE_SCALAR(eeAddrBits); 2456 SERIALIZE_SCALAR(eeDataBits); 2457 SERIALIZE_SCALAR(eeOpcode); 2458 SERIALIZE_SCALAR(eeAddr); 2459 SERIALIZE_SCALAR(lastInterrupt); 2460 SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); 2461 2462 rxFifo.serialize("rxfifo", os); 2463 txFifo.serialize("txfifo", os); 2464 2465 bool txPktExists = txPacket; 2466 SERIALIZE_SCALAR(txPktExists); 2467 if (txPktExists) 2468 txPacket->serialize("txpacket", os); 2469 2470 Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0, 2471 inter_time = 0; 2472 2473 if (rdtrEvent.scheduled()) 2474 rdtr_time = rdtrEvent.when(); 2475 SERIALIZE_SCALAR(rdtr_time); 2476 2477 if (radvEvent.scheduled()) 2478 radv_time = radvEvent.when(); 2479 SERIALIZE_SCALAR(radv_time); 2480 2481 if (tidvEvent.scheduled()) 2482 tidv_time = tidvEvent.when(); 2483 SERIALIZE_SCALAR(tidv_time); 2484 2485 if (tadvEvent.scheduled()) 2486 tadv_time = tadvEvent.when(); 2487 SERIALIZE_SCALAR(tadv_time); 2488 2489 if (interEvent.scheduled()) 2490 inter_time = interEvent.when(); 2491 SERIALIZE_SCALAR(inter_time); 2492 2493 SERIALIZE_SCALAR(pktOffset); 2494 2495 nameOut(os, csprintf("%s.TxDescCache", name())); 2496 txDescCache.serialize(os); 2497 2498 nameOut(os, csprintf("%s.RxDescCache", name())); 2499 rxDescCache.serialize(os); 2500} 2501 2502void 2503IGbE::unserialize(Checkpoint *cp, const std::string §ion) 2504{ 2505 PciDev::unserialize(cp, section); 2506 2507 regs.unserialize(cp, section); 2508 UNSERIALIZE_SCALAR(eeOpBits); 2509 UNSERIALIZE_SCALAR(eeAddrBits); 2510 UNSERIALIZE_SCALAR(eeDataBits); 2511 UNSERIALIZE_SCALAR(eeOpcode); 2512 UNSERIALIZE_SCALAR(eeAddr); 2513 UNSERIALIZE_SCALAR(lastInterrupt); 2514 UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); 2515 2516 rxFifo.unserialize("rxfifo", cp, section); 2517 txFifo.unserialize("txfifo", cp, section); 2518 2519 bool txPktExists; 2520 UNSERIALIZE_SCALAR(txPktExists); 2521 if (txPktExists) { 2522 txPacket = new EthPacketData(16384); 2523 txPacket->unserialize("txpacket", cp, section); 2524 } 2525 2526 rxTick = true; 2527 txTick = true; 2528 txFifoTick = true; 2529 2530 Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time; 2531 UNSERIALIZE_SCALAR(rdtr_time); 2532 UNSERIALIZE_SCALAR(radv_time); 2533 UNSERIALIZE_SCALAR(tidv_time); 2534 UNSERIALIZE_SCALAR(tadv_time); 2535 UNSERIALIZE_SCALAR(inter_time); 2536 2537 if (rdtr_time) 2538 schedule(rdtrEvent, rdtr_time); 2539 2540 if (radv_time) 2541 schedule(radvEvent, radv_time); 2542 2543 if (tidv_time) 2544 schedule(tidvEvent, tidv_time); 2545 2546 if (tadv_time) 2547 schedule(tadvEvent, tadv_time); 2548 2549 if (inter_time) 2550 schedule(interEvent, inter_time); 2551 2552 UNSERIALIZE_SCALAR(pktOffset); 2553 2554 txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section)); 2555 2556 rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section)); 2557} 2558 2559IGbE * 2560IGbEParams::create() 2561{ 2562 return new IGbE(this); 2563} 2564