i8254xGBe.cc revision 11701
13116SN/A/*
23116SN/A * Copyright (c) 2006 The Regents of The University of Michigan
33116SN/A * All rights reserved.
43116SN/A *
53116SN/A * Redistribution and use in source and binary forms, with or without
63116SN/A * modification, are permitted provided that the following conditions are
73116SN/A * met: redistributions of source code must retain the above copyright
83116SN/A * notice, this list of conditions and the following disclaimer;
93116SN/A * redistributions in binary form must reproduce the above copyright
103116SN/A * notice, this list of conditions and the following disclaimer in the
113116SN/A * documentation and/or other materials provided with the distribution;
123116SN/A * neither the name of the copyright holders nor the names of its
133116SN/A * contributors may be used to endorse or promote products derived from
143116SN/A * this software without specific prior written permission.
153116SN/A *
163116SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173116SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183116SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193116SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203116SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213116SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223116SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233116SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243116SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253116SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263116SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273116SN/A *
283116SN/A * Authors: Ali Saidi
293116SN/A */
303116SN/A
313116SN/A/* @file
323116SN/A * Device model for Intel's 8254x line of gigabit ethernet controllers.
333318SN/A * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
343318SN/A * fewest workarounds in the driver. It will probably work with most of the
353318SN/A * other MACs with slight modifications.
363116SN/A */
373116SN/A
3811263Sandreas.sandberg@arm.com#include "dev/net/i8254xGBe.hh"
394263SN/A
404263SN/A/*
414263SN/A * @todo really there are multiple dma engines.. we should implement them.
424263SN/A */
434263SN/A
444762SN/A#include <algorithm>
4510469SN/A#include <memory>
464762SN/A
473116SN/A#include "base/inet.hh"
484263SN/A#include "base/trace.hh"
499152SN/A#include "debug/Drain.hh"
508232SN/A#include "debug/EthernetAll.hh"
513116SN/A#include "mem/packet.hh"
523405SN/A#include "mem/packet_access.hh"
534762SN/A#include "params/IGbE.hh"
543116SN/A#include "sim/stats.hh"
553116SN/A#include "sim/system.hh"
563116SN/A
573318SN/Ausing namespace iGbReg;
584263SN/Ausing namespace Net;
593318SN/A
604981SN/AIGbE::IGbE(const Params *p)
6110913SN/A    : EtherDevice(p), etherInt(NULL), cpa(NULL),
624263SN/A      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
635783SN/A      txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
6411320Ssteve.reinhardt@amd.com      fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
6511320Ssteve.reinhardt@amd.com      fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
6611320Ssteve.reinhardt@amd.com      rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
675535SN/A      rdtrEvent(this), radvEvent(this),
684291SN/A      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
694283SN/A      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
705500SN/A      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
719157SN/A      lastInterrupt(0)
723116SN/A{
734981SN/A    etherInt = new IGbEInt(name() + ".int", this);
744981SN/A
753318SN/A    // Initialized internal registers per Intel documentation
764263SN/A    // All registers intialized to 0 by per register constructor
774218SN/A    regs.ctrl.fd(1);
784218SN/A    regs.ctrl.lrst(1);
794218SN/A    regs.ctrl.speed(2);
804218SN/A    regs.ctrl.frcspd(1);
814218SN/A    regs.sts.speed(3); // Say we're 1000Mbps
824218SN/A    regs.sts.fd(1); // full duplex
834283SN/A    regs.sts.lu(1); // link up
844218SN/A    regs.eecd.fwe(1);
854218SN/A    regs.eecd.ee_type(1);
864263SN/A    regs.imr = 0;
874263SN/A    regs.iam = 0;
884263SN/A    regs.rxdctl.gran(1);
894263SN/A    regs.rxdctl.wthresh(1);
904218SN/A    regs.fcrth(1);
915763SN/A    regs.tdwba = 0;
925763SN/A    regs.rlpml = 0;
935763SN/A    regs.sw_fw_sync = 0;
943116SN/A
954218SN/A    regs.pba.rxa(0x30);
964218SN/A    regs.pba.txa(0x10);
973405SN/A
983318SN/A    eeOpBits            = 0;
993318SN/A    eeAddrBits          = 0;
1003318SN/A    eeDataBits          = 0;
1013318SN/A    eeOpcode            = 0;
1023318SN/A
1033405SN/A    // clear all 64 16 bit words of the eeprom
1043405SN/A    memset(&flash, 0, EEPROM_SIZE*2);
1053405SN/A
1064283SN/A    // Set the MAC address
1074283SN/A    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
1084283SN/A    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
1094283SN/A        flash[x] = htobe(flash[x]);
1104218SN/A
1114218SN/A    uint16_t csum = 0;
1124218SN/A    for (int x = 0; x < EEPROM_SIZE; x++)
1134283SN/A        csum += htobe(flash[x]);
1144283SN/A
1154218SN/A
1163318SN/A    // Magic happy checksum value
1174218SN/A    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
1184263SN/A
1195954SN/A    // Store the MAC address as queue ID
1205954SN/A    macAddr = p->hardware_address;
1215954SN/A
1224263SN/A    rxFifo.clear();
1234263SN/A    txFifo.clear();
1243116SN/A}
1253116SN/A
1269086SN/AIGbE::~IGbE()
1279086SN/A{
1289086SN/A    delete etherInt;
1299086SN/A}
1309086SN/A
1315954SN/Avoid
1325954SN/AIGbE::init()
1335954SN/A{
1345954SN/A    cpa = CPA::cpa();
1359807SN/A    PciDevice::init();
1365954SN/A}
1375954SN/A
1384981SN/AEtherInt*
1394981SN/AIGbE::getEthPort(const std::string &if_name, int idx)
1404981SN/A{
1414981SN/A
1424987SN/A    if (if_name == "interface") {
1434981SN/A        if (etherInt->getPeer())
1444981SN/A            panic("Port already connected to\n");
1454981SN/A        return etherInt;
1464981SN/A    }
1474981SN/A    return NULL;
1484981SN/A}
1493116SN/A
1503116SN/ATick
1513349SN/AIGbE::writeConfig(PacketPtr pkt)
1523116SN/A{
1533116SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1543116SN/A    if (offset < PCI_DEVICE_SPECIFIC)
1559807SN/A        PciDevice::writeConfig(pkt);
1563116SN/A    else
1573116SN/A        panic("Device specific PCI config space not implemented.\n");
1583116SN/A
1596124SN/A    //
1606124SN/A    // Some work may need to be done here based for the pci COMMAND bits.
1616124SN/A    //
1623116SN/A
1639198SN/A    return configDelay;
1643116SN/A}
1653116SN/A
1666124SN/A// Handy macro for range-testing register access addresses
1676124SN/A#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
1686124SN/A
1693116SN/ATick
1703349SN/AIGbE::read(PacketPtr pkt)
1713116SN/A{
1723116SN/A    int bar;
1733116SN/A    Addr daddr;
1743116SN/A
1753116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
1763116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
1773116SN/A
1783116SN/A    // Only Memory register BAR is allowed
1793116SN/A    assert(bar == 0);
1803116SN/A
1813318SN/A    // Only 32bit accesses allowed
1823318SN/A    assert(pkt->getSize() == 4);
1833318SN/A
1844283SN/A    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
1853116SN/A
1866124SN/A    //
1876124SN/A    // Handle read of register here
1886124SN/A    //
1893116SN/A
1903405SN/A
1913318SN/A    switch (daddr) {
1924218SN/A      case REG_CTRL:
1934218SN/A        pkt->set<uint32_t>(regs.ctrl());
1944218SN/A        break;
1954218SN/A      case REG_STATUS:
1964218SN/A        pkt->set<uint32_t>(regs.sts());
1974218SN/A        break;
1984218SN/A      case REG_EECD:
1994218SN/A        pkt->set<uint32_t>(regs.eecd());
2004218SN/A        break;
2014218SN/A      case REG_EERD:
2024218SN/A        pkt->set<uint32_t>(regs.eerd());
2034218SN/A        break;
2044218SN/A      case REG_CTRL_EXT:
2054218SN/A        pkt->set<uint32_t>(regs.ctrl_ext());
2064218SN/A        break;
2074218SN/A      case REG_MDIC:
2084218SN/A        pkt->set<uint32_t>(regs.mdic());
2094218SN/A        break;
2104218SN/A      case REG_ICR:
2116124SN/A        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
2126124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
2134218SN/A        pkt->set<uint32_t>(regs.icr());
2144283SN/A        if (regs.icr.int_assert() || regs.imr == 0) {
2154283SN/A            regs.icr = regs.icr() & ~mask(30);
2164283SN/A            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
2174263SN/A        }
2184283SN/A        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
2194283SN/A            regs.imr &= ~regs.iam;
2204283SN/A        chkInterrupt();
2214218SN/A        break;
2225763SN/A      case REG_EICR:
2235763SN/A        // This is only useful for MSI, but the driver reads it every time
2245763SN/A        // Just don't do anything
2255763SN/A        pkt->set<uint32_t>(0);
2265763SN/A        break;
2274218SN/A      case REG_ITR:
2284218SN/A        pkt->set<uint32_t>(regs.itr());
2294218SN/A        break;
2304218SN/A      case REG_RCTL:
2314218SN/A        pkt->set<uint32_t>(regs.rctl());
2324218SN/A        break;
2334218SN/A      case REG_FCTTV:
2344218SN/A        pkt->set<uint32_t>(regs.fcttv());
2354218SN/A        break;
2364218SN/A      case REG_TCTL:
2374218SN/A        pkt->set<uint32_t>(regs.tctl());
2384218SN/A        break;
2394218SN/A      case REG_PBA:
2404218SN/A        pkt->set<uint32_t>(regs.pba());
2414218SN/A        break;
2424218SN/A      case REG_WUC:
2434218SN/A      case REG_LEDCTL:
2444218SN/A        pkt->set<uint32_t>(0); // We don't care, so just return 0
2454218SN/A        break;
2464218SN/A      case REG_FCRTL:
2474218SN/A        pkt->set<uint32_t>(regs.fcrtl());
2484218SN/A        break;
2494218SN/A      case REG_FCRTH:
2504218SN/A        pkt->set<uint32_t>(regs.fcrth());
2514218SN/A        break;
2524218SN/A      case REG_RDBAL:
2534218SN/A        pkt->set<uint32_t>(regs.rdba.rdbal());
2544218SN/A        break;
2554218SN/A      case REG_RDBAH:
2564218SN/A        pkt->set<uint32_t>(regs.rdba.rdbah());
2574218SN/A        break;
2584218SN/A      case REG_RDLEN:
2594218SN/A        pkt->set<uint32_t>(regs.rdlen());
2604218SN/A        break;
2615763SN/A      case REG_SRRCTL:
2625763SN/A        pkt->set<uint32_t>(regs.srrctl());
2635763SN/A        break;
2644218SN/A      case REG_RDH:
2654218SN/A        pkt->set<uint32_t>(regs.rdh());
2664218SN/A        break;
2674218SN/A      case REG_RDT:
2684218SN/A        pkt->set<uint32_t>(regs.rdt());
2694218SN/A        break;
2704218SN/A      case REG_RDTR:
2714218SN/A        pkt->set<uint32_t>(regs.rdtr());
2724263SN/A        if (regs.rdtr.fpd()) {
2734263SN/A            rxDescCache.writeback(0);
2746124SN/A            DPRINTF(EthernetIntr,
2756124SN/A                    "Posting interrupt because of RDTR.FPD write\n");
2764263SN/A            postInterrupt(IT_RXT);
2774263SN/A            regs.rdtr.fpd(0);
2784263SN/A        }
2794218SN/A        break;
2805763SN/A      case REG_RXDCTL:
2815763SN/A        pkt->set<uint32_t>(regs.rxdctl());
2825763SN/A        break;
2834218SN/A      case REG_RADV:
2844218SN/A        pkt->set<uint32_t>(regs.radv());
2854218SN/A        break;
2864218SN/A      case REG_TDBAL:
2874218SN/A        pkt->set<uint32_t>(regs.tdba.tdbal());
2884218SN/A        break;
2894218SN/A      case REG_TDBAH:
2904218SN/A        pkt->set<uint32_t>(regs.tdba.tdbah());
2914218SN/A        break;
2924218SN/A      case REG_TDLEN:
2934218SN/A        pkt->set<uint32_t>(regs.tdlen());
2944218SN/A        break;
2954218SN/A      case REG_TDH:
2964218SN/A        pkt->set<uint32_t>(regs.tdh());
2974218SN/A        break;
2985763SN/A      case REG_TXDCA_CTL:
2995763SN/A        pkt->set<uint32_t>(regs.txdca_ctl());
3005763SN/A        break;
3014218SN/A      case REG_TDT:
3024218SN/A        pkt->set<uint32_t>(regs.tdt());
3034218SN/A        break;
3044218SN/A      case REG_TIDV:
3054218SN/A        pkt->set<uint32_t>(regs.tidv());
3064218SN/A        break;
3074218SN/A      case REG_TXDCTL:
3084218SN/A        pkt->set<uint32_t>(regs.txdctl());
3094218SN/A        break;
3104218SN/A      case REG_TADV:
3114218SN/A        pkt->set<uint32_t>(regs.tadv());
3124218SN/A        break;
3135763SN/A      case REG_TDWBAL:
3145763SN/A        pkt->set<uint32_t>(regs.tdwba & mask(32));
3155763SN/A        break;
3165763SN/A      case REG_TDWBAH:
3175763SN/A        pkt->set<uint32_t>(regs.tdwba >> 32);
3185763SN/A        break;
3194218SN/A      case REG_RXCSUM:
3204218SN/A        pkt->set<uint32_t>(regs.rxcsum());
3214218SN/A        break;
3225763SN/A      case REG_RLPML:
3235763SN/A        pkt->set<uint32_t>(regs.rlpml);
3245763SN/A        break;
3255763SN/A      case REG_RFCTL:
3265763SN/A        pkt->set<uint32_t>(regs.rfctl());
3275763SN/A        break;
3284218SN/A      case REG_MANC:
3294218SN/A        pkt->set<uint32_t>(regs.manc());
3304218SN/A        break;
3315763SN/A      case REG_SWSM:
3325763SN/A        pkt->set<uint32_t>(regs.swsm());
3335763SN/A        regs.swsm.smbi(1);
3345763SN/A        break;
3355763SN/A      case REG_FWSM:
3365763SN/A        pkt->set<uint32_t>(regs.fwsm());
3375763SN/A        break;
3385763SN/A      case REG_SWFWSYNC:
3395763SN/A        pkt->set<uint32_t>(regs.sw_fw_sync);
3405763SN/A        break;
3413318SN/A      default:
3426124SN/A        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
3436124SN/A            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
3446124SN/A            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) &&
3456124SN/A            !IN_RANGE(daddr, REG_CRCERRS, STATS_REGS_SIZE))
3464218SN/A            panic("Read request to unknown register number: %#x\n", daddr);
3474218SN/A        else
3484218SN/A            pkt->set<uint32_t>(0);
3493318SN/A    };
3503318SN/A
3514870SN/A    pkt->makeAtomicResponse();
3523116SN/A    return pioDelay;
3533116SN/A}
3543116SN/A
3553116SN/ATick
3563349SN/AIGbE::write(PacketPtr pkt)
3573116SN/A{
3583116SN/A    int bar;
3593116SN/A    Addr daddr;
3603116SN/A
3613318SN/A
3623116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
3633116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
3643116SN/A
3653116SN/A    // Only Memory register BAR is allowed
3663116SN/A    assert(bar == 0);
3673116SN/A
3683318SN/A    // Only 32bit accesses allowed
3693318SN/A    assert(pkt->getSize() == sizeof(uint32_t));
3703318SN/A
3716124SN/A    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n",
3726124SN/A            daddr, pkt->get<uint32_t>());
3733116SN/A
3746124SN/A    //
3756124SN/A    // Handle write of register here
3766124SN/A    //
3773318SN/A    uint32_t val = pkt->get<uint32_t>();
3783318SN/A
3794263SN/A    Regs::RCTL oldrctl;
3804263SN/A    Regs::TCTL oldtctl;
3814263SN/A
3823318SN/A    switch (daddr) {
3834218SN/A      case REG_CTRL:
3844218SN/A        regs.ctrl = val;
3854218SN/A        if (regs.ctrl.tfce())
3864218SN/A            warn("TX Flow control enabled, should implement\n");
3874218SN/A        if (regs.ctrl.rfce())
3884218SN/A            warn("RX Flow control enabled, should implement\n");
3894218SN/A        break;
3904218SN/A      case REG_CTRL_EXT:
3914218SN/A        regs.ctrl_ext = val;
3924218SN/A        break;
3934218SN/A      case REG_STATUS:
3944218SN/A        regs.sts = val;
3954218SN/A        break;
3964218SN/A      case REG_EECD:
3974218SN/A        int oldClk;
3984218SN/A        oldClk = regs.eecd.sk();
3994218SN/A        regs.eecd = val;
4004218SN/A        // See if this is a eeprom access and emulate accordingly
4014218SN/A        if (!oldClk && regs.eecd.sk()) {
4024218SN/A            if (eeOpBits < 8) {
4034218SN/A                eeOpcode = eeOpcode << 1 | regs.eecd.din();
4044218SN/A                eeOpBits++;
4054218SN/A            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
4064218SN/A                eeAddr = eeAddr << 1 | regs.eecd.din();
4074218SN/A                eeAddrBits++;
4084218SN/A            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
4094218SN/A                assert(eeAddr>>1 < EEPROM_SIZE);
4104218SN/A                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
4116124SN/A                        flash[eeAddr>>1] >> eeDataBits & 0x1,
4126124SN/A                        flash[eeAddr>>1]);
4134218SN/A                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
4144218SN/A                eeDataBits++;
4154218SN/A            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
4164218SN/A                regs.eecd.dout(0);
4174218SN/A                eeDataBits++;
4184218SN/A            } else
4194218SN/A                panic("What's going on with eeprom interface? opcode:"
4206124SN/A                      " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
4216124SN/A                      (uint32_t)eeOpBits, (uint32_t)eeAddr,
4226124SN/A                      (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
4233318SN/A
4244218SN/A            // Reset everything for the next command
4254218SN/A            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
4266124SN/A                (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
4274218SN/A                eeOpBits = 0;
4284218SN/A                eeAddrBits = 0;
4294218SN/A                eeDataBits = 0;
4306124SN/A                eeOpcode = 0;
4314218SN/A                eeAddr = 0;
4324218SN/A            }
4333318SN/A
4346124SN/A            DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
4354218SN/A                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
4364218SN/A                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
4376124SN/A            if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
4384218SN/A                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
4394218SN/A                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
4406124SN/A                      (uint32_t)eeOpBits);
4413318SN/A
4423318SN/A
4434218SN/A        }
4444218SN/A        // If driver requests eeprom access, immediately give it to it
4454218SN/A        regs.eecd.ee_gnt(regs.eecd.ee_req());
4464218SN/A        break;
4474218SN/A      case REG_EERD:
4484218SN/A        regs.eerd = val;
4495763SN/A        if (regs.eerd.start()) {
4505763SN/A            regs.eerd.done(1);
4515763SN/A            assert(regs.eerd.addr() < EEPROM_SIZE);
4525763SN/A            regs.eerd.data(flash[regs.eerd.addr()]);
4535763SN/A            regs.eerd.start(0);
4545763SN/A            DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
4555763SN/A                    regs.eerd.addr(), regs.eerd.data());
4565763SN/A        }
4574218SN/A        break;
4584218SN/A      case REG_MDIC:
4594218SN/A        regs.mdic = val;
4604218SN/A        if (regs.mdic.i())
4614218SN/A            panic("No support for interrupt on mdic complete\n");
4624218SN/A        if (regs.mdic.phyadd() != 1)
4634218SN/A            panic("No support for reading anything but phy\n");
4646124SN/A        DPRINTF(Ethernet, "%s phy address %x\n",
4656124SN/A                regs.mdic.op() == 1 ? "Writing" : "Reading",
4666124SN/A                regs.mdic.regadd());
4674218SN/A        switch (regs.mdic.regadd()) {
4686124SN/A          case PHY_PSTATUS:
4696124SN/A            regs.mdic.data(0x796D); // link up
4706124SN/A            break;
4716124SN/A          case PHY_PID:
4726124SN/A            regs.mdic.data(params()->phy_pid);
4736124SN/A            break;
4746124SN/A          case PHY_EPID:
4756124SN/A            regs.mdic.data(params()->phy_epid);
4766124SN/A            break;
4776124SN/A          case PHY_GSTATUS:
4786124SN/A            regs.mdic.data(0x7C00);
4796124SN/A            break;
4806124SN/A          case PHY_EPSTATUS:
4816124SN/A            regs.mdic.data(0x3000);
4826124SN/A            break;
4836124SN/A          case PHY_AGC:
4846124SN/A            regs.mdic.data(0x180); // some random length
4856124SN/A            break;
4866124SN/A          default:
4876124SN/A            regs.mdic.data(0);
4884218SN/A        }
4894218SN/A        regs.mdic.r(1);
4904218SN/A        break;
4914218SN/A      case REG_ICR:
4926124SN/A        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
4936124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
4944283SN/A        if (regs.ctrl_ext.iame())
4954283SN/A            regs.imr &= ~regs.iam;
4964263SN/A        regs.icr = ~bits(val,30,0) & regs.icr();
4974283SN/A        chkInterrupt();
4984218SN/A        break;
4994218SN/A      case REG_ITR:
5004218SN/A        regs.itr = val;
5014218SN/A        break;
5024218SN/A      case REG_ICS:
5034291SN/A        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
5044263SN/A        postInterrupt((IntTypes)val);
5054218SN/A        break;
5066124SN/A      case REG_IMS:
5074218SN/A        regs.imr |= val;
5084263SN/A        chkInterrupt();
5094218SN/A        break;
5104218SN/A      case REG_IMC:
5114263SN/A        regs.imr &= ~val;
5124263SN/A        chkInterrupt();
5134218SN/A        break;
5144218SN/A      case REG_IAM:
5154218SN/A        regs.iam = val;
5164218SN/A        break;
5174218SN/A      case REG_RCTL:
5184263SN/A        oldrctl = regs.rctl;
5194218SN/A        regs.rctl = val;
5204263SN/A        if (regs.rctl.rst()) {
5214263SN/A            rxDescCache.reset();
5224291SN/A            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
5234263SN/A            rxFifo.clear();
5244263SN/A            regs.rctl.rst(0);
5254263SN/A        }
5264263SN/A        if (regs.rctl.en())
5274263SN/A            rxTick = true;
5284283SN/A        restartClock();
5294218SN/A        break;
5304218SN/A      case REG_FCTTV:
5314218SN/A        regs.fcttv = val;
5324218SN/A        break;
5334218SN/A      case REG_TCTL:
5344218SN/A        regs.tctl = val;
5354263SN/A        oldtctl = regs.tctl;
5364263SN/A        regs.tctl = val;
5374263SN/A        if (regs.tctl.en())
5386124SN/A            txTick = true;
5394283SN/A        restartClock();
5404263SN/A        if (regs.tctl.en() && !oldtctl.en()) {
5414263SN/A            txDescCache.reset();
5424263SN/A        }
5436124SN/A        break;
5444218SN/A      case REG_PBA:
5454218SN/A        regs.pba.rxa(val);
5464218SN/A        regs.pba.txa(64 - regs.pba.rxa());
5474218SN/A        break;
5484218SN/A      case REG_WUC:
5494218SN/A      case REG_LEDCTL:
5504218SN/A      case REG_FCAL:
5514218SN/A      case REG_FCAH:
5524218SN/A      case REG_FCT:
5534218SN/A      case REG_VET:
5544218SN/A      case REG_AIFS:
5554218SN/A      case REG_TIPG:
5564218SN/A        ; // We don't care, so don't store anything
5574218SN/A        break;
5585763SN/A      case REG_IVAR0:
5595763SN/A        warn("Writing to IVAR0, ignoring...\n");
5605763SN/A        break;
5614218SN/A      case REG_FCRTL:
5624218SN/A        regs.fcrtl = val;
5634218SN/A        break;
5644218SN/A      case REG_FCRTH:
5654218SN/A        regs.fcrth = val;
5664218SN/A        break;
5674218SN/A      case REG_RDBAL:
5684218SN/A        regs.rdba.rdbal( val & ~mask(4));
5694263SN/A        rxDescCache.areaChanged();
5704218SN/A        break;
5714218SN/A      case REG_RDBAH:
5724218SN/A        regs.rdba.rdbah(val);
5734263SN/A        rxDescCache.areaChanged();
5744218SN/A        break;
5754218SN/A      case REG_RDLEN:
5764218SN/A        regs.rdlen = val & ~mask(7);
5774263SN/A        rxDescCache.areaChanged();
5784218SN/A        break;
5795763SN/A      case REG_SRRCTL:
5805763SN/A        regs.srrctl = val;
5815763SN/A        break;
5824218SN/A      case REG_RDH:
5834218SN/A        regs.rdh = val;
5844263SN/A        rxDescCache.areaChanged();
5854218SN/A        break;
5864218SN/A      case REG_RDT:
5874218SN/A        regs.rdt = val;
5884987SN/A        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
58910913SN/A        if (drainState() == DrainState::Running) {
5904987SN/A            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
5914987SN/A            rxDescCache.fetchDescriptors();
5924987SN/A        } else {
5934987SN/A            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
5944987SN/A        }
5954218SN/A        break;
5964218SN/A      case REG_RDTR:
5974218SN/A        regs.rdtr = val;
5984218SN/A        break;
5994218SN/A      case REG_RADV:
6004218SN/A        regs.radv = val;
6014218SN/A        break;
6025763SN/A      case REG_RXDCTL:
6035763SN/A        regs.rxdctl = val;
6045763SN/A        break;
6054218SN/A      case REG_TDBAL:
6064218SN/A        regs.tdba.tdbal( val & ~mask(4));
6074263SN/A        txDescCache.areaChanged();
6084218SN/A        break;
6094218SN/A      case REG_TDBAH:
6104218SN/A        regs.tdba.tdbah(val);
6114263SN/A        txDescCache.areaChanged();
6124218SN/A        break;
6134218SN/A      case REG_TDLEN:
6144218SN/A        regs.tdlen = val & ~mask(7);
6154263SN/A        txDescCache.areaChanged();
6164218SN/A        break;
6174218SN/A      case REG_TDH:
6184218SN/A        regs.tdh = val;
6194263SN/A        txDescCache.areaChanged();
6204218SN/A        break;
6215763SN/A      case REG_TXDCA_CTL:
6225763SN/A        regs.txdca_ctl = val;
6235763SN/A        if (regs.txdca_ctl.enabled())
6245763SN/A            panic("No support for DCA\n");
6255763SN/A        break;
6264218SN/A      case REG_TDT:
6274218SN/A        regs.tdt = val;
6284987SN/A        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
62910913SN/A        if (drainState() == DrainState::Running) {
6304987SN/A            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
6314987SN/A            txDescCache.fetchDescriptors();
6324987SN/A        } else {
6334987SN/A            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
6344987SN/A        }
6354218SN/A        break;
6364218SN/A      case REG_TIDV:
6374218SN/A        regs.tidv = val;
6384218SN/A        break;
6394218SN/A      case REG_TXDCTL:
6404218SN/A        regs.txdctl = val;
6414218SN/A        break;
6424218SN/A      case REG_TADV:
6434218SN/A        regs.tadv = val;
6444218SN/A        break;
6455763SN/A      case REG_TDWBAL:
6465763SN/A        regs.tdwba &= ~mask(32);
6475763SN/A        regs.tdwba |= val;
6486124SN/A        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
6496124SN/A                                        regs.tdwba & mask(1));
6505763SN/A        break;
6515763SN/A      case REG_TDWBAH:
6525763SN/A        regs.tdwba &= mask(32);
6535763SN/A        regs.tdwba |= (uint64_t)val << 32;
6546124SN/A        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
6556124SN/A                                        regs.tdwba & mask(1));
6565763SN/A        break;
6574218SN/A      case REG_RXCSUM:
6584218SN/A        regs.rxcsum = val;
6594218SN/A        break;
6605763SN/A      case REG_RLPML:
6615763SN/A        regs.rlpml = val;
6625763SN/A        break;
6635763SN/A      case REG_RFCTL:
6645763SN/A        regs.rfctl = val;
6655763SN/A        if (regs.rfctl.exsten())
6665763SN/A            panic("Extended RX descriptors not implemented\n");
6675763SN/A        break;
6684218SN/A      case REG_MANC:
6694218SN/A        regs.manc = val;
6704218SN/A        break;
6715763SN/A      case REG_SWSM:
6725763SN/A        regs.swsm = val;
6735763SN/A        if (regs.fwsm.eep_fw_semaphore())
6745763SN/A            regs.swsm.swesmbi(0);
6755763SN/A        break;
6765763SN/A      case REG_SWFWSYNC:
6775763SN/A        regs.sw_fw_sync = val;
6785763SN/A        break;
6793318SN/A      default:
6806124SN/A        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
6816124SN/A            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
6826124SN/A            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4))
6836124SN/A            panic("Write request to unknown register number: %#x\n", daddr);
6843318SN/A    };
6853116SN/A
6864870SN/A    pkt->makeAtomicResponse();
6873116SN/A    return pioDelay;
6883116SN/A}
6893116SN/A
6904263SN/Avoid
6914263SN/AIGbE::postInterrupt(IntTypes t, bool now)
6924263SN/A{
6934283SN/A    assert(t);
6944283SN/A
6954263SN/A    // Interrupt is already pending
6964987SN/A    if (t & regs.icr() && !now)
6974263SN/A        return;
6984263SN/A
6994987SN/A    regs.icr = regs.icr() | t;
7005500SN/A
7017064SN/A    Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval();
7026124SN/A    DPRINTF(EthernetIntr,
7037823SN/A            "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
7047823SN/A            curTick(), regs.itr.interval(), itr_interval);
7055500SN/A
7066124SN/A    if (regs.itr.interval() == 0 || now ||
7077823SN/A        lastInterrupt + itr_interval <= curTick()) {
7084987SN/A        if (interEvent.scheduled()) {
7095606SN/A            deschedule(interEvent);
7104987SN/A        }
7114987SN/A        cpuPostInt();
7124263SN/A    } else {
7136124SN/A        Tick int_time = lastInterrupt + itr_interval;
7146124SN/A        assert(int_time > 0);
7156124SN/A        DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
7165500SN/A                int_time);
7176124SN/A        if (!interEvent.scheduled()) {
7186124SN/A            schedule(interEvent, int_time);
7196124SN/A        }
7204263SN/A    }
7214263SN/A}
7224263SN/A
7234263SN/Avoid
7244987SN/AIGbE::delayIntEvent()
7254987SN/A{
7264987SN/A    cpuPostInt();
7274987SN/A}
7284987SN/A
7294987SN/A
7304987SN/Avoid
7314263SN/AIGbE::cpuPostInt()
7324263SN/A{
7334987SN/A
7345533SN/A    postedInterrupts++;
7355533SN/A
7364987SN/A    if (!(regs.icr() & regs.imr)) {
7374987SN/A        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
7384987SN/A        return;
7394987SN/A    }
7404987SN/A
7414987SN/A    DPRINTF(Ethernet, "Posting Interrupt\n");
7424987SN/A
7434987SN/A
7444987SN/A    if (interEvent.scheduled()) {
7455606SN/A        deschedule(interEvent);
7464987SN/A    }
7474987SN/A
7484263SN/A    if (rdtrEvent.scheduled()) {
7494263SN/A        regs.icr.rxt0(1);
7505606SN/A        deschedule(rdtrEvent);
7514263SN/A    }
7524263SN/A    if (radvEvent.scheduled()) {
7534263SN/A        regs.icr.rxt0(1);
7545606SN/A        deschedule(radvEvent);
7554263SN/A    }
7564263SN/A    if (tadvEvent.scheduled()) {
7574263SN/A        regs.icr.txdw(1);
7585606SN/A        deschedule(tadvEvent);
7594263SN/A    }
7604263SN/A    if (tidvEvent.scheduled()) {
7614263SN/A        regs.icr.txdw(1);
7625606SN/A        deschedule(tidvEvent);
7634263SN/A    }
7644263SN/A
7654263SN/A    regs.icr.int_assert(1);
7664263SN/A    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
7674263SN/A            regs.icr());
7684987SN/A
7694263SN/A    intrPost();
7704987SN/A
7717823SN/A    lastInterrupt = curTick();
7724263SN/A}
7734263SN/A
7744263SN/Avoid
7754263SN/AIGbE::cpuClearInt()
7764263SN/A{
7774283SN/A    if (regs.icr.int_assert()) {
7784283SN/A        regs.icr.int_assert(0);
7796124SN/A        DPRINTF(EthernetIntr,
7806124SN/A                "EINT: Clearing interrupt to CPU now. Vector %#x\n",
7814283SN/A                regs.icr());
7824283SN/A        intrClear();
7834283SN/A    }
7844263SN/A}
7854263SN/A
7864263SN/Avoid
7874263SN/AIGbE::chkInterrupt()
7884263SN/A{
7894987SN/A    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
7904987SN/A            regs.imr);
7914263SN/A    // Check if we need to clear the cpu interrupt
7924283SN/A    if (!(regs.icr() & regs.imr)) {
7934987SN/A        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
7944283SN/A        if (interEvent.scheduled())
7956124SN/A            deschedule(interEvent);
7964283SN/A        if (regs.icr.int_assert())
7974283SN/A            cpuClearInt();
7984283SN/A    }
7996124SN/A    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n",
8006124SN/A            regs.itr(), regs.itr.interval());
8014263SN/A
8024283SN/A    if (regs.icr() & regs.imr) {
8034283SN/A        if (regs.itr.interval() == 0)  {
8044283SN/A            cpuPostInt();
8054283SN/A        } else {
8066124SN/A            DPRINTF(Ethernet,
8076124SN/A                    "Possibly scheduling interrupt because of imr write\n");
8084987SN/A            if (!interEvent.scheduled()) {
8097823SN/A                Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval();
8106124SN/A                DPRINTF(Ethernet, "Scheduling for %d\n", t);
8116124SN/A                schedule(interEvent, t);
8124987SN/A            }
8134283SN/A        }
8144283SN/A    }
8156124SN/A}
8164283SN/A
8174283SN/A
8186124SN/A///////////////////////////// IGbE::DescCache //////////////////////////////
8196124SN/A
8206124SN/Atemplate<class T>
8216124SN/AIGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s)
8226124SN/A    : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0),
82310420SN/A      wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
82410420SN/A      wbDelayEvent(this), fetchDelayEvent(this), fetchEvent(this),
82510420SN/A      wbEvent(this)
8266124SN/A{
8276124SN/A    fetchBuf = new T[size];
8286124SN/A    wbBuf = new T[size];
8296124SN/A}
8306124SN/A
8316124SN/Atemplate<class T>
8326124SN/AIGbE::DescCache<T>::~DescCache()
8336124SN/A{
8346124SN/A    reset();
8359086SN/A    delete[] fetchBuf;
8369086SN/A    delete[] wbBuf;
8376124SN/A}
8386124SN/A
8396124SN/Atemplate<class T>
8406124SN/Avoid
8416124SN/AIGbE::DescCache<T>::areaChanged()
8426124SN/A{
8436124SN/A    if (usedCache.size() > 0 || curFetching || wbOut)
8446124SN/A        panic("Descriptor Address, Length or Head changed. Bad\n");
8456124SN/A    reset();
8466124SN/A
8474263SN/A}
8484263SN/A
8496124SN/Atemplate<class T>
8506124SN/Avoid
8516124SN/AIGbE::DescCache<T>::writeback(Addr aMask)
8526124SN/A{
8536124SN/A    int curHead = descHead();
8546124SN/A    int max_to_wb = usedCache.size();
8556124SN/A
8566124SN/A    // Check if this writeback is less restrictive that the previous
8576124SN/A    // and if so setup another one immediately following it
8586124SN/A    if (wbOut) {
8596124SN/A        if (aMask < wbAlignment) {
8606124SN/A            moreToWb = true;
8616124SN/A            wbAlignment = aMask;
8626124SN/A        }
8636124SN/A        DPRINTF(EthernetDesc,
8646124SN/A                "Writing back already in process, returning\n");
8656124SN/A        return;
8666124SN/A    }
8676124SN/A
8686124SN/A    moreToWb = false;
8696124SN/A    wbAlignment = aMask;
87011320Ssteve.reinhardt@amd.com
8716124SN/A
8726124SN/A    DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
8736124SN/A            "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
8746124SN/A            curHead, descTail(), descLen(), cachePnt, max_to_wb,
8756124SN/A            descLeft());
8766124SN/A
8776124SN/A    if (max_to_wb + curHead >= descLen()) {
8786124SN/A        max_to_wb = descLen() - curHead;
8796124SN/A        moreToWb = true;
8806124SN/A        // this is by definition aligned correctly
8816124SN/A    } else if (wbAlignment != 0) {
8826124SN/A        // align the wb point to the mask
8836124SN/A        max_to_wb = max_to_wb & ~wbAlignment;
8846124SN/A    }
8856124SN/A
8866124SN/A    DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
8876124SN/A
8886124SN/A    if (max_to_wb <= 0) {
8896124SN/A        if (usedCache.size())
8906124SN/A            igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
8916124SN/A        else
8926124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
8936124SN/A        return;
8946124SN/A    }
8956124SN/A
8966124SN/A    wbOut = max_to_wb;
8976124SN/A
89811320Ssteve.reinhardt@amd.com    assert(!wbDelayEvent.scheduled());
8997823SN/A    igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9006124SN/A    igbe->anBegin(annSmWb, "Prepare Writeback Desc");
9016124SN/A}
90211320Ssteve.reinhardt@amd.com
9036124SN/Atemplate<class T>
9046124SN/Avoid
9056124SN/AIGbE::DescCache<T>::writeback1()
9066124SN/A{
9076124SN/A    // If we're draining delay issuing this DMA
90810913SN/A    if (igbe->drainState() != DrainState::Running) {
9097823SN/A        igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9106124SN/A        return;
9116124SN/A    }
9126124SN/A
9136124SN/A    DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
91411320Ssteve.reinhardt@amd.com
9156124SN/A    for (int x = 0; x < wbOut; x++) {
9166124SN/A        assert(usedCache.size());
9176124SN/A        memcpy(&wbBuf[x], usedCache[x], sizeof(T));
9186124SN/A        igbe->anPq(annSmWb, annUsedCacheQ);
9196124SN/A        igbe->anPq(annSmWb, annDescQ);
9206124SN/A        igbe->anQ(annSmWb, annUsedDescQ);
9216124SN/A    }
9226124SN/A
92311320Ssteve.reinhardt@amd.com
9246124SN/A    igbe->anBegin(annSmWb, "Writeback Desc DMA");
9256124SN/A
9266124SN/A    assert(wbOut);
9276124SN/A    igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
9286124SN/A                   wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
9296124SN/A                   igbe->wbCompDelay);
9306124SN/A}
9316124SN/A
9326124SN/Atemplate<class T>
9336124SN/Avoid
9346124SN/AIGbE::DescCache<T>::fetchDescriptors()
9356124SN/A{
9366124SN/A    size_t max_to_fetch;
9376124SN/A
9386124SN/A    if (curFetching) {
9396124SN/A        DPRINTF(EthernetDesc,
9406124SN/A                "Currently fetching %d descriptors, returning\n",
9416124SN/A                curFetching);
9426124SN/A        return;
9436124SN/A    }
9446124SN/A
9456124SN/A    if (descTail() >= cachePnt)
9466124SN/A        max_to_fetch = descTail() - cachePnt;
9476124SN/A    else
9486124SN/A        max_to_fetch = descLen() - cachePnt;
9496124SN/A
9506124SN/A    size_t free_cache = size - usedCache.size() - unusedCache.size();
9516124SN/A
9526124SN/A    if (!max_to_fetch)
9536124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
9546124SN/A    else
9556124SN/A        igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
9566124SN/A
9576124SN/A    if (max_to_fetch) {
9586124SN/A        if (!free_cache)
9596124SN/A            igbe->anWf(annSmFetch, annDescQ);
9606124SN/A        else
9616124SN/A            igbe->anRq(annSmFetch, annDescQ, free_cache);
9626124SN/A    }
9636124SN/A
9646124SN/A    max_to_fetch = std::min(max_to_fetch, free_cache);
96511320Ssteve.reinhardt@amd.com
9666124SN/A
9676124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
9686124SN/A            "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
9696124SN/A            descHead(), descTail(), descLen(), cachePnt,
9706124SN/A            max_to_fetch, descLeft());
9716124SN/A
9726124SN/A    // Nothing to do
9736124SN/A    if (max_to_fetch == 0)
9746124SN/A        return;
97511320Ssteve.reinhardt@amd.com
9766124SN/A    // So we don't have two descriptor fetches going on at once
9776124SN/A    curFetching = max_to_fetch;
9786124SN/A
9796124SN/A    assert(!fetchDelayEvent.scheduled());
9807823SN/A    igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9816124SN/A    igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
9826124SN/A}
9836124SN/A
9846124SN/Atemplate<class T>
9856124SN/Avoid
9866124SN/AIGbE::DescCache<T>::fetchDescriptors1()
9876124SN/A{
9886124SN/A    // If we're draining delay issuing this DMA
98910913SN/A    if (igbe->drainState() != DrainState::Running) {
9907823SN/A        igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9916124SN/A        return;
9926124SN/A    }
9936124SN/A
9946124SN/A    igbe->anBegin(annSmFetch, "Fetch Desc");
9956124SN/A
9966124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
9976124SN/A            descBase() + cachePnt * sizeof(T),
9986124SN/A            pciToDma(descBase() + cachePnt * sizeof(T)),
9996124SN/A            curFetching * sizeof(T));
10006124SN/A    assert(curFetching);
10016124SN/A    igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
10026124SN/A                  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
10036124SN/A                  igbe->fetchCompDelay);
10046124SN/A}
10056124SN/A
10066124SN/Atemplate<class T>
10076124SN/Avoid
10086124SN/AIGbE::DescCache<T>::fetchComplete()
10096124SN/A{
10106124SN/A    T *newDesc;
10116124SN/A    igbe->anBegin(annSmFetch, "Fetch Complete");
10126124SN/A    for (int x = 0; x < curFetching; x++) {
10136124SN/A        newDesc = new T;
10146124SN/A        memcpy(newDesc, &fetchBuf[x], sizeof(T));
10156124SN/A        unusedCache.push_back(newDesc);
10166124SN/A        igbe->anDq(annSmFetch, annUnusedDescQ);
10176124SN/A        igbe->anQ(annSmFetch, annUnusedCacheQ);
10186124SN/A        igbe->anQ(annSmFetch, annDescQ);
10196124SN/A    }
10206124SN/A
10216124SN/A
10226124SN/A#ifndef NDEBUG
10236124SN/A    int oldCp = cachePnt;
10246124SN/A#endif
10256124SN/A
10266124SN/A    cachePnt += curFetching;
10276124SN/A    assert(cachePnt <= descLen());
10286124SN/A    if (cachePnt == descLen())
10296124SN/A        cachePnt = 0;
10306124SN/A
10316124SN/A    curFetching = 0;
10326124SN/A
10336124SN/A    DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
10346124SN/A            oldCp, cachePnt);
10356124SN/A
10366124SN/A    if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
10376124SN/A                                                             cachePnt)) == 0)
10386124SN/A    {
10396124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
10406124SN/A    } else if (!(size - usedCache.size() - unusedCache.size())) {
10416124SN/A        igbe->anWf(annSmFetch, annDescQ);
10426124SN/A    } else {
10436124SN/A        igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
10446124SN/A    }
10456124SN/A
10466124SN/A    enableSm();
10476124SN/A    igbe->checkDrain();
10486124SN/A}
10496124SN/A
10506124SN/Atemplate<class T>
10516124SN/Avoid
10526124SN/AIGbE::DescCache<T>::wbComplete()
10536124SN/A{
10546124SN/A
10556124SN/A    igbe->anBegin(annSmWb, "Finish Writeback");
10566124SN/A
10576124SN/A    long  curHead = descHead();
10586124SN/A#ifndef NDEBUG
10596124SN/A    long oldHead = curHead;
10606124SN/A#endif
106111320Ssteve.reinhardt@amd.com
10626124SN/A    for (int x = 0; x < wbOut; x++) {
10636124SN/A        assert(usedCache.size());
10646124SN/A        delete usedCache[0];
10656124SN/A        usedCache.pop_front();
10666124SN/A
10676124SN/A        igbe->anDq(annSmWb, annUsedCacheQ);
10686124SN/A        igbe->anDq(annSmWb, annDescQ);
10696124SN/A    }
10706124SN/A
10716124SN/A    curHead += wbOut;
10726124SN/A    wbOut = 0;
10736124SN/A
10746124SN/A    if (curHead >= descLen())
10756124SN/A        curHead -= descLen();
10766124SN/A
10776124SN/A    // Update the head
10786124SN/A    updateHead(curHead);
10796124SN/A
10806124SN/A    DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
10816124SN/A            oldHead, curHead);
10826124SN/A
10836124SN/A    // If we still have more to wb, call wb now
10846124SN/A    actionAfterWb();
10856124SN/A    if (moreToWb) {
10866124SN/A        moreToWb = false;
10876124SN/A        DPRINTF(EthernetDesc, "Writeback has more todo\n");
10886124SN/A        writeback(wbAlignment);
10896124SN/A    }
10906124SN/A
10916124SN/A    if (!wbOut) {
10926124SN/A        igbe->checkDrain();
10936124SN/A        if (usedCache.size())
10946124SN/A            igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
10956124SN/A        else
10966124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
10976124SN/A    }
10986124SN/A    fetchAfterWb();
10996124SN/A}
11006124SN/A
11016124SN/Atemplate<class T>
11026124SN/Avoid
11036124SN/AIGbE::DescCache<T>::reset()
11046124SN/A{
11056124SN/A    DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
11066228SN/A    for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
11076124SN/A        delete usedCache[x];
11086228SN/A    for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
11096124SN/A        delete unusedCache[x];
11106124SN/A
11116124SN/A    usedCache.clear();
11126124SN/A    unusedCache.clear();
11136124SN/A
11146124SN/A    cachePnt = 0;
11156124SN/A
11166124SN/A}
11176124SN/A
11186124SN/Atemplate<class T>
11196124SN/Avoid
112010905SN/AIGbE::DescCache<T>::serialize(CheckpointOut &cp) const
11216124SN/A{
11226124SN/A    SERIALIZE_SCALAR(cachePnt);
11236124SN/A    SERIALIZE_SCALAR(curFetching);
11246124SN/A    SERIALIZE_SCALAR(wbOut);
11256124SN/A    SERIALIZE_SCALAR(moreToWb);
11266124SN/A    SERIALIZE_SCALAR(wbAlignment);
11276124SN/A
11286228SN/A    typename CacheType::size_type usedCacheSize = usedCache.size();
11296124SN/A    SERIALIZE_SCALAR(usedCacheSize);
11306228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
113110905SN/A        arrayParamOut(cp, csprintf("usedCache_%d", x),
11326124SN/A                      (uint8_t*)usedCache[x],sizeof(T));
11336124SN/A    }
11346124SN/A
11356228SN/A    typename CacheType::size_type unusedCacheSize = unusedCache.size();
11366124SN/A    SERIALIZE_SCALAR(unusedCacheSize);
11376228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
113810905SN/A        arrayParamOut(cp, csprintf("unusedCache_%d", x),
11396124SN/A                      (uint8_t*)unusedCache[x],sizeof(T));
11406124SN/A    }
11416124SN/A
11426124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11436124SN/A    if (fetchDelayEvent.scheduled())
11446124SN/A        fetch_delay = fetchDelayEvent.when();
11456124SN/A    SERIALIZE_SCALAR(fetch_delay);
11466124SN/A    if (wbDelayEvent.scheduled())
11476124SN/A        wb_delay = wbDelayEvent.when();
11486124SN/A    SERIALIZE_SCALAR(wb_delay);
11496124SN/A
11506124SN/A
11516124SN/A}
11526124SN/A
11536124SN/Atemplate<class T>
11546124SN/Avoid
115510905SN/AIGbE::DescCache<T>::unserialize(CheckpointIn &cp)
11566124SN/A{
11576124SN/A    UNSERIALIZE_SCALAR(cachePnt);
11586124SN/A    UNSERIALIZE_SCALAR(curFetching);
11596124SN/A    UNSERIALIZE_SCALAR(wbOut);
11606124SN/A    UNSERIALIZE_SCALAR(moreToWb);
11616124SN/A    UNSERIALIZE_SCALAR(wbAlignment);
11626124SN/A
11636228SN/A    typename CacheType::size_type usedCacheSize;
11646124SN/A    UNSERIALIZE_SCALAR(usedCacheSize);
11656124SN/A    T *temp;
11666228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
11676124SN/A        temp = new T;
116810905SN/A        arrayParamIn(cp, csprintf("usedCache_%d", x),
11696124SN/A                     (uint8_t*)temp,sizeof(T));
11706124SN/A        usedCache.push_back(temp);
11716124SN/A    }
11726124SN/A
11736228SN/A    typename CacheType::size_type unusedCacheSize;
11746124SN/A    UNSERIALIZE_SCALAR(unusedCacheSize);
11756228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
11766124SN/A        temp = new T;
117710905SN/A        arrayParamIn(cp, csprintf("unusedCache_%d", x),
11786124SN/A                     (uint8_t*)temp,sizeof(T));
11796124SN/A        unusedCache.push_back(temp);
11806124SN/A    }
11816124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11826124SN/A    UNSERIALIZE_SCALAR(fetch_delay);
11836124SN/A    UNSERIALIZE_SCALAR(wb_delay);
11846124SN/A    if (fetch_delay)
11856124SN/A        igbe->schedule(fetchDelayEvent, fetch_delay);
11866124SN/A    if (wb_delay)
11876124SN/A        igbe->schedule(wbDelayEvent, wb_delay);
11886124SN/A
11896124SN/A
11906124SN/A}
11916124SN/A
11926124SN/A///////////////////////////// IGbE::RxDescCache //////////////////////////////
11934263SN/A
11944263SN/AIGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
119511320Ssteve.reinhardt@amd.com    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
11965783SN/A      pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
11974263SN/A
11984263SN/A{
11995954SN/A    annSmFetch = "RX Desc Fetch";
12005954SN/A    annSmWb = "RX Desc Writeback";
12015954SN/A    annUnusedDescQ = "RX Unused Descriptors";
12025954SN/A    annUnusedCacheQ = "RX Unused Descriptor Cache";
12035954SN/A    annUsedCacheQ = "RX Used Descriptor Cache";
12045954SN/A    annUsedDescQ = "RX Used Descriptors";
12055954SN/A    annDescQ = "RX Descriptors";
12064263SN/A}
12073116SN/A
12085339SN/Avoid
12095783SN/AIGbE::RxDescCache::pktSplitDone()
12105783SN/A{
12115783SN/A    splitCount++;
12126124SN/A    DPRINTF(EthernetDesc,
12136124SN/A            "Part of split packet done: splitcount now %d\n", splitCount);
12145783SN/A    assert(splitCount <= 2);
12155783SN/A    if (splitCount != 2)
12165783SN/A        return;
12175783SN/A    splitCount = 0;
12186124SN/A    DPRINTF(EthernetDesc,
12196124SN/A            "Part of split packet done: calling pktComplete()\n");
12205783SN/A    pktComplete();
12215783SN/A}
12225783SN/A
12235783SN/Aint
12245783SN/AIGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
12253116SN/A{
12266124SN/A    assert(unusedCache.size());
12275071SN/A    //if (!unusedCache.size())
12285071SN/A    //    return false;
12294263SN/A
12304263SN/A    pktPtr = packet;
12314452SN/A    pktDone = false;
12326227SN/A    unsigned buf_len, hdr_len;
12335763SN/A
12345763SN/A    RxDesc *desc = unusedCache.front();
12355763SN/A    switch (igbe->regs.srrctl.desctype()) {
12365763SN/A      case RXDT_LEGACY:
12375783SN/A        assert(pkt_offset == 0);
12385783SN/A        bytesCopied = packet->length;
12395763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
12406124SN/A                packet->length, igbe->regs.rctl.descSize());
12415763SN/A        assert(packet->length < igbe->regs.rctl.descSize());
12426124SN/A        igbe->dmaWrite(pciToDma(desc->legacy.buf),
12436124SN/A                       packet->length, &pktEvent, packet->data,
12446124SN/A                       igbe->rxWriteDelay);
12455763SN/A        break;
12465763SN/A      case RXDT_ADV_ONEBUF:
12475783SN/A        assert(pkt_offset == 0);
12485783SN/A        bytesCopied = packet->length;
12495763SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12506124SN/A            igbe->regs.rctl.descSize();
12515763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
12526124SN/A                packet->length, igbe->regs.srrctl(), buf_len);
12535763SN/A        assert(packet->length < buf_len);
12546124SN/A        igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
12556124SN/A                       packet->length, &pktEvent, packet->data,
12566124SN/A                       igbe->rxWriteDelay);
12575783SN/A        desc->adv_wb.header_len = htole(0);
12585783SN/A        desc->adv_wb.sph = htole(0);
12595783SN/A        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
12605783SN/A        break;
12615783SN/A      case RXDT_ADV_SPLIT_A:
12625783SN/A        int split_point;
126311320Ssteve.reinhardt@amd.com
12645783SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12656124SN/A            igbe->regs.rctl.descSize();
126611320Ssteve.reinhardt@amd.com        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
12676124SN/A        DPRINTF(EthernetDesc,
12686124SN/A                "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
12696124SN/A                "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
12706124SN/A                igbe->regs.rctl.lpe(), packet->length, pkt_offset,
12716124SN/A                igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
12726124SN/A                desc->adv_read.pkt, buf_len);
12735783SN/A
12745783SN/A        split_point = hsplit(pktPtr);
12755783SN/A
12765783SN/A        if (packet->length <= hdr_len) {
12775783SN/A            bytesCopied = packet->length;
12785783SN/A            assert(pkt_offset == 0);
12796124SN/A            DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
12806124SN/A            igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
12816124SN/A                           packet->length, &pktEvent, packet->data,
12826124SN/A                           igbe->rxWriteDelay);
12835783SN/A            desc->adv_wb.header_len = htole((uint16_t)packet->length);
12845783SN/A            desc->adv_wb.sph = htole(0);
12855783SN/A            desc->adv_wb.pkt_len = htole(0);
12865783SN/A        } else if (split_point) {
12875783SN/A            if (pkt_offset) {
12885783SN/A                // we are only copying some data, header/data has already been
12895783SN/A                // copied
12906124SN/A                int max_to_copy =
12916124SN/A                    std::min(packet->length - pkt_offset, buf_len);
12925783SN/A                bytesCopied += max_to_copy;
12936124SN/A                DPRINTF(EthernetDesc,
12946124SN/A                        "Hdr split: Continuing data buffer copy\n");
12956124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
12966124SN/A                               max_to_copy, &pktEvent,
12976124SN/A                               packet->data + pkt_offset, igbe->rxWriteDelay);
12985783SN/A                desc->adv_wb.header_len = htole(0);
12995783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
13005783SN/A                desc->adv_wb.sph = htole(0);
13015783SN/A            } else {
13026124SN/A                int max_to_copy =
13036124SN/A                    std::min(packet->length - split_point, buf_len);
13045783SN/A                bytesCopied += max_to_copy + split_point;
130511320Ssteve.reinhardt@amd.com
13066124SN/A                DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
13075783SN/A                        split_point);
13086124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
13096124SN/A                               split_point, &pktHdrEvent,
13106124SN/A                               packet->data, igbe->rxWriteDelay);
13116124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13126124SN/A                               max_to_copy, &pktDataEvent,
13136124SN/A                               packet->data + split_point, igbe->rxWriteDelay);
13145783SN/A                desc->adv_wb.header_len = htole(split_point);
13155783SN/A                desc->adv_wb.sph = 1;
13165783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
13175783SN/A            }
13185783SN/A        } else {
13196124SN/A            panic("Header split not fitting within header buffer or "
13206124SN/A                  "undecodable packet not fitting in header unsupported\n");
13215783SN/A        }
13225763SN/A        break;
13235763SN/A      default:
13245763SN/A        panic("Unimplemnted RX receive buffer type: %d\n",
13256124SN/A              igbe->regs.srrctl.desctype());
13265763SN/A    }
13275783SN/A    return bytesCopied;
13285763SN/A
13293116SN/A}
13303116SN/A
13314263SN/Avoid
13324263SN/AIGbE::RxDescCache::pktComplete()
13334263SN/A{
13344263SN/A    assert(unusedCache.size());
13354263SN/A    RxDesc *desc;
13364263SN/A    desc = unusedCache.front();
13374263SN/A
13385954SN/A    igbe->anBegin("RXS", "Update Desc");
13395954SN/A
13404283SN/A    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
13416124SN/A    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
13426124SN/A            "stripcrc offset: %d value written: %d %d\n",
13435783SN/A            pktPtr->length, bytesCopied, crcfixup,
13444283SN/A            htole((uint16_t)(pktPtr->length + crcfixup)),
13454283SN/A            (uint16_t)(pktPtr->length + crcfixup));
13464283SN/A
13474263SN/A    // no support for anything but starting at 0
13484263SN/A    assert(igbe->regs.rxcsum.pcss() == 0);
13494263SN/A
13504291SN/A    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
13514263SN/A
13525783SN/A    uint16_t status = RXDS_DD;
13534263SN/A    uint8_t err = 0;
13545763SN/A    uint16_t ext_err = 0;
13555763SN/A    uint16_t csum = 0;
13565763SN/A    uint16_t ptype = 0;
13575763SN/A    uint16_t ip_id = 0;
13584452SN/A
13595783SN/A    assert(bytesCopied <= pktPtr->length);
13605783SN/A    if (bytesCopied == pktPtr->length)
13615783SN/A        status |= RXDS_EOP;
13625783SN/A
13634263SN/A    IpPtr ip(pktPtr);
13644452SN/A
13654263SN/A    if (ip) {
13664452SN/A        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
13675763SN/A        ptype |= RXDP_IPV4;
13685763SN/A        ip_id = ip->id();
13694452SN/A
13704263SN/A        if (igbe->regs.rxcsum.ipofld()) {
13714291SN/A            DPRINTF(EthernetDesc, "Checking IP checksum\n");
13724263SN/A            status |= RXDS_IPCS;
13735763SN/A            csum = htole(cksum(ip));
13745485SN/A            igbe->rxIpChecksums++;
13754263SN/A            if (cksum(ip) != 0) {
13764263SN/A                err |= RXDE_IPE;
13775763SN/A                ext_err |= RXDEE_IPE;
13784291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
13794263SN/A            }
13804263SN/A        }
13814263SN/A        TcpPtr tcp(ip);
13824263SN/A        if (tcp && igbe->regs.rxcsum.tuofld()) {
13834291SN/A            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
13844263SN/A            status |= RXDS_TCPCS;
13855763SN/A            ptype |= RXDP_TCP;
13865763SN/A            csum = htole(cksum(tcp));
13875485SN/A            igbe->rxTcpChecksums++;
13884263SN/A            if (cksum(tcp) != 0) {
13894291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
13904263SN/A                err |= RXDE_TCPE;
13915763SN/A                ext_err |= RXDEE_TCPE;
13924263SN/A            }
13934263SN/A        }
13944263SN/A
13954263SN/A        UdpPtr udp(ip);
13964263SN/A        if (udp && igbe->regs.rxcsum.tuofld()) {
13974291SN/A            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
13984263SN/A            status |= RXDS_UDPCS;
13995763SN/A            ptype |= RXDP_UDP;
14005763SN/A            csum = htole(cksum(udp));
14015485SN/A            igbe->rxUdpChecksums++;
14024421SN/A            if (cksum(udp) != 0) {
14034291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
14045763SN/A                ext_err |= RXDEE_TCPE;
14054263SN/A                err |= RXDE_TCPE;
14064263SN/A            }
14074263SN/A        }
14084452SN/A    } else { // if ip
14094452SN/A        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
14104452SN/A    }
14114452SN/A
14125763SN/A    switch (igbe->regs.srrctl.desctype()) {
14135763SN/A      case RXDT_LEGACY:
14145763SN/A        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
14155763SN/A        desc->legacy.status = htole(status);
14165763SN/A        desc->legacy.errors = htole(err);
14175763SN/A        // No vlan support at this point... just set it to 0
14185763SN/A        desc->legacy.vlan = 0;
14195763SN/A        break;
14205783SN/A      case RXDT_ADV_SPLIT_A:
14215763SN/A      case RXDT_ADV_ONEBUF:
14225763SN/A        desc->adv_wb.rss_type = htole(0);
14235763SN/A        desc->adv_wb.pkt_type = htole(ptype);
14245763SN/A        if (igbe->regs.rxcsum.pcsd()) {
14255763SN/A            // no rss support right now
14265763SN/A            desc->adv_wb.rss_hash = htole(0);
14275763SN/A        } else {
14285763SN/A            desc->adv_wb.id = htole(ip_id);
14295763SN/A            desc->adv_wb.csum = htole(csum);
14305763SN/A        }
14315763SN/A        desc->adv_wb.status = htole(status);
14325763SN/A        desc->adv_wb.errors = htole(ext_err);
14335763SN/A        // no vlan support
143411320Ssteve.reinhardt@amd.com        desc->adv_wb.vlan_tag = htole(0);
14355763SN/A        break;
14365763SN/A      default:
14375763SN/A        panic("Unimplemnted RX receive buffer type %d\n",
14386124SN/A              igbe->regs.srrctl.desctype());
14395763SN/A    }
14404263SN/A
14415783SN/A    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
14425783SN/A            desc->adv_read.pkt, desc->adv_read.hdr);
14434263SN/A
14445783SN/A    if (bytesCopied == pktPtr->length) {
14456124SN/A        DPRINTF(EthernetDesc,
14466124SN/A                "Packet completely written to descriptor buffers\n");
14475783SN/A        // Deal with the rx timer interrupts
14485783SN/A        if (igbe->regs.rdtr.delay()) {
14496124SN/A            Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
14506124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
14517823SN/A            igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
14525783SN/A        }
14535783SN/A
14545783SN/A        if (igbe->regs.radv.idv()) {
14556124SN/A            Tick delay = igbe->regs.radv.idv() * igbe->intClock();
14566124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
14575783SN/A            if (!igbe->radvEvent.scheduled()) {
14587823SN/A                igbe->schedule(igbe->radvEvent, curTick() + delay);
14595783SN/A            }
14605783SN/A        }
14615783SN/A
14625783SN/A        // if neither radv or rdtr, maybe itr is set...
14635783SN/A        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
14646124SN/A            DPRINTF(EthernetSM,
14656124SN/A                    "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
14665783SN/A            igbe->postInterrupt(IT_RXT);
14675783SN/A        }
14685783SN/A
14695783SN/A        // If the packet is small enough, interrupt appropriately
14705783SN/A        // I wonder if this is delayed or not?!
14715783SN/A        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
14726124SN/A            DPRINTF(EthernetSM,
14736124SN/A                    "RXS: Posting IT_SRPD beacuse small packet received\n");
14745783SN/A            igbe->postInterrupt(IT_SRPD);
14755783SN/A        }
14765783SN/A        bytesCopied = 0;
14774263SN/A    }
14784263SN/A
14795783SN/A    pktPtr = NULL;
14805783SN/A    igbe->checkDrain();
14815783SN/A    enableSm();
14825783SN/A    pktDone = true;
14834263SN/A
14845954SN/A    igbe->anBegin("RXS", "Done Updating Desc");
14854291SN/A    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
14865954SN/A    igbe->anDq("RXS", annUnusedCacheQ);
14874263SN/A    unusedCache.pop_front();
14885954SN/A    igbe->anQ("RXS", annUsedCacheQ);
14894263SN/A    usedCache.push_back(desc);
14904263SN/A}
14914263SN/A
14924263SN/Avoid
14934263SN/AIGbE::RxDescCache::enableSm()
14944263SN/A{
149510913SN/A    if (igbe->drainState() != DrainState::Draining) {
14965071SN/A        igbe->rxTick = true;
14975071SN/A        igbe->restartClock();
14985071SN/A    }
14994263SN/A}
15004263SN/A
15014263SN/Abool
15024263SN/AIGbE::RxDescCache::packetDone()
15034263SN/A{
15044263SN/A    if (pktDone) {
15054263SN/A        pktDone = false;
15064263SN/A        return true;
15074263SN/A    }
15084263SN/A    return false;
15094263SN/A}
15104263SN/A
15114294SN/Abool
15124294SN/AIGbE::RxDescCache::hasOutstandingEvents()
15134294SN/A{
15144294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
15155783SN/A        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
15165783SN/A        pktDataEvent.scheduled();
151711320Ssteve.reinhardt@amd.com
15184294SN/A}
15194294SN/A
15204294SN/Avoid
152110905SN/AIGbE::RxDescCache::serialize(CheckpointOut &cp) const
15224294SN/A{
152310905SN/A    DescCache<RxDesc>::serialize(cp);
15244294SN/A    SERIALIZE_SCALAR(pktDone);
15255783SN/A    SERIALIZE_SCALAR(splitCount);
15265783SN/A    SERIALIZE_SCALAR(bytesCopied);
15274294SN/A}
15284294SN/A
15294294SN/Avoid
153010905SN/AIGbE::RxDescCache::unserialize(CheckpointIn &cp)
15314294SN/A{
153210905SN/A    DescCache<RxDesc>::unserialize(cp);
15334294SN/A    UNSERIALIZE_SCALAR(pktDone);
15345783SN/A    UNSERIALIZE_SCALAR(splitCount);
15355783SN/A    UNSERIALIZE_SCALAR(bytesCopied);
15364294SN/A}
15374294SN/A
15384294SN/A
15396124SN/A///////////////////////////// IGbE::TxDescCache //////////////////////////////
15404263SN/A
15414263SN/AIGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
15426124SN/A    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
154310420SN/A      pktWaiting(false), pktMultiDesc(false),
154410420SN/A      completionAddress(0), completionEnabled(false),
15458553SN/A      useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
15468553SN/A      tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
15478553SN/A      tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
15488553SN/A      pktEvent(this), headerEvent(this), nullEvent(this)
15494263SN/A{
15505954SN/A    annSmFetch = "TX Desc Fetch";
15515954SN/A    annSmWb = "TX Desc Writeback";
15525954SN/A    annUnusedDescQ = "TX Unused Descriptors";
15535954SN/A    annUnusedCacheQ = "TX Unused Descriptor Cache";
15545954SN/A    annUsedCacheQ = "TX Used Descriptor Cache";
15555954SN/A    annUsedDescQ = "TX Used Descriptors";
15565954SN/A    annDescQ = "TX Descriptors";
15574263SN/A}
15584263SN/A
15595762SN/Avoid
15605762SN/AIGbE::TxDescCache::processContextDesc()
15614263SN/A{
15624263SN/A    assert(unusedCache.size());
15635762SN/A    TxDesc *desc;
156411320Ssteve.reinhardt@amd.com
15655762SN/A    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
15664263SN/A
15676124SN/A    while (!useTso && unusedCache.size() &&
15686124SN/A           TxdOp::isContext(unusedCache.front())) {
15695762SN/A        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
15704263SN/A
15715762SN/A        desc = unusedCache.front();
157211320Ssteve.reinhardt@amd.com        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
15736124SN/A                desc->d1, desc->d2);
15744263SN/A
157511320Ssteve.reinhardt@amd.com
15764263SN/A        // is this going to be a tcp or udp packet?
15774263SN/A        isTcp = TxdOp::tcp(desc) ? true : false;
15784263SN/A
157911320Ssteve.reinhardt@amd.com        // setup all the TSO variables, they'll be ignored if we don't use
15805763SN/A        // tso for this connection
15815763SN/A        tsoHeaderLen = TxdOp::hdrlen(desc);
15825763SN/A        tsoMss  = TxdOp::mss(desc);
15835763SN/A
15845763SN/A        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
15856124SN/A            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
15866124SN/A                    "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
15876124SN/A                    TxdOp::mss(desc), TxdOp::getLen(desc));
15885762SN/A            useTso = true;
15895762SN/A            tsoTotalLen = TxdOp::getLen(desc);
15905762SN/A            tsoLoadedHeader = false;
15915762SN/A            tsoDescBytesUsed = 0;
15925762SN/A            tsoUsedLen = 0;
15935762SN/A            tsoPrevSeq = 0;
15945762SN/A            tsoPktHasHeader = false;
15955762SN/A            tsoPkts = 0;
15968553SN/A            tsoCopyBytes = 0;
15975762SN/A        }
15984263SN/A
15994263SN/A        TxdOp::setDd(desc);
16004263SN/A        unusedCache.pop_front();
16015954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
16024263SN/A        usedCache.push_back(desc);
16035954SN/A        igbe->anQ("TXS", annUsedCacheQ);
16044263SN/A    }
16054263SN/A
16064263SN/A    if (!unusedCache.size())
16075762SN/A        return;
16085762SN/A
16095763SN/A    desc = unusedCache.front();
161011320Ssteve.reinhardt@amd.com    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) &&
16116124SN/A        TxdOp::tse(desc)) {
16126124SN/A        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
161311320Ssteve.reinhardt@amd.com                "hdrlen: %d mss: %d paylen %d\n",
16145763SN/A                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
16155763SN/A        useTso = true;
16165763SN/A        tsoTotalLen = TxdOp::getTsoLen(desc);
16175763SN/A        tsoLoadedHeader = false;
16185763SN/A        tsoDescBytesUsed = 0;
16195763SN/A        tsoUsedLen = 0;
16205763SN/A        tsoPrevSeq = 0;
16215763SN/A        tsoPktHasHeader = false;
16225763SN/A        tsoPkts = 0;
16235763SN/A    }
16245763SN/A
16255762SN/A    if (useTso && !tsoLoadedHeader) {
16265762SN/A        // we need to fetch a header
16275762SN/A        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
16285762SN/A        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
16295762SN/A        pktWaiting = true;
16305762SN/A        assert(tsoHeaderLen <= 256);
16316124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
16326124SN/A                      tsoHeaderLen, &headerEvent, tsoHeader, 0);
16335762SN/A    }
16345762SN/A}
16355762SN/A
16365762SN/Avoid
16375762SN/AIGbE::TxDescCache::headerComplete()
16385762SN/A{
16395762SN/A    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
16405762SN/A    pktWaiting = false;
16415762SN/A
16425762SN/A    assert(unusedCache.size());
16435762SN/A    TxDesc *desc = unusedCache.front();
16445762SN/A    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
16455762SN/A            TxdOp::getLen(desc), tsoHeaderLen);
16465762SN/A
16475762SN/A    if (TxdOp::getLen(desc) == tsoHeaderLen) {
16485762SN/A        tsoDescBytesUsed = 0;
16495762SN/A        tsoLoadedHeader = true;
16505762SN/A        unusedCache.pop_front();
16515762SN/A        usedCache.push_back(desc);
16525762SN/A    } else {
16539189SN/A        DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
16549189SN/A        tsoDescBytesUsed = tsoHeaderLen;
16559189SN/A        tsoLoadedHeader = true;
16565762SN/A    }
16575762SN/A    enableSm();
16585762SN/A    igbe->checkDrain();
16595762SN/A}
16605762SN/A
16616227SN/Aunsigned
16625762SN/AIGbE::TxDescCache::getPacketSize(EthPacketPtr p)
16635762SN/A{
16645762SN/A    if (!unusedCache.size())
16656227SN/A        return 0;
166611320Ssteve.reinhardt@amd.com
16675762SN/A    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
16685762SN/A
16695762SN/A    assert(!useTso || tsoLoadedHeader);
16706227SN/A    TxDesc *desc = unusedCache.front();
16715762SN/A
16725762SN/A    if (useTso) {
16736124SN/A        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
16746124SN/A                "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
16756124SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
16766124SN/A                "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
16776124SN/A                tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
16788553SN/A
167911320Ssteve.reinhardt@amd.com        if (tsoPktHasHeader)
16806124SN/A            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length,
16818553SN/A                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16825762SN/A        else
16836124SN/A            tsoCopyBytes =  std::min(tsoMss,
168411320Ssteve.reinhardt@amd.com                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16856227SN/A        unsigned pkt_size =
168611320Ssteve.reinhardt@amd.com            tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
16878553SN/A
16888553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
16898553SN/A                "this descLen: %d\n",
16908553SN/A                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
16918553SN/A        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
16925762SN/A        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
16935762SN/A        return pkt_size;
16945762SN/A    }
16954263SN/A
16964291SN/A    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
16976124SN/A            TxdOp::getLen(unusedCache.front()));
16985762SN/A    return TxdOp::getLen(desc);
16994263SN/A}
17004263SN/A
17014263SN/Avoid
17024263SN/AIGbE::TxDescCache::getPacketData(EthPacketPtr p)
17034263SN/A{
17044263SN/A    assert(unusedCache.size());
17054263SN/A
17064263SN/A    TxDesc *desc;
17074263SN/A    desc = unusedCache.front();
17084263SN/A
17096124SN/A    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
17106124SN/A            "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
17116124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17126124SN/A           TxdOp::getLen(desc));
17134263SN/A
17144263SN/A    pktPtr = p;
17154263SN/A
17164263SN/A    pktWaiting = true;
17174263SN/A
17185404SN/A    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
171911320Ssteve.reinhardt@amd.com
17205762SN/A    if (useTso) {
17215762SN/A        assert(tsoLoadedHeader);
17225762SN/A        if (!tsoPktHasHeader) {
17236124SN/A            DPRINTF(EthernetDesc,
17246124SN/A                    "Loading TSO header (%d bytes) into start of packet\n",
17256124SN/A                    tsoHeaderLen);
17265762SN/A            memcpy(p->data, &tsoHeader,tsoHeaderLen);
17275762SN/A            p->length +=tsoHeaderLen;
17285762SN/A            tsoPktHasHeader = true;
17295762SN/A        }
17305762SN/A    }
173111320Ssteve.reinhardt@amd.com
17325762SN/A    if (useTso) {
17336124SN/A        DPRINTF(EthernetDesc,
17346124SN/A                "Starting DMA of packet at offset %d length: %d\n",
17355762SN/A                p->length, tsoCopyBytes);
17366124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc))
17376124SN/A                      + tsoDescBytesUsed,
17386124SN/A                      tsoCopyBytes, &pktEvent, p->data + p->length,
17396124SN/A                      igbe->txReadDelay);
17408553SN/A        tsoDescBytesUsed += tsoCopyBytes;
17418553SN/A        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
17425762SN/A    } else {
17436124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
17446124SN/A                      TxdOp::getLen(desc), &pktEvent, p->data + p->length,
17456124SN/A                      igbe->txReadDelay);
17465762SN/A    }
17474263SN/A}
17484263SN/A
17494263SN/Avoid
17504263SN/AIGbE::TxDescCache::pktComplete()
17514263SN/A{
17524263SN/A
17534263SN/A    TxDesc *desc;
17544263SN/A    assert(unusedCache.size());
17554263SN/A    assert(pktPtr);
17564263SN/A
17575954SN/A    igbe->anBegin("TXS", "Update Desc");
17585954SN/A
17594291SN/A    DPRINTF(EthernetDesc, "DMA of packet complete\n");
17604263SN/A
17615339SN/A
17624263SN/A    desc = unusedCache.front();
17636124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17646124SN/A           TxdOp::getLen(desc));
17654263SN/A
17666124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
17676124SN/A            desc->d1, desc->d2);
17684283SN/A
17695762SN/A    // Set the length of the data in the EtherPacket
17705762SN/A    if (useTso) {
17718553SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
17728553SN/A            "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
17738553SN/A            tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
177411701Smichael.lebeane@amd.com        pktPtr->simLength += tsoCopyBytes;
17755762SN/A        pktPtr->length += tsoCopyBytes;
17765762SN/A        tsoUsedLen += tsoCopyBytes;
17778553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
17788553SN/A            tsoDescBytesUsed, tsoCopyBytes);
177911701Smichael.lebeane@amd.com    } else {
178011701Smichael.lebeane@amd.com        pktPtr->simLength += TxdOp::getLen(desc);
17815404SN/A        pktPtr->length += TxdOp::getLen(desc);
178211701Smichael.lebeane@amd.com    }
17835762SN/A
17845762SN/A
178511320Ssteve.reinhardt@amd.com
178611320Ssteve.reinhardt@amd.com    if ((!TxdOp::eop(desc) && !useTso) ||
17876124SN/A        (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
17886124SN/A         tsoTotalLen != tsoUsedLen && useTso)) {
17895762SN/A        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
17905954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
17914283SN/A        unusedCache.pop_front();
17925954SN/A        igbe->anQ("TXS", annUsedCacheQ);
17934283SN/A        usedCache.push_back(desc);
17945762SN/A
17955762SN/A        tsoDescBytesUsed = 0;
17964283SN/A        pktDone = true;
17974283SN/A        pktWaiting = false;
17985404SN/A        pktMultiDesc = true;
17995404SN/A
18005404SN/A        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
18015404SN/A                pktPtr->length);
18024283SN/A        pktPtr = NULL;
18034283SN/A
18044438SN/A        enableSm();
18055071SN/A        igbe->checkDrain();
18064283SN/A        return;
18074283SN/A    }
18085762SN/A
18095762SN/A
18105404SN/A    pktMultiDesc = false;
18114263SN/A    // no support for vlans
18124263SN/A    assert(!TxdOp::vle(desc));
18134263SN/A
18144263SN/A    // we only support single packet descriptors at this point
18155762SN/A    if (!useTso)
18165762SN/A        assert(TxdOp::eop(desc));
18174263SN/A
18184263SN/A    // set that this packet is done
18195762SN/A    if (TxdOp::rs(desc))
18205762SN/A        TxdOp::setDd(desc);
18214263SN/A
18226124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
18236124SN/A            desc->d1, desc->d2);
18244283SN/A
18255762SN/A    if (useTso) {
18265762SN/A        IpPtr ip(pktPtr);
18275762SN/A        if (ip) {
18285762SN/A            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
18295762SN/A                    tsoPkts);
18305762SN/A            ip->id(ip->id() + tsoPkts++);
183111320Ssteve.reinhardt@amd.com            ip->len(pktPtr->length - EthPtr(pktPtr)->size());
183211320Ssteve.reinhardt@amd.com
18335762SN/A            TcpPtr tcp(ip);
18345762SN/A            if (tcp) {
18356124SN/A                DPRINTF(EthernetDesc,
18366124SN/A                        "TSO: Modifying TCP header. old seq %d + %d\n",
18376124SN/A                        tcp->seq(), tsoPrevSeq);
18385762SN/A                tcp->seq(tcp->seq() + tsoPrevSeq);
18395762SN/A                if (tsoUsedLen != tsoTotalLen)
18405762SN/A                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
18415762SN/A            }
18425762SN/A            UdpPtr udp(ip);
18435762SN/A            if (udp) {
18445762SN/A                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
18455762SN/A                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
18465762SN/A            }
18475762SN/A        }
18485762SN/A        tsoPrevSeq = tsoUsedLen;
18495762SN/A    }
18505762SN/A
18514452SN/A    if (DTRACE(EthernetDesc)) {
18524452SN/A        IpPtr ip(pktPtr);
18534452SN/A        if (ip)
18544452SN/A            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
18554452SN/A                    ip->id());
18564452SN/A        else
18574452SN/A            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
18584452SN/A    }
18594452SN/A
18604263SN/A    // Checksums are only ofloaded for new descriptor types
18614263SN/A    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
18624291SN/A        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
18634263SN/A        IpPtr ip(pktPtr);
18645404SN/A        assert(ip);
18654263SN/A        if (TxdOp::ixsm(desc)) {
18664263SN/A            ip->sum(0);
18674263SN/A            ip->sum(cksum(ip));
18685485SN/A            igbe->txIpChecksums++;
18694291SN/A            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
18704263SN/A        }
18714987SN/A        if (TxdOp::txsm(desc)) {
18724987SN/A            TcpPtr tcp(ip);
18734987SN/A            UdpPtr udp(ip);
18744987SN/A            if (tcp) {
18756124SN/A                tcp->sum(0);
18766124SN/A                tcp->sum(cksum(tcp));
18776124SN/A                igbe->txTcpChecksums++;
18786124SN/A                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
18794987SN/A            } else if (udp) {
18806124SN/A                assert(udp);
18816124SN/A                udp->sum(0);
18826124SN/A                udp->sum(cksum(udp));
18836124SN/A                igbe->txUdpChecksums++;
18846124SN/A                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
18854987SN/A            } else {
18864987SN/A                panic("Told to checksum, but don't know how\n");
18874987SN/A            }
18884263SN/A        }
18894263SN/A    }
18904263SN/A
18914263SN/A    if (TxdOp::ide(desc)) {
18924263SN/A        // Deal with the rx timer interrupts
18934291SN/A        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
18944263SN/A        if (igbe->regs.tidv.idv()) {
18956124SN/A            Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
18964291SN/A            DPRINTF(EthernetDesc, "setting tidv\n");
18977823SN/A            igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
18984263SN/A        }
18994263SN/A
19004263SN/A        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
19016124SN/A            Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
19024291SN/A            DPRINTF(EthernetDesc, "setting tadv\n");
19034987SN/A            if (!igbe->tadvEvent.scheduled()) {
19047823SN/A                igbe->schedule(igbe->tadvEvent, curTick() + delay);
19054987SN/A            }
19064263SN/A        }
19074263SN/A    }
19084263SN/A
19094283SN/A
19105762SN/A    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
19115762SN/A        DPRINTF(EthernetDesc, "Descriptor Done\n");
19125954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
19135762SN/A        unusedCache.pop_front();
19145954SN/A        igbe->anQ("TXS", annUsedCacheQ);
19155762SN/A        usedCache.push_back(desc);
19165762SN/A        tsoDescBytesUsed = 0;
19175762SN/A    }
19184283SN/A
19195762SN/A    if (useTso && tsoUsedLen == tsoTotalLen)
19205762SN/A        useTso = false;
19215762SN/A
19225762SN/A
19236124SN/A    DPRINTF(EthernetDesc,
19246124SN/A            "------Packet of %d bytes ready for transmission-------\n",
19255762SN/A            pktPtr->length);
19264263SN/A    pktDone = true;
19274263SN/A    pktWaiting = false;
19284263SN/A    pktPtr = NULL;
19295762SN/A    tsoPktHasHeader = false;
19304283SN/A
19314283SN/A    if (igbe->regs.txdctl.wthresh() == 0) {
19325954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19334291SN/A        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
19344283SN/A        writeback(0);
19358984SN/A    } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
19366124SN/A               descInBlock(usedCache.size())) {
19375763SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19385954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19395763SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19408984SN/A    } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
19414291SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19425954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19434283SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19444283SN/A    }
19455763SN/A
19464438SN/A    enableSm();
19474294SN/A    igbe->checkDrain();
19484294SN/A}
19494283SN/A
19504294SN/Avoid
195111320Ssteve.reinhardt@amd.comIGbE::TxDescCache::actionAfterWb()
19525763SN/A{
19535763SN/A    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
19545763SN/A            completionEnabled);
19555763SN/A    igbe->postInterrupt(iGbReg::IT_TXDW);
195611320Ssteve.reinhardt@amd.com    if (completionEnabled) {
19575763SN/A        descEnd = igbe->regs.tdh();
19586124SN/A        DPRINTF(EthernetDesc,
19596124SN/A                "Completion writing back value: %d to addr: %#x\n", descEnd,
19605763SN/A                completionAddress);
19616124SN/A        igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)),
19626124SN/A                       sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
19635763SN/A    }
19645763SN/A}
19655763SN/A
19665763SN/Avoid
196710905SN/AIGbE::TxDescCache::serialize(CheckpointOut &cp) const
19684294SN/A{
196910905SN/A    DescCache<TxDesc>::serialize(cp);
197010905SN/A
19714294SN/A    SERIALIZE_SCALAR(pktDone);
19724294SN/A    SERIALIZE_SCALAR(isTcp);
19734294SN/A    SERIALIZE_SCALAR(pktWaiting);
19745404SN/A    SERIALIZE_SCALAR(pktMultiDesc);
19755762SN/A
19765762SN/A    SERIALIZE_SCALAR(useTso);
19775762SN/A    SERIALIZE_SCALAR(tsoHeaderLen);
19785762SN/A    SERIALIZE_SCALAR(tsoMss);
19795762SN/A    SERIALIZE_SCALAR(tsoTotalLen);
19805762SN/A    SERIALIZE_SCALAR(tsoUsedLen);
19815762SN/A    SERIALIZE_SCALAR(tsoPrevSeq);;
19825762SN/A    SERIALIZE_SCALAR(tsoPktPayloadBytes);
19835762SN/A    SERIALIZE_SCALAR(tsoLoadedHeader);
19845762SN/A    SERIALIZE_SCALAR(tsoPktHasHeader);
19855762SN/A    SERIALIZE_ARRAY(tsoHeader, 256);
19865762SN/A    SERIALIZE_SCALAR(tsoDescBytesUsed);
19875762SN/A    SERIALIZE_SCALAR(tsoCopyBytes);
19885762SN/A    SERIALIZE_SCALAR(tsoPkts);
19895762SN/A
19905763SN/A    SERIALIZE_SCALAR(completionAddress);
19915763SN/A    SERIALIZE_SCALAR(completionEnabled);
19925763SN/A    SERIALIZE_SCALAR(descEnd);
19934294SN/A}
19944294SN/A
19954294SN/Avoid
199610905SN/AIGbE::TxDescCache::unserialize(CheckpointIn &cp)
19974294SN/A{
199810905SN/A    DescCache<TxDesc>::unserialize(cp);
199910905SN/A
20004294SN/A    UNSERIALIZE_SCALAR(pktDone);
20014294SN/A    UNSERIALIZE_SCALAR(isTcp);
20024294SN/A    UNSERIALIZE_SCALAR(pktWaiting);
20035404SN/A    UNSERIALIZE_SCALAR(pktMultiDesc);
20045762SN/A
20055762SN/A    UNSERIALIZE_SCALAR(useTso);
20065762SN/A    UNSERIALIZE_SCALAR(tsoHeaderLen);
20075762SN/A    UNSERIALIZE_SCALAR(tsoMss);
20085762SN/A    UNSERIALIZE_SCALAR(tsoTotalLen);
20095762SN/A    UNSERIALIZE_SCALAR(tsoUsedLen);
20105762SN/A    UNSERIALIZE_SCALAR(tsoPrevSeq);;
20115762SN/A    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
20125762SN/A    UNSERIALIZE_SCALAR(tsoLoadedHeader);
20135762SN/A    UNSERIALIZE_SCALAR(tsoPktHasHeader);
20145762SN/A    UNSERIALIZE_ARRAY(tsoHeader, 256);
20155762SN/A    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
20165762SN/A    UNSERIALIZE_SCALAR(tsoCopyBytes);
20175762SN/A    UNSERIALIZE_SCALAR(tsoPkts);
20185763SN/A
20195763SN/A    UNSERIALIZE_SCALAR(completionAddress);
20205763SN/A    UNSERIALIZE_SCALAR(completionEnabled);
20215763SN/A    UNSERIALIZE_SCALAR(descEnd);
20224263SN/A}
20234263SN/A
20244263SN/Abool
20254263SN/AIGbE::TxDescCache::packetAvailable()
20264263SN/A{
20274263SN/A    if (pktDone) {
20284263SN/A        pktDone = false;
20294263SN/A        return true;
20304263SN/A    }
20314263SN/A    return false;
20324263SN/A}
20334263SN/A
20344263SN/Avoid
20354263SN/AIGbE::TxDescCache::enableSm()
20364263SN/A{
203710913SN/A    if (igbe->drainState() != DrainState::Draining) {
20385071SN/A        igbe->txTick = true;
20395071SN/A        igbe->restartClock();
20405071SN/A    }
20414263SN/A}
20424263SN/A
20434294SN/Abool
20444294SN/AIGbE::TxDescCache::hasOutstandingEvents()
20454294SN/A{
20464294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
20474294SN/A        fetchEvent.scheduled();
20484294SN/A}
20494263SN/A
20504263SN/A
20514263SN/A///////////////////////////////////// IGbE /////////////////////////////////
20524263SN/A
20534263SN/Avoid
20544283SN/AIGbE::restartClock()
20554283SN/A{
20565606SN/A    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
205710913SN/A        drainState() == DrainState::Running)
20589180SN/A        schedule(tickEvent, clockEdge(Cycles(1)));
20594283SN/A}
20604283SN/A
206110913SN/ADrainState
206210913SN/AIGbE::drain()
20634294SN/A{
206410912SN/A    unsigned int count(0);
20654294SN/A    if (rxDescCache.hasOutstandingEvents() ||
20666124SN/A        txDescCache.hasOutstandingEvents()) {
20674294SN/A        count++;
20684294SN/A    }
20694294SN/A
20704294SN/A    txFifoTick = false;
20714294SN/A    txTick = false;
20724294SN/A    rxTick = false;
20734294SN/A
20744294SN/A    if (tickEvent.scheduled())
20755606SN/A        deschedule(tickEvent);
20764294SN/A
20779152SN/A    if (count) {
20789152SN/A        DPRINTF(Drain, "IGbE not drained\n");
207910913SN/A        return DrainState::Draining;
20809152SN/A    } else
208110913SN/A        return DrainState::Drained;
20824294SN/A}
20834294SN/A
20844294SN/Avoid
20859342SN/AIGbE::drainResume()
20864294SN/A{
20879342SN/A    Drainable::drainResume();
20884294SN/A
20894294SN/A    txFifoTick = true;
20904294SN/A    txTick = true;
20914294SN/A    rxTick = true;
20924294SN/A
20934294SN/A    restartClock();
20945954SN/A    DPRINTF(EthernetSM, "resuming from drain");
20954294SN/A}
20964294SN/A
20974294SN/Avoid
20984294SN/AIGbE::checkDrain()
20994294SN/A{
210010913SN/A    if (drainState() != DrainState::Draining)
21014294SN/A        return;
21024294SN/A
21034987SN/A    txFifoTick = false;
21044987SN/A    txTick = false;
21054987SN/A    rxTick = false;
21064987SN/A    if (!rxDescCache.hasOutstandingEvents() &&
21076124SN/A        !txDescCache.hasOutstandingEvents()) {
21089152SN/A        DPRINTF(Drain, "IGbE done draining, processing drain event\n");
210910913SN/A        signalDrainDone();
21104294SN/A    }
21114294SN/A}
21124283SN/A
21134283SN/Avoid
21144263SN/AIGbE::txStateMachine()
21154263SN/A{
21164263SN/A    if (!regs.tctl.en()) {
21174263SN/A        txTick = false;
21184283SN/A        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
21194263SN/A        return;
21204263SN/A    }
21214263SN/A
21224283SN/A    // If we have a packet available and it's length is not 0 (meaning it's not
21234283SN/A    // a multidescriptor packet) put it in the fifo, otherwise an the next
21244283SN/A    // iteration we'll get the rest of the data
21255404SN/A    if (txPacket && txDescCache.packetAvailable()
21266124SN/A        && !txDescCache.packetMultiDesc() && txPacket->length) {
21275954SN/A        anQ("TXS", "TX FIFO Q");
21284263SN/A        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
21298641SN/A#ifndef NDEBUG
21308641SN/A        bool success =
21318641SN/A#endif
21328641SN/A            txFifo.push(txPacket);
213310913SN/A        txFifoTick = true && drainState() != DrainState::Draining;
21344263SN/A        assert(success);
21354263SN/A        txPacket = NULL;
21365954SN/A        anBegin("TXS", "Desc Writeback");
21374291SN/A        txDescCache.writeback((cacheBlockSize()-1)>>4);
21384263SN/A        return;
21394263SN/A    }
21404263SN/A
21414263SN/A    // Only support descriptor granularity
21426124SN/A    if (regs.txdctl.lwthresh() &&
21436124SN/A        txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
21444263SN/A        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
21454263SN/A        postInterrupt(IT_TXDLOW);
21464263SN/A    }
21474263SN/A
21484263SN/A    if (!txPacket) {
214910469SN/A        txPacket = std::make_shared<EthPacketData>(16384);
21504263SN/A    }
21514263SN/A
21524263SN/A    if (!txDescCache.packetWaiting()) {
21534263SN/A        if (txDescCache.descLeft() == 0) {
21544987SN/A            postInterrupt(IT_TXQE);
21555954SN/A            anBegin("TXS", "Desc Writeback");
21564987SN/A            txDescCache.writeback(0);
21575954SN/A            anBegin("TXS", "Desc Fetch");
21585954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21595071SN/A            txDescCache.fetchDescriptors();
21604283SN/A            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
21614283SN/A                    "writeback stopping ticking and posting TXQE\n");
21624263SN/A            txTick = false;
21634291SN/A            return;
21644263SN/A        }
21654263SN/A
21664283SN/A
21674263SN/A        if (!(txDescCache.descUnused())) {
21685954SN/A            anBegin("TXS", "Desc Fetch");
21695071SN/A            txDescCache.fetchDescriptors();
21705954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21716124SN/A            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
21726124SN/A                    "fetching and stopping ticking\n");
21734263SN/A            txTick = false;
21744263SN/A            return;
21754263SN/A        }
21765954SN/A        anPq("TXS", txDescCache.annUnusedCacheQ);
21774263SN/A
21785339SN/A
21795762SN/A        txDescCache.processContextDesc();
21805762SN/A        if (txDescCache.packetWaiting()) {
21816124SN/A            DPRINTF(EthernetSM,
21826124SN/A                    "TXS: Fetching TSO header, stopping ticking\n");
21835762SN/A            txTick = false;
21845762SN/A            return;
21855762SN/A        }
21865762SN/A
21876227SN/A        unsigned size = txDescCache.getPacketSize(txPacket);
21884283SN/A        if (size > 0 && txFifo.avail() > size) {
21895954SN/A            anRq("TXS", "TX FIFO Q");
21905954SN/A            anBegin("TXS", "DMA Packet");
21916124SN/A            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
21926124SN/A                    "beginning DMA of next packet\n", size);
21934283SN/A            txFifo.reserve(size);
21944263SN/A            txDescCache.getPacketData(txPacket);
21956227SN/A        } else if (size == 0) {
21964987SN/A            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
21976124SN/A            DPRINTF(EthernetSM,
21986124SN/A                    "TXS: No packets to get, writing back used descriptors\n");
21995954SN/A            anBegin("TXS", "Desc Writeback");
22004263SN/A            txDescCache.writeback(0);
22014291SN/A        } else {
22025954SN/A            anWf("TXS", "TX FIFO Q");
22034291SN/A            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
22044291SN/A                    "available in FIFO\n");
22054291SN/A            txTick = false;
22064263SN/A        }
22074263SN/A
22084291SN/A
22094263SN/A        return;
22104263SN/A    }
22114438SN/A    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
22124438SN/A    txTick = false;
22134263SN/A}
22144263SN/A
22154263SN/Abool
22164263SN/AIGbE::ethRxPkt(EthPacketPtr pkt)
22174263SN/A{
22185485SN/A    rxBytes += pkt->length;
22195485SN/A    rxPackets++;
22205485SN/A
22214263SN/A    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
22225954SN/A    anBegin("RXQ", "Wire Recv");
22235954SN/A
22244987SN/A
22254263SN/A    if (!regs.rctl.en()) {
22264263SN/A        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
22275954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22284263SN/A        return true;
22294263SN/A    }
22304263SN/A
22314263SN/A    // restart the state machines if they are stopped
223210913SN/A    rxTick = true && drainState() != DrainState::Draining;
22334263SN/A    if ((rxTick || txTick) && !tickEvent.scheduled()) {
22346124SN/A        DPRINTF(EthernetSM,
22356124SN/A                "RXS: received packet into fifo, starting ticking\n");
22364283SN/A        restartClock();
22374263SN/A    }
22384263SN/A
22394263SN/A    if (!rxFifo.push(pkt)) {
22404263SN/A        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
22414263SN/A        postInterrupt(IT_RXO, true);
22425954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22434263SN/A        return false;
22444263SN/A    }
22455339SN/A
22465954SN/A    if (CPA::available() && cpa->enabled()) {
22475954SN/A        assert(sys->numSystemsRunning <= 2);
22485954SN/A        System *other_sys;
22495954SN/A        if (sys->systemList[0] == sys)
22505954SN/A            other_sys = sys->systemList[1];
22515954SN/A        else
22525954SN/A            other_sys = sys->systemList[0];
22535954SN/A
22545954SN/A        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22555954SN/A        anQ("RXQ", "RX FIFO Q");
22565954SN/A        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22575954SN/A    }
22585954SN/A
22594263SN/A    return true;
22604263SN/A}
22614263SN/A
22624263SN/A
22634263SN/Avoid
22644263SN/AIGbE::rxStateMachine()
22654263SN/A{
22664263SN/A    if (!regs.rctl.en()) {
22674263SN/A        rxTick = false;
22684263SN/A        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
22694263SN/A        return;
22704263SN/A    }
22714263SN/A
22724263SN/A    // If the packet is done check for interrupts/descriptors/etc
22734263SN/A    if (rxDescCache.packetDone()) {
22744452SN/A        rxDmaPacket = false;
22754263SN/A        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
22764263SN/A        int descLeft = rxDescCache.descLeft();
22775783SN/A        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
22785783SN/A                descLeft, regs.rctl.rdmts(), regs.rdlen());
22794263SN/A        switch (regs.rctl.rdmts()) {
22806124SN/A          case 2: if (descLeft > .125 * regs.rdlen()) break;
22816124SN/A          case 1: if (descLeft > .250 * regs.rdlen()) break;
22826124SN/A          case 0: if (descLeft > .500 * regs.rdlen())  break;
22836124SN/A            DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
22846124SN/A                    "because of descriptors left\n");
22856124SN/A            postInterrupt(IT_RXDMT);
22866124SN/A            break;
22874263SN/A        }
22884263SN/A
22895783SN/A        if (rxFifo.empty())
22905783SN/A            rxDescCache.writeback(0);
22915783SN/A
22924263SN/A        if (descLeft == 0) {
22935954SN/A            anBegin("RXS", "Writeback Descriptors");
22944263SN/A            rxDescCache.writeback(0);
22955339SN/A            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
22965339SN/A                    " writeback and stopping ticking\n");
22974263SN/A            rxTick = false;
22984263SN/A        }
22994263SN/A
23004263SN/A        // only support descriptor granulaties
23014263SN/A        assert(regs.rxdctl.gran());
23024263SN/A
23034263SN/A        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
23046124SN/A            DPRINTF(EthernetSM,
23056124SN/A                    "RXS: Writing back because WTHRESH >= descUsed\n");
23065954SN/A            anBegin("RXS", "Writeback Descriptors");
23074283SN/A            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
23084283SN/A                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
23094283SN/A            else
23104283SN/A                rxDescCache.writeback((cacheBlockSize()-1)>>4);
23114263SN/A        }
23124263SN/A
23134263SN/A        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
23146124SN/A            ((rxDescCache.descLeft() - rxDescCache.descUnused()) >
23156124SN/A             regs.rxdctl.hthresh())) {
23166124SN/A            DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
23176124SN/A                    "descUnused < PTHRESH\n");
23185954SN/A            anBegin("RXS", "Fetch Descriptors");
23194263SN/A            rxDescCache.fetchDescriptors();
23204263SN/A        }
23214263SN/A
23224263SN/A        if (rxDescCache.descUnused() == 0) {
23235954SN/A            anBegin("RXS", "Fetch Descriptors");
23245071SN/A            rxDescCache.fetchDescriptors();
23255954SN/A            anWe("RXS", rxDescCache.annUnusedCacheQ);
23264291SN/A            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23274291SN/A                    "fetching descriptors and stopping ticking\n");
23284263SN/A            rxTick = false;
23294263SN/A        }
23304263SN/A        return;
23314263SN/A    }
23324263SN/A
23334452SN/A    if (rxDmaPacket) {
23346124SN/A        DPRINTF(EthernetSM,
23356124SN/A                "RXS: stopping ticking until packet DMA completes\n");
23364452SN/A        rxTick = false;
23374452SN/A        return;
23384452SN/A    }
23394452SN/A
23404263SN/A    if (!rxDescCache.descUnused()) {
23415954SN/A        anBegin("RXS", "Fetch Descriptors");
23425071SN/A        rxDescCache.fetchDescriptors();
23435954SN/A        anWe("RXS", rxDescCache.annUnusedCacheQ);
23446124SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23456124SN/A                "stopping ticking\n");
23464263SN/A        rxTick = false;
23474263SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
23484263SN/A        return;
23494263SN/A    }
23505954SN/A    anPq("RXS", rxDescCache.annUnusedCacheQ);
23514263SN/A
23524263SN/A    if (rxFifo.empty()) {
23535954SN/A        anWe("RXS", "RX FIFO Q");
23544263SN/A        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
23554263SN/A        rxTick = false;
23564263SN/A        return;
23574263SN/A    }
23585954SN/A    anPq("RXS", "RX FIFO Q");
23595954SN/A    anBegin("RXS", "Get Desc");
23604263SN/A
23614263SN/A    EthPacketPtr pkt;
23624263SN/A    pkt = rxFifo.front();
23634263SN/A
23645339SN/A
23655783SN/A    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
23664263SN/A    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
23675783SN/A    if (pktOffset == pkt->length) {
23685954SN/A        anBegin( "RXS", "FIFO Dequeue");
23695783SN/A        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
23705783SN/A        pktOffset = 0;
23715954SN/A        anDq("RXS", "RX FIFO Q");
23725783SN/A        rxFifo.pop();
23735783SN/A    }
23745783SN/A
23755339SN/A    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
23765339SN/A    rxTick = false;
23775339SN/A    rxDmaPacket = true;
23785954SN/A    anBegin("RXS", "DMA Packet");
23794263SN/A}
23804263SN/A
23814263SN/Avoid
23824263SN/AIGbE::txWire()
23834263SN/A{
23844263SN/A    if (txFifo.empty()) {
23855954SN/A        anWe("TXQ", "TX FIFO Q");
23864291SN/A        txFifoTick = false;
23874263SN/A        return;
23884263SN/A    }
23894263SN/A
23905339SN/A
23915954SN/A    anPq("TXQ", "TX FIFO Q");
23925339SN/A    if (etherInt->sendPacket(txFifo.front())) {
239310702SN/A        anQ("TXQ", "WireQ");
23944987SN/A        if (DTRACE(EthernetSM)) {
23954987SN/A            IpPtr ip(txFifo.front());
23964987SN/A            if (ip)
23974987SN/A                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
23984987SN/A                        ip->id());
23994987SN/A            else
24004987SN/A                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
24014987SN/A        }
24025954SN/A        anDq("TXQ", "TX FIFO Q");
24035954SN/A        anBegin("TXQ", "Wire Send");
24046124SN/A        DPRINTF(EthernetSM,
24056124SN/A                "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
24064263SN/A                txFifo.avail());
24075485SN/A
24085485SN/A        txBytes += txFifo.front()->length;
24095485SN/A        txPackets++;
24105538SN/A        txFifoTick = false;
24115485SN/A
24124263SN/A        txFifo.pop();
24135339SN/A    } else {
24145339SN/A        // We'll get woken up when the packet ethTxDone() gets called
24155339SN/A        txFifoTick = false;
24164263SN/A    }
24174263SN/A}
24184263SN/A
24194263SN/Avoid
24204263SN/AIGbE::tick()
24214263SN/A{
24224283SN/A    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
24234263SN/A
24244263SN/A    if (rxTick)
24254263SN/A        rxStateMachine();
24264263SN/A
24274291SN/A    if (txTick)
24284263SN/A        txStateMachine();
24294291SN/A
24304291SN/A    if (txFifoTick)
24314263SN/A        txWire();
24324263SN/A
24334291SN/A
24344291SN/A    if (rxTick || txTick || txFifoTick)
24359179SN/A        schedule(tickEvent, curTick() + clockPeriod());
24364263SN/A}
24373116SN/A
24383116SN/Avoid
24393116SN/AIGbE::ethTxDone()
24403116SN/A{
24415954SN/A    anBegin("TXQ", "Send Done");
24424291SN/A    // restart the tx state machines if they are stopped
24434291SN/A    // fifo to send another packet
24444291SN/A    // tx sm to put more data into the fifo
244510913SN/A    txFifoTick = true && drainState() != DrainState::Draining;
244610913SN/A    if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
24474987SN/A        txTick = true;
24484291SN/A
24494283SN/A    restartClock();
24505395SN/A    txWire();
24514294SN/A    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
24523116SN/A}
24533116SN/A
24543116SN/Avoid
245510905SN/AIGbE::serialize(CheckpointOut &cp) const
24563116SN/A{
245710905SN/A    PciDevice::serialize(cp);
24584294SN/A
245910905SN/A    regs.serialize(cp);
24604294SN/A    SERIALIZE_SCALAR(eeOpBits);
24614294SN/A    SERIALIZE_SCALAR(eeAddrBits);
24624294SN/A    SERIALIZE_SCALAR(eeDataBits);
24634294SN/A    SERIALIZE_SCALAR(eeOpcode);
24644294SN/A    SERIALIZE_SCALAR(eeAddr);
24655500SN/A    SERIALIZE_SCALAR(lastInterrupt);
24664294SN/A    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
24674294SN/A
246810905SN/A    rxFifo.serialize("rxfifo", cp);
246910905SN/A    txFifo.serialize("txfifo", cp);
24704294SN/A
247110469SN/A    bool txPktExists = txPacket != nullptr;
24724294SN/A    SERIALIZE_SCALAR(txPktExists);
24734294SN/A    if (txPktExists)
247410905SN/A        txPacket->serialize("txpacket", cp);
24754294SN/A
24764294SN/A    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
24776124SN/A        inter_time = 0;
24784294SN/A
24794294SN/A    if (rdtrEvent.scheduled())
24806124SN/A        rdtr_time = rdtrEvent.when();
24814294SN/A    SERIALIZE_SCALAR(rdtr_time);
24824294SN/A
24834294SN/A    if (radvEvent.scheduled())
24846124SN/A        radv_time = radvEvent.when();
24854294SN/A    SERIALIZE_SCALAR(radv_time);
24864294SN/A
24874294SN/A    if (tidvEvent.scheduled())
24886124SN/A        tidv_time = tidvEvent.when();
24894294SN/A    SERIALIZE_SCALAR(tidv_time);
24904294SN/A
24914294SN/A    if (tadvEvent.scheduled())
24926124SN/A        tadv_time = tadvEvent.when();
24934294SN/A    SERIALIZE_SCALAR(tadv_time);
24944294SN/A
24954294SN/A    if (interEvent.scheduled())
24966124SN/A        inter_time = interEvent.when();
24974294SN/A    SERIALIZE_SCALAR(inter_time);
24984294SN/A
24995783SN/A    SERIALIZE_SCALAR(pktOffset);
25005783SN/A
250110905SN/A    txDescCache.serializeSection(cp, "TxDescCache");
250210905SN/A    rxDescCache.serializeSection(cp, "RxDescCache");
25033116SN/A}
25043116SN/A
25053116SN/Avoid
250610905SN/AIGbE::unserialize(CheckpointIn &cp)
25073116SN/A{
250810905SN/A    PciDevice::unserialize(cp);
25094294SN/A
251010905SN/A    regs.unserialize(cp);
25114294SN/A    UNSERIALIZE_SCALAR(eeOpBits);
25124294SN/A    UNSERIALIZE_SCALAR(eeAddrBits);
25134294SN/A    UNSERIALIZE_SCALAR(eeDataBits);
25144294SN/A    UNSERIALIZE_SCALAR(eeOpcode);
25154294SN/A    UNSERIALIZE_SCALAR(eeAddr);
25165500SN/A    UNSERIALIZE_SCALAR(lastInterrupt);
25174294SN/A    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
25184294SN/A
251910905SN/A    rxFifo.unserialize("rxfifo", cp);
252010905SN/A    txFifo.unserialize("txfifo", cp);
25214294SN/A
25224294SN/A    bool txPktExists;
25234294SN/A    UNSERIALIZE_SCALAR(txPktExists);
25244294SN/A    if (txPktExists) {
252511701Smichael.lebeane@amd.com        txPacket = std::make_shared<EthPacketData>();
252610905SN/A        txPacket->unserialize("txpacket", cp);
25274294SN/A    }
25284294SN/A
25294294SN/A    rxTick = true;
25304294SN/A    txTick = true;
25314294SN/A    txFifoTick = true;
25324294SN/A
25334294SN/A    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
25344294SN/A    UNSERIALIZE_SCALAR(rdtr_time);
25354294SN/A    UNSERIALIZE_SCALAR(radv_time);
25364294SN/A    UNSERIALIZE_SCALAR(tidv_time);
25374294SN/A    UNSERIALIZE_SCALAR(tadv_time);
25384294SN/A    UNSERIALIZE_SCALAR(inter_time);
25394294SN/A
25404294SN/A    if (rdtr_time)
25415606SN/A        schedule(rdtrEvent, rdtr_time);
25424294SN/A
25434294SN/A    if (radv_time)
25445606SN/A        schedule(radvEvent, radv_time);
25454294SN/A
25464294SN/A    if (tidv_time)
25475606SN/A        schedule(tidvEvent, tidv_time);
25484294SN/A
25494294SN/A    if (tadv_time)
25505606SN/A        schedule(tadvEvent, tadv_time);
25514294SN/A
25524294SN/A    if (inter_time)
25535606SN/A        schedule(interEvent, inter_time);
25544294SN/A
25555783SN/A    UNSERIALIZE_SCALAR(pktOffset);
25565783SN/A
255710905SN/A    txDescCache.unserializeSection(cp, "TxDescCache");
255810905SN/A    rxDescCache.unserializeSection(cp, "RxDescCache");
25593116SN/A}
25603116SN/A
25614762SN/AIGbE *
25624762SN/AIGbEParams::create()
25633116SN/A{
25644762SN/A    return new IGbE(this);
25653116SN/A}
2566