i8254xGBe.cc revision 12087
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),
6212064Sgabeblack@google.com      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), inTick(false),
6312064Sgabeblack@google.com      rxTick(false), txTick(false), txFifoTick(false), rxDmaPacket(false),
6412064Sgabeblack@google.com      pktOffset(0), 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),
6712087Sspwilson2@wisc.edu      rdtrEvent([this]{ rdtrProcess(); }, name()),
6812087Sspwilson2@wisc.edu      radvEvent([this]{ radvProcess(); }, name()),
6912087Sspwilson2@wisc.edu      tadvEvent([this]{ tadvProcess(); }, name()),
7012087Sspwilson2@wisc.edu      tidvEvent([this]{ tidvProcess(); }, name()),
7112087Sspwilson2@wisc.edu      tickEvent([this]{ tick(); }, name()),
7212087Sspwilson2@wisc.edu      interEvent([this]{ delayIntEvent(); }, name()),
734283SN/A      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
745500SN/A      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
759157SN/A      lastInterrupt(0)
763116SN/A{
774981SN/A    etherInt = new IGbEInt(name() + ".int", this);
784981SN/A
793318SN/A    // Initialized internal registers per Intel documentation
804263SN/A    // All registers intialized to 0 by per register constructor
814218SN/A    regs.ctrl.fd(1);
824218SN/A    regs.ctrl.lrst(1);
834218SN/A    regs.ctrl.speed(2);
844218SN/A    regs.ctrl.frcspd(1);
854218SN/A    regs.sts.speed(3); // Say we're 1000Mbps
864218SN/A    regs.sts.fd(1); // full duplex
874283SN/A    regs.sts.lu(1); // link up
884218SN/A    regs.eecd.fwe(1);
894218SN/A    regs.eecd.ee_type(1);
904263SN/A    regs.imr = 0;
914263SN/A    regs.iam = 0;
924263SN/A    regs.rxdctl.gran(1);
934263SN/A    regs.rxdctl.wthresh(1);
944218SN/A    regs.fcrth(1);
955763SN/A    regs.tdwba = 0;
965763SN/A    regs.rlpml = 0;
975763SN/A    regs.sw_fw_sync = 0;
983116SN/A
994218SN/A    regs.pba.rxa(0x30);
1004218SN/A    regs.pba.txa(0x10);
1013405SN/A
1023318SN/A    eeOpBits            = 0;
1033318SN/A    eeAddrBits          = 0;
1043318SN/A    eeDataBits          = 0;
1053318SN/A    eeOpcode            = 0;
1063318SN/A
1073405SN/A    // clear all 64 16 bit words of the eeprom
1083405SN/A    memset(&flash, 0, EEPROM_SIZE*2);
1093405SN/A
1104283SN/A    // Set the MAC address
1114283SN/A    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
1124283SN/A    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
1134283SN/A        flash[x] = htobe(flash[x]);
1144218SN/A
1154218SN/A    uint16_t csum = 0;
1164218SN/A    for (int x = 0; x < EEPROM_SIZE; x++)
1174283SN/A        csum += htobe(flash[x]);
1184283SN/A
1194218SN/A
1203318SN/A    // Magic happy checksum value
1214218SN/A    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
1224263SN/A
1235954SN/A    // Store the MAC address as queue ID
1245954SN/A    macAddr = p->hardware_address;
1255954SN/A
1264263SN/A    rxFifo.clear();
1274263SN/A    txFifo.clear();
1283116SN/A}
1293116SN/A
1309086SN/AIGbE::~IGbE()
1319086SN/A{
1329086SN/A    delete etherInt;
1339086SN/A}
1349086SN/A
1355954SN/Avoid
1365954SN/AIGbE::init()
1375954SN/A{
1385954SN/A    cpa = CPA::cpa();
1399807SN/A    PciDevice::init();
1405954SN/A}
1415954SN/A
1424981SN/AEtherInt*
1434981SN/AIGbE::getEthPort(const std::string &if_name, int idx)
1444981SN/A{
1454981SN/A
1464987SN/A    if (if_name == "interface") {
1474981SN/A        if (etherInt->getPeer())
1484981SN/A            panic("Port already connected to\n");
1494981SN/A        return etherInt;
1504981SN/A    }
1514981SN/A    return NULL;
1524981SN/A}
1533116SN/A
1543116SN/ATick
1553349SN/AIGbE::writeConfig(PacketPtr pkt)
1563116SN/A{
1573116SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1583116SN/A    if (offset < PCI_DEVICE_SPECIFIC)
1599807SN/A        PciDevice::writeConfig(pkt);
1603116SN/A    else
1613116SN/A        panic("Device specific PCI config space not implemented.\n");
1623116SN/A
1636124SN/A    //
1646124SN/A    // Some work may need to be done here based for the pci COMMAND bits.
1656124SN/A    //
1663116SN/A
1679198SN/A    return configDelay;
1683116SN/A}
1693116SN/A
1706124SN/A// Handy macro for range-testing register access addresses
1716124SN/A#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
1726124SN/A
1733116SN/ATick
1743349SN/AIGbE::read(PacketPtr pkt)
1753116SN/A{
1763116SN/A    int bar;
1773116SN/A    Addr daddr;
1783116SN/A
1793116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
1803116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
1813116SN/A
1823116SN/A    // Only Memory register BAR is allowed
1833116SN/A    assert(bar == 0);
1843116SN/A
1853318SN/A    // Only 32bit accesses allowed
1863318SN/A    assert(pkt->getSize() == 4);
1873318SN/A
1884283SN/A    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
1893116SN/A
1906124SN/A    //
1916124SN/A    // Handle read of register here
1926124SN/A    //
1933116SN/A
1943405SN/A
1953318SN/A    switch (daddr) {
1964218SN/A      case REG_CTRL:
1974218SN/A        pkt->set<uint32_t>(regs.ctrl());
1984218SN/A        break;
1994218SN/A      case REG_STATUS:
2004218SN/A        pkt->set<uint32_t>(regs.sts());
2014218SN/A        break;
2024218SN/A      case REG_EECD:
2034218SN/A        pkt->set<uint32_t>(regs.eecd());
2044218SN/A        break;
2054218SN/A      case REG_EERD:
2064218SN/A        pkt->set<uint32_t>(regs.eerd());
2074218SN/A        break;
2084218SN/A      case REG_CTRL_EXT:
2094218SN/A        pkt->set<uint32_t>(regs.ctrl_ext());
2104218SN/A        break;
2114218SN/A      case REG_MDIC:
2124218SN/A        pkt->set<uint32_t>(regs.mdic());
2134218SN/A        break;
2144218SN/A      case REG_ICR:
2156124SN/A        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
2166124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
2174218SN/A        pkt->set<uint32_t>(regs.icr());
2184283SN/A        if (regs.icr.int_assert() || regs.imr == 0) {
2194283SN/A            regs.icr = regs.icr() & ~mask(30);
2204283SN/A            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
2214263SN/A        }
2224283SN/A        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
2234283SN/A            regs.imr &= ~regs.iam;
2244283SN/A        chkInterrupt();
2254218SN/A        break;
2265763SN/A      case REG_EICR:
2275763SN/A        // This is only useful for MSI, but the driver reads it every time
2285763SN/A        // Just don't do anything
2295763SN/A        pkt->set<uint32_t>(0);
2305763SN/A        break;
2314218SN/A      case REG_ITR:
2324218SN/A        pkt->set<uint32_t>(regs.itr());
2334218SN/A        break;
2344218SN/A      case REG_RCTL:
2354218SN/A        pkt->set<uint32_t>(regs.rctl());
2364218SN/A        break;
2374218SN/A      case REG_FCTTV:
2384218SN/A        pkt->set<uint32_t>(regs.fcttv());
2394218SN/A        break;
2404218SN/A      case REG_TCTL:
2414218SN/A        pkt->set<uint32_t>(regs.tctl());
2424218SN/A        break;
2434218SN/A      case REG_PBA:
2444218SN/A        pkt->set<uint32_t>(regs.pba());
2454218SN/A        break;
2464218SN/A      case REG_WUC:
24711810Sbaz21@cam.ac.uk      case REG_WUFC:
24811810Sbaz21@cam.ac.uk      case REG_WUS:
2494218SN/A      case REG_LEDCTL:
2504218SN/A        pkt->set<uint32_t>(0); // We don't care, so just return 0
2514218SN/A        break;
2524218SN/A      case REG_FCRTL:
2534218SN/A        pkt->set<uint32_t>(regs.fcrtl());
2544218SN/A        break;
2554218SN/A      case REG_FCRTH:
2564218SN/A        pkt->set<uint32_t>(regs.fcrth());
2574218SN/A        break;
2584218SN/A      case REG_RDBAL:
2594218SN/A        pkt->set<uint32_t>(regs.rdba.rdbal());
2604218SN/A        break;
2614218SN/A      case REG_RDBAH:
2624218SN/A        pkt->set<uint32_t>(regs.rdba.rdbah());
2634218SN/A        break;
2644218SN/A      case REG_RDLEN:
2654218SN/A        pkt->set<uint32_t>(regs.rdlen());
2664218SN/A        break;
2675763SN/A      case REG_SRRCTL:
2685763SN/A        pkt->set<uint32_t>(regs.srrctl());
2695763SN/A        break;
2704218SN/A      case REG_RDH:
2714218SN/A        pkt->set<uint32_t>(regs.rdh());
2724218SN/A        break;
2734218SN/A      case REG_RDT:
2744218SN/A        pkt->set<uint32_t>(regs.rdt());
2754218SN/A        break;
2764218SN/A      case REG_RDTR:
2774218SN/A        pkt->set<uint32_t>(regs.rdtr());
2784263SN/A        if (regs.rdtr.fpd()) {
2794263SN/A            rxDescCache.writeback(0);
2806124SN/A            DPRINTF(EthernetIntr,
2816124SN/A                    "Posting interrupt because of RDTR.FPD write\n");
2824263SN/A            postInterrupt(IT_RXT);
2834263SN/A            regs.rdtr.fpd(0);
2844263SN/A        }
2854218SN/A        break;
2865763SN/A      case REG_RXDCTL:
2875763SN/A        pkt->set<uint32_t>(regs.rxdctl());
2885763SN/A        break;
2894218SN/A      case REG_RADV:
2904218SN/A        pkt->set<uint32_t>(regs.radv());
2914218SN/A        break;
2924218SN/A      case REG_TDBAL:
2934218SN/A        pkt->set<uint32_t>(regs.tdba.tdbal());
2944218SN/A        break;
2954218SN/A      case REG_TDBAH:
2964218SN/A        pkt->set<uint32_t>(regs.tdba.tdbah());
2974218SN/A        break;
2984218SN/A      case REG_TDLEN:
2994218SN/A        pkt->set<uint32_t>(regs.tdlen());
3004218SN/A        break;
3014218SN/A      case REG_TDH:
3024218SN/A        pkt->set<uint32_t>(regs.tdh());
3034218SN/A        break;
3045763SN/A      case REG_TXDCA_CTL:
3055763SN/A        pkt->set<uint32_t>(regs.txdca_ctl());
3065763SN/A        break;
3074218SN/A      case REG_TDT:
3084218SN/A        pkt->set<uint32_t>(regs.tdt());
3094218SN/A        break;
3104218SN/A      case REG_TIDV:
3114218SN/A        pkt->set<uint32_t>(regs.tidv());
3124218SN/A        break;
3134218SN/A      case REG_TXDCTL:
3144218SN/A        pkt->set<uint32_t>(regs.txdctl());
3154218SN/A        break;
3164218SN/A      case REG_TADV:
3174218SN/A        pkt->set<uint32_t>(regs.tadv());
3184218SN/A        break;
3195763SN/A      case REG_TDWBAL:
3205763SN/A        pkt->set<uint32_t>(regs.tdwba & mask(32));
3215763SN/A        break;
3225763SN/A      case REG_TDWBAH:
3235763SN/A        pkt->set<uint32_t>(regs.tdwba >> 32);
3245763SN/A        break;
3254218SN/A      case REG_RXCSUM:
3264218SN/A        pkt->set<uint32_t>(regs.rxcsum());
3274218SN/A        break;
3285763SN/A      case REG_RLPML:
3295763SN/A        pkt->set<uint32_t>(regs.rlpml);
3305763SN/A        break;
3315763SN/A      case REG_RFCTL:
3325763SN/A        pkt->set<uint32_t>(regs.rfctl());
3335763SN/A        break;
3344218SN/A      case REG_MANC:
3354218SN/A        pkt->set<uint32_t>(regs.manc());
3364218SN/A        break;
3375763SN/A      case REG_SWSM:
3385763SN/A        pkt->set<uint32_t>(regs.swsm());
3395763SN/A        regs.swsm.smbi(1);
3405763SN/A        break;
3415763SN/A      case REG_FWSM:
3425763SN/A        pkt->set<uint32_t>(regs.fwsm());
3435763SN/A        break;
3445763SN/A      case REG_SWFWSYNC:
3455763SN/A        pkt->set<uint32_t>(regs.sw_fw_sync);
3465763SN/A        break;
3473318SN/A      default:
3486124SN/A        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
3496124SN/A            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
3506124SN/A            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) &&
3516124SN/A            !IN_RANGE(daddr, REG_CRCERRS, STATS_REGS_SIZE))
3524218SN/A            panic("Read request to unknown register number: %#x\n", daddr);
3534218SN/A        else
3544218SN/A            pkt->set<uint32_t>(0);
3553318SN/A    };
3563318SN/A
3574870SN/A    pkt->makeAtomicResponse();
3583116SN/A    return pioDelay;
3593116SN/A}
3603116SN/A
3613116SN/ATick
3623349SN/AIGbE::write(PacketPtr pkt)
3633116SN/A{
3643116SN/A    int bar;
3653116SN/A    Addr daddr;
3663116SN/A
3673318SN/A
3683116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
3693116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
3703116SN/A
3713116SN/A    // Only Memory register BAR is allowed
3723116SN/A    assert(bar == 0);
3733116SN/A
3743318SN/A    // Only 32bit accesses allowed
3753318SN/A    assert(pkt->getSize() == sizeof(uint32_t));
3763318SN/A
3776124SN/A    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n",
3786124SN/A            daddr, pkt->get<uint32_t>());
3793116SN/A
3806124SN/A    //
3816124SN/A    // Handle write of register here
3826124SN/A    //
3833318SN/A    uint32_t val = pkt->get<uint32_t>();
3843318SN/A
3854263SN/A    Regs::RCTL oldrctl;
3864263SN/A    Regs::TCTL oldtctl;
3874263SN/A
3883318SN/A    switch (daddr) {
3894218SN/A      case REG_CTRL:
3904218SN/A        regs.ctrl = val;
3914218SN/A        if (regs.ctrl.tfce())
3924218SN/A            warn("TX Flow control enabled, should implement\n");
3934218SN/A        if (regs.ctrl.rfce())
3944218SN/A            warn("RX Flow control enabled, should implement\n");
3954218SN/A        break;
3964218SN/A      case REG_CTRL_EXT:
3974218SN/A        regs.ctrl_ext = val;
3984218SN/A        break;
3994218SN/A      case REG_STATUS:
4004218SN/A        regs.sts = val;
4014218SN/A        break;
4024218SN/A      case REG_EECD:
4034218SN/A        int oldClk;
4044218SN/A        oldClk = regs.eecd.sk();
4054218SN/A        regs.eecd = val;
4064218SN/A        // See if this is a eeprom access and emulate accordingly
4074218SN/A        if (!oldClk && regs.eecd.sk()) {
4084218SN/A            if (eeOpBits < 8) {
4094218SN/A                eeOpcode = eeOpcode << 1 | regs.eecd.din();
4104218SN/A                eeOpBits++;
4114218SN/A            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
4124218SN/A                eeAddr = eeAddr << 1 | regs.eecd.din();
4134218SN/A                eeAddrBits++;
4144218SN/A            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
4154218SN/A                assert(eeAddr>>1 < EEPROM_SIZE);
4164218SN/A                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
4176124SN/A                        flash[eeAddr>>1] >> eeDataBits & 0x1,
4186124SN/A                        flash[eeAddr>>1]);
4194218SN/A                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
4204218SN/A                eeDataBits++;
4214218SN/A            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
4224218SN/A                regs.eecd.dout(0);
4234218SN/A                eeDataBits++;
4244218SN/A            } else
4254218SN/A                panic("What's going on with eeprom interface? opcode:"
4266124SN/A                      " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
4276124SN/A                      (uint32_t)eeOpBits, (uint32_t)eeAddr,
4286124SN/A                      (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
4293318SN/A
4304218SN/A            // Reset everything for the next command
4314218SN/A            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
4326124SN/A                (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
4334218SN/A                eeOpBits = 0;
4344218SN/A                eeAddrBits = 0;
4354218SN/A                eeDataBits = 0;
4366124SN/A                eeOpcode = 0;
4374218SN/A                eeAddr = 0;
4384218SN/A            }
4393318SN/A
4406124SN/A            DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
4414218SN/A                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
4424218SN/A                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
4436124SN/A            if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
4444218SN/A                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
4454218SN/A                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
4466124SN/A                      (uint32_t)eeOpBits);
4473318SN/A
4483318SN/A
4494218SN/A        }
4504218SN/A        // If driver requests eeprom access, immediately give it to it
4514218SN/A        regs.eecd.ee_gnt(regs.eecd.ee_req());
4524218SN/A        break;
4534218SN/A      case REG_EERD:
4544218SN/A        regs.eerd = val;
4555763SN/A        if (regs.eerd.start()) {
4565763SN/A            regs.eerd.done(1);
4575763SN/A            assert(regs.eerd.addr() < EEPROM_SIZE);
4585763SN/A            regs.eerd.data(flash[regs.eerd.addr()]);
4595763SN/A            regs.eerd.start(0);
4605763SN/A            DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
4615763SN/A                    regs.eerd.addr(), regs.eerd.data());
4625763SN/A        }
4634218SN/A        break;
4644218SN/A      case REG_MDIC:
4654218SN/A        regs.mdic = val;
4664218SN/A        if (regs.mdic.i())
4674218SN/A            panic("No support for interrupt on mdic complete\n");
4684218SN/A        if (regs.mdic.phyadd() != 1)
4694218SN/A            panic("No support for reading anything but phy\n");
4706124SN/A        DPRINTF(Ethernet, "%s phy address %x\n",
4716124SN/A                regs.mdic.op() == 1 ? "Writing" : "Reading",
4726124SN/A                regs.mdic.regadd());
4734218SN/A        switch (regs.mdic.regadd()) {
4746124SN/A          case PHY_PSTATUS:
4756124SN/A            regs.mdic.data(0x796D); // link up
4766124SN/A            break;
4776124SN/A          case PHY_PID:
4786124SN/A            regs.mdic.data(params()->phy_pid);
4796124SN/A            break;
4806124SN/A          case PHY_EPID:
4816124SN/A            regs.mdic.data(params()->phy_epid);
4826124SN/A            break;
4836124SN/A          case PHY_GSTATUS:
4846124SN/A            regs.mdic.data(0x7C00);
4856124SN/A            break;
4866124SN/A          case PHY_EPSTATUS:
4876124SN/A            regs.mdic.data(0x3000);
4886124SN/A            break;
4896124SN/A          case PHY_AGC:
4906124SN/A            regs.mdic.data(0x180); // some random length
4916124SN/A            break;
4926124SN/A          default:
4936124SN/A            regs.mdic.data(0);
4944218SN/A        }
4954218SN/A        regs.mdic.r(1);
4964218SN/A        break;
4974218SN/A      case REG_ICR:
4986124SN/A        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
4996124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
5004283SN/A        if (regs.ctrl_ext.iame())
5014283SN/A            regs.imr &= ~regs.iam;
5024263SN/A        regs.icr = ~bits(val,30,0) & regs.icr();
5034283SN/A        chkInterrupt();
5044218SN/A        break;
5054218SN/A      case REG_ITR:
5064218SN/A        regs.itr = val;
5074218SN/A        break;
5084218SN/A      case REG_ICS:
5094291SN/A        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
5104263SN/A        postInterrupt((IntTypes)val);
5114218SN/A        break;
5126124SN/A      case REG_IMS:
5134218SN/A        regs.imr |= val;
5144263SN/A        chkInterrupt();
5154218SN/A        break;
5164218SN/A      case REG_IMC:
5174263SN/A        regs.imr &= ~val;
5184263SN/A        chkInterrupt();
5194218SN/A        break;
5204218SN/A      case REG_IAM:
5214218SN/A        regs.iam = val;
5224218SN/A        break;
5234218SN/A      case REG_RCTL:
5244263SN/A        oldrctl = regs.rctl;
5254218SN/A        regs.rctl = val;
5264263SN/A        if (regs.rctl.rst()) {
5274263SN/A            rxDescCache.reset();
5284291SN/A            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
5294263SN/A            rxFifo.clear();
5304263SN/A            regs.rctl.rst(0);
5314263SN/A        }
5324263SN/A        if (regs.rctl.en())
5334263SN/A            rxTick = true;
5344283SN/A        restartClock();
5354218SN/A        break;
5364218SN/A      case REG_FCTTV:
5374218SN/A        regs.fcttv = val;
5384218SN/A        break;
5394218SN/A      case REG_TCTL:
5404218SN/A        regs.tctl = val;
5414263SN/A        oldtctl = regs.tctl;
5424263SN/A        regs.tctl = val;
5434263SN/A        if (regs.tctl.en())
5446124SN/A            txTick = true;
5454283SN/A        restartClock();
5464263SN/A        if (regs.tctl.en() && !oldtctl.en()) {
5474263SN/A            txDescCache.reset();
5484263SN/A        }
5496124SN/A        break;
5504218SN/A      case REG_PBA:
5514218SN/A        regs.pba.rxa(val);
5524218SN/A        regs.pba.txa(64 - regs.pba.rxa());
5534218SN/A        break;
5544218SN/A      case REG_WUC:
55511810Sbaz21@cam.ac.uk      case REG_WUFC:
55611810Sbaz21@cam.ac.uk      case REG_WUS:
5574218SN/A      case REG_LEDCTL:
5584218SN/A      case REG_FCAL:
5594218SN/A      case REG_FCAH:
5604218SN/A      case REG_FCT:
5614218SN/A      case REG_VET:
5624218SN/A      case REG_AIFS:
5634218SN/A      case REG_TIPG:
5644218SN/A        ; // We don't care, so don't store anything
5654218SN/A        break;
5665763SN/A      case REG_IVAR0:
5675763SN/A        warn("Writing to IVAR0, ignoring...\n");
5685763SN/A        break;
5694218SN/A      case REG_FCRTL:
5704218SN/A        regs.fcrtl = val;
5714218SN/A        break;
5724218SN/A      case REG_FCRTH:
5734218SN/A        regs.fcrth = val;
5744218SN/A        break;
5754218SN/A      case REG_RDBAL:
5764218SN/A        regs.rdba.rdbal( val & ~mask(4));
5774263SN/A        rxDescCache.areaChanged();
5784218SN/A        break;
5794218SN/A      case REG_RDBAH:
5804218SN/A        regs.rdba.rdbah(val);
5814263SN/A        rxDescCache.areaChanged();
5824218SN/A        break;
5834218SN/A      case REG_RDLEN:
5844218SN/A        regs.rdlen = val & ~mask(7);
5854263SN/A        rxDescCache.areaChanged();
5864218SN/A        break;
5875763SN/A      case REG_SRRCTL:
5885763SN/A        regs.srrctl = val;
5895763SN/A        break;
5904218SN/A      case REG_RDH:
5914218SN/A        regs.rdh = val;
5924263SN/A        rxDescCache.areaChanged();
5934218SN/A        break;
5944218SN/A      case REG_RDT:
5954218SN/A        regs.rdt = val;
5964987SN/A        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
59710913SN/A        if (drainState() == DrainState::Running) {
5984987SN/A            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
5994987SN/A            rxDescCache.fetchDescriptors();
6004987SN/A        } else {
6014987SN/A            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
6024987SN/A        }
6034218SN/A        break;
6044218SN/A      case REG_RDTR:
6054218SN/A        regs.rdtr = val;
6064218SN/A        break;
6074218SN/A      case REG_RADV:
6084218SN/A        regs.radv = val;
6094218SN/A        break;
6105763SN/A      case REG_RXDCTL:
6115763SN/A        regs.rxdctl = val;
6125763SN/A        break;
6134218SN/A      case REG_TDBAL:
6144218SN/A        regs.tdba.tdbal( val & ~mask(4));
6154263SN/A        txDescCache.areaChanged();
6164218SN/A        break;
6174218SN/A      case REG_TDBAH:
6184218SN/A        regs.tdba.tdbah(val);
6194263SN/A        txDescCache.areaChanged();
6204218SN/A        break;
6214218SN/A      case REG_TDLEN:
6224218SN/A        regs.tdlen = val & ~mask(7);
6234263SN/A        txDescCache.areaChanged();
6244218SN/A        break;
6254218SN/A      case REG_TDH:
6264218SN/A        regs.tdh = val;
6274263SN/A        txDescCache.areaChanged();
6284218SN/A        break;
6295763SN/A      case REG_TXDCA_CTL:
6305763SN/A        regs.txdca_ctl = val;
6315763SN/A        if (regs.txdca_ctl.enabled())
6325763SN/A            panic("No support for DCA\n");
6335763SN/A        break;
6344218SN/A      case REG_TDT:
6354218SN/A        regs.tdt = val;
6364987SN/A        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
63710913SN/A        if (drainState() == DrainState::Running) {
6384987SN/A            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
6394987SN/A            txDescCache.fetchDescriptors();
6404987SN/A        } else {
6414987SN/A            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
6424987SN/A        }
6434218SN/A        break;
6444218SN/A      case REG_TIDV:
6454218SN/A        regs.tidv = val;
6464218SN/A        break;
6474218SN/A      case REG_TXDCTL:
6484218SN/A        regs.txdctl = val;
6494218SN/A        break;
6504218SN/A      case REG_TADV:
6514218SN/A        regs.tadv = val;
6524218SN/A        break;
6535763SN/A      case REG_TDWBAL:
6545763SN/A        regs.tdwba &= ~mask(32);
6555763SN/A        regs.tdwba |= val;
6566124SN/A        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
6576124SN/A                                        regs.tdwba & mask(1));
6585763SN/A        break;
6595763SN/A      case REG_TDWBAH:
6605763SN/A        regs.tdwba &= mask(32);
6615763SN/A        regs.tdwba |= (uint64_t)val << 32;
6626124SN/A        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
6636124SN/A                                        regs.tdwba & mask(1));
6645763SN/A        break;
6654218SN/A      case REG_RXCSUM:
6664218SN/A        regs.rxcsum = val;
6674218SN/A        break;
6685763SN/A      case REG_RLPML:
6695763SN/A        regs.rlpml = val;
6705763SN/A        break;
6715763SN/A      case REG_RFCTL:
6725763SN/A        regs.rfctl = val;
6735763SN/A        if (regs.rfctl.exsten())
6745763SN/A            panic("Extended RX descriptors not implemented\n");
6755763SN/A        break;
6764218SN/A      case REG_MANC:
6774218SN/A        regs.manc = val;
6784218SN/A        break;
6795763SN/A      case REG_SWSM:
6805763SN/A        regs.swsm = val;
6815763SN/A        if (regs.fwsm.eep_fw_semaphore())
6825763SN/A            regs.swsm.swesmbi(0);
6835763SN/A        break;
6845763SN/A      case REG_SWFWSYNC:
6855763SN/A        regs.sw_fw_sync = val;
6865763SN/A        break;
6873318SN/A      default:
6886124SN/A        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
6896124SN/A            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
6906124SN/A            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4))
6916124SN/A            panic("Write request to unknown register number: %#x\n", daddr);
6923318SN/A    };
6933116SN/A
6944870SN/A    pkt->makeAtomicResponse();
6953116SN/A    return pioDelay;
6963116SN/A}
6973116SN/A
6984263SN/Avoid
6994263SN/AIGbE::postInterrupt(IntTypes t, bool now)
7004263SN/A{
7014283SN/A    assert(t);
7024283SN/A
7034263SN/A    // Interrupt is already pending
7044987SN/A    if (t & regs.icr() && !now)
7054263SN/A        return;
7064263SN/A
7074987SN/A    regs.icr = regs.icr() | t;
7085500SN/A
7097064SN/A    Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval();
7106124SN/A    DPRINTF(EthernetIntr,
7117823SN/A            "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
7127823SN/A            curTick(), regs.itr.interval(), itr_interval);
7135500SN/A
7146124SN/A    if (regs.itr.interval() == 0 || now ||
7157823SN/A        lastInterrupt + itr_interval <= curTick()) {
7164987SN/A        if (interEvent.scheduled()) {
7175606SN/A            deschedule(interEvent);
7184987SN/A        }
7194987SN/A        cpuPostInt();
7204263SN/A    } else {
7216124SN/A        Tick int_time = lastInterrupt + itr_interval;
7226124SN/A        assert(int_time > 0);
7236124SN/A        DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
7245500SN/A                int_time);
7256124SN/A        if (!interEvent.scheduled()) {
7266124SN/A            schedule(interEvent, int_time);
7276124SN/A        }
7284263SN/A    }
7294263SN/A}
7304263SN/A
7314263SN/Avoid
7324987SN/AIGbE::delayIntEvent()
7334987SN/A{
7344987SN/A    cpuPostInt();
7354987SN/A}
7364987SN/A
7374987SN/A
7384987SN/Avoid
7394263SN/AIGbE::cpuPostInt()
7404263SN/A{
7414987SN/A
7425533SN/A    postedInterrupts++;
7435533SN/A
7444987SN/A    if (!(regs.icr() & regs.imr)) {
7454987SN/A        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
7464987SN/A        return;
7474987SN/A    }
7484987SN/A
7494987SN/A    DPRINTF(Ethernet, "Posting Interrupt\n");
7504987SN/A
7514987SN/A
7524987SN/A    if (interEvent.scheduled()) {
7535606SN/A        deschedule(interEvent);
7544987SN/A    }
7554987SN/A
7564263SN/A    if (rdtrEvent.scheduled()) {
7574263SN/A        regs.icr.rxt0(1);
7585606SN/A        deschedule(rdtrEvent);
7594263SN/A    }
7604263SN/A    if (radvEvent.scheduled()) {
7614263SN/A        regs.icr.rxt0(1);
7625606SN/A        deschedule(radvEvent);
7634263SN/A    }
7644263SN/A    if (tadvEvent.scheduled()) {
7654263SN/A        regs.icr.txdw(1);
7665606SN/A        deschedule(tadvEvent);
7674263SN/A    }
7684263SN/A    if (tidvEvent.scheduled()) {
7694263SN/A        regs.icr.txdw(1);
7705606SN/A        deschedule(tidvEvent);
7714263SN/A    }
7724263SN/A
7734263SN/A    regs.icr.int_assert(1);
7744263SN/A    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
7754263SN/A            regs.icr());
7764987SN/A
7774263SN/A    intrPost();
7784987SN/A
7797823SN/A    lastInterrupt = curTick();
7804263SN/A}
7814263SN/A
7824263SN/Avoid
7834263SN/AIGbE::cpuClearInt()
7844263SN/A{
7854283SN/A    if (regs.icr.int_assert()) {
7864283SN/A        regs.icr.int_assert(0);
7876124SN/A        DPRINTF(EthernetIntr,
7886124SN/A                "EINT: Clearing interrupt to CPU now. Vector %#x\n",
7894283SN/A                regs.icr());
7904283SN/A        intrClear();
7914283SN/A    }
7924263SN/A}
7934263SN/A
7944263SN/Avoid
7954263SN/AIGbE::chkInterrupt()
7964263SN/A{
7974987SN/A    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
7984987SN/A            regs.imr);
7994263SN/A    // Check if we need to clear the cpu interrupt
8004283SN/A    if (!(regs.icr() & regs.imr)) {
8014987SN/A        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
8024283SN/A        if (interEvent.scheduled())
8036124SN/A            deschedule(interEvent);
8044283SN/A        if (regs.icr.int_assert())
8054283SN/A            cpuClearInt();
8064283SN/A    }
8076124SN/A    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n",
8086124SN/A            regs.itr(), regs.itr.interval());
8094263SN/A
8104283SN/A    if (regs.icr() & regs.imr) {
8114283SN/A        if (regs.itr.interval() == 0)  {
8124283SN/A            cpuPostInt();
8134283SN/A        } else {
8146124SN/A            DPRINTF(Ethernet,
8156124SN/A                    "Possibly scheduling interrupt because of imr write\n");
8164987SN/A            if (!interEvent.scheduled()) {
8177823SN/A                Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval();
8186124SN/A                DPRINTF(Ethernet, "Scheduling for %d\n", t);
8196124SN/A                schedule(interEvent, t);
8204987SN/A            }
8214283SN/A        }
8224283SN/A    }
8236124SN/A}
8244283SN/A
8254283SN/A
8266124SN/A///////////////////////////// IGbE::DescCache //////////////////////////////
8276124SN/A
8286124SN/Atemplate<class T>
8296124SN/AIGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s)
8306124SN/A    : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0),
83110420SN/A      wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
83212087Sspwilson2@wisc.edu      wbDelayEvent([this]{ writeback1(); }, n),
83312087Sspwilson2@wisc.edu      fetchDelayEvent([this]{ fetchDescriptors1(); }, n),
83412087Sspwilson2@wisc.edu      fetchEvent([this]{ fetchComplete(); }, n),
83512087Sspwilson2@wisc.edu      wbEvent([this]{ wbComplete(); }, n)
8366124SN/A{
8376124SN/A    fetchBuf = new T[size];
8386124SN/A    wbBuf = new T[size];
8396124SN/A}
8406124SN/A
8416124SN/Atemplate<class T>
8426124SN/AIGbE::DescCache<T>::~DescCache()
8436124SN/A{
8446124SN/A    reset();
8459086SN/A    delete[] fetchBuf;
8469086SN/A    delete[] wbBuf;
8476124SN/A}
8486124SN/A
8496124SN/Atemplate<class T>
8506124SN/Avoid
8516124SN/AIGbE::DescCache<T>::areaChanged()
8526124SN/A{
8536124SN/A    if (usedCache.size() > 0 || curFetching || wbOut)
8546124SN/A        panic("Descriptor Address, Length or Head changed. Bad\n");
8556124SN/A    reset();
8566124SN/A
8574263SN/A}
8584263SN/A
8596124SN/Atemplate<class T>
8606124SN/Avoid
8616124SN/AIGbE::DescCache<T>::writeback(Addr aMask)
8626124SN/A{
8636124SN/A    int curHead = descHead();
8646124SN/A    int max_to_wb = usedCache.size();
8656124SN/A
8666124SN/A    // Check if this writeback is less restrictive that the previous
8676124SN/A    // and if so setup another one immediately following it
8686124SN/A    if (wbOut) {
8696124SN/A        if (aMask < wbAlignment) {
8706124SN/A            moreToWb = true;
8716124SN/A            wbAlignment = aMask;
8726124SN/A        }
8736124SN/A        DPRINTF(EthernetDesc,
8746124SN/A                "Writing back already in process, returning\n");
8756124SN/A        return;
8766124SN/A    }
8776124SN/A
8786124SN/A    moreToWb = false;
8796124SN/A    wbAlignment = aMask;
88011320Ssteve.reinhardt@amd.com
8816124SN/A
8826124SN/A    DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
8836124SN/A            "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
8846124SN/A            curHead, descTail(), descLen(), cachePnt, max_to_wb,
8856124SN/A            descLeft());
8866124SN/A
8876124SN/A    if (max_to_wb + curHead >= descLen()) {
8886124SN/A        max_to_wb = descLen() - curHead;
8896124SN/A        moreToWb = true;
8906124SN/A        // this is by definition aligned correctly
8916124SN/A    } else if (wbAlignment != 0) {
8926124SN/A        // align the wb point to the mask
8936124SN/A        max_to_wb = max_to_wb & ~wbAlignment;
8946124SN/A    }
8956124SN/A
8966124SN/A    DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
8976124SN/A
8986124SN/A    if (max_to_wb <= 0) {
8996124SN/A        if (usedCache.size())
9006124SN/A            igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
9016124SN/A        else
9026124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
9036124SN/A        return;
9046124SN/A    }
9056124SN/A
9066124SN/A    wbOut = max_to_wb;
9076124SN/A
90811320Ssteve.reinhardt@amd.com    assert(!wbDelayEvent.scheduled());
9097823SN/A    igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9106124SN/A    igbe->anBegin(annSmWb, "Prepare Writeback Desc");
9116124SN/A}
91211320Ssteve.reinhardt@amd.com
9136124SN/Atemplate<class T>
9146124SN/Avoid
9156124SN/AIGbE::DescCache<T>::writeback1()
9166124SN/A{
9176124SN/A    // If we're draining delay issuing this DMA
91810913SN/A    if (igbe->drainState() != DrainState::Running) {
9197823SN/A        igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9206124SN/A        return;
9216124SN/A    }
9226124SN/A
9236124SN/A    DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
92411320Ssteve.reinhardt@amd.com
9256124SN/A    for (int x = 0; x < wbOut; x++) {
9266124SN/A        assert(usedCache.size());
9276124SN/A        memcpy(&wbBuf[x], usedCache[x], sizeof(T));
9286124SN/A        igbe->anPq(annSmWb, annUsedCacheQ);
9296124SN/A        igbe->anPq(annSmWb, annDescQ);
9306124SN/A        igbe->anQ(annSmWb, annUsedDescQ);
9316124SN/A    }
9326124SN/A
93311320Ssteve.reinhardt@amd.com
9346124SN/A    igbe->anBegin(annSmWb, "Writeback Desc DMA");
9356124SN/A
9366124SN/A    assert(wbOut);
9376124SN/A    igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
9386124SN/A                   wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
9396124SN/A                   igbe->wbCompDelay);
9406124SN/A}
9416124SN/A
9426124SN/Atemplate<class T>
9436124SN/Avoid
9446124SN/AIGbE::DescCache<T>::fetchDescriptors()
9456124SN/A{
9466124SN/A    size_t max_to_fetch;
9476124SN/A
9486124SN/A    if (curFetching) {
9496124SN/A        DPRINTF(EthernetDesc,
9506124SN/A                "Currently fetching %d descriptors, returning\n",
9516124SN/A                curFetching);
9526124SN/A        return;
9536124SN/A    }
9546124SN/A
9556124SN/A    if (descTail() >= cachePnt)
9566124SN/A        max_to_fetch = descTail() - cachePnt;
9576124SN/A    else
9586124SN/A        max_to_fetch = descLen() - cachePnt;
9596124SN/A
9606124SN/A    size_t free_cache = size - usedCache.size() - unusedCache.size();
9616124SN/A
9626124SN/A    if (!max_to_fetch)
9636124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
9646124SN/A    else
9656124SN/A        igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
9666124SN/A
9676124SN/A    if (max_to_fetch) {
9686124SN/A        if (!free_cache)
9696124SN/A            igbe->anWf(annSmFetch, annDescQ);
9706124SN/A        else
9716124SN/A            igbe->anRq(annSmFetch, annDescQ, free_cache);
9726124SN/A    }
9736124SN/A
9746124SN/A    max_to_fetch = std::min(max_to_fetch, free_cache);
97511320Ssteve.reinhardt@amd.com
9766124SN/A
9776124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
9786124SN/A            "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
9796124SN/A            descHead(), descTail(), descLen(), cachePnt,
9806124SN/A            max_to_fetch, descLeft());
9816124SN/A
9826124SN/A    // Nothing to do
9836124SN/A    if (max_to_fetch == 0)
9846124SN/A        return;
98511320Ssteve.reinhardt@amd.com
9866124SN/A    // So we don't have two descriptor fetches going on at once
9876124SN/A    curFetching = max_to_fetch;
9886124SN/A
9896124SN/A    assert(!fetchDelayEvent.scheduled());
9907823SN/A    igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9916124SN/A    igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
9926124SN/A}
9936124SN/A
9946124SN/Atemplate<class T>
9956124SN/Avoid
9966124SN/AIGbE::DescCache<T>::fetchDescriptors1()
9976124SN/A{
9986124SN/A    // If we're draining delay issuing this DMA
99910913SN/A    if (igbe->drainState() != DrainState::Running) {
10007823SN/A        igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
10016124SN/A        return;
10026124SN/A    }
10036124SN/A
10046124SN/A    igbe->anBegin(annSmFetch, "Fetch Desc");
10056124SN/A
10066124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
10076124SN/A            descBase() + cachePnt * sizeof(T),
10086124SN/A            pciToDma(descBase() + cachePnt * sizeof(T)),
10096124SN/A            curFetching * sizeof(T));
10106124SN/A    assert(curFetching);
10116124SN/A    igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
10126124SN/A                  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
10136124SN/A                  igbe->fetchCompDelay);
10146124SN/A}
10156124SN/A
10166124SN/Atemplate<class T>
10176124SN/Avoid
10186124SN/AIGbE::DescCache<T>::fetchComplete()
10196124SN/A{
10206124SN/A    T *newDesc;
10216124SN/A    igbe->anBegin(annSmFetch, "Fetch Complete");
10226124SN/A    for (int x = 0; x < curFetching; x++) {
10236124SN/A        newDesc = new T;
10246124SN/A        memcpy(newDesc, &fetchBuf[x], sizeof(T));
10256124SN/A        unusedCache.push_back(newDesc);
10266124SN/A        igbe->anDq(annSmFetch, annUnusedDescQ);
10276124SN/A        igbe->anQ(annSmFetch, annUnusedCacheQ);
10286124SN/A        igbe->anQ(annSmFetch, annDescQ);
10296124SN/A    }
10306124SN/A
10316124SN/A
10326124SN/A#ifndef NDEBUG
10336124SN/A    int oldCp = cachePnt;
10346124SN/A#endif
10356124SN/A
10366124SN/A    cachePnt += curFetching;
10376124SN/A    assert(cachePnt <= descLen());
10386124SN/A    if (cachePnt == descLen())
10396124SN/A        cachePnt = 0;
10406124SN/A
10416124SN/A    curFetching = 0;
10426124SN/A
10436124SN/A    DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
10446124SN/A            oldCp, cachePnt);
10456124SN/A
10466124SN/A    if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
10476124SN/A                                                             cachePnt)) == 0)
10486124SN/A    {
10496124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
10506124SN/A    } else if (!(size - usedCache.size() - unusedCache.size())) {
10516124SN/A        igbe->anWf(annSmFetch, annDescQ);
10526124SN/A    } else {
10536124SN/A        igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
10546124SN/A    }
10556124SN/A
10566124SN/A    enableSm();
10576124SN/A    igbe->checkDrain();
10586124SN/A}
10596124SN/A
10606124SN/Atemplate<class T>
10616124SN/Avoid
10626124SN/AIGbE::DescCache<T>::wbComplete()
10636124SN/A{
10646124SN/A
10656124SN/A    igbe->anBegin(annSmWb, "Finish Writeback");
10666124SN/A
10676124SN/A    long  curHead = descHead();
10686124SN/A#ifndef NDEBUG
10696124SN/A    long oldHead = curHead;
10706124SN/A#endif
107111320Ssteve.reinhardt@amd.com
10726124SN/A    for (int x = 0; x < wbOut; x++) {
10736124SN/A        assert(usedCache.size());
10746124SN/A        delete usedCache[0];
10756124SN/A        usedCache.pop_front();
10766124SN/A
10776124SN/A        igbe->anDq(annSmWb, annUsedCacheQ);
10786124SN/A        igbe->anDq(annSmWb, annDescQ);
10796124SN/A    }
10806124SN/A
10816124SN/A    curHead += wbOut;
10826124SN/A    wbOut = 0;
10836124SN/A
10846124SN/A    if (curHead >= descLen())
10856124SN/A        curHead -= descLen();
10866124SN/A
10876124SN/A    // Update the head
10886124SN/A    updateHead(curHead);
10896124SN/A
10906124SN/A    DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
10916124SN/A            oldHead, curHead);
10926124SN/A
10936124SN/A    // If we still have more to wb, call wb now
10946124SN/A    actionAfterWb();
10956124SN/A    if (moreToWb) {
10966124SN/A        moreToWb = false;
10976124SN/A        DPRINTF(EthernetDesc, "Writeback has more todo\n");
10986124SN/A        writeback(wbAlignment);
10996124SN/A    }
11006124SN/A
11016124SN/A    if (!wbOut) {
11026124SN/A        igbe->checkDrain();
11036124SN/A        if (usedCache.size())
11046124SN/A            igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
11056124SN/A        else
11066124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
11076124SN/A    }
11086124SN/A    fetchAfterWb();
11096124SN/A}
11106124SN/A
11116124SN/Atemplate<class T>
11126124SN/Avoid
11136124SN/AIGbE::DescCache<T>::reset()
11146124SN/A{
11156124SN/A    DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
11166228SN/A    for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
11176124SN/A        delete usedCache[x];
11186228SN/A    for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
11196124SN/A        delete unusedCache[x];
11206124SN/A
11216124SN/A    usedCache.clear();
11226124SN/A    unusedCache.clear();
11236124SN/A
11246124SN/A    cachePnt = 0;
11256124SN/A
11266124SN/A}
11276124SN/A
11286124SN/Atemplate<class T>
11296124SN/Avoid
113010905SN/AIGbE::DescCache<T>::serialize(CheckpointOut &cp) const
11316124SN/A{
11326124SN/A    SERIALIZE_SCALAR(cachePnt);
11336124SN/A    SERIALIZE_SCALAR(curFetching);
11346124SN/A    SERIALIZE_SCALAR(wbOut);
11356124SN/A    SERIALIZE_SCALAR(moreToWb);
11366124SN/A    SERIALIZE_SCALAR(wbAlignment);
11376124SN/A
11386228SN/A    typename CacheType::size_type usedCacheSize = usedCache.size();
11396124SN/A    SERIALIZE_SCALAR(usedCacheSize);
11406228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
114110905SN/A        arrayParamOut(cp, csprintf("usedCache_%d", x),
11426124SN/A                      (uint8_t*)usedCache[x],sizeof(T));
11436124SN/A    }
11446124SN/A
11456228SN/A    typename CacheType::size_type unusedCacheSize = unusedCache.size();
11466124SN/A    SERIALIZE_SCALAR(unusedCacheSize);
11476228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
114810905SN/A        arrayParamOut(cp, csprintf("unusedCache_%d", x),
11496124SN/A                      (uint8_t*)unusedCache[x],sizeof(T));
11506124SN/A    }
11516124SN/A
11526124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11536124SN/A    if (fetchDelayEvent.scheduled())
11546124SN/A        fetch_delay = fetchDelayEvent.when();
11556124SN/A    SERIALIZE_SCALAR(fetch_delay);
11566124SN/A    if (wbDelayEvent.scheduled())
11576124SN/A        wb_delay = wbDelayEvent.when();
11586124SN/A    SERIALIZE_SCALAR(wb_delay);
11596124SN/A
11606124SN/A
11616124SN/A}
11626124SN/A
11636124SN/Atemplate<class T>
11646124SN/Avoid
116510905SN/AIGbE::DescCache<T>::unserialize(CheckpointIn &cp)
11666124SN/A{
11676124SN/A    UNSERIALIZE_SCALAR(cachePnt);
11686124SN/A    UNSERIALIZE_SCALAR(curFetching);
11696124SN/A    UNSERIALIZE_SCALAR(wbOut);
11706124SN/A    UNSERIALIZE_SCALAR(moreToWb);
11716124SN/A    UNSERIALIZE_SCALAR(wbAlignment);
11726124SN/A
11736228SN/A    typename CacheType::size_type usedCacheSize;
11746124SN/A    UNSERIALIZE_SCALAR(usedCacheSize);
11756124SN/A    T *temp;
11766228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
11776124SN/A        temp = new T;
117810905SN/A        arrayParamIn(cp, csprintf("usedCache_%d", x),
11796124SN/A                     (uint8_t*)temp,sizeof(T));
11806124SN/A        usedCache.push_back(temp);
11816124SN/A    }
11826124SN/A
11836228SN/A    typename CacheType::size_type unusedCacheSize;
11846124SN/A    UNSERIALIZE_SCALAR(unusedCacheSize);
11856228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
11866124SN/A        temp = new T;
118710905SN/A        arrayParamIn(cp, csprintf("unusedCache_%d", x),
11886124SN/A                     (uint8_t*)temp,sizeof(T));
11896124SN/A        unusedCache.push_back(temp);
11906124SN/A    }
11916124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11926124SN/A    UNSERIALIZE_SCALAR(fetch_delay);
11936124SN/A    UNSERIALIZE_SCALAR(wb_delay);
11946124SN/A    if (fetch_delay)
11956124SN/A        igbe->schedule(fetchDelayEvent, fetch_delay);
11966124SN/A    if (wb_delay)
11976124SN/A        igbe->schedule(wbDelayEvent, wb_delay);
11986124SN/A
11996124SN/A
12006124SN/A}
12016124SN/A
12026124SN/A///////////////////////////// IGbE::RxDescCache //////////////////////////////
12034263SN/A
12044263SN/AIGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
120511320Ssteve.reinhardt@amd.com    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
120612087Sspwilson2@wisc.edu    pktEvent([this]{ pktComplete(); }, n),
120712087Sspwilson2@wisc.edu    pktHdrEvent([this]{ pktSplitDone(); }, n),
120812087Sspwilson2@wisc.edu    pktDataEvent([this]{ pktSplitDone(); }, n)
12094263SN/A
12104263SN/A{
12115954SN/A    annSmFetch = "RX Desc Fetch";
12125954SN/A    annSmWb = "RX Desc Writeback";
12135954SN/A    annUnusedDescQ = "RX Unused Descriptors";
12145954SN/A    annUnusedCacheQ = "RX Unused Descriptor Cache";
12155954SN/A    annUsedCacheQ = "RX Used Descriptor Cache";
12165954SN/A    annUsedDescQ = "RX Used Descriptors";
12175954SN/A    annDescQ = "RX Descriptors";
12184263SN/A}
12193116SN/A
12205339SN/Avoid
12215783SN/AIGbE::RxDescCache::pktSplitDone()
12225783SN/A{
12235783SN/A    splitCount++;
12246124SN/A    DPRINTF(EthernetDesc,
12256124SN/A            "Part of split packet done: splitcount now %d\n", splitCount);
12265783SN/A    assert(splitCount <= 2);
12275783SN/A    if (splitCount != 2)
12285783SN/A        return;
12295783SN/A    splitCount = 0;
12306124SN/A    DPRINTF(EthernetDesc,
12316124SN/A            "Part of split packet done: calling pktComplete()\n");
12325783SN/A    pktComplete();
12335783SN/A}
12345783SN/A
12355783SN/Aint
12365783SN/AIGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
12373116SN/A{
12386124SN/A    assert(unusedCache.size());
12395071SN/A    //if (!unusedCache.size())
12405071SN/A    //    return false;
12414263SN/A
12424263SN/A    pktPtr = packet;
12434452SN/A    pktDone = false;
12446227SN/A    unsigned buf_len, hdr_len;
12455763SN/A
12465763SN/A    RxDesc *desc = unusedCache.front();
12475763SN/A    switch (igbe->regs.srrctl.desctype()) {
12485763SN/A      case RXDT_LEGACY:
12495783SN/A        assert(pkt_offset == 0);
12505783SN/A        bytesCopied = packet->length;
12515763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
12526124SN/A                packet->length, igbe->regs.rctl.descSize());
12535763SN/A        assert(packet->length < igbe->regs.rctl.descSize());
12546124SN/A        igbe->dmaWrite(pciToDma(desc->legacy.buf),
12556124SN/A                       packet->length, &pktEvent, packet->data,
12566124SN/A                       igbe->rxWriteDelay);
12575763SN/A        break;
12585763SN/A      case RXDT_ADV_ONEBUF:
12595783SN/A        assert(pkt_offset == 0);
12605783SN/A        bytesCopied = packet->length;
12615763SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12626124SN/A            igbe->regs.rctl.descSize();
12635763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
12646124SN/A                packet->length, igbe->regs.srrctl(), buf_len);
12655763SN/A        assert(packet->length < buf_len);
12666124SN/A        igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
12676124SN/A                       packet->length, &pktEvent, packet->data,
12686124SN/A                       igbe->rxWriteDelay);
12695783SN/A        desc->adv_wb.header_len = htole(0);
12705783SN/A        desc->adv_wb.sph = htole(0);
12715783SN/A        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
12725783SN/A        break;
12735783SN/A      case RXDT_ADV_SPLIT_A:
12745783SN/A        int split_point;
127511320Ssteve.reinhardt@amd.com
12765783SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12776124SN/A            igbe->regs.rctl.descSize();
127811320Ssteve.reinhardt@amd.com        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
12796124SN/A        DPRINTF(EthernetDesc,
12806124SN/A                "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
12816124SN/A                "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
12826124SN/A                igbe->regs.rctl.lpe(), packet->length, pkt_offset,
12836124SN/A                igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
12846124SN/A                desc->adv_read.pkt, buf_len);
12855783SN/A
12865783SN/A        split_point = hsplit(pktPtr);
12875783SN/A
12885783SN/A        if (packet->length <= hdr_len) {
12895783SN/A            bytesCopied = packet->length;
12905783SN/A            assert(pkt_offset == 0);
12916124SN/A            DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
12926124SN/A            igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
12936124SN/A                           packet->length, &pktEvent, packet->data,
12946124SN/A                           igbe->rxWriteDelay);
12955783SN/A            desc->adv_wb.header_len = htole((uint16_t)packet->length);
12965783SN/A            desc->adv_wb.sph = htole(0);
12975783SN/A            desc->adv_wb.pkt_len = htole(0);
12985783SN/A        } else if (split_point) {
12995783SN/A            if (pkt_offset) {
13005783SN/A                // we are only copying some data, header/data has already been
13015783SN/A                // copied
13026124SN/A                int max_to_copy =
13036124SN/A                    std::min(packet->length - pkt_offset, buf_len);
13045783SN/A                bytesCopied += max_to_copy;
13056124SN/A                DPRINTF(EthernetDesc,
13066124SN/A                        "Hdr split: Continuing data buffer copy\n");
13076124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13086124SN/A                               max_to_copy, &pktEvent,
13096124SN/A                               packet->data + pkt_offset, igbe->rxWriteDelay);
13105783SN/A                desc->adv_wb.header_len = htole(0);
13115783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
13125783SN/A                desc->adv_wb.sph = htole(0);
13135783SN/A            } else {
13146124SN/A                int max_to_copy =
13156124SN/A                    std::min(packet->length - split_point, buf_len);
13165783SN/A                bytesCopied += max_to_copy + split_point;
131711320Ssteve.reinhardt@amd.com
13186124SN/A                DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
13195783SN/A                        split_point);
13206124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
13216124SN/A                               split_point, &pktHdrEvent,
13226124SN/A                               packet->data, igbe->rxWriteDelay);
13236124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13246124SN/A                               max_to_copy, &pktDataEvent,
13256124SN/A                               packet->data + split_point, igbe->rxWriteDelay);
13265783SN/A                desc->adv_wb.header_len = htole(split_point);
13275783SN/A                desc->adv_wb.sph = 1;
13285783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
13295783SN/A            }
13305783SN/A        } else {
13316124SN/A            panic("Header split not fitting within header buffer or "
13326124SN/A                  "undecodable packet not fitting in header unsupported\n");
13335783SN/A        }
13345763SN/A        break;
13355763SN/A      default:
13365763SN/A        panic("Unimplemnted RX receive buffer type: %d\n",
13376124SN/A              igbe->regs.srrctl.desctype());
13385763SN/A    }
13395783SN/A    return bytesCopied;
13405763SN/A
13413116SN/A}
13423116SN/A
13434263SN/Avoid
13444263SN/AIGbE::RxDescCache::pktComplete()
13454263SN/A{
13464263SN/A    assert(unusedCache.size());
13474263SN/A    RxDesc *desc;
13484263SN/A    desc = unusedCache.front();
13494263SN/A
13505954SN/A    igbe->anBegin("RXS", "Update Desc");
13515954SN/A
13524283SN/A    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
13536124SN/A    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
13546124SN/A            "stripcrc offset: %d value written: %d %d\n",
13555783SN/A            pktPtr->length, bytesCopied, crcfixup,
13564283SN/A            htole((uint16_t)(pktPtr->length + crcfixup)),
13574283SN/A            (uint16_t)(pktPtr->length + crcfixup));
13584283SN/A
13594263SN/A    // no support for anything but starting at 0
13604263SN/A    assert(igbe->regs.rxcsum.pcss() == 0);
13614263SN/A
13624291SN/A    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
13634263SN/A
13645783SN/A    uint16_t status = RXDS_DD;
13654263SN/A    uint8_t err = 0;
13665763SN/A    uint16_t ext_err = 0;
13675763SN/A    uint16_t csum = 0;
13685763SN/A    uint16_t ptype = 0;
13695763SN/A    uint16_t ip_id = 0;
13704452SN/A
13715783SN/A    assert(bytesCopied <= pktPtr->length);
13725783SN/A    if (bytesCopied == pktPtr->length)
13735783SN/A        status |= RXDS_EOP;
13745783SN/A
13754263SN/A    IpPtr ip(pktPtr);
13764452SN/A
13774263SN/A    if (ip) {
13784452SN/A        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
13795763SN/A        ptype |= RXDP_IPV4;
13805763SN/A        ip_id = ip->id();
13814452SN/A
13824263SN/A        if (igbe->regs.rxcsum.ipofld()) {
13834291SN/A            DPRINTF(EthernetDesc, "Checking IP checksum\n");
13844263SN/A            status |= RXDS_IPCS;
13855763SN/A            csum = htole(cksum(ip));
13865485SN/A            igbe->rxIpChecksums++;
13874263SN/A            if (cksum(ip) != 0) {
13884263SN/A                err |= RXDE_IPE;
13895763SN/A                ext_err |= RXDEE_IPE;
13904291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
13914263SN/A            }
13924263SN/A        }
13934263SN/A        TcpPtr tcp(ip);
13944263SN/A        if (tcp && igbe->regs.rxcsum.tuofld()) {
13954291SN/A            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
13964263SN/A            status |= RXDS_TCPCS;
13975763SN/A            ptype |= RXDP_TCP;
13985763SN/A            csum = htole(cksum(tcp));
13995485SN/A            igbe->rxTcpChecksums++;
14004263SN/A            if (cksum(tcp) != 0) {
14014291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
14024263SN/A                err |= RXDE_TCPE;
14035763SN/A                ext_err |= RXDEE_TCPE;
14044263SN/A            }
14054263SN/A        }
14064263SN/A
14074263SN/A        UdpPtr udp(ip);
14084263SN/A        if (udp && igbe->regs.rxcsum.tuofld()) {
14094291SN/A            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
14104263SN/A            status |= RXDS_UDPCS;
14115763SN/A            ptype |= RXDP_UDP;
14125763SN/A            csum = htole(cksum(udp));
14135485SN/A            igbe->rxUdpChecksums++;
14144421SN/A            if (cksum(udp) != 0) {
14154291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
14165763SN/A                ext_err |= RXDEE_TCPE;
14174263SN/A                err |= RXDE_TCPE;
14184263SN/A            }
14194263SN/A        }
14204452SN/A    } else { // if ip
14214452SN/A        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
14224452SN/A    }
14234452SN/A
14245763SN/A    switch (igbe->regs.srrctl.desctype()) {
14255763SN/A      case RXDT_LEGACY:
14265763SN/A        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
14275763SN/A        desc->legacy.status = htole(status);
14285763SN/A        desc->legacy.errors = htole(err);
14295763SN/A        // No vlan support at this point... just set it to 0
14305763SN/A        desc->legacy.vlan = 0;
14315763SN/A        break;
14325783SN/A      case RXDT_ADV_SPLIT_A:
14335763SN/A      case RXDT_ADV_ONEBUF:
14345763SN/A        desc->adv_wb.rss_type = htole(0);
14355763SN/A        desc->adv_wb.pkt_type = htole(ptype);
14365763SN/A        if (igbe->regs.rxcsum.pcsd()) {
14375763SN/A            // no rss support right now
14385763SN/A            desc->adv_wb.rss_hash = htole(0);
14395763SN/A        } else {
14405763SN/A            desc->adv_wb.id = htole(ip_id);
14415763SN/A            desc->adv_wb.csum = htole(csum);
14425763SN/A        }
14435763SN/A        desc->adv_wb.status = htole(status);
14445763SN/A        desc->adv_wb.errors = htole(ext_err);
14455763SN/A        // no vlan support
144611320Ssteve.reinhardt@amd.com        desc->adv_wb.vlan_tag = htole(0);
14475763SN/A        break;
14485763SN/A      default:
14495763SN/A        panic("Unimplemnted RX receive buffer type %d\n",
14506124SN/A              igbe->regs.srrctl.desctype());
14515763SN/A    }
14524263SN/A
14535783SN/A    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
14545783SN/A            desc->adv_read.pkt, desc->adv_read.hdr);
14554263SN/A
14565783SN/A    if (bytesCopied == pktPtr->length) {
14576124SN/A        DPRINTF(EthernetDesc,
14586124SN/A                "Packet completely written to descriptor buffers\n");
14595783SN/A        // Deal with the rx timer interrupts
14605783SN/A        if (igbe->regs.rdtr.delay()) {
14616124SN/A            Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
14626124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
14637823SN/A            igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
14645783SN/A        }
14655783SN/A
14665783SN/A        if (igbe->regs.radv.idv()) {
14676124SN/A            Tick delay = igbe->regs.radv.idv() * igbe->intClock();
14686124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
14695783SN/A            if (!igbe->radvEvent.scheduled()) {
14707823SN/A                igbe->schedule(igbe->radvEvent, curTick() + delay);
14715783SN/A            }
14725783SN/A        }
14735783SN/A
14745783SN/A        // if neither radv or rdtr, maybe itr is set...
14755783SN/A        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
14766124SN/A            DPRINTF(EthernetSM,
14776124SN/A                    "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
14785783SN/A            igbe->postInterrupt(IT_RXT);
14795783SN/A        }
14805783SN/A
14815783SN/A        // If the packet is small enough, interrupt appropriately
14825783SN/A        // I wonder if this is delayed or not?!
14835783SN/A        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
14846124SN/A            DPRINTF(EthernetSM,
14856124SN/A                    "RXS: Posting IT_SRPD beacuse small packet received\n");
14865783SN/A            igbe->postInterrupt(IT_SRPD);
14875783SN/A        }
14885783SN/A        bytesCopied = 0;
14894263SN/A    }
14904263SN/A
14915783SN/A    pktPtr = NULL;
14925783SN/A    igbe->checkDrain();
14935783SN/A    enableSm();
14945783SN/A    pktDone = true;
14954263SN/A
14965954SN/A    igbe->anBegin("RXS", "Done Updating Desc");
14974291SN/A    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
14985954SN/A    igbe->anDq("RXS", annUnusedCacheQ);
14994263SN/A    unusedCache.pop_front();
15005954SN/A    igbe->anQ("RXS", annUsedCacheQ);
15014263SN/A    usedCache.push_back(desc);
15024263SN/A}
15034263SN/A
15044263SN/Avoid
15054263SN/AIGbE::RxDescCache::enableSm()
15064263SN/A{
150710913SN/A    if (igbe->drainState() != DrainState::Draining) {
15085071SN/A        igbe->rxTick = true;
15095071SN/A        igbe->restartClock();
15105071SN/A    }
15114263SN/A}
15124263SN/A
15134263SN/Abool
15144263SN/AIGbE::RxDescCache::packetDone()
15154263SN/A{
15164263SN/A    if (pktDone) {
15174263SN/A        pktDone = false;
15184263SN/A        return true;
15194263SN/A    }
15204263SN/A    return false;
15214263SN/A}
15224263SN/A
15234294SN/Abool
15244294SN/AIGbE::RxDescCache::hasOutstandingEvents()
15254294SN/A{
15264294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
15275783SN/A        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
15285783SN/A        pktDataEvent.scheduled();
152911320Ssteve.reinhardt@amd.com
15304294SN/A}
15314294SN/A
15324294SN/Avoid
153310905SN/AIGbE::RxDescCache::serialize(CheckpointOut &cp) const
15344294SN/A{
153510905SN/A    DescCache<RxDesc>::serialize(cp);
15364294SN/A    SERIALIZE_SCALAR(pktDone);
15375783SN/A    SERIALIZE_SCALAR(splitCount);
15385783SN/A    SERIALIZE_SCALAR(bytesCopied);
15394294SN/A}
15404294SN/A
15414294SN/Avoid
154210905SN/AIGbE::RxDescCache::unserialize(CheckpointIn &cp)
15434294SN/A{
154410905SN/A    DescCache<RxDesc>::unserialize(cp);
15454294SN/A    UNSERIALIZE_SCALAR(pktDone);
15465783SN/A    UNSERIALIZE_SCALAR(splitCount);
15475783SN/A    UNSERIALIZE_SCALAR(bytesCopied);
15484294SN/A}
15494294SN/A
15504294SN/A
15516124SN/A///////////////////////////// IGbE::TxDescCache //////////////////////////////
15524263SN/A
15534263SN/AIGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
15546124SN/A    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
155510420SN/A      pktWaiting(false), pktMultiDesc(false),
155610420SN/A      completionAddress(0), completionEnabled(false),
15578553SN/A      useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
15588553SN/A      tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
15598553SN/A      tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
156012087Sspwilson2@wisc.edu    pktEvent([this]{ pktComplete(); }, n),
156112087Sspwilson2@wisc.edu    headerEvent([this]{ headerComplete(); }, n),
156212087Sspwilson2@wisc.edu    nullEvent([this]{ nullCallback(); }, n)
15634263SN/A{
15645954SN/A    annSmFetch = "TX Desc Fetch";
15655954SN/A    annSmWb = "TX Desc Writeback";
15665954SN/A    annUnusedDescQ = "TX Unused Descriptors";
15675954SN/A    annUnusedCacheQ = "TX Unused Descriptor Cache";
15685954SN/A    annUsedCacheQ = "TX Used Descriptor Cache";
15695954SN/A    annUsedDescQ = "TX Used Descriptors";
15705954SN/A    annDescQ = "TX Descriptors";
15714263SN/A}
15724263SN/A
15735762SN/Avoid
15745762SN/AIGbE::TxDescCache::processContextDesc()
15754263SN/A{
15764263SN/A    assert(unusedCache.size());
15775762SN/A    TxDesc *desc;
157811320Ssteve.reinhardt@amd.com
15795762SN/A    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
15804263SN/A
15816124SN/A    while (!useTso && unusedCache.size() &&
15826124SN/A           TxdOp::isContext(unusedCache.front())) {
15835762SN/A        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
15844263SN/A
15855762SN/A        desc = unusedCache.front();
158611320Ssteve.reinhardt@amd.com        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
15876124SN/A                desc->d1, desc->d2);
15884263SN/A
158911320Ssteve.reinhardt@amd.com
15904263SN/A        // is this going to be a tcp or udp packet?
15914263SN/A        isTcp = TxdOp::tcp(desc) ? true : false;
15924263SN/A
159311320Ssteve.reinhardt@amd.com        // setup all the TSO variables, they'll be ignored if we don't use
15945763SN/A        // tso for this connection
15955763SN/A        tsoHeaderLen = TxdOp::hdrlen(desc);
15965763SN/A        tsoMss  = TxdOp::mss(desc);
15975763SN/A
15985763SN/A        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
15996124SN/A            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
16006124SN/A                    "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
16016124SN/A                    TxdOp::mss(desc), TxdOp::getLen(desc));
16025762SN/A            useTso = true;
16035762SN/A            tsoTotalLen = TxdOp::getLen(desc);
16045762SN/A            tsoLoadedHeader = false;
16055762SN/A            tsoDescBytesUsed = 0;
16065762SN/A            tsoUsedLen = 0;
16075762SN/A            tsoPrevSeq = 0;
16085762SN/A            tsoPktHasHeader = false;
16095762SN/A            tsoPkts = 0;
16108553SN/A            tsoCopyBytes = 0;
16115762SN/A        }
16124263SN/A
16134263SN/A        TxdOp::setDd(desc);
16144263SN/A        unusedCache.pop_front();
16155954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
16164263SN/A        usedCache.push_back(desc);
16175954SN/A        igbe->anQ("TXS", annUsedCacheQ);
16184263SN/A    }
16194263SN/A
16204263SN/A    if (!unusedCache.size())
16215762SN/A        return;
16225762SN/A
16235763SN/A    desc = unusedCache.front();
162411320Ssteve.reinhardt@amd.com    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) &&
16256124SN/A        TxdOp::tse(desc)) {
16266124SN/A        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
162711320Ssteve.reinhardt@amd.com                "hdrlen: %d mss: %d paylen %d\n",
16285763SN/A                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
16295763SN/A        useTso = true;
16305763SN/A        tsoTotalLen = TxdOp::getTsoLen(desc);
16315763SN/A        tsoLoadedHeader = false;
16325763SN/A        tsoDescBytesUsed = 0;
16335763SN/A        tsoUsedLen = 0;
16345763SN/A        tsoPrevSeq = 0;
16355763SN/A        tsoPktHasHeader = false;
16365763SN/A        tsoPkts = 0;
16375763SN/A    }
16385763SN/A
16395762SN/A    if (useTso && !tsoLoadedHeader) {
16405762SN/A        // we need to fetch a header
16415762SN/A        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
16425762SN/A        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
16435762SN/A        pktWaiting = true;
16445762SN/A        assert(tsoHeaderLen <= 256);
16456124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
16466124SN/A                      tsoHeaderLen, &headerEvent, tsoHeader, 0);
16475762SN/A    }
16485762SN/A}
16495762SN/A
16505762SN/Avoid
16515762SN/AIGbE::TxDescCache::headerComplete()
16525762SN/A{
16535762SN/A    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
16545762SN/A    pktWaiting = false;
16555762SN/A
16565762SN/A    assert(unusedCache.size());
16575762SN/A    TxDesc *desc = unusedCache.front();
16585762SN/A    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
16595762SN/A            TxdOp::getLen(desc), tsoHeaderLen);
16605762SN/A
16615762SN/A    if (TxdOp::getLen(desc) == tsoHeaderLen) {
16625762SN/A        tsoDescBytesUsed = 0;
16635762SN/A        tsoLoadedHeader = true;
16645762SN/A        unusedCache.pop_front();
16655762SN/A        usedCache.push_back(desc);
16665762SN/A    } else {
16679189SN/A        DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
16689189SN/A        tsoDescBytesUsed = tsoHeaderLen;
16699189SN/A        tsoLoadedHeader = true;
16705762SN/A    }
16715762SN/A    enableSm();
16725762SN/A    igbe->checkDrain();
16735762SN/A}
16745762SN/A
16756227SN/Aunsigned
16765762SN/AIGbE::TxDescCache::getPacketSize(EthPacketPtr p)
16775762SN/A{
16785762SN/A    if (!unusedCache.size())
16796227SN/A        return 0;
168011320Ssteve.reinhardt@amd.com
16815762SN/A    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
16825762SN/A
16835762SN/A    assert(!useTso || tsoLoadedHeader);
16846227SN/A    TxDesc *desc = unusedCache.front();
16855762SN/A
16865762SN/A    if (useTso) {
16876124SN/A        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
16886124SN/A                "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
16896124SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
16906124SN/A                "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
16916124SN/A                tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
16928553SN/A
169311320Ssteve.reinhardt@amd.com        if (tsoPktHasHeader)
16946124SN/A            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length,
16958553SN/A                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16965762SN/A        else
16976124SN/A            tsoCopyBytes =  std::min(tsoMss,
169811320Ssteve.reinhardt@amd.com                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16996227SN/A        unsigned pkt_size =
170011320Ssteve.reinhardt@amd.com            tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
17018553SN/A
17028553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
17038553SN/A                "this descLen: %d\n",
17048553SN/A                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
17058553SN/A        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
17065762SN/A        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
17075762SN/A        return pkt_size;
17085762SN/A    }
17094263SN/A
17104291SN/A    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
17116124SN/A            TxdOp::getLen(unusedCache.front()));
17125762SN/A    return TxdOp::getLen(desc);
17134263SN/A}
17144263SN/A
17154263SN/Avoid
17164263SN/AIGbE::TxDescCache::getPacketData(EthPacketPtr p)
17174263SN/A{
17184263SN/A    assert(unusedCache.size());
17194263SN/A
17204263SN/A    TxDesc *desc;
17214263SN/A    desc = unusedCache.front();
17224263SN/A
17236124SN/A    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
17246124SN/A            "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
17256124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17266124SN/A           TxdOp::getLen(desc));
17274263SN/A
17284263SN/A    pktPtr = p;
17294263SN/A
17304263SN/A    pktWaiting = true;
17314263SN/A
17325404SN/A    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
173311320Ssteve.reinhardt@amd.com
17345762SN/A    if (useTso) {
17355762SN/A        assert(tsoLoadedHeader);
17365762SN/A        if (!tsoPktHasHeader) {
17376124SN/A            DPRINTF(EthernetDesc,
17386124SN/A                    "Loading TSO header (%d bytes) into start of packet\n",
17396124SN/A                    tsoHeaderLen);
17405762SN/A            memcpy(p->data, &tsoHeader,tsoHeaderLen);
17415762SN/A            p->length +=tsoHeaderLen;
17425762SN/A            tsoPktHasHeader = true;
17435762SN/A        }
17445762SN/A    }
174511320Ssteve.reinhardt@amd.com
17465762SN/A    if (useTso) {
17476124SN/A        DPRINTF(EthernetDesc,
17486124SN/A                "Starting DMA of packet at offset %d length: %d\n",
17495762SN/A                p->length, tsoCopyBytes);
17506124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc))
17516124SN/A                      + tsoDescBytesUsed,
17526124SN/A                      tsoCopyBytes, &pktEvent, p->data + p->length,
17536124SN/A                      igbe->txReadDelay);
17548553SN/A        tsoDescBytesUsed += tsoCopyBytes;
17558553SN/A        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
17565762SN/A    } else {
17576124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
17586124SN/A                      TxdOp::getLen(desc), &pktEvent, p->data + p->length,
17596124SN/A                      igbe->txReadDelay);
17605762SN/A    }
17614263SN/A}
17624263SN/A
17634263SN/Avoid
17644263SN/AIGbE::TxDescCache::pktComplete()
17654263SN/A{
17664263SN/A
17674263SN/A    TxDesc *desc;
17684263SN/A    assert(unusedCache.size());
17694263SN/A    assert(pktPtr);
17704263SN/A
17715954SN/A    igbe->anBegin("TXS", "Update Desc");
17725954SN/A
17734291SN/A    DPRINTF(EthernetDesc, "DMA of packet complete\n");
17744263SN/A
17755339SN/A
17764263SN/A    desc = unusedCache.front();
17776124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17786124SN/A           TxdOp::getLen(desc));
17794263SN/A
17806124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
17816124SN/A            desc->d1, desc->d2);
17824283SN/A
17835762SN/A    // Set the length of the data in the EtherPacket
17845762SN/A    if (useTso) {
17858553SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
17868553SN/A            "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
17878553SN/A            tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
178811701Smichael.lebeane@amd.com        pktPtr->simLength += tsoCopyBytes;
17895762SN/A        pktPtr->length += tsoCopyBytes;
17905762SN/A        tsoUsedLen += tsoCopyBytes;
17918553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
17928553SN/A            tsoDescBytesUsed, tsoCopyBytes);
179311701Smichael.lebeane@amd.com    } else {
179411701Smichael.lebeane@amd.com        pktPtr->simLength += TxdOp::getLen(desc);
17955404SN/A        pktPtr->length += TxdOp::getLen(desc);
179611701Smichael.lebeane@amd.com    }
17975762SN/A
17985762SN/A
179911320Ssteve.reinhardt@amd.com
180011320Ssteve.reinhardt@amd.com    if ((!TxdOp::eop(desc) && !useTso) ||
18016124SN/A        (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
18026124SN/A         tsoTotalLen != tsoUsedLen && useTso)) {
18035762SN/A        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
18045954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
18054283SN/A        unusedCache.pop_front();
18065954SN/A        igbe->anQ("TXS", annUsedCacheQ);
18074283SN/A        usedCache.push_back(desc);
18085762SN/A
18095762SN/A        tsoDescBytesUsed = 0;
18104283SN/A        pktDone = true;
18114283SN/A        pktWaiting = false;
18125404SN/A        pktMultiDesc = true;
18135404SN/A
18145404SN/A        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
18155404SN/A                pktPtr->length);
18164283SN/A        pktPtr = NULL;
18174283SN/A
18184438SN/A        enableSm();
18195071SN/A        igbe->checkDrain();
18204283SN/A        return;
18214283SN/A    }
18225762SN/A
18235762SN/A
18245404SN/A    pktMultiDesc = false;
18254263SN/A    // no support for vlans
18264263SN/A    assert(!TxdOp::vle(desc));
18274263SN/A
18284263SN/A    // we only support single packet descriptors at this point
18295762SN/A    if (!useTso)
18305762SN/A        assert(TxdOp::eop(desc));
18314263SN/A
18324263SN/A    // set that this packet is done
18335762SN/A    if (TxdOp::rs(desc))
18345762SN/A        TxdOp::setDd(desc);
18354263SN/A
18366124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
18376124SN/A            desc->d1, desc->d2);
18384283SN/A
18395762SN/A    if (useTso) {
18405762SN/A        IpPtr ip(pktPtr);
18415762SN/A        if (ip) {
18425762SN/A            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
18435762SN/A                    tsoPkts);
18445762SN/A            ip->id(ip->id() + tsoPkts++);
184511320Ssteve.reinhardt@amd.com            ip->len(pktPtr->length - EthPtr(pktPtr)->size());
184611320Ssteve.reinhardt@amd.com
18475762SN/A            TcpPtr tcp(ip);
18485762SN/A            if (tcp) {
18496124SN/A                DPRINTF(EthernetDesc,
18506124SN/A                        "TSO: Modifying TCP header. old seq %d + %d\n",
18516124SN/A                        tcp->seq(), tsoPrevSeq);
18525762SN/A                tcp->seq(tcp->seq() + tsoPrevSeq);
18535762SN/A                if (tsoUsedLen != tsoTotalLen)
18545762SN/A                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
18555762SN/A            }
18565762SN/A            UdpPtr udp(ip);
18575762SN/A            if (udp) {
18585762SN/A                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
18595762SN/A                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
18605762SN/A            }
18615762SN/A        }
18625762SN/A        tsoPrevSeq = tsoUsedLen;
18635762SN/A    }
18645762SN/A
18654452SN/A    if (DTRACE(EthernetDesc)) {
18664452SN/A        IpPtr ip(pktPtr);
18674452SN/A        if (ip)
18684452SN/A            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
18694452SN/A                    ip->id());
18704452SN/A        else
18714452SN/A            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
18724452SN/A    }
18734452SN/A
18744263SN/A    // Checksums are only ofloaded for new descriptor types
18754263SN/A    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
18764291SN/A        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
18774263SN/A        IpPtr ip(pktPtr);
18785404SN/A        assert(ip);
18794263SN/A        if (TxdOp::ixsm(desc)) {
18804263SN/A            ip->sum(0);
18814263SN/A            ip->sum(cksum(ip));
18825485SN/A            igbe->txIpChecksums++;
18834291SN/A            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
18844263SN/A        }
18854987SN/A        if (TxdOp::txsm(desc)) {
18864987SN/A            TcpPtr tcp(ip);
18874987SN/A            UdpPtr udp(ip);
18884987SN/A            if (tcp) {
18896124SN/A                tcp->sum(0);
18906124SN/A                tcp->sum(cksum(tcp));
18916124SN/A                igbe->txTcpChecksums++;
18926124SN/A                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
18934987SN/A            } else if (udp) {
18946124SN/A                assert(udp);
18956124SN/A                udp->sum(0);
18966124SN/A                udp->sum(cksum(udp));
18976124SN/A                igbe->txUdpChecksums++;
18986124SN/A                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
18994987SN/A            } else {
19004987SN/A                panic("Told to checksum, but don't know how\n");
19014987SN/A            }
19024263SN/A        }
19034263SN/A    }
19044263SN/A
19054263SN/A    if (TxdOp::ide(desc)) {
19064263SN/A        // Deal with the rx timer interrupts
19074291SN/A        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
19084263SN/A        if (igbe->regs.tidv.idv()) {
19096124SN/A            Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
19104291SN/A            DPRINTF(EthernetDesc, "setting tidv\n");
19117823SN/A            igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
19124263SN/A        }
19134263SN/A
19144263SN/A        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
19156124SN/A            Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
19164291SN/A            DPRINTF(EthernetDesc, "setting tadv\n");
19174987SN/A            if (!igbe->tadvEvent.scheduled()) {
19187823SN/A                igbe->schedule(igbe->tadvEvent, curTick() + delay);
19194987SN/A            }
19204263SN/A        }
19214263SN/A    }
19224263SN/A
19234283SN/A
19245762SN/A    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
19255762SN/A        DPRINTF(EthernetDesc, "Descriptor Done\n");
19265954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
19275762SN/A        unusedCache.pop_front();
19285954SN/A        igbe->anQ("TXS", annUsedCacheQ);
19295762SN/A        usedCache.push_back(desc);
19305762SN/A        tsoDescBytesUsed = 0;
19315762SN/A    }
19324283SN/A
19335762SN/A    if (useTso && tsoUsedLen == tsoTotalLen)
19345762SN/A        useTso = false;
19355762SN/A
19365762SN/A
19376124SN/A    DPRINTF(EthernetDesc,
19386124SN/A            "------Packet of %d bytes ready for transmission-------\n",
19395762SN/A            pktPtr->length);
19404263SN/A    pktDone = true;
19414263SN/A    pktWaiting = false;
19424263SN/A    pktPtr = NULL;
19435762SN/A    tsoPktHasHeader = false;
19444283SN/A
19454283SN/A    if (igbe->regs.txdctl.wthresh() == 0) {
19465954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19474291SN/A        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
19484283SN/A        writeback(0);
19498984SN/A    } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
19506124SN/A               descInBlock(usedCache.size())) {
19515763SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19525954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19535763SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19548984SN/A    } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
19554291SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19565954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19574283SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19584283SN/A    }
19595763SN/A
19604438SN/A    enableSm();
19614294SN/A    igbe->checkDrain();
19624294SN/A}
19634283SN/A
19644294SN/Avoid
196511320Ssteve.reinhardt@amd.comIGbE::TxDescCache::actionAfterWb()
19665763SN/A{
19675763SN/A    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
19685763SN/A            completionEnabled);
19695763SN/A    igbe->postInterrupt(iGbReg::IT_TXDW);
197011320Ssteve.reinhardt@amd.com    if (completionEnabled) {
19715763SN/A        descEnd = igbe->regs.tdh();
19726124SN/A        DPRINTF(EthernetDesc,
19736124SN/A                "Completion writing back value: %d to addr: %#x\n", descEnd,
19745763SN/A                completionAddress);
19756124SN/A        igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)),
19766124SN/A                       sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
19775763SN/A    }
19785763SN/A}
19795763SN/A
19805763SN/Avoid
198110905SN/AIGbE::TxDescCache::serialize(CheckpointOut &cp) const
19824294SN/A{
198310905SN/A    DescCache<TxDesc>::serialize(cp);
198410905SN/A
19854294SN/A    SERIALIZE_SCALAR(pktDone);
19864294SN/A    SERIALIZE_SCALAR(isTcp);
19874294SN/A    SERIALIZE_SCALAR(pktWaiting);
19885404SN/A    SERIALIZE_SCALAR(pktMultiDesc);
19895762SN/A
19905762SN/A    SERIALIZE_SCALAR(useTso);
19915762SN/A    SERIALIZE_SCALAR(tsoHeaderLen);
19925762SN/A    SERIALIZE_SCALAR(tsoMss);
19935762SN/A    SERIALIZE_SCALAR(tsoTotalLen);
19945762SN/A    SERIALIZE_SCALAR(tsoUsedLen);
19955762SN/A    SERIALIZE_SCALAR(tsoPrevSeq);;
19965762SN/A    SERIALIZE_SCALAR(tsoPktPayloadBytes);
19975762SN/A    SERIALIZE_SCALAR(tsoLoadedHeader);
19985762SN/A    SERIALIZE_SCALAR(tsoPktHasHeader);
19995762SN/A    SERIALIZE_ARRAY(tsoHeader, 256);
20005762SN/A    SERIALIZE_SCALAR(tsoDescBytesUsed);
20015762SN/A    SERIALIZE_SCALAR(tsoCopyBytes);
20025762SN/A    SERIALIZE_SCALAR(tsoPkts);
20035762SN/A
20045763SN/A    SERIALIZE_SCALAR(completionAddress);
20055763SN/A    SERIALIZE_SCALAR(completionEnabled);
20065763SN/A    SERIALIZE_SCALAR(descEnd);
20074294SN/A}
20084294SN/A
20094294SN/Avoid
201010905SN/AIGbE::TxDescCache::unserialize(CheckpointIn &cp)
20114294SN/A{
201210905SN/A    DescCache<TxDesc>::unserialize(cp);
201310905SN/A
20144294SN/A    UNSERIALIZE_SCALAR(pktDone);
20154294SN/A    UNSERIALIZE_SCALAR(isTcp);
20164294SN/A    UNSERIALIZE_SCALAR(pktWaiting);
20175404SN/A    UNSERIALIZE_SCALAR(pktMultiDesc);
20185762SN/A
20195762SN/A    UNSERIALIZE_SCALAR(useTso);
20205762SN/A    UNSERIALIZE_SCALAR(tsoHeaderLen);
20215762SN/A    UNSERIALIZE_SCALAR(tsoMss);
20225762SN/A    UNSERIALIZE_SCALAR(tsoTotalLen);
20235762SN/A    UNSERIALIZE_SCALAR(tsoUsedLen);
20245762SN/A    UNSERIALIZE_SCALAR(tsoPrevSeq);;
20255762SN/A    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
20265762SN/A    UNSERIALIZE_SCALAR(tsoLoadedHeader);
20275762SN/A    UNSERIALIZE_SCALAR(tsoPktHasHeader);
20285762SN/A    UNSERIALIZE_ARRAY(tsoHeader, 256);
20295762SN/A    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
20305762SN/A    UNSERIALIZE_SCALAR(tsoCopyBytes);
20315762SN/A    UNSERIALIZE_SCALAR(tsoPkts);
20325763SN/A
20335763SN/A    UNSERIALIZE_SCALAR(completionAddress);
20345763SN/A    UNSERIALIZE_SCALAR(completionEnabled);
20355763SN/A    UNSERIALIZE_SCALAR(descEnd);
20364263SN/A}
20374263SN/A
20384263SN/Abool
20394263SN/AIGbE::TxDescCache::packetAvailable()
20404263SN/A{
20414263SN/A    if (pktDone) {
20424263SN/A        pktDone = false;
20434263SN/A        return true;
20444263SN/A    }
20454263SN/A    return false;
20464263SN/A}
20474263SN/A
20484263SN/Avoid
20494263SN/AIGbE::TxDescCache::enableSm()
20504263SN/A{
205110913SN/A    if (igbe->drainState() != DrainState::Draining) {
20525071SN/A        igbe->txTick = true;
20535071SN/A        igbe->restartClock();
20545071SN/A    }
20554263SN/A}
20564263SN/A
20574294SN/Abool
20584294SN/AIGbE::TxDescCache::hasOutstandingEvents()
20594294SN/A{
20604294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
20614294SN/A        fetchEvent.scheduled();
20624294SN/A}
20634263SN/A
20644263SN/A
20654263SN/A///////////////////////////////////// IGbE /////////////////////////////////
20664263SN/A
20674263SN/Avoid
20684283SN/AIGbE::restartClock()
20694283SN/A{
20705606SN/A    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
207110913SN/A        drainState() == DrainState::Running)
20729180SN/A        schedule(tickEvent, clockEdge(Cycles(1)));
20734283SN/A}
20744283SN/A
207510913SN/ADrainState
207610913SN/AIGbE::drain()
20774294SN/A{
207810912SN/A    unsigned int count(0);
20794294SN/A    if (rxDescCache.hasOutstandingEvents() ||
20806124SN/A        txDescCache.hasOutstandingEvents()) {
20814294SN/A        count++;
20824294SN/A    }
20834294SN/A
20844294SN/A    txFifoTick = false;
20854294SN/A    txTick = false;
20864294SN/A    rxTick = false;
20874294SN/A
20884294SN/A    if (tickEvent.scheduled())
20895606SN/A        deschedule(tickEvent);
20904294SN/A
20919152SN/A    if (count) {
20929152SN/A        DPRINTF(Drain, "IGbE not drained\n");
209310913SN/A        return DrainState::Draining;
20949152SN/A    } else
209510913SN/A        return DrainState::Drained;
20964294SN/A}
20974294SN/A
20984294SN/Avoid
20999342SN/AIGbE::drainResume()
21004294SN/A{
21019342SN/A    Drainable::drainResume();
21024294SN/A
21034294SN/A    txFifoTick = true;
21044294SN/A    txTick = true;
21054294SN/A    rxTick = true;
21064294SN/A
21074294SN/A    restartClock();
21085954SN/A    DPRINTF(EthernetSM, "resuming from drain");
21094294SN/A}
21104294SN/A
21114294SN/Avoid
21124294SN/AIGbE::checkDrain()
21134294SN/A{
211410913SN/A    if (drainState() != DrainState::Draining)
21154294SN/A        return;
21164294SN/A
21174987SN/A    txFifoTick = false;
21184987SN/A    txTick = false;
21194987SN/A    rxTick = false;
21204987SN/A    if (!rxDescCache.hasOutstandingEvents() &&
21216124SN/A        !txDescCache.hasOutstandingEvents()) {
21229152SN/A        DPRINTF(Drain, "IGbE done draining, processing drain event\n");
212310913SN/A        signalDrainDone();
21244294SN/A    }
21254294SN/A}
21264283SN/A
21274283SN/Avoid
21284263SN/AIGbE::txStateMachine()
21294263SN/A{
21304263SN/A    if (!regs.tctl.en()) {
21314263SN/A        txTick = false;
21324283SN/A        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
21334263SN/A        return;
21344263SN/A    }
21354263SN/A
21364283SN/A    // If we have a packet available and it's length is not 0 (meaning it's not
21374283SN/A    // a multidescriptor packet) put it in the fifo, otherwise an the next
21384283SN/A    // iteration we'll get the rest of the data
21395404SN/A    if (txPacket && txDescCache.packetAvailable()
21406124SN/A        && !txDescCache.packetMultiDesc() && txPacket->length) {
21415954SN/A        anQ("TXS", "TX FIFO Q");
21424263SN/A        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
21438641SN/A#ifndef NDEBUG
21448641SN/A        bool success =
21458641SN/A#endif
21468641SN/A            txFifo.push(txPacket);
214710913SN/A        txFifoTick = true && drainState() != DrainState::Draining;
21484263SN/A        assert(success);
21494263SN/A        txPacket = NULL;
21505954SN/A        anBegin("TXS", "Desc Writeback");
21514291SN/A        txDescCache.writeback((cacheBlockSize()-1)>>4);
21524263SN/A        return;
21534263SN/A    }
21544263SN/A
21554263SN/A    // Only support descriptor granularity
21566124SN/A    if (regs.txdctl.lwthresh() &&
21576124SN/A        txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
21584263SN/A        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
21594263SN/A        postInterrupt(IT_TXDLOW);
21604263SN/A    }
21614263SN/A
21624263SN/A    if (!txPacket) {
216310469SN/A        txPacket = std::make_shared<EthPacketData>(16384);
21644263SN/A    }
21654263SN/A
21664263SN/A    if (!txDescCache.packetWaiting()) {
21674263SN/A        if (txDescCache.descLeft() == 0) {
21684987SN/A            postInterrupt(IT_TXQE);
21695954SN/A            anBegin("TXS", "Desc Writeback");
21704987SN/A            txDescCache.writeback(0);
21715954SN/A            anBegin("TXS", "Desc Fetch");
21725954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21735071SN/A            txDescCache.fetchDescriptors();
21744283SN/A            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
21754283SN/A                    "writeback stopping ticking and posting TXQE\n");
21764263SN/A            txTick = false;
21774291SN/A            return;
21784263SN/A        }
21794263SN/A
21804283SN/A
21814263SN/A        if (!(txDescCache.descUnused())) {
21825954SN/A            anBegin("TXS", "Desc Fetch");
21835071SN/A            txDescCache.fetchDescriptors();
21845954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21856124SN/A            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
21866124SN/A                    "fetching and stopping ticking\n");
21874263SN/A            txTick = false;
21884263SN/A            return;
21894263SN/A        }
21905954SN/A        anPq("TXS", txDescCache.annUnusedCacheQ);
21914263SN/A
21925339SN/A
21935762SN/A        txDescCache.processContextDesc();
21945762SN/A        if (txDescCache.packetWaiting()) {
21956124SN/A            DPRINTF(EthernetSM,
21966124SN/A                    "TXS: Fetching TSO header, stopping ticking\n");
21975762SN/A            txTick = false;
21985762SN/A            return;
21995762SN/A        }
22005762SN/A
22016227SN/A        unsigned size = txDescCache.getPacketSize(txPacket);
22024283SN/A        if (size > 0 && txFifo.avail() > size) {
22035954SN/A            anRq("TXS", "TX FIFO Q");
22045954SN/A            anBegin("TXS", "DMA Packet");
22056124SN/A            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
22066124SN/A                    "beginning DMA of next packet\n", size);
22074283SN/A            txFifo.reserve(size);
22084263SN/A            txDescCache.getPacketData(txPacket);
22096227SN/A        } else if (size == 0) {
22104987SN/A            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
22116124SN/A            DPRINTF(EthernetSM,
22126124SN/A                    "TXS: No packets to get, writing back used descriptors\n");
22135954SN/A            anBegin("TXS", "Desc Writeback");
22144263SN/A            txDescCache.writeback(0);
22154291SN/A        } else {
22165954SN/A            anWf("TXS", "TX FIFO Q");
22174291SN/A            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
22184291SN/A                    "available in FIFO\n");
22194291SN/A            txTick = false;
22204263SN/A        }
22214263SN/A
22224291SN/A
22234263SN/A        return;
22244263SN/A    }
22254438SN/A    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
22264438SN/A    txTick = false;
22274263SN/A}
22284263SN/A
22294263SN/Abool
22304263SN/AIGbE::ethRxPkt(EthPacketPtr pkt)
22314263SN/A{
22325485SN/A    rxBytes += pkt->length;
22335485SN/A    rxPackets++;
22345485SN/A
22354263SN/A    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
22365954SN/A    anBegin("RXQ", "Wire Recv");
22375954SN/A
22384987SN/A
22394263SN/A    if (!regs.rctl.en()) {
22404263SN/A        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
22415954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22424263SN/A        return true;
22434263SN/A    }
22444263SN/A
22454263SN/A    // restart the state machines if they are stopped
224610913SN/A    rxTick = true && drainState() != DrainState::Draining;
22474263SN/A    if ((rxTick || txTick) && !tickEvent.scheduled()) {
22486124SN/A        DPRINTF(EthernetSM,
22496124SN/A                "RXS: received packet into fifo, starting ticking\n");
22504283SN/A        restartClock();
22514263SN/A    }
22524263SN/A
22534263SN/A    if (!rxFifo.push(pkt)) {
22544263SN/A        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
22554263SN/A        postInterrupt(IT_RXO, true);
22565954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22574263SN/A        return false;
22584263SN/A    }
22595339SN/A
22605954SN/A    if (CPA::available() && cpa->enabled()) {
22615954SN/A        assert(sys->numSystemsRunning <= 2);
22625954SN/A        System *other_sys;
22635954SN/A        if (sys->systemList[0] == sys)
22645954SN/A            other_sys = sys->systemList[1];
22655954SN/A        else
22665954SN/A            other_sys = sys->systemList[0];
22675954SN/A
22685954SN/A        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22695954SN/A        anQ("RXQ", "RX FIFO Q");
22705954SN/A        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22715954SN/A    }
22725954SN/A
22734263SN/A    return true;
22744263SN/A}
22754263SN/A
22764263SN/A
22774263SN/Avoid
22784263SN/AIGbE::rxStateMachine()
22794263SN/A{
22804263SN/A    if (!regs.rctl.en()) {
22814263SN/A        rxTick = false;
22824263SN/A        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
22834263SN/A        return;
22844263SN/A    }
22854263SN/A
22864263SN/A    // If the packet is done check for interrupts/descriptors/etc
22874263SN/A    if (rxDescCache.packetDone()) {
22884452SN/A        rxDmaPacket = false;
22894263SN/A        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
22904263SN/A        int descLeft = rxDescCache.descLeft();
22915783SN/A        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
22925783SN/A                descLeft, regs.rctl.rdmts(), regs.rdlen());
22934263SN/A        switch (regs.rctl.rdmts()) {
22946124SN/A          case 2: if (descLeft > .125 * regs.rdlen()) break;
22956124SN/A          case 1: if (descLeft > .250 * regs.rdlen()) break;
22966124SN/A          case 0: if (descLeft > .500 * regs.rdlen())  break;
22976124SN/A            DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
22986124SN/A                    "because of descriptors left\n");
22996124SN/A            postInterrupt(IT_RXDMT);
23006124SN/A            break;
23014263SN/A        }
23024263SN/A
23035783SN/A        if (rxFifo.empty())
23045783SN/A            rxDescCache.writeback(0);
23055783SN/A
23064263SN/A        if (descLeft == 0) {
23075954SN/A            anBegin("RXS", "Writeback Descriptors");
23084263SN/A            rxDescCache.writeback(0);
23095339SN/A            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
23105339SN/A                    " writeback and stopping ticking\n");
23114263SN/A            rxTick = false;
23124263SN/A        }
23134263SN/A
23144263SN/A        // only support descriptor granulaties
23154263SN/A        assert(regs.rxdctl.gran());
23164263SN/A
23174263SN/A        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
23186124SN/A            DPRINTF(EthernetSM,
23196124SN/A                    "RXS: Writing back because WTHRESH >= descUsed\n");
23205954SN/A            anBegin("RXS", "Writeback Descriptors");
23214283SN/A            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
23224283SN/A                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
23234283SN/A            else
23244283SN/A                rxDescCache.writeback((cacheBlockSize()-1)>>4);
23254263SN/A        }
23264263SN/A
23274263SN/A        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
23286124SN/A            ((rxDescCache.descLeft() - rxDescCache.descUnused()) >
23296124SN/A             regs.rxdctl.hthresh())) {
23306124SN/A            DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
23316124SN/A                    "descUnused < PTHRESH\n");
23325954SN/A            anBegin("RXS", "Fetch Descriptors");
23334263SN/A            rxDescCache.fetchDescriptors();
23344263SN/A        }
23354263SN/A
23364263SN/A        if (rxDescCache.descUnused() == 0) {
23375954SN/A            anBegin("RXS", "Fetch Descriptors");
23385071SN/A            rxDescCache.fetchDescriptors();
23395954SN/A            anWe("RXS", rxDescCache.annUnusedCacheQ);
23404291SN/A            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23414291SN/A                    "fetching descriptors and stopping ticking\n");
23424263SN/A            rxTick = false;
23434263SN/A        }
23444263SN/A        return;
23454263SN/A    }
23464263SN/A
23474452SN/A    if (rxDmaPacket) {
23486124SN/A        DPRINTF(EthernetSM,
23496124SN/A                "RXS: stopping ticking until packet DMA completes\n");
23504452SN/A        rxTick = false;
23514452SN/A        return;
23524452SN/A    }
23534452SN/A
23544263SN/A    if (!rxDescCache.descUnused()) {
23555954SN/A        anBegin("RXS", "Fetch Descriptors");
23565071SN/A        rxDescCache.fetchDescriptors();
23575954SN/A        anWe("RXS", rxDescCache.annUnusedCacheQ);
23586124SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23596124SN/A                "stopping ticking\n");
23604263SN/A        rxTick = false;
23614263SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
23624263SN/A        return;
23634263SN/A    }
23645954SN/A    anPq("RXS", rxDescCache.annUnusedCacheQ);
23654263SN/A
23664263SN/A    if (rxFifo.empty()) {
23675954SN/A        anWe("RXS", "RX FIFO Q");
23684263SN/A        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
23694263SN/A        rxTick = false;
23704263SN/A        return;
23714263SN/A    }
23725954SN/A    anPq("RXS", "RX FIFO Q");
23735954SN/A    anBegin("RXS", "Get Desc");
23744263SN/A
23754263SN/A    EthPacketPtr pkt;
23764263SN/A    pkt = rxFifo.front();
23774263SN/A
23785339SN/A
23795783SN/A    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
23804263SN/A    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
23815783SN/A    if (pktOffset == pkt->length) {
23825954SN/A        anBegin( "RXS", "FIFO Dequeue");
23835783SN/A        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
23845783SN/A        pktOffset = 0;
23855954SN/A        anDq("RXS", "RX FIFO Q");
23865783SN/A        rxFifo.pop();
23875783SN/A    }
23885783SN/A
23895339SN/A    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
23905339SN/A    rxTick = false;
23915339SN/A    rxDmaPacket = true;
23925954SN/A    anBegin("RXS", "DMA Packet");
23934263SN/A}
23944263SN/A
23954263SN/Avoid
23964263SN/AIGbE::txWire()
23974263SN/A{
239812064Sgabeblack@google.com    txFifoTick = false;
239912064Sgabeblack@google.com
24004263SN/A    if (txFifo.empty()) {
24015954SN/A        anWe("TXQ", "TX FIFO Q");
24024263SN/A        return;
24034263SN/A    }
24044263SN/A
24055339SN/A
24065954SN/A    anPq("TXQ", "TX FIFO Q");
24075339SN/A    if (etherInt->sendPacket(txFifo.front())) {
240810702SN/A        anQ("TXQ", "WireQ");
24094987SN/A        if (DTRACE(EthernetSM)) {
24104987SN/A            IpPtr ip(txFifo.front());
24114987SN/A            if (ip)
24124987SN/A                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
24134987SN/A                        ip->id());
24144987SN/A            else
24154987SN/A                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
24164987SN/A        }
24175954SN/A        anDq("TXQ", "TX FIFO Q");
24185954SN/A        anBegin("TXQ", "Wire Send");
24196124SN/A        DPRINTF(EthernetSM,
24206124SN/A                "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
24214263SN/A                txFifo.avail());
24225485SN/A
24235485SN/A        txBytes += txFifo.front()->length;
24245485SN/A        txPackets++;
24255485SN/A
24264263SN/A        txFifo.pop();
24274263SN/A    }
24284263SN/A}
24294263SN/A
24304263SN/Avoid
24314263SN/AIGbE::tick()
24324263SN/A{
24334283SN/A    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
24344263SN/A
243512064Sgabeblack@google.com    inTick = true;
243612064Sgabeblack@google.com
24374263SN/A    if (rxTick)
24384263SN/A        rxStateMachine();
24394263SN/A
24404291SN/A    if (txTick)
24414263SN/A        txStateMachine();
24424291SN/A
244312064Sgabeblack@google.com    // If txWire returns and txFifoTick is still set, that means the data we
244412064Sgabeblack@google.com    // sent to the other end was already accepted and we can send another
244512064Sgabeblack@google.com    // frame right away. This is consistent with the previous behavior which
244612064Sgabeblack@google.com    // would send another frame if one was ready in ethTxDone. This version
244712064Sgabeblack@google.com    // avoids growing the stack with each frame sent which can cause stack
244812064Sgabeblack@google.com    // overflow.
244912064Sgabeblack@google.com    while (txFifoTick)
24504263SN/A        txWire();
24514263SN/A
24524291SN/A    if (rxTick || txTick || txFifoTick)
24539179SN/A        schedule(tickEvent, curTick() + clockPeriod());
245412064Sgabeblack@google.com
245512064Sgabeblack@google.com    inTick = false;
24564263SN/A}
24573116SN/A
24583116SN/Avoid
24593116SN/AIGbE::ethTxDone()
24603116SN/A{
24615954SN/A    anBegin("TXQ", "Send Done");
24624291SN/A    // restart the tx state machines if they are stopped
24634291SN/A    // fifo to send another packet
24644291SN/A    // tx sm to put more data into the fifo
246510913SN/A    txFifoTick = true && drainState() != DrainState::Draining;
246610913SN/A    if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
24674987SN/A        txTick = true;
24684291SN/A
246912064Sgabeblack@google.com    if (!inTick)
247012064Sgabeblack@google.com        restartClock();
24714294SN/A    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
24723116SN/A}
24733116SN/A
24743116SN/Avoid
247510905SN/AIGbE::serialize(CheckpointOut &cp) const
24763116SN/A{
247710905SN/A    PciDevice::serialize(cp);
24784294SN/A
247910905SN/A    regs.serialize(cp);
24804294SN/A    SERIALIZE_SCALAR(eeOpBits);
24814294SN/A    SERIALIZE_SCALAR(eeAddrBits);
24824294SN/A    SERIALIZE_SCALAR(eeDataBits);
24834294SN/A    SERIALIZE_SCALAR(eeOpcode);
24844294SN/A    SERIALIZE_SCALAR(eeAddr);
24855500SN/A    SERIALIZE_SCALAR(lastInterrupt);
24864294SN/A    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
24874294SN/A
248810905SN/A    rxFifo.serialize("rxfifo", cp);
248910905SN/A    txFifo.serialize("txfifo", cp);
24904294SN/A
249110469SN/A    bool txPktExists = txPacket != nullptr;
24924294SN/A    SERIALIZE_SCALAR(txPktExists);
24934294SN/A    if (txPktExists)
249410905SN/A        txPacket->serialize("txpacket", cp);
24954294SN/A
24964294SN/A    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
24976124SN/A        inter_time = 0;
24984294SN/A
24994294SN/A    if (rdtrEvent.scheduled())
25006124SN/A        rdtr_time = rdtrEvent.when();
25014294SN/A    SERIALIZE_SCALAR(rdtr_time);
25024294SN/A
25034294SN/A    if (radvEvent.scheduled())
25046124SN/A        radv_time = radvEvent.when();
25054294SN/A    SERIALIZE_SCALAR(radv_time);
25064294SN/A
25074294SN/A    if (tidvEvent.scheduled())
25086124SN/A        tidv_time = tidvEvent.when();
25094294SN/A    SERIALIZE_SCALAR(tidv_time);
25104294SN/A
25114294SN/A    if (tadvEvent.scheduled())
25126124SN/A        tadv_time = tadvEvent.when();
25134294SN/A    SERIALIZE_SCALAR(tadv_time);
25144294SN/A
25154294SN/A    if (interEvent.scheduled())
25166124SN/A        inter_time = interEvent.when();
25174294SN/A    SERIALIZE_SCALAR(inter_time);
25184294SN/A
25195783SN/A    SERIALIZE_SCALAR(pktOffset);
25205783SN/A
252110905SN/A    txDescCache.serializeSection(cp, "TxDescCache");
252210905SN/A    rxDescCache.serializeSection(cp, "RxDescCache");
25233116SN/A}
25243116SN/A
25253116SN/Avoid
252610905SN/AIGbE::unserialize(CheckpointIn &cp)
25273116SN/A{
252810905SN/A    PciDevice::unserialize(cp);
25294294SN/A
253010905SN/A    regs.unserialize(cp);
25314294SN/A    UNSERIALIZE_SCALAR(eeOpBits);
25324294SN/A    UNSERIALIZE_SCALAR(eeAddrBits);
25334294SN/A    UNSERIALIZE_SCALAR(eeDataBits);
25344294SN/A    UNSERIALIZE_SCALAR(eeOpcode);
25354294SN/A    UNSERIALIZE_SCALAR(eeAddr);
25365500SN/A    UNSERIALIZE_SCALAR(lastInterrupt);
25374294SN/A    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
25384294SN/A
253910905SN/A    rxFifo.unserialize("rxfifo", cp);
254010905SN/A    txFifo.unserialize("txfifo", cp);
25414294SN/A
25424294SN/A    bool txPktExists;
25434294SN/A    UNSERIALIZE_SCALAR(txPktExists);
25444294SN/A    if (txPktExists) {
254511719Smichael.lebeane@amd.com        txPacket = std::make_shared<EthPacketData>(16384);
254610905SN/A        txPacket->unserialize("txpacket", cp);
25474294SN/A    }
25484294SN/A
25494294SN/A    rxTick = true;
25504294SN/A    txTick = true;
25514294SN/A    txFifoTick = true;
25524294SN/A
25534294SN/A    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
25544294SN/A    UNSERIALIZE_SCALAR(rdtr_time);
25554294SN/A    UNSERIALIZE_SCALAR(radv_time);
25564294SN/A    UNSERIALIZE_SCALAR(tidv_time);
25574294SN/A    UNSERIALIZE_SCALAR(tadv_time);
25584294SN/A    UNSERIALIZE_SCALAR(inter_time);
25594294SN/A
25604294SN/A    if (rdtr_time)
25615606SN/A        schedule(rdtrEvent, rdtr_time);
25624294SN/A
25634294SN/A    if (radv_time)
25645606SN/A        schedule(radvEvent, radv_time);
25654294SN/A
25664294SN/A    if (tidv_time)
25675606SN/A        schedule(tidvEvent, tidv_time);
25684294SN/A
25694294SN/A    if (tadv_time)
25705606SN/A        schedule(tadvEvent, tadv_time);
25714294SN/A
25724294SN/A    if (inter_time)
25735606SN/A        schedule(interEvent, inter_time);
25744294SN/A
25755783SN/A    UNSERIALIZE_SCALAR(pktOffset);
25765783SN/A
257710905SN/A    txDescCache.unserializeSection(cp, "TxDescCache");
257810905SN/A    rxDescCache.unserializeSection(cp, "RxDescCache");
25793116SN/A}
25803116SN/A
25814762SN/AIGbE *
25824762SN/AIGbEParams::create()
25833116SN/A{
25844762SN/A    return new IGbE(this);
25853116SN/A}
2586