i8254xGBe.cc revision 5783
18150SN/A/* 28150SN/A * Copyright (c) 2006 The Regents of The University of Michigan 311957Sgabeblack@google.com * All rights reserved. 411957Sgabeblack@google.com * 511957Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 611957Sgabeblack@google.com * modification, are permitted provided that the following conditions are 711957Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 811957Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 911957Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1011957Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1111957Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1211957Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1311957Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1411957Sgabeblack@google.com * this software without specific prior written permission. 1511957Sgabeblack@google.com * 1611957Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1711957Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1811957Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1911957Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2011957Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2111957Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2211957Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2311957Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411957Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511957Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611957Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2711957Sgabeblack@google.com * 2811957Sgabeblack@google.com * Authors: Ali Saidi 2911957Sgabeblack@google.com */ 3011957Sgabeblack@google.com 3111957Sgabeblack@google.com/* @file 3211957Sgabeblack@google.com * Device model for Intel's 8254x line of gigabit ethernet controllers. 3311957Sgabeblack@google.com * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the 3411957Sgabeblack@google.com * fewest workarounds in the driver. It will probably work with most of the 3511957Sgabeblack@google.com * other MACs with slight modifications. 3611957Sgabeblack@google.com */ 3711957Sgabeblack@google.com 3811957Sgabeblack@google.com 3911957Sgabeblack@google.com/* 4011957Sgabeblack@google.com * @todo really there are multiple dma engines.. we should implement them. 4111957Sgabeblack@google.com */ 4211957Sgabeblack@google.com 4311957Sgabeblack@google.com#include <algorithm> 4411957Sgabeblack@google.com 4511957Sgabeblack@google.com#include "base/inet.hh" 4611957Sgabeblack@google.com#include "base/trace.hh" 4711957Sgabeblack@google.com#include "dev/i8254xGBe.hh" 4811957Sgabeblack@google.com#include "mem/packet.hh" 4911957Sgabeblack@google.com#include "mem/packet_access.hh" 5011957Sgabeblack@google.com#include "params/IGbE.hh" 5111957Sgabeblack@google.com#include "sim/stats.hh" 5211957Sgabeblack@google.com#include "sim/system.hh" 5311957Sgabeblack@google.com 5411957Sgabeblack@google.comusing namespace iGbReg; 5511957Sgabeblack@google.comusing namespace Net; 5611957Sgabeblack@google.com 5711957Sgabeblack@google.comIGbE::IGbE(const Params *p) 5811957Sgabeblack@google.com : EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control), 5911957Sgabeblack@google.com rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), 6011957Sgabeblack@google.com txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0), 6111957Sgabeblack@google.com fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), 6211957Sgabeblack@google.com fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), 6311957Sgabeblack@google.com rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay), 6411957Sgabeblack@google.com rdtrEvent(this), radvEvent(this), 6511957Sgabeblack@google.com tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this), 6611957Sgabeblack@google.com rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), 6711957Sgabeblack@google.com txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), 6811957Sgabeblack@google.com clock(p->clock), lastInterrupt(0) 6911957Sgabeblack@google.com{ 7011957Sgabeblack@google.com etherInt = new IGbEInt(name() + ".int", this); 7111957Sgabeblack@google.com 7211957Sgabeblack@google.com // Initialized internal registers per Intel documentation 7311957Sgabeblack@google.com // All registers intialized to 0 by per register constructor 7411957Sgabeblack@google.com regs.ctrl.fd(1); 7511957Sgabeblack@google.com regs.ctrl.lrst(1); 7611957Sgabeblack@google.com regs.ctrl.speed(2); 7711957Sgabeblack@google.com regs.ctrl.frcspd(1); 7811957Sgabeblack@google.com regs.sts.speed(3); // Say we're 1000Mbps 7911957Sgabeblack@google.com regs.sts.fd(1); // full duplex 8011957Sgabeblack@google.com regs.sts.lu(1); // link up 8111957Sgabeblack@google.com regs.eecd.fwe(1); 8211957Sgabeblack@google.com regs.eecd.ee_type(1); 8311957Sgabeblack@google.com regs.imr = 0; 8411957Sgabeblack@google.com regs.iam = 0; 8511957Sgabeblack@google.com regs.rxdctl.gran(1); 8611957Sgabeblack@google.com regs.rxdctl.wthresh(1); 8711957Sgabeblack@google.com regs.fcrth(1); 8811957Sgabeblack@google.com regs.tdwba = 0; 8911957Sgabeblack@google.com regs.rlpml = 0; 9011957Sgabeblack@google.com regs.sw_fw_sync = 0; 9111957Sgabeblack@google.com 9211957Sgabeblack@google.com regs.pba.rxa(0x30); 9311957Sgabeblack@google.com regs.pba.txa(0x10); 9411957Sgabeblack@google.com 9511957Sgabeblack@google.com eeOpBits = 0; 9611957Sgabeblack@google.com eeAddrBits = 0; 9711957Sgabeblack@google.com eeDataBits = 0; 9811957Sgabeblack@google.com eeOpcode = 0; 9911957Sgabeblack@google.com 10011957Sgabeblack@google.com // clear all 64 16 bit words of the eeprom 10111957Sgabeblack@google.com memset(&flash, 0, EEPROM_SIZE*2); 10211957Sgabeblack@google.com 10311957Sgabeblack@google.com // Set the MAC address 10411957Sgabeblack@google.com memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN); 10511957Sgabeblack@google.com for (int x = 0; x < ETH_ADDR_LEN/2; x++) 10611957Sgabeblack@google.com flash[x] = htobe(flash[x]); 10711957Sgabeblack@google.com 10811957Sgabeblack@google.com uint16_t csum = 0; 10911957Sgabeblack@google.com for (int x = 0; x < EEPROM_SIZE; x++) 11011957Sgabeblack@google.com csum += htobe(flash[x]); 11111957Sgabeblack@google.com 11211957Sgabeblack@google.com 11311957Sgabeblack@google.com // Magic happy checksum value 11411957Sgabeblack@google.com flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); 11511957Sgabeblack@google.com 11611957Sgabeblack@google.com rxFifo.clear(); 11711957Sgabeblack@google.com txFifo.clear(); 11811957Sgabeblack@google.com} 11911957Sgabeblack@google.com 12011957Sgabeblack@google.comEtherInt* 12111957Sgabeblack@google.comIGbE::getEthPort(const std::string &if_name, int idx) 12211957Sgabeblack@google.com{ 12311957Sgabeblack@google.com 12411957Sgabeblack@google.com if (if_name == "interface") { 12511957Sgabeblack@google.com if (etherInt->getPeer()) 12611957Sgabeblack@google.com panic("Port already connected to\n"); 12711957Sgabeblack@google.com return etherInt; 12811957Sgabeblack@google.com } 12911957Sgabeblack@google.com return NULL; 13011957Sgabeblack@google.com} 13111957Sgabeblack@google.com 13211957Sgabeblack@google.comTick 13311957Sgabeblack@google.comIGbE::writeConfig(PacketPtr pkt) 13411957Sgabeblack@google.com{ 13511957Sgabeblack@google.com int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 13611957Sgabeblack@google.com if (offset < PCI_DEVICE_SPECIFIC) 13711957Sgabeblack@google.com PciDev::writeConfig(pkt); 13811957Sgabeblack@google.com else 13911957Sgabeblack@google.com panic("Device specific PCI config space not implemented.\n"); 14011957Sgabeblack@google.com 14111957Sgabeblack@google.com /// 14211957Sgabeblack@google.com /// Some work may need to be done here based for the pci COMMAND bits. 14311957Sgabeblack@google.com /// 14411957Sgabeblack@google.com 14511957Sgabeblack@google.com return pioDelay; 14611957Sgabeblack@google.com} 14711957Sgabeblack@google.com 14811957Sgabeblack@google.comTick 14911957Sgabeblack@google.comIGbE::read(PacketPtr pkt) 15011957Sgabeblack@google.com{ 15111957Sgabeblack@google.com int bar; 15211957Sgabeblack@google.com Addr daddr; 15311957Sgabeblack@google.com 15411957Sgabeblack@google.com if (!getBAR(pkt->getAddr(), bar, daddr)) 15511957Sgabeblack@google.com panic("Invalid PCI memory access to unmapped memory.\n"); 15611957Sgabeblack@google.com 15711957Sgabeblack@google.com // Only Memory register BAR is allowed 15811957Sgabeblack@google.com assert(bar == 0); 15911957Sgabeblack@google.com 16011957Sgabeblack@google.com // Only 32bit accesses allowed 16111957Sgabeblack@google.com assert(pkt->getSize() == 4); 16211957Sgabeblack@google.com 16311957Sgabeblack@google.com DPRINTF(Ethernet, "Read device register %#X\n", daddr); 16411957Sgabeblack@google.com 16511957Sgabeblack@google.com pkt->allocate(); 16611957Sgabeblack@google.com 16711957Sgabeblack@google.com /// 16811957Sgabeblack@google.com /// Handle read of register here 16911957Sgabeblack@google.com /// 17011957Sgabeblack@google.com 17111957Sgabeblack@google.com 17211957Sgabeblack@google.com switch (daddr) { 17311957Sgabeblack@google.com case REG_CTRL: 17411957Sgabeblack@google.com pkt->set<uint32_t>(regs.ctrl()); 17511957Sgabeblack@google.com break; 17611957Sgabeblack@google.com case REG_STATUS: 17711957Sgabeblack@google.com pkt->set<uint32_t>(regs.sts()); 17811957Sgabeblack@google.com break; 17911957Sgabeblack@google.com case REG_EECD: 18011957Sgabeblack@google.com pkt->set<uint32_t>(regs.eecd()); 18111957Sgabeblack@google.com break; 18211957Sgabeblack@google.com case REG_EERD: 18311957Sgabeblack@google.com pkt->set<uint32_t>(regs.eerd()); 18411957Sgabeblack@google.com break; 18511957Sgabeblack@google.com case REG_CTRL_EXT: 18611957Sgabeblack@google.com pkt->set<uint32_t>(regs.ctrl_ext()); 18711957Sgabeblack@google.com break; 18811957Sgabeblack@google.com case REG_MDIC: 18911957Sgabeblack@google.com pkt->set<uint32_t>(regs.mdic()); 19011957Sgabeblack@google.com break; 19111957Sgabeblack@google.com case REG_ICR: 19211957Sgabeblack@google.com DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(), 19311957Sgabeblack@google.com regs.imr, regs.iam, regs.ctrl_ext.iame()); 19411957Sgabeblack@google.com pkt->set<uint32_t>(regs.icr()); 19511957Sgabeblack@google.com if (regs.icr.int_assert() || regs.imr == 0) { 19611957Sgabeblack@google.com regs.icr = regs.icr() & ~mask(30); 19711957Sgabeblack@google.com DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr()); 19811957Sgabeblack@google.com } 19911957Sgabeblack@google.com if (regs.ctrl_ext.iame() && regs.icr.int_assert()) 20011957Sgabeblack@google.com regs.imr &= ~regs.iam; 20111957Sgabeblack@google.com chkInterrupt(); 20211957Sgabeblack@google.com break; 20311957Sgabeblack@google.com case REG_EICR: 20411957Sgabeblack@google.com // This is only useful for MSI, but the driver reads it every time 20511957Sgabeblack@google.com // Just don't do anything 20611957Sgabeblack@google.com pkt->set<uint32_t>(0); 20711957Sgabeblack@google.com break; 20811957Sgabeblack@google.com case REG_ITR: 20911957Sgabeblack@google.com pkt->set<uint32_t>(regs.itr()); 21011957Sgabeblack@google.com break; 21111957Sgabeblack@google.com case REG_RCTL: 21211957Sgabeblack@google.com pkt->set<uint32_t>(regs.rctl()); 21311957Sgabeblack@google.com break; 21411957Sgabeblack@google.com case REG_FCTTV: 21511957Sgabeblack@google.com pkt->set<uint32_t>(regs.fcttv()); 21611957Sgabeblack@google.com break; 21711957Sgabeblack@google.com case REG_TCTL: 21811957Sgabeblack@google.com pkt->set<uint32_t>(regs.tctl()); 21911957Sgabeblack@google.com break; 22011957Sgabeblack@google.com case REG_PBA: 22111957Sgabeblack@google.com pkt->set<uint32_t>(regs.pba()); 22211957Sgabeblack@google.com break; 22311957Sgabeblack@google.com case REG_WUC: 22411957Sgabeblack@google.com case REG_LEDCTL: 22511957Sgabeblack@google.com pkt->set<uint32_t>(0); // We don't care, so just return 0 22611957Sgabeblack@google.com break; 22711957Sgabeblack@google.com case REG_FCRTL: 22811957Sgabeblack@google.com pkt->set<uint32_t>(regs.fcrtl()); 22911957Sgabeblack@google.com break; 23011957Sgabeblack@google.com case REG_FCRTH: 23111957Sgabeblack@google.com pkt->set<uint32_t>(regs.fcrth()); 23211957Sgabeblack@google.com break; 23311957Sgabeblack@google.com case REG_RDBAL: 23411957Sgabeblack@google.com pkt->set<uint32_t>(regs.rdba.rdbal()); 23511957Sgabeblack@google.com break; 23611957Sgabeblack@google.com case REG_RDBAH: 23711957Sgabeblack@google.com pkt->set<uint32_t>(regs.rdba.rdbah()); 23811957Sgabeblack@google.com break; 23911957Sgabeblack@google.com case REG_RDLEN: 24011957Sgabeblack@google.com pkt->set<uint32_t>(regs.rdlen()); 24111957Sgabeblack@google.com break; 24211957Sgabeblack@google.com case REG_SRRCTL: 24311957Sgabeblack@google.com pkt->set<uint32_t>(regs.srrctl()); 24411957Sgabeblack@google.com break; 24511957Sgabeblack@google.com case REG_RDH: 24611957Sgabeblack@google.com pkt->set<uint32_t>(regs.rdh()); 24711957Sgabeblack@google.com break; 24811957Sgabeblack@google.com case REG_RDT: 24911957Sgabeblack@google.com pkt->set<uint32_t>(regs.rdt()); 25011957Sgabeblack@google.com break; 25111957Sgabeblack@google.com case REG_RDTR: 25211957Sgabeblack@google.com pkt->set<uint32_t>(regs.rdtr()); 25311957Sgabeblack@google.com if (regs.rdtr.fpd()) { 25411957Sgabeblack@google.com rxDescCache.writeback(0); 25511957Sgabeblack@google.com DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n"); 25611957Sgabeblack@google.com postInterrupt(IT_RXT); 25711957Sgabeblack@google.com regs.rdtr.fpd(0); 25811957Sgabeblack@google.com } 25911957Sgabeblack@google.com break; 26011957Sgabeblack@google.com case REG_RXDCTL: 26111957Sgabeblack@google.com pkt->set<uint32_t>(regs.rxdctl()); 26211957Sgabeblack@google.com break; 26311957Sgabeblack@google.com case REG_RADV: 26411957Sgabeblack@google.com pkt->set<uint32_t>(regs.radv()); 26511957Sgabeblack@google.com break; 26611957Sgabeblack@google.com case REG_TDBAL: 26711957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdba.tdbal()); 26811957Sgabeblack@google.com break; 26911957Sgabeblack@google.com case REG_TDBAH: 27011957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdba.tdbah()); 27111957Sgabeblack@google.com break; 27211957Sgabeblack@google.com case REG_TDLEN: 27311957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdlen()); 27411957Sgabeblack@google.com break; 27511957Sgabeblack@google.com case REG_TDH: 27611957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdh()); 27711957Sgabeblack@google.com break; 27811957Sgabeblack@google.com case REG_TXDCA_CTL: 27911957Sgabeblack@google.com pkt->set<uint32_t>(regs.txdca_ctl()); 28011957Sgabeblack@google.com break; 28111957Sgabeblack@google.com case REG_TDT: 28211957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdt()); 28311957Sgabeblack@google.com break; 28411957Sgabeblack@google.com case REG_TIDV: 28511957Sgabeblack@google.com pkt->set<uint32_t>(regs.tidv()); 28611957Sgabeblack@google.com break; 28711957Sgabeblack@google.com case REG_TXDCTL: 28811957Sgabeblack@google.com pkt->set<uint32_t>(regs.txdctl()); 28911957Sgabeblack@google.com break; 29011957Sgabeblack@google.com case REG_TADV: 29111957Sgabeblack@google.com pkt->set<uint32_t>(regs.tadv()); 29211957Sgabeblack@google.com break; 29311957Sgabeblack@google.com case REG_TDWBAL: 29411957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdwba & mask(32)); 29511957Sgabeblack@google.com break; 29611957Sgabeblack@google.com case REG_TDWBAH: 29711957Sgabeblack@google.com pkt->set<uint32_t>(regs.tdwba >> 32); 29811957Sgabeblack@google.com break; 29911957Sgabeblack@google.com case REG_RXCSUM: 30011957Sgabeblack@google.com pkt->set<uint32_t>(regs.rxcsum()); 30111957Sgabeblack@google.com break; 30211957Sgabeblack@google.com case REG_RLPML: 30311957Sgabeblack@google.com pkt->set<uint32_t>(regs.rlpml); 30411957Sgabeblack@google.com break; 30511957Sgabeblack@google.com case REG_RFCTL: 30611957Sgabeblack@google.com pkt->set<uint32_t>(regs.rfctl()); 30711957Sgabeblack@google.com break; 30811957Sgabeblack@google.com case REG_MANC: 30911957Sgabeblack@google.com pkt->set<uint32_t>(regs.manc()); 31011957Sgabeblack@google.com break; 31111957Sgabeblack@google.com case REG_SWSM: 31211957Sgabeblack@google.com pkt->set<uint32_t>(regs.swsm()); 31311957Sgabeblack@google.com regs.swsm.smbi(1); 31411957Sgabeblack@google.com break; 31511957Sgabeblack@google.com case REG_FWSM: 31611957Sgabeblack@google.com pkt->set<uint32_t>(regs.fwsm()); 31711957Sgabeblack@google.com break; 31811957Sgabeblack@google.com case REG_SWFWSYNC: 31911957Sgabeblack@google.com pkt->set<uint32_t>(regs.sw_fw_sync); 32011957Sgabeblack@google.com break; 32111957Sgabeblack@google.com default: 32211957Sgabeblack@google.com if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && 32311957Sgabeblack@google.com !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && 32411957Sgabeblack@google.com !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) && 32511957Sgabeblack@google.com !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE))) 32611957Sgabeblack@google.com panic("Read request to unknown register number: %#x\n", daddr); 32711957Sgabeblack@google.com else 32811957Sgabeblack@google.com pkt->set<uint32_t>(0); 32911957Sgabeblack@google.com }; 33011957Sgabeblack@google.com 33111957Sgabeblack@google.com pkt->makeAtomicResponse(); 33211957Sgabeblack@google.com return pioDelay; 33311957Sgabeblack@google.com} 33411957Sgabeblack@google.com 33511957Sgabeblack@google.comTick 33611957Sgabeblack@google.comIGbE::write(PacketPtr pkt) 33711957Sgabeblack@google.com{ 33811957Sgabeblack@google.com int bar; 33911957Sgabeblack@google.com Addr daddr; 34011957Sgabeblack@google.com 34111957Sgabeblack@google.com 34211957Sgabeblack@google.com if (!getBAR(pkt->getAddr(), bar, daddr)) 34311957Sgabeblack@google.com panic("Invalid PCI memory access to unmapped memory.\n"); 34411957Sgabeblack@google.com 34511957Sgabeblack@google.com // Only Memory register BAR is allowed 34611957Sgabeblack@google.com assert(bar == 0); 34711957Sgabeblack@google.com 34811957Sgabeblack@google.com // Only 32bit accesses allowed 34911957Sgabeblack@google.com assert(pkt->getSize() == sizeof(uint32_t)); 35011957Sgabeblack@google.com 35111957Sgabeblack@google.com DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>()); 35211957Sgabeblack@google.com 35311957Sgabeblack@google.com /// 35411957Sgabeblack@google.com /// Handle write of register here 35511957Sgabeblack@google.com /// 35611957Sgabeblack@google.com uint32_t val = pkt->get<uint32_t>(); 35711957Sgabeblack@google.com 35811957Sgabeblack@google.com Regs::RCTL oldrctl; 35911957Sgabeblack@google.com Regs::TCTL oldtctl; 36011957Sgabeblack@google.com 36111957Sgabeblack@google.com switch (daddr) { 36211957Sgabeblack@google.com case REG_CTRL: 36311957Sgabeblack@google.com regs.ctrl = val; 36411957Sgabeblack@google.com if (regs.ctrl.tfce()) 36511957Sgabeblack@google.com warn("TX Flow control enabled, should implement\n"); 36611957Sgabeblack@google.com if (regs.ctrl.rfce()) 36711957Sgabeblack@google.com warn("RX Flow control enabled, should implement\n"); 36811957Sgabeblack@google.com break; 36911957Sgabeblack@google.com case REG_CTRL_EXT: 37011957Sgabeblack@google.com regs.ctrl_ext = val; 37111957Sgabeblack@google.com break; 37211957Sgabeblack@google.com case REG_STATUS: 37311957Sgabeblack@google.com regs.sts = val; 37411957Sgabeblack@google.com break; 37511957Sgabeblack@google.com case REG_EECD: 37611957Sgabeblack@google.com int oldClk; 37711957Sgabeblack@google.com oldClk = regs.eecd.sk(); 37811957Sgabeblack@google.com regs.eecd = val; 37911957Sgabeblack@google.com // See if this is a eeprom access and emulate accordingly 38011957Sgabeblack@google.com if (!oldClk && regs.eecd.sk()) { 38111957Sgabeblack@google.com if (eeOpBits < 8) { 38211957Sgabeblack@google.com eeOpcode = eeOpcode << 1 | regs.eecd.din(); 38311957Sgabeblack@google.com eeOpBits++; 38411957Sgabeblack@google.com } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 38511957Sgabeblack@google.com eeAddr = eeAddr << 1 | regs.eecd.din(); 38611957Sgabeblack@google.com eeAddrBits++; 38711957Sgabeblack@google.com } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { 38811957Sgabeblack@google.com assert(eeAddr>>1 < EEPROM_SIZE); 38911957Sgabeblack@google.com DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", 39011957Sgabeblack@google.com flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); 39111957Sgabeblack@google.com regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1); 39211957Sgabeblack@google.com eeDataBits++; 39311957Sgabeblack@google.com } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { 39411957Sgabeblack@google.com regs.eecd.dout(0); 39511957Sgabeblack@google.com eeDataBits++; 39611957Sgabeblack@google.com } else 39711957Sgabeblack@google.com panic("What's going on with eeprom interface? opcode:" 39811957Sgabeblack@google.com " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, 39911957Sgabeblack@google.com (uint32_t)eeOpBits, (uint32_t)eeAddr, 40011957Sgabeblack@google.com (uint32_t)eeAddrBits, (uint32_t)eeDataBits); 40111957Sgabeblack@google.com 40211957Sgabeblack@google.com // Reset everything for the next command 40311957Sgabeblack@google.com if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || 40411957Sgabeblack@google.com (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { 40511957Sgabeblack@google.com eeOpBits = 0; 40611957Sgabeblack@google.com eeAddrBits = 0; 40711957Sgabeblack@google.com eeDataBits = 0; 40811957Sgabeblack@google.com eeOpcode = 0; 40911957Sgabeblack@google.com eeAddr = 0; 41011957Sgabeblack@google.com } 41111957Sgabeblack@google.com 41211957Sgabeblack@google.com DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", 41311957Sgabeblack@google.com (uint32_t)eeOpcode, (uint32_t) eeOpBits, 41411957Sgabeblack@google.com (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); 41511957Sgabeblack@google.com if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || 41611957Sgabeblack@google.com eeOpcode == EEPROM_RDSR_OPCODE_SPI )) 41711957Sgabeblack@google.com panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, 41811957Sgabeblack@google.com (uint32_t)eeOpBits); 41911957Sgabeblack@google.com 42011957Sgabeblack@google.com 42111957Sgabeblack@google.com } 42211957Sgabeblack@google.com // If driver requests eeprom access, immediately give it to it 42311957Sgabeblack@google.com regs.eecd.ee_gnt(regs.eecd.ee_req()); 42411957Sgabeblack@google.com break; 42511957Sgabeblack@google.com case REG_EERD: 42611957Sgabeblack@google.com regs.eerd = val; 42711957Sgabeblack@google.com if (regs.eerd.start()) { 42811957Sgabeblack@google.com regs.eerd.done(1); 42911957Sgabeblack@google.com assert(regs.eerd.addr() < EEPROM_SIZE); 43011957Sgabeblack@google.com regs.eerd.data(flash[regs.eerd.addr()]); 43111957Sgabeblack@google.com regs.eerd.start(0); 43211957Sgabeblack@google.com DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n", 43311957Sgabeblack@google.com regs.eerd.addr(), regs.eerd.data()); 43411957Sgabeblack@google.com } 43511957Sgabeblack@google.com break; 43611957Sgabeblack@google.com case REG_MDIC: 43711957Sgabeblack@google.com regs.mdic = val; 43811957Sgabeblack@google.com if (regs.mdic.i()) 43911957Sgabeblack@google.com panic("No support for interrupt on mdic complete\n"); 44011957Sgabeblack@google.com if (regs.mdic.phyadd() != 1) 44111957Sgabeblack@google.com panic("No support for reading anything but phy\n"); 44211957Sgabeblack@google.com DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing" 44311957Sgabeblack@google.com : "Reading", regs.mdic.regadd()); 44411957Sgabeblack@google.com switch (regs.mdic.regadd()) { 44511957Sgabeblack@google.com case PHY_PSTATUS: 44611957Sgabeblack@google.com regs.mdic.data(0x796D); // link up 44711957Sgabeblack@google.com break; 44811957Sgabeblack@google.com case PHY_PID: 44911957Sgabeblack@google.com regs.mdic.data(params()->phy_pid); 45011957Sgabeblack@google.com break; 45111957Sgabeblack@google.com case PHY_EPID: 45211957Sgabeblack@google.com regs.mdic.data(params()->phy_epid); 45311957Sgabeblack@google.com break; 45411957Sgabeblack@google.com case PHY_GSTATUS: 45511957Sgabeblack@google.com regs.mdic.data(0x7C00); 45611957Sgabeblack@google.com break; 45711957Sgabeblack@google.com case PHY_EPSTATUS: 45811957Sgabeblack@google.com regs.mdic.data(0x3000); 45911957Sgabeblack@google.com break; 46011957Sgabeblack@google.com case PHY_AGC: 46111957Sgabeblack@google.com regs.mdic.data(0x180); // some random length 46211957Sgabeblack@google.com break; 46311957Sgabeblack@google.com default: 46411957Sgabeblack@google.com regs.mdic.data(0); 46511957Sgabeblack@google.com } 46611957Sgabeblack@google.com regs.mdic.r(1); 46711957Sgabeblack@google.com break; 46811957Sgabeblack@google.com case REG_ICR: 46911957Sgabeblack@google.com DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(), 47011957Sgabeblack@google.com regs.imr, regs.iam, regs.ctrl_ext.iame()); 47111957Sgabeblack@google.com if (regs.ctrl_ext.iame()) 47211957Sgabeblack@google.com regs.imr &= ~regs.iam; 47311957Sgabeblack@google.com regs.icr = ~bits(val,30,0) & regs.icr(); 47411957Sgabeblack@google.com chkInterrupt(); 47511957Sgabeblack@google.com break; 47611957Sgabeblack@google.com case REG_ITR: 47711957Sgabeblack@google.com regs.itr = val; 47811957Sgabeblack@google.com break; 47911957Sgabeblack@google.com case REG_ICS: 48011957Sgabeblack@google.com DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n"); 48111957Sgabeblack@google.com postInterrupt((IntTypes)val); 48211957Sgabeblack@google.com break; 48311957Sgabeblack@google.com case REG_IMS: 48411957Sgabeblack@google.com regs.imr |= val; 48511957Sgabeblack@google.com chkInterrupt(); 48611957Sgabeblack@google.com break; 48711957Sgabeblack@google.com case REG_IMC: 48811957Sgabeblack@google.com regs.imr &= ~val; 48911957Sgabeblack@google.com chkInterrupt(); 49011957Sgabeblack@google.com break; 49111957Sgabeblack@google.com case REG_IAM: 49211957Sgabeblack@google.com regs.iam = val; 49311957Sgabeblack@google.com break; 49411957Sgabeblack@google.com case REG_RCTL: 49511957Sgabeblack@google.com oldrctl = regs.rctl; 49611957Sgabeblack@google.com regs.rctl = val; 49711957Sgabeblack@google.com if (regs.rctl.rst()) { 49811957Sgabeblack@google.com rxDescCache.reset(); 49911957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Got RESET!\n"); 50011957Sgabeblack@google.com rxFifo.clear(); 50111957Sgabeblack@google.com regs.rctl.rst(0); 50211957Sgabeblack@google.com } 50311957Sgabeblack@google.com if (regs.rctl.en()) 50411957Sgabeblack@google.com rxTick = true; 50511957Sgabeblack@google.com restartClock(); 50611957Sgabeblack@google.com break; 50711957Sgabeblack@google.com case REG_FCTTV: 50811957Sgabeblack@google.com regs.fcttv = val; 50911957Sgabeblack@google.com break; 51011957Sgabeblack@google.com case REG_TCTL: 51111957Sgabeblack@google.com regs.tctl = val; 51211957Sgabeblack@google.com oldtctl = regs.tctl; 51311957Sgabeblack@google.com regs.tctl = val; 51411957Sgabeblack@google.com if (regs.tctl.en()) 51511957Sgabeblack@google.com txTick = true; 51611957Sgabeblack@google.com restartClock(); 51711957Sgabeblack@google.com if (regs.tctl.en() && !oldtctl.en()) { 51811957Sgabeblack@google.com txDescCache.reset(); 51911957Sgabeblack@google.com } 52011957Sgabeblack@google.com break; 52111957Sgabeblack@google.com case REG_PBA: 52211957Sgabeblack@google.com regs.pba.rxa(val); 52311957Sgabeblack@google.com regs.pba.txa(64 - regs.pba.rxa()); 52411957Sgabeblack@google.com break; 52511957Sgabeblack@google.com case REG_WUC: 52611957Sgabeblack@google.com case REG_LEDCTL: 52711957Sgabeblack@google.com case REG_FCAL: 52811957Sgabeblack@google.com case REG_FCAH: 52911957Sgabeblack@google.com case REG_FCT: 53011957Sgabeblack@google.com case REG_VET: 53111957Sgabeblack@google.com case REG_AIFS: 53211957Sgabeblack@google.com case REG_TIPG: 53311957Sgabeblack@google.com ; // We don't care, so don't store anything 53411957Sgabeblack@google.com break; 53511957Sgabeblack@google.com case REG_IVAR0: 53611957Sgabeblack@google.com warn("Writing to IVAR0, ignoring...\n"); 53711957Sgabeblack@google.com break; 53811957Sgabeblack@google.com case REG_FCRTL: 53911957Sgabeblack@google.com regs.fcrtl = val; 54011957Sgabeblack@google.com break; 54111957Sgabeblack@google.com case REG_FCRTH: 54211957Sgabeblack@google.com regs.fcrth = val; 54311957Sgabeblack@google.com break; 54411957Sgabeblack@google.com case REG_RDBAL: 54511957Sgabeblack@google.com regs.rdba.rdbal( val & ~mask(4)); 54611957Sgabeblack@google.com rxDescCache.areaChanged(); 54711957Sgabeblack@google.com break; 54811957Sgabeblack@google.com case REG_RDBAH: 54911957Sgabeblack@google.com regs.rdba.rdbah(val); 55011957Sgabeblack@google.com rxDescCache.areaChanged(); 55111957Sgabeblack@google.com break; 55211957Sgabeblack@google.com case REG_RDLEN: 55311957Sgabeblack@google.com regs.rdlen = val & ~mask(7); 55411957Sgabeblack@google.com rxDescCache.areaChanged(); 55511957Sgabeblack@google.com break; 55611957Sgabeblack@google.com case REG_SRRCTL: 55711957Sgabeblack@google.com regs.srrctl = val; 55811957Sgabeblack@google.com break; 55911957Sgabeblack@google.com case REG_RDH: 56011957Sgabeblack@google.com regs.rdh = val; 56111957Sgabeblack@google.com rxDescCache.areaChanged(); 56211957Sgabeblack@google.com break; 56311957Sgabeblack@google.com case REG_RDT: 56411957Sgabeblack@google.com regs.rdt = val; 56511957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: RDT Updated.\n"); 56611957Sgabeblack@google.com if (getState() == SimObject::Running) { 56711957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n"); 56811957Sgabeblack@google.com rxDescCache.fetchDescriptors(); 56911957Sgabeblack@google.com } else { 57011957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n"); 57111957Sgabeblack@google.com } 57211957Sgabeblack@google.com break; 57311957Sgabeblack@google.com case REG_RDTR: 57411957Sgabeblack@google.com regs.rdtr = val; 57511957Sgabeblack@google.com break; 57611957Sgabeblack@google.com case REG_RADV: 57711957Sgabeblack@google.com regs.radv = val; 57811957Sgabeblack@google.com break; 57911957Sgabeblack@google.com case REG_RXDCTL: 58011957Sgabeblack@google.com regs.rxdctl = val; 58111957Sgabeblack@google.com break; 58211957Sgabeblack@google.com case REG_TDBAL: 58311957Sgabeblack@google.com regs.tdba.tdbal( val & ~mask(4)); 58411957Sgabeblack@google.com txDescCache.areaChanged(); 58511957Sgabeblack@google.com break; 58611957Sgabeblack@google.com case REG_TDBAH: 58711957Sgabeblack@google.com regs.tdba.tdbah(val); 58811957Sgabeblack@google.com txDescCache.areaChanged(); 58911957Sgabeblack@google.com break; 59011957Sgabeblack@google.com case REG_TDLEN: 59111957Sgabeblack@google.com regs.tdlen = val & ~mask(7); 59211957Sgabeblack@google.com txDescCache.areaChanged(); 59311957Sgabeblack@google.com break; 59411957Sgabeblack@google.com case REG_TDH: 59511957Sgabeblack@google.com regs.tdh = val; 59611957Sgabeblack@google.com txDescCache.areaChanged(); 59711957Sgabeblack@google.com break; 59811957Sgabeblack@google.com case REG_TXDCA_CTL: 59911957Sgabeblack@google.com regs.txdca_ctl = val; 60011957Sgabeblack@google.com if (regs.txdca_ctl.enabled()) 60111957Sgabeblack@google.com panic("No support for DCA\n"); 60211957Sgabeblack@google.com break; 60311957Sgabeblack@google.com case REG_TDT: 60411957Sgabeblack@google.com regs.tdt = val; 60511957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n"); 60611957Sgabeblack@google.com if (getState() == SimObject::Running) { 60711957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n"); 60811957Sgabeblack@google.com txDescCache.fetchDescriptors(); 60911957Sgabeblack@google.com } else { 61011957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n"); 61111957Sgabeblack@google.com } 61211957Sgabeblack@google.com break; 61311957Sgabeblack@google.com case REG_TIDV: 61411957Sgabeblack@google.com regs.tidv = val; 61511957Sgabeblack@google.com break; 61611957Sgabeblack@google.com case REG_TXDCTL: 61711957Sgabeblack@google.com regs.txdctl = val; 61811957Sgabeblack@google.com break; 61911957Sgabeblack@google.com case REG_TADV: 62011957Sgabeblack@google.com regs.tadv = val; 62111957Sgabeblack@google.com break; 62211957Sgabeblack@google.com case REG_TDWBAL: 62311957Sgabeblack@google.com regs.tdwba &= ~mask(32); 62411957Sgabeblack@google.com regs.tdwba |= val; 62511957Sgabeblack@google.com txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1)); 62611957Sgabeblack@google.com break; 62711957Sgabeblack@google.com case REG_TDWBAH: 62811957Sgabeblack@google.com regs.tdwba &= mask(32); 62911957Sgabeblack@google.com regs.tdwba |= (uint64_t)val << 32; 63011957Sgabeblack@google.com txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1)); 63111957Sgabeblack@google.com break; 63211957Sgabeblack@google.com case REG_RXCSUM: 63311957Sgabeblack@google.com regs.rxcsum = val; 63411957Sgabeblack@google.com break; 63511957Sgabeblack@google.com case REG_RLPML: 63611957Sgabeblack@google.com regs.rlpml = val; 63711957Sgabeblack@google.com break; 63811957Sgabeblack@google.com case REG_RFCTL: 63911957Sgabeblack@google.com regs.rfctl = val; 64011957Sgabeblack@google.com if (regs.rfctl.exsten()) 64111957Sgabeblack@google.com panic("Extended RX descriptors not implemented\n"); 64211957Sgabeblack@google.com break; 64311957Sgabeblack@google.com case REG_MANC: 64411957Sgabeblack@google.com regs.manc = val; 64511957Sgabeblack@google.com break; 64611957Sgabeblack@google.com case REG_SWSM: 64711957Sgabeblack@google.com regs.swsm = val; 64811957Sgabeblack@google.com if (regs.fwsm.eep_fw_semaphore()) 64911957Sgabeblack@google.com regs.swsm.swesmbi(0); 65011957Sgabeblack@google.com break; 65111957Sgabeblack@google.com case REG_SWFWSYNC: 65211957Sgabeblack@google.com regs.sw_fw_sync = val; 65311957Sgabeblack@google.com break; 65411957Sgabeblack@google.com default: 65511957Sgabeblack@google.com if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && 65611957Sgabeblack@google.com !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && 65711957Sgabeblack@google.com !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4))) 65811957Sgabeblack@google.com panic("Write request to unknown register number: %#x\n", daddr); 65911957Sgabeblack@google.com }; 66011957Sgabeblack@google.com 66111957Sgabeblack@google.com pkt->makeAtomicResponse(); 66211957Sgabeblack@google.com return pioDelay; 66311957Sgabeblack@google.com} 66411957Sgabeblack@google.com 66511957Sgabeblack@google.comvoid 66611957Sgabeblack@google.comIGbE::postInterrupt(IntTypes t, bool now) 66711957Sgabeblack@google.com{ 66811957Sgabeblack@google.com assert(t); 66911957Sgabeblack@google.com 67011957Sgabeblack@google.com // Interrupt is already pending 67111957Sgabeblack@google.com if (t & regs.icr() && !now) 67211957Sgabeblack@google.com return; 67311957Sgabeblack@google.com 67411957Sgabeblack@google.com regs.icr = regs.icr() | t; 67511957Sgabeblack@google.com 67611957Sgabeblack@google.com Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval(); 67711957Sgabeblack@google.com DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n", 67811957Sgabeblack@google.com curTick, regs.itr.interval(), itr_interval); 67911957Sgabeblack@google.com 68011957Sgabeblack@google.com if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) { 68111957Sgabeblack@google.com if (interEvent.scheduled()) { 68211957Sgabeblack@google.com deschedule(interEvent); 68311957Sgabeblack@google.com } 68411957Sgabeblack@google.com cpuPostInt(); 68511957Sgabeblack@google.com } else { 68611957Sgabeblack@google.com Tick int_time = lastInterrupt + itr_interval; 68711957Sgabeblack@google.com assert(int_time > 0); 68811957Sgabeblack@google.com DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n", 68911957Sgabeblack@google.com int_time); 69011957Sgabeblack@google.com if (!interEvent.scheduled()) { 69111957Sgabeblack@google.com schedule(interEvent, int_time); 69211957Sgabeblack@google.com } 69311957Sgabeblack@google.com } 69411957Sgabeblack@google.com} 69511957Sgabeblack@google.com 69611957Sgabeblack@google.comvoid 69711957Sgabeblack@google.comIGbE::delayIntEvent() 69811957Sgabeblack@google.com{ 69911957Sgabeblack@google.com cpuPostInt(); 70011957Sgabeblack@google.com} 70111957Sgabeblack@google.com 70211957Sgabeblack@google.com 70311957Sgabeblack@google.comvoid 70411957Sgabeblack@google.comIGbE::cpuPostInt() 70511957Sgabeblack@google.com{ 70611957Sgabeblack@google.com 70711957Sgabeblack@google.com postedInterrupts++; 70811957Sgabeblack@google.com 70911957Sgabeblack@google.com if (!(regs.icr() & regs.imr)) { 71011957Sgabeblack@google.com DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n"); 71111957Sgabeblack@google.com return; 71211957Sgabeblack@google.com } 71311957Sgabeblack@google.com 71411957Sgabeblack@google.com DPRINTF(Ethernet, "Posting Interrupt\n"); 71511957Sgabeblack@google.com 71611957Sgabeblack@google.com 71711957Sgabeblack@google.com if (interEvent.scheduled()) { 71811957Sgabeblack@google.com deschedule(interEvent); 71911957Sgabeblack@google.com } 72011957Sgabeblack@google.com 72111957Sgabeblack@google.com if (rdtrEvent.scheduled()) { 72211957Sgabeblack@google.com regs.icr.rxt0(1); 72311957Sgabeblack@google.com deschedule(rdtrEvent); 72411957Sgabeblack@google.com } 72511957Sgabeblack@google.com if (radvEvent.scheduled()) { 72611957Sgabeblack@google.com regs.icr.rxt0(1); 72711957Sgabeblack@google.com deschedule(radvEvent); 72811957Sgabeblack@google.com } 72911957Sgabeblack@google.com if (tadvEvent.scheduled()) { 73011957Sgabeblack@google.com regs.icr.txdw(1); 73111957Sgabeblack@google.com deschedule(tadvEvent); 73211957Sgabeblack@google.com } 73311957Sgabeblack@google.com if (tidvEvent.scheduled()) { 73411957Sgabeblack@google.com regs.icr.txdw(1); 73511957Sgabeblack@google.com deschedule(tidvEvent); 73611957Sgabeblack@google.com } 73711957Sgabeblack@google.com 73811957Sgabeblack@google.com regs.icr.int_assert(1); 73911957Sgabeblack@google.com DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n", 74011957Sgabeblack@google.com regs.icr()); 74111957Sgabeblack@google.com 74211957Sgabeblack@google.com intrPost(); 74311957Sgabeblack@google.com 74411957Sgabeblack@google.com lastInterrupt = curTick; 74511957Sgabeblack@google.com} 74611957Sgabeblack@google.com 74711957Sgabeblack@google.comvoid 74811957Sgabeblack@google.comIGbE::cpuClearInt() 74911957Sgabeblack@google.com{ 75011957Sgabeblack@google.com if (regs.icr.int_assert()) { 75111957Sgabeblack@google.com regs.icr.int_assert(0); 75211957Sgabeblack@google.com DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n", 75311957Sgabeblack@google.com regs.icr()); 75411957Sgabeblack@google.com intrClear(); 75511957Sgabeblack@google.com } 75611957Sgabeblack@google.com} 75711957Sgabeblack@google.com 75811957Sgabeblack@google.comvoid 75911957Sgabeblack@google.comIGbE::chkInterrupt() 76011957Sgabeblack@google.com{ 76111957Sgabeblack@google.com DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(), 76211957Sgabeblack@google.com regs.imr); 76311957Sgabeblack@google.com // Check if we need to clear the cpu interrupt 76411957Sgabeblack@google.com if (!(regs.icr() & regs.imr)) { 76511957Sgabeblack@google.com DPRINTF(Ethernet, "Mask cleaned all interrupts\n"); 76611957Sgabeblack@google.com if (interEvent.scheduled()) 76711957Sgabeblack@google.com deschedule(interEvent); 76811957Sgabeblack@google.com if (regs.icr.int_assert()) 76911957Sgabeblack@google.com cpuClearInt(); 77011957Sgabeblack@google.com } 77111957Sgabeblack@google.com DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval()); 77211957Sgabeblack@google.com 77311957Sgabeblack@google.com if (regs.icr() & regs.imr) { 77411957Sgabeblack@google.com if (regs.itr.interval() == 0) { 77511957Sgabeblack@google.com cpuPostInt(); 77611957Sgabeblack@google.com } else { 77711957Sgabeblack@google.com DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n"); 77811957Sgabeblack@google.com if (!interEvent.scheduled()) { 77911957Sgabeblack@google.com DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns 78011957Sgabeblack@google.com * 256 * regs.itr.interval()); 78111957Sgabeblack@google.com schedule(interEvent, 78211957Sgabeblack@google.com curTick + Clock::Int::ns * 256 * regs.itr.interval()); 78311957Sgabeblack@google.com } 78411957Sgabeblack@google.com } 78511957Sgabeblack@google.com } 78611957Sgabeblack@google.com 78711957Sgabeblack@google.com 78811957Sgabeblack@google.com} 78911957Sgabeblack@google.com 79011957Sgabeblack@google.com 79111957Sgabeblack@google.comIGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) 79211957Sgabeblack@google.com : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0), 79311957Sgabeblack@google.com pktEvent(this), pktHdrEvent(this), pktDataEvent(this) 79411957Sgabeblack@google.com 79511957Sgabeblack@google.com{ 79611957Sgabeblack@google.com} 79711957Sgabeblack@google.com 79811957Sgabeblack@google.comvoid 79911957Sgabeblack@google.comIGbE::RxDescCache::pktSplitDone() 80011957Sgabeblack@google.com{ 80111957Sgabeblack@google.com splitCount++; 80211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Part of split packet done: splitcount now %d\n", splitCount); 80311957Sgabeblack@google.com assert(splitCount <= 2); 80411957Sgabeblack@google.com if (splitCount != 2) 80511957Sgabeblack@google.com return; 80611957Sgabeblack@google.com splitCount = 0; 80711957Sgabeblack@google.com DPRINTF(EthernetDesc, "Part of split packet done: calling pktComplete()\n"); 80811957Sgabeblack@google.com pktComplete(); 80911957Sgabeblack@google.com} 81011957Sgabeblack@google.com 81111957Sgabeblack@google.comint 81211957Sgabeblack@google.comIGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset) 81311957Sgabeblack@google.com{ 81411957Sgabeblack@google.com assert(unusedCache.size()); 81511957Sgabeblack@google.com //if (!unusedCache.size()) 81611957Sgabeblack@google.com // return false; 81711957Sgabeblack@google.com 81811957Sgabeblack@google.com pktPtr = packet; 81911957Sgabeblack@google.com pktDone = false; 82011957Sgabeblack@google.com int buf_len, hdr_len; 82111957Sgabeblack@google.com 82211957Sgabeblack@google.com RxDesc *desc = unusedCache.front(); 82311957Sgabeblack@google.com switch (igbe->regs.srrctl.desctype()) { 82411957Sgabeblack@google.com case RXDT_LEGACY: 82511957Sgabeblack@google.com assert(pkt_offset == 0); 82611957Sgabeblack@google.com bytesCopied = packet->length; 82711957Sgabeblack@google.com DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n", 82811957Sgabeblack@google.com packet->length, igbe->regs.rctl.descSize()); 82911957Sgabeblack@google.com assert(packet->length < igbe->regs.rctl.descSize()); 83011957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(desc->legacy.buf), packet->length, &pktEvent, 83111957Sgabeblack@google.com packet->data, igbe->rxWriteDelay); 83211957Sgabeblack@google.com break; 83311957Sgabeblack@google.com case RXDT_ADV_ONEBUF: 83411957Sgabeblack@google.com assert(pkt_offset == 0); 83511957Sgabeblack@google.com bytesCopied = packet->length; 83611957Sgabeblack@google.com buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : 83711957Sgabeblack@google.com igbe->regs.rctl.descSize(); 83811957Sgabeblack@google.com DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n", 83911957Sgabeblack@google.com packet->length, igbe->regs.srrctl(), buf_len); 84011957Sgabeblack@google.com assert(packet->length < buf_len); 84111957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), packet->length, &pktEvent, 84211957Sgabeblack@google.com packet->data, igbe->rxWriteDelay); 84311957Sgabeblack@google.com desc->adv_wb.header_len = htole(0); 84411957Sgabeblack@google.com desc->adv_wb.sph = htole(0); 84511957Sgabeblack@google.com desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length)); 84611957Sgabeblack@google.com break; 84711957Sgabeblack@google.com case RXDT_ADV_SPLIT_A: 84811957Sgabeblack@google.com int split_point; 84911957Sgabeblack@google.com 85011957Sgabeblack@google.com buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() : 85111957Sgabeblack@google.com igbe->regs.rctl.descSize(); 85211957Sgabeblack@google.com hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0; 85311957Sgabeblack@google.com DPRINTF(EthernetDesc, "lpe: %d Packet Length: %d offset: %d srrctl: %#x hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n", 85411957Sgabeblack@google.com igbe->regs.rctl.lpe(), packet->length, pkt_offset, igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, desc->adv_read.pkt, buf_len); 85511957Sgabeblack@google.com 85611957Sgabeblack@google.com split_point = hsplit(pktPtr); 85711957Sgabeblack@google.com 85811957Sgabeblack@google.com if (packet->length <= hdr_len) { 85911957Sgabeblack@google.com bytesCopied = packet->length; 86011957Sgabeblack@google.com assert(pkt_offset == 0); 86111957Sgabeblack@google.com DPRINTF(EthernetDesc, "Header Splitting: Entire packet being placed in header\n"); 86211957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), packet->length, &pktEvent, 86311957Sgabeblack@google.com packet->data, igbe->rxWriteDelay); 86411957Sgabeblack@google.com desc->adv_wb.header_len = htole((uint16_t)packet->length); 86511957Sgabeblack@google.com desc->adv_wb.sph = htole(0); 86611957Sgabeblack@google.com desc->adv_wb.pkt_len = htole(0); 86711957Sgabeblack@google.com } else if (split_point) { 86811957Sgabeblack@google.com if (pkt_offset) { 86911957Sgabeblack@google.com // we are only copying some data, header/data has already been 87011957Sgabeblack@google.com // copied 87111957Sgabeblack@google.com int max_to_copy = std::min(packet->length - pkt_offset, buf_len); 87211957Sgabeblack@google.com bytesCopied += max_to_copy; 87311957Sgabeblack@google.com DPRINTF(EthernetDesc, "Header Splitting: Continuing data buffer copy\n"); 87411957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),max_to_copy, &pktEvent, 87511957Sgabeblack@google.com packet->data + pkt_offset, igbe->rxWriteDelay); 87611957Sgabeblack@google.com desc->adv_wb.header_len = htole(0); 87711957Sgabeblack@google.com desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy); 87811957Sgabeblack@google.com desc->adv_wb.sph = htole(0); 87911957Sgabeblack@google.com } else { 88011957Sgabeblack@google.com int max_to_copy = std::min(packet->length - split_point, buf_len); 88111957Sgabeblack@google.com bytesCopied += max_to_copy + split_point; 88211957Sgabeblack@google.com 88311957Sgabeblack@google.com DPRINTF(EthernetDesc, "Header Splitting: splitting at %d\n", 88411957Sgabeblack@google.com split_point); 88511957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), split_point, &pktHdrEvent, 88611957Sgabeblack@google.com packet->data, igbe->rxWriteDelay); 88711957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), 88811957Sgabeblack@google.com max_to_copy, &pktDataEvent, packet->data + split_point, igbe->rxWriteDelay); 88911957Sgabeblack@google.com desc->adv_wb.header_len = htole(split_point); 89011957Sgabeblack@google.com desc->adv_wb.sph = 1; 89111957Sgabeblack@google.com desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy)); 89211957Sgabeblack@google.com } 89311957Sgabeblack@google.com } else { 89411957Sgabeblack@google.com panic("Header split not fitting within header buffer or undecodable" 89511957Sgabeblack@google.com " packet not fitting in header unsupported\n"); 89611957Sgabeblack@google.com } 89711957Sgabeblack@google.com break; 89811957Sgabeblack@google.com default: 89911957Sgabeblack@google.com panic("Unimplemnted RX receive buffer type: %d\n", 90011957Sgabeblack@google.com igbe->regs.srrctl.desctype()); 90111957Sgabeblack@google.com } 90211957Sgabeblack@google.com return bytesCopied; 90311957Sgabeblack@google.com 90411957Sgabeblack@google.com} 90511957Sgabeblack@google.com 90611957Sgabeblack@google.comvoid 90711957Sgabeblack@google.comIGbE::RxDescCache::pktComplete() 90811957Sgabeblack@google.com{ 90911957Sgabeblack@google.com assert(unusedCache.size()); 91011957Sgabeblack@google.com RxDesc *desc; 91111957Sgabeblack@google.com desc = unusedCache.front(); 91211957Sgabeblack@google.com 91311957Sgabeblack@google.com uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ; 91411957Sgabeblack@google.com DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d stripcrc offset: %d value written: %d %d\n", 91511957Sgabeblack@google.com pktPtr->length, bytesCopied, crcfixup, 91611957Sgabeblack@google.com htole((uint16_t)(pktPtr->length + crcfixup)), 91711957Sgabeblack@google.com (uint16_t)(pktPtr->length + crcfixup)); 91811957Sgabeblack@google.com 91911957Sgabeblack@google.com // no support for anything but starting at 0 92011957Sgabeblack@google.com assert(igbe->regs.rxcsum.pcss() == 0); 92111957Sgabeblack@google.com 92211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n"); 92311957Sgabeblack@google.com 92411957Sgabeblack@google.com uint16_t status = RXDS_DD; 92511957Sgabeblack@google.com uint8_t err = 0; 92611957Sgabeblack@google.com uint16_t ext_err = 0; 92711957Sgabeblack@google.com uint16_t csum = 0; 92811957Sgabeblack@google.com uint16_t ptype = 0; 92911957Sgabeblack@google.com uint16_t ip_id = 0; 93011957Sgabeblack@google.com 93111957Sgabeblack@google.com assert(bytesCopied <= pktPtr->length); 93211957Sgabeblack@google.com if (bytesCopied == pktPtr->length) 93311957Sgabeblack@google.com status |= RXDS_EOP; 93411957Sgabeblack@google.com 93511957Sgabeblack@google.com IpPtr ip(pktPtr); 93611957Sgabeblack@google.com 93711957Sgabeblack@google.com if (ip) { 93811957Sgabeblack@google.com DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); 93911957Sgabeblack@google.com ptype |= RXDP_IPV4; 94011957Sgabeblack@google.com ip_id = ip->id(); 94111957Sgabeblack@google.com 94211957Sgabeblack@google.com if (igbe->regs.rxcsum.ipofld()) { 94311957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checking IP checksum\n"); 94411957Sgabeblack@google.com status |= RXDS_IPCS; 94511957Sgabeblack@google.com csum = htole(cksum(ip)); 94611957Sgabeblack@google.com igbe->rxIpChecksums++; 94711957Sgabeblack@google.com if (cksum(ip) != 0) { 94811957Sgabeblack@google.com err |= RXDE_IPE; 94911957Sgabeblack@google.com ext_err |= RXDEE_IPE; 95011957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 95111957Sgabeblack@google.com } 95211957Sgabeblack@google.com } 95311957Sgabeblack@google.com TcpPtr tcp(ip); 95411957Sgabeblack@google.com if (tcp && igbe->regs.rxcsum.tuofld()) { 95511957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checking TCP checksum\n"); 95611957Sgabeblack@google.com status |= RXDS_TCPCS; 95711957Sgabeblack@google.com ptype |= RXDP_TCP; 95811957Sgabeblack@google.com csum = htole(cksum(tcp)); 95911957Sgabeblack@google.com igbe->rxTcpChecksums++; 96011957Sgabeblack@google.com if (cksum(tcp) != 0) { 96111957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 96211957Sgabeblack@google.com err |= RXDE_TCPE; 96311957Sgabeblack@google.com ext_err |= RXDEE_TCPE; 96411957Sgabeblack@google.com } 96511957Sgabeblack@google.com } 96611957Sgabeblack@google.com 96711957Sgabeblack@google.com UdpPtr udp(ip); 96811957Sgabeblack@google.com if (udp && igbe->regs.rxcsum.tuofld()) { 96911957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checking UDP checksum\n"); 97011957Sgabeblack@google.com status |= RXDS_UDPCS; 97111957Sgabeblack@google.com ptype |= RXDP_UDP; 97211957Sgabeblack@google.com csum = htole(cksum(udp)); 97311957Sgabeblack@google.com igbe->rxUdpChecksums++; 97411957Sgabeblack@google.com if (cksum(udp) != 0) { 97511957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checksum is bad!!\n"); 97611957Sgabeblack@google.com ext_err |= RXDEE_TCPE; 97711957Sgabeblack@google.com err |= RXDE_TCPE; 97811957Sgabeblack@google.com } 97911957Sgabeblack@google.com } 98011957Sgabeblack@google.com } else { // if ip 98111957Sgabeblack@google.com DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); 98211957Sgabeblack@google.com } 98311957Sgabeblack@google.com 98411957Sgabeblack@google.com switch (igbe->regs.srrctl.desctype()) { 98511957Sgabeblack@google.com case RXDT_LEGACY: 98611957Sgabeblack@google.com desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup)); 98711957Sgabeblack@google.com desc->legacy.status = htole(status); 98811957Sgabeblack@google.com desc->legacy.errors = htole(err); 98911957Sgabeblack@google.com // No vlan support at this point... just set it to 0 99011957Sgabeblack@google.com desc->legacy.vlan = 0; 99111957Sgabeblack@google.com break; 99211957Sgabeblack@google.com case RXDT_ADV_SPLIT_A: 99311957Sgabeblack@google.com case RXDT_ADV_ONEBUF: 99411957Sgabeblack@google.com desc->adv_wb.rss_type = htole(0); 99511957Sgabeblack@google.com desc->adv_wb.pkt_type = htole(ptype); 99611957Sgabeblack@google.com if (igbe->regs.rxcsum.pcsd()) { 99711957Sgabeblack@google.com // no rss support right now 99811957Sgabeblack@google.com desc->adv_wb.rss_hash = htole(0); 99911957Sgabeblack@google.com } else { 100011957Sgabeblack@google.com desc->adv_wb.id = htole(ip_id); 100111957Sgabeblack@google.com desc->adv_wb.csum = htole(csum); 100211957Sgabeblack@google.com } 100311957Sgabeblack@google.com desc->adv_wb.status = htole(status); 100411957Sgabeblack@google.com desc->adv_wb.errors = htole(ext_err); 100511957Sgabeblack@google.com // no vlan support 100611957Sgabeblack@google.com desc->adv_wb.vlan_tag = htole(0); 100711957Sgabeblack@google.com break; 100811957Sgabeblack@google.com default: 100911957Sgabeblack@google.com panic("Unimplemnted RX receive buffer type %d\n", 101011957Sgabeblack@google.com igbe->regs.srrctl.desctype()); 101111957Sgabeblack@google.com } 101211957Sgabeblack@google.com 101311957Sgabeblack@google.com DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n", 101411957Sgabeblack@google.com desc->adv_read.pkt, desc->adv_read.hdr); 101511957Sgabeblack@google.com 101611957Sgabeblack@google.com if (bytesCopied == pktPtr->length) { 101711957Sgabeblack@google.com DPRINTF(EthernetDesc, "Packet completely written to descriptor buffers\n"); 101811957Sgabeblack@google.com // Deal with the rx timer interrupts 101911957Sgabeblack@google.com if (igbe->regs.rdtr.delay()) { 102011957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", 102111957Sgabeblack@google.com igbe->regs.rdtr.delay() * igbe->intClock()); 102211957Sgabeblack@google.com igbe->reschedule(igbe->rdtrEvent, 102311957Sgabeblack@google.com curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true); 102411957Sgabeblack@google.com } 102511957Sgabeblack@google.com 102611957Sgabeblack@google.com if (igbe->regs.radv.idv()) { 102711957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", 102811957Sgabeblack@google.com igbe->regs.radv.idv() * igbe->intClock()); 102911957Sgabeblack@google.com if (!igbe->radvEvent.scheduled()) { 103011957Sgabeblack@google.com igbe->schedule(igbe->radvEvent, 103111957Sgabeblack@google.com curTick + igbe->regs.radv.idv() * igbe->intClock()); 103211957Sgabeblack@google.com } 103311957Sgabeblack@google.com } 103411957Sgabeblack@google.com 103511957Sgabeblack@google.com // if neither radv or rdtr, maybe itr is set... 103611957Sgabeblack@google.com if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) { 103711957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); 103811957Sgabeblack@google.com igbe->postInterrupt(IT_RXT); 103911957Sgabeblack@google.com } 104011957Sgabeblack@google.com 104111957Sgabeblack@google.com // If the packet is small enough, interrupt appropriately 104211957Sgabeblack@google.com // I wonder if this is delayed or not?! 104311957Sgabeblack@google.com if (pktPtr->length <= igbe->regs.rsrpd.idv()) { 104411957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); 104511957Sgabeblack@google.com igbe->postInterrupt(IT_SRPD); 104611957Sgabeblack@google.com } 104711957Sgabeblack@google.com bytesCopied = 0; 104811957Sgabeblack@google.com } 104911957Sgabeblack@google.com 105011957Sgabeblack@google.com pktPtr = NULL; 105111957Sgabeblack@google.com igbe->checkDrain(); 105211957Sgabeblack@google.com enableSm(); 105311957Sgabeblack@google.com pktDone = true; 105411957Sgabeblack@google.com 105511957Sgabeblack@google.com DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); 105611957Sgabeblack@google.com unusedCache.pop_front(); 105711957Sgabeblack@google.com usedCache.push_back(desc); 105811957Sgabeblack@google.com} 105911957Sgabeblack@google.com 106011957Sgabeblack@google.comvoid 106111957Sgabeblack@google.comIGbE::RxDescCache::enableSm() 106211957Sgabeblack@google.com{ 106311957Sgabeblack@google.com if (!igbe->drainEvent) { 106411957Sgabeblack@google.com igbe->rxTick = true; 106511957Sgabeblack@google.com igbe->restartClock(); 106611957Sgabeblack@google.com } 106711957Sgabeblack@google.com} 106811957Sgabeblack@google.com 106911957Sgabeblack@google.combool 107011957Sgabeblack@google.comIGbE::RxDescCache::packetDone() 107111957Sgabeblack@google.com{ 107211957Sgabeblack@google.com if (pktDone) { 107311957Sgabeblack@google.com pktDone = false; 107411957Sgabeblack@google.com return true; 107511957Sgabeblack@google.com } 107611957Sgabeblack@google.com return false; 107711957Sgabeblack@google.com} 107811957Sgabeblack@google.com 107911957Sgabeblack@google.combool 108011957Sgabeblack@google.comIGbE::RxDescCache::hasOutstandingEvents() 108111957Sgabeblack@google.com{ 108211957Sgabeblack@google.com return pktEvent.scheduled() || wbEvent.scheduled() || 108311957Sgabeblack@google.com fetchEvent.scheduled() || pktHdrEvent.scheduled() || 108411957Sgabeblack@google.com pktDataEvent.scheduled(); 108511957Sgabeblack@google.com 108611957Sgabeblack@google.com} 108711957Sgabeblack@google.com 108811957Sgabeblack@google.comvoid 108911957Sgabeblack@google.comIGbE::RxDescCache::serialize(std::ostream &os) 109011957Sgabeblack@google.com{ 109111957Sgabeblack@google.com DescCache<RxDesc>::serialize(os); 109211957Sgabeblack@google.com SERIALIZE_SCALAR(pktDone); 109311957Sgabeblack@google.com SERIALIZE_SCALAR(splitCount); 109411957Sgabeblack@google.com SERIALIZE_SCALAR(bytesCopied); 109511957Sgabeblack@google.com} 109611957Sgabeblack@google.com 109711957Sgabeblack@google.comvoid 109811957Sgabeblack@google.comIGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion) 109911957Sgabeblack@google.com{ 110011957Sgabeblack@google.com DescCache<RxDesc>::unserialize(cp, section); 110111957Sgabeblack@google.com UNSERIALIZE_SCALAR(pktDone); 110211957Sgabeblack@google.com UNSERIALIZE_SCALAR(splitCount); 110311957Sgabeblack@google.com UNSERIALIZE_SCALAR(bytesCopied); 110411957Sgabeblack@google.com} 110511957Sgabeblack@google.com 110611957Sgabeblack@google.com 110711957Sgabeblack@google.com///////////////////////////////////// IGbE::TxDesc ///////////////////////////////// 110811957Sgabeblack@google.com 110911957Sgabeblack@google.comIGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) 111011957Sgabeblack@google.com : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false), 111111957Sgabeblack@google.com useTso(false), pktEvent(this), headerEvent(this), nullEvent(this) 111211957Sgabeblack@google.com 111311957Sgabeblack@google.com{ 111411957Sgabeblack@google.com} 111511957Sgabeblack@google.com 111611957Sgabeblack@google.comvoid 111711957Sgabeblack@google.comIGbE::TxDescCache::processContextDesc() 111811957Sgabeblack@google.com{ 111911957Sgabeblack@google.com assert(unusedCache.size()); 112011957Sgabeblack@google.com TxDesc *desc; 112111957Sgabeblack@google.com 112211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Checking and processing context descriptors\n"); 112311957Sgabeblack@google.com 112411957Sgabeblack@google.com while (!useTso && unusedCache.size() && TxdOp::isContext(unusedCache.front())) { 112511957Sgabeblack@google.com DPRINTF(EthernetDesc, "Got context descriptor type...\n"); 112611957Sgabeblack@google.com 112711957Sgabeblack@google.com desc = unusedCache.front(); 112811957Sgabeblack@google.com DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", 112911957Sgabeblack@google.com desc->d1, desc->d2); 113011957Sgabeblack@google.com 113111957Sgabeblack@google.com 113211957Sgabeblack@google.com // is this going to be a tcp or udp packet? 113311957Sgabeblack@google.com isTcp = TxdOp::tcp(desc) ? true : false; 113411957Sgabeblack@google.com 113511957Sgabeblack@google.com // setup all the TSO variables, they'll be ignored if we don't use 113611957Sgabeblack@google.com // tso for this connection 113711957Sgabeblack@google.com tsoHeaderLen = TxdOp::hdrlen(desc); 113811957Sgabeblack@google.com tsoMss = TxdOp::mss(desc); 113911957Sgabeblack@google.com 114011957Sgabeblack@google.com if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) { 114111957Sgabeblack@google.com DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n", 114211957Sgabeblack@google.com TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc)); 114311957Sgabeblack@google.com useTso = true; 114411957Sgabeblack@google.com tsoTotalLen = TxdOp::getLen(desc); 114511957Sgabeblack@google.com tsoLoadedHeader = false; 114611957Sgabeblack@google.com tsoDescBytesUsed = 0; 114711957Sgabeblack@google.com tsoUsedLen = 0; 114811957Sgabeblack@google.com tsoPrevSeq = 0; 114911957Sgabeblack@google.com tsoPktHasHeader = false; 115011957Sgabeblack@google.com tsoPkts = 0; 115111957Sgabeblack@google.com 115211957Sgabeblack@google.com } 115311957Sgabeblack@google.com 115411957Sgabeblack@google.com TxdOp::setDd(desc); 115511957Sgabeblack@google.com unusedCache.pop_front(); 115611957Sgabeblack@google.com usedCache.push_back(desc); 115711957Sgabeblack@google.com } 115811957Sgabeblack@google.com 115911957Sgabeblack@google.com if (!unusedCache.size()) 116011957Sgabeblack@google.com return; 116111957Sgabeblack@google.com 116211957Sgabeblack@google.com desc = unusedCache.front(); 116311957Sgabeblack@google.com if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) { 116411957Sgabeblack@google.com DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n", 116511957Sgabeblack@google.com tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc)); 116611957Sgabeblack@google.com useTso = true; 116711957Sgabeblack@google.com tsoTotalLen = TxdOp::getTsoLen(desc); 116811957Sgabeblack@google.com tsoLoadedHeader = false; 116911957Sgabeblack@google.com tsoDescBytesUsed = 0; 117011957Sgabeblack@google.com tsoUsedLen = 0; 117111957Sgabeblack@google.com tsoPrevSeq = 0; 117211957Sgabeblack@google.com tsoPktHasHeader = false; 117311957Sgabeblack@google.com tsoPkts = 0; 117411957Sgabeblack@google.com } 117511957Sgabeblack@google.com 117611957Sgabeblack@google.com if (useTso && !tsoLoadedHeader) { 117711957Sgabeblack@google.com // we need to fetch a header 117811957Sgabeblack@google.com DPRINTF(EthernetDesc, "Starting DMA of TSO header\n"); 117911957Sgabeblack@google.com assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen); 118011957Sgabeblack@google.com pktWaiting = true; 118111957Sgabeblack@google.com assert(tsoHeaderLen <= 256); 118211957Sgabeblack@google.com igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), 118311957Sgabeblack@google.com tsoHeaderLen, &headerEvent, tsoHeader, 0); 118411957Sgabeblack@google.com } 118511957Sgabeblack@google.com} 118611957Sgabeblack@google.com 118711957Sgabeblack@google.comvoid 118811957Sgabeblack@google.comIGbE::TxDescCache::headerComplete() 118911957Sgabeblack@google.com{ 119011957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n"); 119111957Sgabeblack@google.com pktWaiting = false; 119211957Sgabeblack@google.com 119311957Sgabeblack@google.com assert(unusedCache.size()); 119411957Sgabeblack@google.com TxDesc *desc = unusedCache.front(); 119511957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n", 119611957Sgabeblack@google.com TxdOp::getLen(desc), tsoHeaderLen); 119711957Sgabeblack@google.com 119811957Sgabeblack@google.com if (TxdOp::getLen(desc) == tsoHeaderLen) { 119911957Sgabeblack@google.com tsoDescBytesUsed = 0; 120011957Sgabeblack@google.com tsoLoadedHeader = true; 120111957Sgabeblack@google.com unusedCache.pop_front(); 120211957Sgabeblack@google.com usedCache.push_back(desc); 120311957Sgabeblack@google.com } else { 120411957Sgabeblack@google.com // I don't think this case happens, I think the headrer is always 120511957Sgabeblack@google.com // it's own packet, if it wasn't it might be as simple as just 120611957Sgabeblack@google.com // incrementing descBytesUsed by the header length, but I'm not 120711957Sgabeblack@google.com // completely sure 120811957Sgabeblack@google.com panic("TSO header part of bigger packet, not implemented\n"); 120911957Sgabeblack@google.com } 121011957Sgabeblack@google.com enableSm(); 121111957Sgabeblack@google.com igbe->checkDrain(); 121211957Sgabeblack@google.com} 121311957Sgabeblack@google.com 121411957Sgabeblack@google.comint 121511957Sgabeblack@google.comIGbE::TxDescCache::getPacketSize(EthPacketPtr p) 121611957Sgabeblack@google.com{ 121711957Sgabeblack@google.com TxDesc *desc; 121811957Sgabeblack@google.com 121911957Sgabeblack@google.com 122011957Sgabeblack@google.com if (!unusedCache.size()) 122111957Sgabeblack@google.com return -1; 122211957Sgabeblack@google.com 122311957Sgabeblack@google.com DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); 122411957Sgabeblack@google.com 122511957Sgabeblack@google.com assert(!useTso || tsoLoadedHeader); 122611957Sgabeblack@google.com desc = unusedCache.front(); 122711957Sgabeblack@google.com 122811957Sgabeblack@google.com 122911957Sgabeblack@google.com if (useTso) { 123011957Sgabeblack@google.com DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 123111957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n", 123211957Sgabeblack@google.com useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader); 123311957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d this descLen: %d\n", 123411957Sgabeblack@google.com tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc)); 123511957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader); 123611957Sgabeblack@google.com 123711957Sgabeblack@google.com if (tsoPktHasHeader) 123811957Sgabeblack@google.com tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length, TxdOp::getLen(desc) - tsoDescBytesUsed); 123911957Sgabeblack@google.com else 124011957Sgabeblack@google.com tsoCopyBytes = std::min(tsoMss, TxdOp::getLen(desc) - tsoDescBytesUsed); 124111957Sgabeblack@google.com Addr pkt_size = tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen); 124211957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size); 124311957Sgabeblack@google.com return pkt_size; 124411957Sgabeblack@google.com } 124511957Sgabeblack@google.com 124611957Sgabeblack@google.com DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", 124711957Sgabeblack@google.com TxdOp::getLen(unusedCache.front())); 124811957Sgabeblack@google.com return TxdOp::getLen(desc); 124911957Sgabeblack@google.com} 125011957Sgabeblack@google.com 125111957Sgabeblack@google.comvoid 125211957Sgabeblack@google.comIGbE::TxDescCache::getPacketData(EthPacketPtr p) 125311957Sgabeblack@google.com{ 125411957Sgabeblack@google.com assert(unusedCache.size()); 125511957Sgabeblack@google.com 125611957Sgabeblack@google.com TxDesc *desc; 125711957Sgabeblack@google.com desc = unusedCache.front(); 125811957Sgabeblack@google.com 125911957Sgabeblack@google.com DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 126011957Sgabeblack@google.com assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); 126111957Sgabeblack@google.com 126211957Sgabeblack@google.com pktPtr = p; 126311957Sgabeblack@google.com 126411957Sgabeblack@google.com pktWaiting = true; 126511957Sgabeblack@google.com 126611957Sgabeblack@google.com DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); 126711957Sgabeblack@google.com 126811957Sgabeblack@google.com if (useTso) { 126911957Sgabeblack@google.com assert(tsoLoadedHeader); 127011957Sgabeblack@google.com if (!tsoPktHasHeader) { 127111957Sgabeblack@google.com DPRINTF(EthernetDesc, "Loading TSO header (%d bytes) into start of packet\n", 127211957Sgabeblack@google.com tsoHeaderLen); 127311957Sgabeblack@google.com memcpy(p->data, &tsoHeader,tsoHeaderLen); 127411957Sgabeblack@google.com p->length +=tsoHeaderLen; 127511957Sgabeblack@google.com tsoPktHasHeader = true; 127611957Sgabeblack@google.com } 127711957Sgabeblack@google.com } 127811957Sgabeblack@google.com 127911957Sgabeblack@google.com if (useTso) { 128011957Sgabeblack@google.com tsoDescBytesUsed += tsoCopyBytes; 128111957Sgabeblack@google.com assert(tsoDescBytesUsed <= TxdOp::getLen(desc)); 128211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d length: %d\n", 128311957Sgabeblack@google.com p->length, tsoCopyBytes); 128411957Sgabeblack@google.com igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)) + tsoDescBytesUsed, 128511957Sgabeblack@google.com tsoCopyBytes, &pktEvent, p->data + p->length, igbe->txReadDelay); 128611957Sgabeblack@google.com } else { 128711957Sgabeblack@google.com igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), 128811957Sgabeblack@google.com TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay); 128911957Sgabeblack@google.com } 129011957Sgabeblack@google.com} 129111957Sgabeblack@google.com 129211957Sgabeblack@google.comvoid 129311957Sgabeblack@google.comIGbE::TxDescCache::pktComplete() 129411957Sgabeblack@google.com{ 129511957Sgabeblack@google.com 129611957Sgabeblack@google.com TxDesc *desc; 129711957Sgabeblack@google.com assert(unusedCache.size()); 129811957Sgabeblack@google.com assert(pktPtr); 129911957Sgabeblack@google.com 130011957Sgabeblack@google.com DPRINTF(EthernetDesc, "DMA of packet complete\n"); 130111957Sgabeblack@google.com 130211957Sgabeblack@google.com 130311957Sgabeblack@google.com desc = unusedCache.front(); 130411957Sgabeblack@google.com assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); 130511957Sgabeblack@google.com 130611957Sgabeblack@google.com DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 130711957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n", 130811957Sgabeblack@google.com useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader); 130911957Sgabeblack@google.com 131011957Sgabeblack@google.com // Set the length of the data in the EtherPacket 131111957Sgabeblack@google.com if (useTso) { 131211957Sgabeblack@google.com pktPtr->length += tsoCopyBytes; 131311957Sgabeblack@google.com tsoUsedLen += tsoCopyBytes; 131411957Sgabeblack@google.com } else 131511957Sgabeblack@google.com pktPtr->length += TxdOp::getLen(desc); 131611957Sgabeblack@google.com 131711957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n", 131811957Sgabeblack@google.com tsoDescBytesUsed, tsoCopyBytes); 131911957Sgabeblack@google.com 132011957Sgabeblack@google.com 132111957Sgabeblack@google.com if ((!TxdOp::eop(desc) && !useTso) || 132211957Sgabeblack@google.com (pktPtr->length < ( tsoMss + tsoHeaderLen) && tsoTotalLen != tsoUsedLen)) { 132311957Sgabeblack@google.com assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc))); 132411957Sgabeblack@google.com unusedCache.pop_front(); 132511957Sgabeblack@google.com usedCache.push_back(desc); 132611957Sgabeblack@google.com 132711957Sgabeblack@google.com tsoDescBytesUsed = 0; 132811957Sgabeblack@google.com pktDone = true; 132911957Sgabeblack@google.com pktWaiting = false; 133011957Sgabeblack@google.com pktMultiDesc = true; 133111957Sgabeblack@google.com 133211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n", 133311957Sgabeblack@google.com pktPtr->length); 133411957Sgabeblack@google.com pktPtr = NULL; 133511957Sgabeblack@google.com 133611957Sgabeblack@google.com enableSm(); 133711957Sgabeblack@google.com igbe->checkDrain(); 133811957Sgabeblack@google.com return; 133911957Sgabeblack@google.com } 134011957Sgabeblack@google.com 134111957Sgabeblack@google.com 134211957Sgabeblack@google.com pktMultiDesc = false; 134311957Sgabeblack@google.com // no support for vlans 134411957Sgabeblack@google.com assert(!TxdOp::vle(desc)); 134511957Sgabeblack@google.com 134611957Sgabeblack@google.com // we only support single packet descriptors at this point 134711957Sgabeblack@google.com if (!useTso) 134811957Sgabeblack@google.com assert(TxdOp::eop(desc)); 134911957Sgabeblack@google.com 135011957Sgabeblack@google.com // set that this packet is done 135111957Sgabeblack@google.com if (TxdOp::rs(desc)) 135211957Sgabeblack@google.com TxdOp::setDd(desc); 135311957Sgabeblack@google.com 135411957Sgabeblack@google.com DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); 135511957Sgabeblack@google.com 135611957Sgabeblack@google.com if (useTso) { 135711957Sgabeblack@google.com IpPtr ip(pktPtr); 135811957Sgabeblack@google.com if (ip) { 135911957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n", 136011957Sgabeblack@google.com tsoPkts); 136111957Sgabeblack@google.com ip->id(ip->id() + tsoPkts++); 136211957Sgabeblack@google.com ip->len(pktPtr->length - EthPtr(pktPtr)->size()); 136311957Sgabeblack@google.com 136411957Sgabeblack@google.com TcpPtr tcp(ip); 136511957Sgabeblack@google.com if (tcp) { 136611957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: Modifying TCP header. old seq %d + %d\n", 136711957Sgabeblack@google.com tcp->seq(), tsoPrevSeq); 136811957Sgabeblack@google.com tcp->seq(tcp->seq() + tsoPrevSeq); 136911957Sgabeblack@google.com if (tsoUsedLen != tsoTotalLen) 137011957Sgabeblack@google.com tcp->flags(tcp->flags() & ~9); // clear fin & psh 137111957Sgabeblack@google.com } 137211957Sgabeblack@google.com UdpPtr udp(ip); 137311957Sgabeblack@google.com if (udp) { 137411957Sgabeblack@google.com DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n"); 137511957Sgabeblack@google.com udp->len(pktPtr->length - EthPtr(pktPtr)->size()); 137611957Sgabeblack@google.com } 137711957Sgabeblack@google.com } 137811957Sgabeblack@google.com tsoPrevSeq = tsoUsedLen; 137911957Sgabeblack@google.com } 138011957Sgabeblack@google.com 138111957Sgabeblack@google.com if (DTRACE(EthernetDesc)) { 138211957Sgabeblack@google.com IpPtr ip(pktPtr); 138311957Sgabeblack@google.com if (ip) 138411957Sgabeblack@google.com DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", 138511957Sgabeblack@google.com ip->id()); 138611957Sgabeblack@google.com else 138711957Sgabeblack@google.com DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); 138811957Sgabeblack@google.com } 138911957Sgabeblack@google.com 139011957Sgabeblack@google.com // Checksums are only ofloaded for new descriptor types 139111957Sgabeblack@google.com if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { 139211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); 139311957Sgabeblack@google.com IpPtr ip(pktPtr); 139411957Sgabeblack@google.com assert(ip); 139511957Sgabeblack@google.com if (TxdOp::ixsm(desc)) { 139611957Sgabeblack@google.com ip->sum(0); 139711957Sgabeblack@google.com ip->sum(cksum(ip)); 139811957Sgabeblack@google.com igbe->txIpChecksums++; 139911957Sgabeblack@google.com DPRINTF(EthernetDesc, "Calculated IP checksum\n"); 140011957Sgabeblack@google.com } 140111957Sgabeblack@google.com if (TxdOp::txsm(desc)) { 140211957Sgabeblack@google.com TcpPtr tcp(ip); 140311957Sgabeblack@google.com UdpPtr udp(ip); 140411957Sgabeblack@google.com if (tcp) { 140511957Sgabeblack@google.com tcp->sum(0); 140611957Sgabeblack@google.com tcp->sum(cksum(tcp)); 140711957Sgabeblack@google.com igbe->txTcpChecksums++; 140811957Sgabeblack@google.com DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); 140911957Sgabeblack@google.com } else if (udp) { 141011957Sgabeblack@google.com assert(udp); 141111957Sgabeblack@google.com udp->sum(0); 141211957Sgabeblack@google.com udp->sum(cksum(udp)); 141311957Sgabeblack@google.com igbe->txUdpChecksums++; 141411957Sgabeblack@google.com DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); 141511957Sgabeblack@google.com } else { 141611957Sgabeblack@google.com panic("Told to checksum, but don't know how\n"); 141711957Sgabeblack@google.com } 141811957Sgabeblack@google.com } 141911957Sgabeblack@google.com } 142011957Sgabeblack@google.com 142111957Sgabeblack@google.com if (TxdOp::ide(desc)) { 142211957Sgabeblack@google.com // Deal with the rx timer interrupts 142311957Sgabeblack@google.com DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); 142411957Sgabeblack@google.com if (igbe->regs.tidv.idv()) { 142511957Sgabeblack@google.com DPRINTF(EthernetDesc, "setting tidv\n"); 142611957Sgabeblack@google.com igbe->reschedule(igbe->tidvEvent, 142711957Sgabeblack@google.com curTick + igbe->regs.tidv.idv() * igbe->intClock(), true); 142811957Sgabeblack@google.com } 142911957Sgabeblack@google.com 143011957Sgabeblack@google.com if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { 143111957Sgabeblack@google.com DPRINTF(EthernetDesc, "setting tadv\n"); 143211957Sgabeblack@google.com if (!igbe->tadvEvent.scheduled()) { 143311957Sgabeblack@google.com igbe->schedule(igbe->tadvEvent, 143411957Sgabeblack@google.com curTick + igbe->regs.tadv.idv() * igbe->intClock()); 143511957Sgabeblack@google.com } 143611957Sgabeblack@google.com } 143711957Sgabeblack@google.com } 143811957Sgabeblack@google.com 143911957Sgabeblack@google.com 144011957Sgabeblack@google.com if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) { 144111957Sgabeblack@google.com DPRINTF(EthernetDesc, "Descriptor Done\n"); 144211957Sgabeblack@google.com unusedCache.pop_front(); 144311957Sgabeblack@google.com usedCache.push_back(desc); 144411957Sgabeblack@google.com tsoDescBytesUsed = 0; 144511957Sgabeblack@google.com } 144611957Sgabeblack@google.com 144711957Sgabeblack@google.com if (useTso && tsoUsedLen == tsoTotalLen) 144811957Sgabeblack@google.com useTso = false; 144911957Sgabeblack@google.com 145011957Sgabeblack@google.com 145111957Sgabeblack@google.com DPRINTF(EthernetDesc, "------Packet of %d bytes ready for transmission-------\n", 145211957Sgabeblack@google.com pktPtr->length); 145311957Sgabeblack@google.com pktDone = true; 145411957Sgabeblack@google.com pktWaiting = false; 145511957Sgabeblack@google.com pktPtr = NULL; 145611957Sgabeblack@google.com tsoPktHasHeader = false; 145711957Sgabeblack@google.com 145811957Sgabeblack@google.com if (igbe->regs.txdctl.wthresh() == 0) { 145911957Sgabeblack@google.com DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); 146011957Sgabeblack@google.com writeback(0); 146111957Sgabeblack@google.com } else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >= 146211957Sgabeblack@google.com descInBlock(usedCache.size())) { 146311957Sgabeblack@google.com DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); 146411957Sgabeblack@google.com writeback((igbe->cacheBlockSize()-1)>>4); 146511957Sgabeblack@google.com } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) { 146611957Sgabeblack@google.com DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); 146711957Sgabeblack@google.com writeback((igbe->cacheBlockSize()-1)>>4); 146811957Sgabeblack@google.com } 146911957Sgabeblack@google.com 147011957Sgabeblack@google.com enableSm(); 147111957Sgabeblack@google.com igbe->checkDrain(); 147211957Sgabeblack@google.com} 147311957Sgabeblack@google.com 147411957Sgabeblack@google.comvoid 147511957Sgabeblack@google.comIGbE::TxDescCache::actionAfterWb() 147611957Sgabeblack@google.com{ 147711957Sgabeblack@google.com DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n", 147811957Sgabeblack@google.com completionEnabled); 147911957Sgabeblack@google.com igbe->postInterrupt(iGbReg::IT_TXDW); 148011957Sgabeblack@google.com if (completionEnabled) { 148111957Sgabeblack@google.com descEnd = igbe->regs.tdh(); 148211957Sgabeblack@google.com DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd, 148311957Sgabeblack@google.com completionAddress); 148411957Sgabeblack@google.com igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)), 148511957Sgabeblack@google.com sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0); 148611957Sgabeblack@google.com } 148711957Sgabeblack@google.com} 148811957Sgabeblack@google.com 148911957Sgabeblack@google.comvoid 149011957Sgabeblack@google.comIGbE::TxDescCache::serialize(std::ostream &os) 149111957Sgabeblack@google.com{ 149211957Sgabeblack@google.com DescCache<TxDesc>::serialize(os); 149311957Sgabeblack@google.com SERIALIZE_SCALAR(pktDone); 149411957Sgabeblack@google.com SERIALIZE_SCALAR(isTcp); 149511957Sgabeblack@google.com SERIALIZE_SCALAR(pktWaiting); 149611957Sgabeblack@google.com SERIALIZE_SCALAR(pktMultiDesc); 149711957Sgabeblack@google.com 149811957Sgabeblack@google.com SERIALIZE_SCALAR(useTso); 149911957Sgabeblack@google.com SERIALIZE_SCALAR(tsoHeaderLen); 150011957Sgabeblack@google.com SERIALIZE_SCALAR(tsoMss); 150111957Sgabeblack@google.com SERIALIZE_SCALAR(tsoTotalLen); 150211957Sgabeblack@google.com SERIALIZE_SCALAR(tsoUsedLen); 150311957Sgabeblack@google.com SERIALIZE_SCALAR(tsoPrevSeq);; 150411957Sgabeblack@google.com SERIALIZE_SCALAR(tsoPktPayloadBytes); 150511957Sgabeblack@google.com SERIALIZE_SCALAR(tsoLoadedHeader); 150611957Sgabeblack@google.com SERIALIZE_SCALAR(tsoPktHasHeader); 150711957Sgabeblack@google.com SERIALIZE_ARRAY(tsoHeader, 256); 150811957Sgabeblack@google.com SERIALIZE_SCALAR(tsoDescBytesUsed); 150911957Sgabeblack@google.com SERIALIZE_SCALAR(tsoCopyBytes); 151011957Sgabeblack@google.com SERIALIZE_SCALAR(tsoPkts); 151111957Sgabeblack@google.com 151211957Sgabeblack@google.com SERIALIZE_SCALAR(completionAddress); 151311957Sgabeblack@google.com SERIALIZE_SCALAR(completionEnabled); 151411957Sgabeblack@google.com SERIALIZE_SCALAR(descEnd); 151511957Sgabeblack@google.com} 151611957Sgabeblack@google.com 151711957Sgabeblack@google.comvoid 151811957Sgabeblack@google.comIGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion) 151911957Sgabeblack@google.com{ 152011957Sgabeblack@google.com DescCache<TxDesc>::unserialize(cp, section); 152111957Sgabeblack@google.com UNSERIALIZE_SCALAR(pktDone); 152211957Sgabeblack@google.com UNSERIALIZE_SCALAR(isTcp); 152311957Sgabeblack@google.com UNSERIALIZE_SCALAR(pktWaiting); 152411957Sgabeblack@google.com UNSERIALIZE_SCALAR(pktMultiDesc); 152511957Sgabeblack@google.com 152611957Sgabeblack@google.com UNSERIALIZE_SCALAR(useTso); 152711957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoHeaderLen); 152811957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoMss); 152911957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoTotalLen); 153011957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoUsedLen); 153111957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoPrevSeq);; 153211957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoPktPayloadBytes); 153311957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoLoadedHeader); 153411957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoPktHasHeader); 153511957Sgabeblack@google.com UNSERIALIZE_ARRAY(tsoHeader, 256); 153611957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoDescBytesUsed); 153711957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoCopyBytes); 153811957Sgabeblack@google.com UNSERIALIZE_SCALAR(tsoPkts); 153911957Sgabeblack@google.com 154011957Sgabeblack@google.com UNSERIALIZE_SCALAR(completionAddress); 154111957Sgabeblack@google.com UNSERIALIZE_SCALAR(completionEnabled); 154211957Sgabeblack@google.com UNSERIALIZE_SCALAR(descEnd); 154311957Sgabeblack@google.com} 154411957Sgabeblack@google.com 154511957Sgabeblack@google.combool 154611957Sgabeblack@google.comIGbE::TxDescCache::packetAvailable() 154711957Sgabeblack@google.com{ 154811957Sgabeblack@google.com if (pktDone) { 154911957Sgabeblack@google.com pktDone = false; 155011957Sgabeblack@google.com return true; 155111957Sgabeblack@google.com } 155211957Sgabeblack@google.com return false; 155311957Sgabeblack@google.com} 155411957Sgabeblack@google.com 155511957Sgabeblack@google.comvoid 155611957Sgabeblack@google.comIGbE::TxDescCache::enableSm() 155711957Sgabeblack@google.com{ 155811957Sgabeblack@google.com if (!igbe->drainEvent) { 155911957Sgabeblack@google.com igbe->txTick = true; 156011957Sgabeblack@google.com igbe->restartClock(); 156111957Sgabeblack@google.com } 156211957Sgabeblack@google.com} 156311957Sgabeblack@google.com 156411957Sgabeblack@google.combool 156511957Sgabeblack@google.comIGbE::TxDescCache::hasOutstandingEvents() 156611957Sgabeblack@google.com{ 156711957Sgabeblack@google.com return pktEvent.scheduled() || wbEvent.scheduled() || 156811957Sgabeblack@google.com fetchEvent.scheduled(); 156911957Sgabeblack@google.com} 157011957Sgabeblack@google.com 157111957Sgabeblack@google.com 157211957Sgabeblack@google.com///////////////////////////////////// IGbE ///////////////////////////////// 157311957Sgabeblack@google.com 157411957Sgabeblack@google.comvoid 157511957Sgabeblack@google.comIGbE::restartClock() 157611957Sgabeblack@google.com{ 157711957Sgabeblack@google.com if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && 157811957Sgabeblack@google.com getState() == SimObject::Running) 157911957Sgabeblack@google.com schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1)); 158011957Sgabeblack@google.com} 158111957Sgabeblack@google.com 158211957Sgabeblack@google.comunsigned int 158311957Sgabeblack@google.comIGbE::drain(Event *de) 158411957Sgabeblack@google.com{ 158511957Sgabeblack@google.com unsigned int count; 158611957Sgabeblack@google.com count = pioPort->drain(de) + dmaPort->drain(de); 158711957Sgabeblack@google.com if (rxDescCache.hasOutstandingEvents() || 158811957Sgabeblack@google.com txDescCache.hasOutstandingEvents()) { 158911957Sgabeblack@google.com count++; 159011957Sgabeblack@google.com drainEvent = de; 159111957Sgabeblack@google.com } 159211957Sgabeblack@google.com 159311957Sgabeblack@google.com txFifoTick = false; 159411957Sgabeblack@google.com txTick = false; 159511957Sgabeblack@google.com rxTick = false; 159611957Sgabeblack@google.com 159711957Sgabeblack@google.com if (tickEvent.scheduled()) 159811957Sgabeblack@google.com deschedule(tickEvent); 159911957Sgabeblack@google.com 160011957Sgabeblack@google.com if (count) 160111957Sgabeblack@google.com changeState(Draining); 160211957Sgabeblack@google.com else 160311957Sgabeblack@google.com changeState(Drained); 160411957Sgabeblack@google.com 160511957Sgabeblack@google.com return count; 160611957Sgabeblack@google.com} 160711957Sgabeblack@google.com 160811957Sgabeblack@google.comvoid 160911957Sgabeblack@google.comIGbE::resume() 161011957Sgabeblack@google.com{ 161111957Sgabeblack@google.com SimObject::resume(); 161211957Sgabeblack@google.com 161311957Sgabeblack@google.com txFifoTick = true; 161411957Sgabeblack@google.com txTick = true; 161511957Sgabeblack@google.com rxTick = true; 161611957Sgabeblack@google.com 161711957Sgabeblack@google.com restartClock(); 161811957Sgabeblack@google.com} 161911957Sgabeblack@google.com 162011957Sgabeblack@google.comvoid 162111957Sgabeblack@google.comIGbE::checkDrain() 162211957Sgabeblack@google.com{ 162311957Sgabeblack@google.com if (!drainEvent) 162411957Sgabeblack@google.com return; 162511957Sgabeblack@google.com 162611957Sgabeblack@google.com txFifoTick = false; 162711957Sgabeblack@google.com txTick = false; 162811957Sgabeblack@google.com rxTick = false; 162911957Sgabeblack@google.com if (!rxDescCache.hasOutstandingEvents() && 163011957Sgabeblack@google.com !txDescCache.hasOutstandingEvents()) { 163111957Sgabeblack@google.com drainEvent->process(); 163211957Sgabeblack@google.com drainEvent = NULL; 163311957Sgabeblack@google.com } 163411957Sgabeblack@google.com} 163511957Sgabeblack@google.com 163611957Sgabeblack@google.comvoid 163711957Sgabeblack@google.comIGbE::txStateMachine() 163811957Sgabeblack@google.com{ 163911957Sgabeblack@google.com if (!regs.tctl.en()) { 164011957Sgabeblack@google.com txTick = false; 164111957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n"); 164211957Sgabeblack@google.com return; 164311957Sgabeblack@google.com } 164411957Sgabeblack@google.com 164511957Sgabeblack@google.com // If we have a packet available and it's length is not 0 (meaning it's not 164611957Sgabeblack@google.com // a multidescriptor packet) put it in the fifo, otherwise an the next 164711957Sgabeblack@google.com // iteration we'll get the rest of the data 164811957Sgabeblack@google.com if (txPacket && txDescCache.packetAvailable() 164911957Sgabeblack@google.com && !txDescCache.packetMultiDesc() && txPacket->length) { 165011957Sgabeblack@google.com bool success; 165111957Sgabeblack@google.com 165211957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); 165311957Sgabeblack@google.com success = txFifo.push(txPacket); 165411957Sgabeblack@google.com txFifoTick = true && !drainEvent; 165511957Sgabeblack@google.com assert(success); 165611957Sgabeblack@google.com txPacket = NULL; 165711957Sgabeblack@google.com txDescCache.writeback((cacheBlockSize()-1)>>4); 165811957Sgabeblack@google.com return; 165911957Sgabeblack@google.com } 166011957Sgabeblack@google.com 166111957Sgabeblack@google.com // Only support descriptor granularity 166211957Sgabeblack@google.com if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) { 166311957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n"); 166411957Sgabeblack@google.com postInterrupt(IT_TXDLOW); 166511957Sgabeblack@google.com } 166611957Sgabeblack@google.com 166711957Sgabeblack@google.com if (!txPacket) { 166811957Sgabeblack@google.com txPacket = new EthPacketData(16384); 166911957Sgabeblack@google.com } 167011957Sgabeblack@google.com 167111957Sgabeblack@google.com if (!txDescCache.packetWaiting()) { 167211957Sgabeblack@google.com if (txDescCache.descLeft() == 0) { 167311957Sgabeblack@google.com postInterrupt(IT_TXQE); 167411957Sgabeblack@google.com txDescCache.writeback(0); 167511957Sgabeblack@google.com txDescCache.fetchDescriptors(); 167611957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing " 167711957Sgabeblack@google.com "writeback stopping ticking and posting TXQE\n"); 167811957Sgabeblack@google.com txTick = false; 167911957Sgabeblack@google.com return; 168011957Sgabeblack@google.com } 168111957Sgabeblack@google.com 168211957Sgabeblack@google.com 168311957Sgabeblack@google.com if (!(txDescCache.descUnused())) { 168411957Sgabeblack@google.com txDescCache.fetchDescriptors(); 168511957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n"); 168611957Sgabeblack@google.com txTick = false; 168711957Sgabeblack@google.com return; 168811957Sgabeblack@google.com } 168911957Sgabeblack@google.com 169011957Sgabeblack@google.com 169111957Sgabeblack@google.com txDescCache.processContextDesc(); 169211957Sgabeblack@google.com if (txDescCache.packetWaiting()) { 169311957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: Fetching TSO header, stopping ticking\n"); 169411957Sgabeblack@google.com txTick = false; 169511957Sgabeblack@google.com return; 169611957Sgabeblack@google.com } 169711957Sgabeblack@google.com 169811957Sgabeblack@google.com int size; 169911957Sgabeblack@google.com size = txDescCache.getPacketSize(txPacket); 170011957Sgabeblack@google.com if (size > 0 && txFifo.avail() > size) { 170111957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining " 170211957Sgabeblack@google.com "DMA of next packet\n", size); 170311957Sgabeblack@google.com txFifo.reserve(size); 170411957Sgabeblack@google.com txDescCache.getPacketData(txPacket); 170511957Sgabeblack@google.com } else if (size <= 0) { 170611957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size); 170711957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); 170811957Sgabeblack@google.com txDescCache.writeback(0); 170911957Sgabeblack@google.com } else { 171011957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " 171111957Sgabeblack@google.com "available in FIFO\n"); 171211957Sgabeblack@google.com txTick = false; 171311957Sgabeblack@google.com } 171411957Sgabeblack@google.com 171511957Sgabeblack@google.com 171611957Sgabeblack@google.com return; 171711957Sgabeblack@google.com } 171811957Sgabeblack@google.com DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n"); 171911957Sgabeblack@google.com txTick = false; 172011957Sgabeblack@google.com} 172111957Sgabeblack@google.com 172211957Sgabeblack@google.combool 172311957Sgabeblack@google.comIGbE::ethRxPkt(EthPacketPtr pkt) 172411957Sgabeblack@google.com{ 172511957Sgabeblack@google.com rxBytes += pkt->length; 172611957Sgabeblack@google.com rxPackets++; 172711957Sgabeblack@google.com 172811957Sgabeblack@google.com DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); 172911957Sgabeblack@google.com 173011957Sgabeblack@google.com if (!regs.rctl.en()) { 173111957Sgabeblack@google.com DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n"); 173211957Sgabeblack@google.com return true; 173311957Sgabeblack@google.com } 173411957Sgabeblack@google.com 173511957Sgabeblack@google.com // restart the state machines if they are stopped 173611957Sgabeblack@google.com rxTick = true && !drainEvent; 173711957Sgabeblack@google.com if ((rxTick || txTick) && !tickEvent.scheduled()) { 173811957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n"); 173911957Sgabeblack@google.com restartClock(); 174011957Sgabeblack@google.com } 174111957Sgabeblack@google.com 174211957Sgabeblack@google.com if (!rxFifo.push(pkt)) { 174311957Sgabeblack@google.com DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n"); 174411957Sgabeblack@google.com postInterrupt(IT_RXO, true); 174511957Sgabeblack@google.com return false; 174611957Sgabeblack@google.com } 174711957Sgabeblack@google.com 174811957Sgabeblack@google.com return true; 174911957Sgabeblack@google.com} 175011957Sgabeblack@google.com 175111957Sgabeblack@google.com 175211957Sgabeblack@google.comvoid 175311957Sgabeblack@google.comIGbE::rxStateMachine() 175411957Sgabeblack@google.com{ 175511957Sgabeblack@google.com if (!regs.rctl.en()) { 175611957Sgabeblack@google.com rxTick = false; 175711957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n"); 175811957Sgabeblack@google.com return; 175911957Sgabeblack@google.com } 176011957Sgabeblack@google.com 176111957Sgabeblack@google.com // If the packet is done check for interrupts/descriptors/etc 176211957Sgabeblack@google.com if (rxDescCache.packetDone()) { 176311957Sgabeblack@google.com rxDmaPacket = false; 176411957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); 176511957Sgabeblack@google.com int descLeft = rxDescCache.descLeft(); 176611957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n", 176711957Sgabeblack@google.com descLeft, regs.rctl.rdmts(), regs.rdlen()); 176811957Sgabeblack@google.com switch (regs.rctl.rdmts()) { 176911957Sgabeblack@google.com case 2: if (descLeft > .125 * regs.rdlen()) break; 177011957Sgabeblack@google.com case 1: if (descLeft > .250 * regs.rdlen()) break; 177111957Sgabeblack@google.com case 0: if (descLeft > .500 * regs.rdlen()) break; 177211957Sgabeblack@google.com DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n"); 177311957Sgabeblack@google.com postInterrupt(IT_RXDMT); 177411957Sgabeblack@google.com break; 177511957Sgabeblack@google.com } 177611957Sgabeblack@google.com 177711957Sgabeblack@google.com if (rxFifo.empty()) 177811957Sgabeblack@google.com rxDescCache.writeback(0); 177911957Sgabeblack@google.com 178011957Sgabeblack@google.com if (descLeft == 0) { 178111957Sgabeblack@google.com rxDescCache.writeback(0); 178211957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" 178311957Sgabeblack@google.com " writeback and stopping ticking\n"); 178411957Sgabeblack@google.com rxTick = false; 178511957Sgabeblack@google.com } 178611957Sgabeblack@google.com 178711957Sgabeblack@google.com // only support descriptor granulaties 178811957Sgabeblack@google.com assert(regs.rxdctl.gran()); 178911957Sgabeblack@google.com 179011957Sgabeblack@google.com if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) { 179111957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n"); 179211957Sgabeblack@google.com if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4)) 179311957Sgabeblack@google.com rxDescCache.writeback(regs.rxdctl.wthresh()-1); 179411957Sgabeblack@google.com else 179511957Sgabeblack@google.com rxDescCache.writeback((cacheBlockSize()-1)>>4); 179611957Sgabeblack@google.com } 179711957Sgabeblack@google.com 179811957Sgabeblack@google.com if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) && 179911957Sgabeblack@google.com ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) { 180011957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n"); 180111957Sgabeblack@google.com rxDescCache.fetchDescriptors(); 180211957Sgabeblack@google.com } 180311957Sgabeblack@google.com 180411957Sgabeblack@google.com if (rxDescCache.descUnused() == 0) { 180511957Sgabeblack@google.com rxDescCache.fetchDescriptors(); 180611957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " 180711957Sgabeblack@google.com "fetching descriptors and stopping ticking\n"); 180811957Sgabeblack@google.com rxTick = false; 180911957Sgabeblack@google.com } 181011957Sgabeblack@google.com return; 181111957Sgabeblack@google.com } 181211957Sgabeblack@google.com 181311957Sgabeblack@google.com if (rxDmaPacket) { 181411957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); 181511957Sgabeblack@google.com rxTick = false; 181611957Sgabeblack@google.com return; 181711957Sgabeblack@google.com } 181811957Sgabeblack@google.com 181911957Sgabeblack@google.com if (!rxDescCache.descUnused()) { 182011957Sgabeblack@google.com rxDescCache.fetchDescriptors(); 182111957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); 182211957Sgabeblack@google.com rxTick = false; 182311957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); 182411957Sgabeblack@google.com return; 182511957Sgabeblack@google.com } 182611957Sgabeblack@google.com 182711957Sgabeblack@google.com if (rxFifo.empty()) { 182811957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n"); 182911957Sgabeblack@google.com rxTick = false; 183011957Sgabeblack@google.com return; 183111957Sgabeblack@google.com } 183211957Sgabeblack@google.com 183311957Sgabeblack@google.com EthPacketPtr pkt; 183411957Sgabeblack@google.com pkt = rxFifo.front(); 183511957Sgabeblack@google.com 183611957Sgabeblack@google.com 183711957Sgabeblack@google.com pktOffset = rxDescCache.writePacket(pkt, pktOffset); 183811957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); 183911957Sgabeblack@google.com if (pktOffset == pkt->length) { 184011957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); 184111957Sgabeblack@google.com pktOffset = 0; 184211957Sgabeblack@google.com rxFifo.pop(); 184311957Sgabeblack@google.com } 184411957Sgabeblack@google.com 184511957Sgabeblack@google.com DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); 184611957Sgabeblack@google.com rxTick = false; 184711957Sgabeblack@google.com rxDmaPacket = true; 184811957Sgabeblack@google.com} 184911957Sgabeblack@google.com 185011957Sgabeblack@google.comvoid 185111957Sgabeblack@google.comIGbE::txWire() 185211957Sgabeblack@google.com{ 185311957Sgabeblack@google.com if (txFifo.empty()) { 185411957Sgabeblack@google.com txFifoTick = false; 185511957Sgabeblack@google.com return; 185611957Sgabeblack@google.com } 185711957Sgabeblack@google.com 185811957Sgabeblack@google.com 185911957Sgabeblack@google.com if (etherInt->sendPacket(txFifo.front())) { 186011957Sgabeblack@google.com if (DTRACE(EthernetSM)) { 186111957Sgabeblack@google.com IpPtr ip(txFifo.front()); 186211957Sgabeblack@google.com if (ip) 186311957Sgabeblack@google.com DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n", 186411957Sgabeblack@google.com ip->id()); 186511957Sgabeblack@google.com else 186611957Sgabeblack@google.com DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n"); 186711957Sgabeblack@google.com } 186811957Sgabeblack@google.com DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n", 186911957Sgabeblack@google.com txFifo.avail()); 187011957Sgabeblack@google.com 187111957Sgabeblack@google.com txBytes += txFifo.front()->length; 187211957Sgabeblack@google.com txPackets++; 187311957Sgabeblack@google.com txFifoTick = false; 187411957Sgabeblack@google.com 187511957Sgabeblack@google.com txFifo.pop(); 187611957Sgabeblack@google.com } else { 187711957Sgabeblack@google.com // We'll get woken up when the packet ethTxDone() gets called 187811957Sgabeblack@google.com txFifoTick = false; 187911957Sgabeblack@google.com } 188011957Sgabeblack@google.com} 188111957Sgabeblack@google.com 188211957Sgabeblack@google.comvoid 188311957Sgabeblack@google.comIGbE::tick() 18848150SN/A{ 18858150SN/A 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