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
14213784Sgabeblack@google.comPort &
14313784Sgabeblack@google.comIGbE::getPort(const std::string &if_name, PortID idx)
1444981SN/A{
14513784Sgabeblack@google.com    if (if_name == "interface")
14613784Sgabeblack@google.com        return *etherInt;
14713784Sgabeblack@google.com    return EtherDevice::getPort(if_name, idx);
1484981SN/A}
1493116SN/A
1503116SN/ATick
1513349SN/AIGbE::writeConfig(PacketPtr pkt)
1523116SN/A{
1533116SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1543116SN/A    if (offset < PCI_DEVICE_SPECIFIC)
1559807SN/A        PciDevice::writeConfig(pkt);
1563116SN/A    else
1573116SN/A        panic("Device specific PCI config space not implemented.\n");
1583116SN/A
1596124SN/A    //
1606124SN/A    // Some work may need to be done here based for the pci COMMAND bits.
1616124SN/A    //
1623116SN/A
1639198SN/A    return configDelay;
1643116SN/A}
1653116SN/A
1666124SN/A// Handy macro for range-testing register access addresses
1676124SN/A#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
1686124SN/A
1693116SN/ATick
1703349SN/AIGbE::read(PacketPtr pkt)
1713116SN/A{
1723116SN/A    int bar;
1733116SN/A    Addr daddr;
1743116SN/A
1753116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
1763116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
1773116SN/A
1783116SN/A    // Only Memory register BAR is allowed
1793116SN/A    assert(bar == 0);
1803116SN/A
1813318SN/A    // Only 32bit accesses allowed
1823318SN/A    assert(pkt->getSize() == 4);
1833318SN/A
1844283SN/A    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
1853116SN/A
1866124SN/A    //
1876124SN/A    // Handle read of register here
1886124SN/A    //
1893116SN/A
1903405SN/A
1913318SN/A    switch (daddr) {
1924218SN/A      case REG_CTRL:
19313342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.ctrl());
1944218SN/A        break;
1954218SN/A      case REG_STATUS:
19613342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.sts());
1974218SN/A        break;
1984218SN/A      case REG_EECD:
19913342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.eecd());
2004218SN/A        break;
2014218SN/A      case REG_EERD:
20213342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.eerd());
2034218SN/A        break;
2044218SN/A      case REG_CTRL_EXT:
20513342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.ctrl_ext());
2064218SN/A        break;
2074218SN/A      case REG_MDIC:
20813342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.mdic());
2094218SN/A        break;
2104218SN/A      case REG_ICR:
2116124SN/A        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
2126124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
21313342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.icr());
2144283SN/A        if (regs.icr.int_assert() || regs.imr == 0) {
2154283SN/A            regs.icr = regs.icr() & ~mask(30);
2164283SN/A            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
2174263SN/A        }
2184283SN/A        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
2194283SN/A            regs.imr &= ~regs.iam;
2204283SN/A        chkInterrupt();
2214218SN/A        break;
2225763SN/A      case REG_EICR:
2235763SN/A        // This is only useful for MSI, but the driver reads it every time
2245763SN/A        // Just don't do anything
22513342Sgabeblack@google.com        pkt->setLE<uint32_t>(0);
2265763SN/A        break;
2274218SN/A      case REG_ITR:
22813342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.itr());
2294218SN/A        break;
2304218SN/A      case REG_RCTL:
23113342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rctl());
2324218SN/A        break;
2334218SN/A      case REG_FCTTV:
23413342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.fcttv());
2354218SN/A        break;
2364218SN/A      case REG_TCTL:
23713342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tctl());
2384218SN/A        break;
2394218SN/A      case REG_PBA:
24013342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.pba());
2414218SN/A        break;
2424218SN/A      case REG_WUC:
24311810Sbaz21@cam.ac.uk      case REG_WUFC:
24411810Sbaz21@cam.ac.uk      case REG_WUS:
2454218SN/A      case REG_LEDCTL:
24613342Sgabeblack@google.com        pkt->setLE<uint32_t>(0); // We don't care, so just return 0
2474218SN/A        break;
2484218SN/A      case REG_FCRTL:
24913342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.fcrtl());
2504218SN/A        break;
2514218SN/A      case REG_FCRTH:
25213342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.fcrth());
2534218SN/A        break;
2544218SN/A      case REG_RDBAL:
25513342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rdba.rdbal());
2564218SN/A        break;
2574218SN/A      case REG_RDBAH:
25813342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rdba.rdbah());
2594218SN/A        break;
2604218SN/A      case REG_RDLEN:
26113342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rdlen());
2624218SN/A        break;
2635763SN/A      case REG_SRRCTL:
26413342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.srrctl());
2655763SN/A        break;
2664218SN/A      case REG_RDH:
26713342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rdh());
2684218SN/A        break;
2694218SN/A      case REG_RDT:
27013342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rdt());
2714218SN/A        break;
2724218SN/A      case REG_RDTR:
27313342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rdtr());
2744263SN/A        if (regs.rdtr.fpd()) {
2754263SN/A            rxDescCache.writeback(0);
2766124SN/A            DPRINTF(EthernetIntr,
2776124SN/A                    "Posting interrupt because of RDTR.FPD write\n");
2784263SN/A            postInterrupt(IT_RXT);
2794263SN/A            regs.rdtr.fpd(0);
2804263SN/A        }
2814218SN/A        break;
2825763SN/A      case REG_RXDCTL:
28313342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rxdctl());
2845763SN/A        break;
2854218SN/A      case REG_RADV:
28613342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.radv());
2874218SN/A        break;
2884218SN/A      case REG_TDBAL:
28913342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdba.tdbal());
2904218SN/A        break;
2914218SN/A      case REG_TDBAH:
29213342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdba.tdbah());
2934218SN/A        break;
2944218SN/A      case REG_TDLEN:
29513342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdlen());
2964218SN/A        break;
2974218SN/A      case REG_TDH:
29813342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdh());
2994218SN/A        break;
3005763SN/A      case REG_TXDCA_CTL:
30113342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.txdca_ctl());
3025763SN/A        break;
3034218SN/A      case REG_TDT:
30413342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdt());
3054218SN/A        break;
3064218SN/A      case REG_TIDV:
30713342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tidv());
3084218SN/A        break;
3094218SN/A      case REG_TXDCTL:
31013342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.txdctl());
3114218SN/A        break;
3124218SN/A      case REG_TADV:
31313342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tadv());
3144218SN/A        break;
3155763SN/A      case REG_TDWBAL:
31613342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdwba & mask(32));
3175763SN/A        break;
3185763SN/A      case REG_TDWBAH:
31913342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.tdwba >> 32);
3205763SN/A        break;
3214218SN/A      case REG_RXCSUM:
32213342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rxcsum());
3234218SN/A        break;
3245763SN/A      case REG_RLPML:
32513342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rlpml);
3265763SN/A        break;
3275763SN/A      case REG_RFCTL:
32813342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.rfctl());
3295763SN/A        break;
3304218SN/A      case REG_MANC:
33113342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.manc());
3324218SN/A        break;
3335763SN/A      case REG_SWSM:
33413342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.swsm());
3355763SN/A        regs.swsm.smbi(1);
3365763SN/A        break;
3375763SN/A      case REG_FWSM:
33813342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.fwsm());
3395763SN/A        break;
3405763SN/A      case REG_SWFWSYNC:
34113342Sgabeblack@google.com        pkt->setLE<uint32_t>(regs.sw_fw_sync);
3425763SN/A        break;
3433318SN/A      default:
3446124SN/A        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
3456124SN/A            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
3466124SN/A            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) &&
3476124SN/A            !IN_RANGE(daddr, REG_CRCERRS, STATS_REGS_SIZE))
3484218SN/A            panic("Read request to unknown register number: %#x\n", daddr);
3494218SN/A        else
35013342Sgabeblack@google.com            pkt->setLE<uint32_t>(0);
3513318SN/A    };
3523318SN/A
3534870SN/A    pkt->makeAtomicResponse();
3543116SN/A    return pioDelay;
3553116SN/A}
3563116SN/A
3573116SN/ATick
3583349SN/AIGbE::write(PacketPtr pkt)
3593116SN/A{
3603116SN/A    int bar;
3613116SN/A    Addr daddr;
3623116SN/A
3633318SN/A
3643116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
3653116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
3663116SN/A
3673116SN/A    // Only Memory register BAR is allowed
3683116SN/A    assert(bar == 0);
3693116SN/A
3703318SN/A    // Only 32bit accesses allowed
3713318SN/A    assert(pkt->getSize() == sizeof(uint32_t));
3723318SN/A
3736124SN/A    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n",
37413342Sgabeblack@google.com            daddr, pkt->getLE<uint32_t>());
3753116SN/A
3766124SN/A    //
3776124SN/A    // Handle write of register here
3786124SN/A    //
37913342Sgabeblack@google.com    uint32_t val = pkt->getLE<uint32_t>();
3803318SN/A
3814263SN/A    Regs::RCTL oldrctl;
3824263SN/A    Regs::TCTL oldtctl;
3834263SN/A
3843318SN/A    switch (daddr) {
3854218SN/A      case REG_CTRL:
3864218SN/A        regs.ctrl = val;
3874218SN/A        if (regs.ctrl.tfce())
3884218SN/A            warn("TX Flow control enabled, should implement\n");
3894218SN/A        if (regs.ctrl.rfce())
3904218SN/A            warn("RX Flow control enabled, should implement\n");
3914218SN/A        break;
3924218SN/A      case REG_CTRL_EXT:
3934218SN/A        regs.ctrl_ext = val;
3944218SN/A        break;
3954218SN/A      case REG_STATUS:
3964218SN/A        regs.sts = val;
3974218SN/A        break;
3984218SN/A      case REG_EECD:
3994218SN/A        int oldClk;
4004218SN/A        oldClk = regs.eecd.sk();
4014218SN/A        regs.eecd = val;
4024218SN/A        // See if this is a eeprom access and emulate accordingly
4034218SN/A        if (!oldClk && regs.eecd.sk()) {
4044218SN/A            if (eeOpBits < 8) {
4054218SN/A                eeOpcode = eeOpcode << 1 | regs.eecd.din();
4064218SN/A                eeOpBits++;
4074218SN/A            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
4084218SN/A                eeAddr = eeAddr << 1 | regs.eecd.din();
4094218SN/A                eeAddrBits++;
4104218SN/A            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
4114218SN/A                assert(eeAddr>>1 < EEPROM_SIZE);
4124218SN/A                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
4136124SN/A                        flash[eeAddr>>1] >> eeDataBits & 0x1,
4146124SN/A                        flash[eeAddr>>1]);
4154218SN/A                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
4164218SN/A                eeDataBits++;
4174218SN/A            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
4184218SN/A                regs.eecd.dout(0);
4194218SN/A                eeDataBits++;
4204218SN/A            } else
4214218SN/A                panic("What's going on with eeprom interface? opcode:"
4226124SN/A                      " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
4236124SN/A                      (uint32_t)eeOpBits, (uint32_t)eeAddr,
4246124SN/A                      (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
4253318SN/A
4264218SN/A            // Reset everything for the next command
4274218SN/A            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
4286124SN/A                (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
4294218SN/A                eeOpBits = 0;
4304218SN/A                eeAddrBits = 0;
4314218SN/A                eeDataBits = 0;
4326124SN/A                eeOpcode = 0;
4334218SN/A                eeAddr = 0;
4344218SN/A            }
4353318SN/A
4366124SN/A            DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
4374218SN/A                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
4384218SN/A                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
4396124SN/A            if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
4404218SN/A                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
4414218SN/A                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
4426124SN/A                      (uint32_t)eeOpBits);
4433318SN/A
4443318SN/A
4454218SN/A        }
4464218SN/A        // If driver requests eeprom access, immediately give it to it
4474218SN/A        regs.eecd.ee_gnt(regs.eecd.ee_req());
4484218SN/A        break;
4494218SN/A      case REG_EERD:
4504218SN/A        regs.eerd = val;
4515763SN/A        if (regs.eerd.start()) {
4525763SN/A            regs.eerd.done(1);
4535763SN/A            assert(regs.eerd.addr() < EEPROM_SIZE);
4545763SN/A            regs.eerd.data(flash[regs.eerd.addr()]);
4555763SN/A            regs.eerd.start(0);
4565763SN/A            DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
4575763SN/A                    regs.eerd.addr(), regs.eerd.data());
4585763SN/A        }
4594218SN/A        break;
4604218SN/A      case REG_MDIC:
4614218SN/A        regs.mdic = val;
4624218SN/A        if (regs.mdic.i())
4634218SN/A            panic("No support for interrupt on mdic complete\n");
4644218SN/A        if (regs.mdic.phyadd() != 1)
4654218SN/A            panic("No support for reading anything but phy\n");
4666124SN/A        DPRINTF(Ethernet, "%s phy address %x\n",
4676124SN/A                regs.mdic.op() == 1 ? "Writing" : "Reading",
4686124SN/A                regs.mdic.regadd());
4694218SN/A        switch (regs.mdic.regadd()) {
4706124SN/A          case PHY_PSTATUS:
4716124SN/A            regs.mdic.data(0x796D); // link up
4726124SN/A            break;
4736124SN/A          case PHY_PID:
4746124SN/A            regs.mdic.data(params()->phy_pid);
4756124SN/A            break;
4766124SN/A          case PHY_EPID:
4776124SN/A            regs.mdic.data(params()->phy_epid);
4786124SN/A            break;
4796124SN/A          case PHY_GSTATUS:
4806124SN/A            regs.mdic.data(0x7C00);
4816124SN/A            break;
4826124SN/A          case PHY_EPSTATUS:
4836124SN/A            regs.mdic.data(0x3000);
4846124SN/A            break;
4856124SN/A          case PHY_AGC:
4866124SN/A            regs.mdic.data(0x180); // some random length
4876124SN/A            break;
4886124SN/A          default:
4896124SN/A            regs.mdic.data(0);
4904218SN/A        }
4914218SN/A        regs.mdic.r(1);
4924218SN/A        break;
4934218SN/A      case REG_ICR:
4946124SN/A        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
4956124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
4964283SN/A        if (regs.ctrl_ext.iame())
4974283SN/A            regs.imr &= ~regs.iam;
4984263SN/A        regs.icr = ~bits(val,30,0) & regs.icr();
4994283SN/A        chkInterrupt();
5004218SN/A        break;
5014218SN/A      case REG_ITR:
5024218SN/A        regs.itr = val;
5034218SN/A        break;
5044218SN/A      case REG_ICS:
5054291SN/A        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
5064263SN/A        postInterrupt((IntTypes)val);
5074218SN/A        break;
5086124SN/A      case REG_IMS:
5094218SN/A        regs.imr |= val;
5104263SN/A        chkInterrupt();
5114218SN/A        break;
5124218SN/A      case REG_IMC:
5134263SN/A        regs.imr &= ~val;
5144263SN/A        chkInterrupt();
5154218SN/A        break;
5164218SN/A      case REG_IAM:
5174218SN/A        regs.iam = val;
5184218SN/A        break;
5194218SN/A      case REG_RCTL:
5204263SN/A        oldrctl = regs.rctl;
5214218SN/A        regs.rctl = val;
5224263SN/A        if (regs.rctl.rst()) {
5234263SN/A            rxDescCache.reset();
5244291SN/A            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
5254263SN/A            rxFifo.clear();
5264263SN/A            regs.rctl.rst(0);
5274263SN/A        }
5284263SN/A        if (regs.rctl.en())
5294263SN/A            rxTick = true;
5304283SN/A        restartClock();
5314218SN/A        break;
5324218SN/A      case REG_FCTTV:
5334218SN/A        regs.fcttv = val;
5344218SN/A        break;
5354218SN/A      case REG_TCTL:
5364218SN/A        regs.tctl = val;
5374263SN/A        oldtctl = regs.tctl;
5384263SN/A        regs.tctl = val;
5394263SN/A        if (regs.tctl.en())
5406124SN/A            txTick = true;
5414283SN/A        restartClock();
5424263SN/A        if (regs.tctl.en() && !oldtctl.en()) {
5434263SN/A            txDescCache.reset();
5444263SN/A        }
5456124SN/A        break;
5464218SN/A      case REG_PBA:
5474218SN/A        regs.pba.rxa(val);
5484218SN/A        regs.pba.txa(64 - regs.pba.rxa());
5494218SN/A        break;
5504218SN/A      case REG_WUC:
55111810Sbaz21@cam.ac.uk      case REG_WUFC:
55211810Sbaz21@cam.ac.uk      case REG_WUS:
5534218SN/A      case REG_LEDCTL:
5544218SN/A      case REG_FCAL:
5554218SN/A      case REG_FCAH:
5564218SN/A      case REG_FCT:
5574218SN/A      case REG_VET:
5584218SN/A      case REG_AIFS:
5594218SN/A      case REG_TIPG:
5604218SN/A        ; // We don't care, so don't store anything
5614218SN/A        break;
5625763SN/A      case REG_IVAR0:
5635763SN/A        warn("Writing to IVAR0, ignoring...\n");
5645763SN/A        break;
5654218SN/A      case REG_FCRTL:
5664218SN/A        regs.fcrtl = val;
5674218SN/A        break;
5684218SN/A      case REG_FCRTH:
5694218SN/A        regs.fcrth = val;
5704218SN/A        break;
5714218SN/A      case REG_RDBAL:
5724218SN/A        regs.rdba.rdbal( val & ~mask(4));
5734263SN/A        rxDescCache.areaChanged();
5744218SN/A        break;
5754218SN/A      case REG_RDBAH:
5764218SN/A        regs.rdba.rdbah(val);
5774263SN/A        rxDescCache.areaChanged();
5784218SN/A        break;
5794218SN/A      case REG_RDLEN:
5804218SN/A        regs.rdlen = val & ~mask(7);
5814263SN/A        rxDescCache.areaChanged();
5824218SN/A        break;
5835763SN/A      case REG_SRRCTL:
5845763SN/A        regs.srrctl = val;
5855763SN/A        break;
5864218SN/A      case REG_RDH:
5874218SN/A        regs.rdh = val;
5884263SN/A        rxDescCache.areaChanged();
5894218SN/A        break;
5904218SN/A      case REG_RDT:
5914218SN/A        regs.rdt = val;
5924987SN/A        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
59310913SN/A        if (drainState() == DrainState::Running) {
5944987SN/A            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
5954987SN/A            rxDescCache.fetchDescriptors();
5964987SN/A        } else {
5974987SN/A            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
5984987SN/A        }
5994218SN/A        break;
6004218SN/A      case REG_RDTR:
6014218SN/A        regs.rdtr = val;
6024218SN/A        break;
6034218SN/A      case REG_RADV:
6044218SN/A        regs.radv = val;
6054218SN/A        break;
6065763SN/A      case REG_RXDCTL:
6075763SN/A        regs.rxdctl = val;
6085763SN/A        break;
6094218SN/A      case REG_TDBAL:
6104218SN/A        regs.tdba.tdbal( val & ~mask(4));
6114263SN/A        txDescCache.areaChanged();
6124218SN/A        break;
6134218SN/A      case REG_TDBAH:
6144218SN/A        regs.tdba.tdbah(val);
6154263SN/A        txDescCache.areaChanged();
6164218SN/A        break;
6174218SN/A      case REG_TDLEN:
6184218SN/A        regs.tdlen = val & ~mask(7);
6194263SN/A        txDescCache.areaChanged();
6204218SN/A        break;
6214218SN/A      case REG_TDH:
6224218SN/A        regs.tdh = val;
6234263SN/A        txDescCache.areaChanged();
6244218SN/A        break;
6255763SN/A      case REG_TXDCA_CTL:
6265763SN/A        regs.txdca_ctl = val;
6275763SN/A        if (regs.txdca_ctl.enabled())
6285763SN/A            panic("No support for DCA\n");
6295763SN/A        break;
6304218SN/A      case REG_TDT:
6314218SN/A        regs.tdt = val;
6324987SN/A        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
63310913SN/A        if (drainState() == DrainState::Running) {
6344987SN/A            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
6354987SN/A            txDescCache.fetchDescriptors();
6364987SN/A        } else {
6374987SN/A            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
6384987SN/A        }
6394218SN/A        break;
6404218SN/A      case REG_TIDV:
6414218SN/A        regs.tidv = val;
6424218SN/A        break;
6434218SN/A      case REG_TXDCTL:
6444218SN/A        regs.txdctl = val;
6454218SN/A        break;
6464218SN/A      case REG_TADV:
6474218SN/A        regs.tadv = val;
6484218SN/A        break;
6495763SN/A      case REG_TDWBAL:
6505763SN/A        regs.tdwba &= ~mask(32);
6515763SN/A        regs.tdwba |= val;
6526124SN/A        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
6536124SN/A                                        regs.tdwba & mask(1));
6545763SN/A        break;
6555763SN/A      case REG_TDWBAH:
6565763SN/A        regs.tdwba &= mask(32);
6575763SN/A        regs.tdwba |= (uint64_t)val << 32;
6586124SN/A        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
6596124SN/A                                        regs.tdwba & mask(1));
6605763SN/A        break;
6614218SN/A      case REG_RXCSUM:
6624218SN/A        regs.rxcsum = val;
6634218SN/A        break;
6645763SN/A      case REG_RLPML:
6655763SN/A        regs.rlpml = val;
6665763SN/A        break;
6675763SN/A      case REG_RFCTL:
6685763SN/A        regs.rfctl = val;
6695763SN/A        if (regs.rfctl.exsten())
6705763SN/A            panic("Extended RX descriptors not implemented\n");
6715763SN/A        break;
6724218SN/A      case REG_MANC:
6734218SN/A        regs.manc = val;
6744218SN/A        break;
6755763SN/A      case REG_SWSM:
6765763SN/A        regs.swsm = val;
6775763SN/A        if (regs.fwsm.eep_fw_semaphore())
6785763SN/A            regs.swsm.swesmbi(0);
6795763SN/A        break;
6805763SN/A      case REG_SWFWSYNC:
6815763SN/A        regs.sw_fw_sync = val;
6825763SN/A        break;
6833318SN/A      default:
6846124SN/A        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
6856124SN/A            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
6866124SN/A            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4))
6876124SN/A            panic("Write request to unknown register number: %#x\n", daddr);
6883318SN/A    };
6893116SN/A
6904870SN/A    pkt->makeAtomicResponse();
6913116SN/A    return pioDelay;
6923116SN/A}
6933116SN/A
6944263SN/Avoid
6954263SN/AIGbE::postInterrupt(IntTypes t, bool now)
6964263SN/A{
6974283SN/A    assert(t);
6984283SN/A
6994263SN/A    // Interrupt is already pending
7004987SN/A    if (t & regs.icr() && !now)
7014263SN/A        return;
7024263SN/A
7034987SN/A    regs.icr = regs.icr() | t;
7045500SN/A
7057064SN/A    Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval();
7066124SN/A    DPRINTF(EthernetIntr,
7077823SN/A            "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
7087823SN/A            curTick(), regs.itr.interval(), itr_interval);
7095500SN/A
7106124SN/A    if (regs.itr.interval() == 0 || now ||
7117823SN/A        lastInterrupt + itr_interval <= curTick()) {
7124987SN/A        if (interEvent.scheduled()) {
7135606SN/A            deschedule(interEvent);
7144987SN/A        }
7154987SN/A        cpuPostInt();
7164263SN/A    } else {
7176124SN/A        Tick int_time = lastInterrupt + itr_interval;
7186124SN/A        assert(int_time > 0);
7196124SN/A        DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
7205500SN/A                int_time);
7216124SN/A        if (!interEvent.scheduled()) {
7226124SN/A            schedule(interEvent, int_time);
7236124SN/A        }
7244263SN/A    }
7254263SN/A}
7264263SN/A
7274263SN/Avoid
7284987SN/AIGbE::delayIntEvent()
7294987SN/A{
7304987SN/A    cpuPostInt();
7314987SN/A}
7324987SN/A
7334987SN/A
7344987SN/Avoid
7354263SN/AIGbE::cpuPostInt()
7364263SN/A{
7374987SN/A
7385533SN/A    postedInterrupts++;
7395533SN/A
7404987SN/A    if (!(regs.icr() & regs.imr)) {
7414987SN/A        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
7424987SN/A        return;
7434987SN/A    }
7444987SN/A
7454987SN/A    DPRINTF(Ethernet, "Posting Interrupt\n");
7464987SN/A
7474987SN/A
7484987SN/A    if (interEvent.scheduled()) {
7495606SN/A        deschedule(interEvent);
7504987SN/A    }
7514987SN/A
7524263SN/A    if (rdtrEvent.scheduled()) {
7534263SN/A        regs.icr.rxt0(1);
7545606SN/A        deschedule(rdtrEvent);
7554263SN/A    }
7564263SN/A    if (radvEvent.scheduled()) {
7574263SN/A        regs.icr.rxt0(1);
7585606SN/A        deschedule(radvEvent);
7594263SN/A    }
7604263SN/A    if (tadvEvent.scheduled()) {
7614263SN/A        regs.icr.txdw(1);
7625606SN/A        deschedule(tadvEvent);
7634263SN/A    }
7644263SN/A    if (tidvEvent.scheduled()) {
7654263SN/A        regs.icr.txdw(1);
7665606SN/A        deschedule(tidvEvent);
7674263SN/A    }
7684263SN/A
7694263SN/A    regs.icr.int_assert(1);
7704263SN/A    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
7714263SN/A            regs.icr());
7724987SN/A
7734263SN/A    intrPost();
7744987SN/A
7757823SN/A    lastInterrupt = curTick();
7764263SN/A}
7774263SN/A
7784263SN/Avoid
7794263SN/AIGbE::cpuClearInt()
7804263SN/A{
7814283SN/A    if (regs.icr.int_assert()) {
7824283SN/A        regs.icr.int_assert(0);
7836124SN/A        DPRINTF(EthernetIntr,
7846124SN/A                "EINT: Clearing interrupt to CPU now. Vector %#x\n",
7854283SN/A                regs.icr());
7864283SN/A        intrClear();
7874283SN/A    }
7884263SN/A}
7894263SN/A
7904263SN/Avoid
7914263SN/AIGbE::chkInterrupt()
7924263SN/A{
7934987SN/A    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
7944987SN/A            regs.imr);
7954263SN/A    // Check if we need to clear the cpu interrupt
7964283SN/A    if (!(regs.icr() & regs.imr)) {
7974987SN/A        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
7984283SN/A        if (interEvent.scheduled())
7996124SN/A            deschedule(interEvent);
8004283SN/A        if (regs.icr.int_assert())
8014283SN/A            cpuClearInt();
8024283SN/A    }
8036124SN/A    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n",
8046124SN/A            regs.itr(), regs.itr.interval());
8054263SN/A
8064283SN/A    if (regs.icr() & regs.imr) {
8074283SN/A        if (regs.itr.interval() == 0)  {
8084283SN/A            cpuPostInt();
8094283SN/A        } else {
8106124SN/A            DPRINTF(Ethernet,
8116124SN/A                    "Possibly scheduling interrupt because of imr write\n");
8124987SN/A            if (!interEvent.scheduled()) {
8137823SN/A                Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval();
8146124SN/A                DPRINTF(Ethernet, "Scheduling for %d\n", t);
8156124SN/A                schedule(interEvent, t);
8164987SN/A            }
8174283SN/A        }
8184283SN/A    }
8196124SN/A}
8204283SN/A
8214283SN/A
8226124SN/A///////////////////////////// IGbE::DescCache //////////////////////////////
8236124SN/A
8246124SN/Atemplate<class T>
8256124SN/AIGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s)
8266124SN/A    : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0),
82710420SN/A      wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
82812087Sspwilson2@wisc.edu      wbDelayEvent([this]{ writeback1(); }, n),
82912087Sspwilson2@wisc.edu      fetchDelayEvent([this]{ fetchDescriptors1(); }, n),
83012087Sspwilson2@wisc.edu      fetchEvent([this]{ fetchComplete(); }, n),
83112087Sspwilson2@wisc.edu      wbEvent([this]{ wbComplete(); }, n)
8326124SN/A{
8336124SN/A    fetchBuf = new T[size];
8346124SN/A    wbBuf = new T[size];
8356124SN/A}
8366124SN/A
8376124SN/Atemplate<class T>
8386124SN/AIGbE::DescCache<T>::~DescCache()
8396124SN/A{
8406124SN/A    reset();
8419086SN/A    delete[] fetchBuf;
8429086SN/A    delete[] wbBuf;
8436124SN/A}
8446124SN/A
8456124SN/Atemplate<class T>
8466124SN/Avoid
8476124SN/AIGbE::DescCache<T>::areaChanged()
8486124SN/A{
8496124SN/A    if (usedCache.size() > 0 || curFetching || wbOut)
8506124SN/A        panic("Descriptor Address, Length or Head changed. Bad\n");
8516124SN/A    reset();
8526124SN/A
8534263SN/A}
8544263SN/A
8556124SN/Atemplate<class T>
8566124SN/Avoid
8576124SN/AIGbE::DescCache<T>::writeback(Addr aMask)
8586124SN/A{
8596124SN/A    int curHead = descHead();
8606124SN/A    int max_to_wb = usedCache.size();
8616124SN/A
8626124SN/A    // Check if this writeback is less restrictive that the previous
8636124SN/A    // and if so setup another one immediately following it
8646124SN/A    if (wbOut) {
8656124SN/A        if (aMask < wbAlignment) {
8666124SN/A            moreToWb = true;
8676124SN/A            wbAlignment = aMask;
8686124SN/A        }
8696124SN/A        DPRINTF(EthernetDesc,
8706124SN/A                "Writing back already in process, returning\n");
8716124SN/A        return;
8726124SN/A    }
8736124SN/A
8746124SN/A    moreToWb = false;
8756124SN/A    wbAlignment = aMask;
87611320Ssteve.reinhardt@amd.com
8776124SN/A
8786124SN/A    DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
8796124SN/A            "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
8806124SN/A            curHead, descTail(), descLen(), cachePnt, max_to_wb,
8816124SN/A            descLeft());
8826124SN/A
8836124SN/A    if (max_to_wb + curHead >= descLen()) {
8846124SN/A        max_to_wb = descLen() - curHead;
8856124SN/A        moreToWb = true;
8866124SN/A        // this is by definition aligned correctly
8876124SN/A    } else if (wbAlignment != 0) {
8886124SN/A        // align the wb point to the mask
8896124SN/A        max_to_wb = max_to_wb & ~wbAlignment;
8906124SN/A    }
8916124SN/A
8926124SN/A    DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
8936124SN/A
8946124SN/A    if (max_to_wb <= 0) {
8956124SN/A        if (usedCache.size())
8966124SN/A            igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
8976124SN/A        else
8986124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
8996124SN/A        return;
9006124SN/A    }
9016124SN/A
9026124SN/A    wbOut = max_to_wb;
9036124SN/A
90411320Ssteve.reinhardt@amd.com    assert(!wbDelayEvent.scheduled());
9057823SN/A    igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9066124SN/A    igbe->anBegin(annSmWb, "Prepare Writeback Desc");
9076124SN/A}
90811320Ssteve.reinhardt@amd.com
9096124SN/Atemplate<class T>
9106124SN/Avoid
9116124SN/AIGbE::DescCache<T>::writeback1()
9126124SN/A{
9136124SN/A    // If we're draining delay issuing this DMA
91410913SN/A    if (igbe->drainState() != DrainState::Running) {
9157823SN/A        igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9166124SN/A        return;
9176124SN/A    }
9186124SN/A
9196124SN/A    DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
92011320Ssteve.reinhardt@amd.com
9216124SN/A    for (int x = 0; x < wbOut; x++) {
9226124SN/A        assert(usedCache.size());
9236124SN/A        memcpy(&wbBuf[x], usedCache[x], sizeof(T));
9246124SN/A        igbe->anPq(annSmWb, annUsedCacheQ);
9256124SN/A        igbe->anPq(annSmWb, annDescQ);
9266124SN/A        igbe->anQ(annSmWb, annUsedDescQ);
9276124SN/A    }
9286124SN/A
92911320Ssteve.reinhardt@amd.com
9306124SN/A    igbe->anBegin(annSmWb, "Writeback Desc DMA");
9316124SN/A
9326124SN/A    assert(wbOut);
9336124SN/A    igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
9346124SN/A                   wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
9356124SN/A                   igbe->wbCompDelay);
9366124SN/A}
9376124SN/A
9386124SN/Atemplate<class T>
9396124SN/Avoid
9406124SN/AIGbE::DescCache<T>::fetchDescriptors()
9416124SN/A{
9426124SN/A    size_t max_to_fetch;
9436124SN/A
9446124SN/A    if (curFetching) {
9456124SN/A        DPRINTF(EthernetDesc,
9466124SN/A                "Currently fetching %d descriptors, returning\n",
9476124SN/A                curFetching);
9486124SN/A        return;
9496124SN/A    }
9506124SN/A
9516124SN/A    if (descTail() >= cachePnt)
9526124SN/A        max_to_fetch = descTail() - cachePnt;
9536124SN/A    else
9546124SN/A        max_to_fetch = descLen() - cachePnt;
9556124SN/A
9566124SN/A    size_t free_cache = size - usedCache.size() - unusedCache.size();
9576124SN/A
9586124SN/A    if (!max_to_fetch)
9596124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
9606124SN/A    else
9616124SN/A        igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
9626124SN/A
9636124SN/A    if (max_to_fetch) {
9646124SN/A        if (!free_cache)
9656124SN/A            igbe->anWf(annSmFetch, annDescQ);
9666124SN/A        else
9676124SN/A            igbe->anRq(annSmFetch, annDescQ, free_cache);
9686124SN/A    }
9696124SN/A
9706124SN/A    max_to_fetch = std::min(max_to_fetch, free_cache);
97111320Ssteve.reinhardt@amd.com
9726124SN/A
9736124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
9746124SN/A            "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
9756124SN/A            descHead(), descTail(), descLen(), cachePnt,
9766124SN/A            max_to_fetch, descLeft());
9776124SN/A
9786124SN/A    // Nothing to do
9796124SN/A    if (max_to_fetch == 0)
9806124SN/A        return;
98111320Ssteve.reinhardt@amd.com
9826124SN/A    // So we don't have two descriptor fetches going on at once
9836124SN/A    curFetching = max_to_fetch;
9846124SN/A
9856124SN/A    assert(!fetchDelayEvent.scheduled());
9867823SN/A    igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9876124SN/A    igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
9886124SN/A}
9896124SN/A
9906124SN/Atemplate<class T>
9916124SN/Avoid
9926124SN/AIGbE::DescCache<T>::fetchDescriptors1()
9936124SN/A{
9946124SN/A    // If we're draining delay issuing this DMA
99510913SN/A    if (igbe->drainState() != DrainState::Running) {
9967823SN/A        igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9976124SN/A        return;
9986124SN/A    }
9996124SN/A
10006124SN/A    igbe->anBegin(annSmFetch, "Fetch Desc");
10016124SN/A
10026124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
10036124SN/A            descBase() + cachePnt * sizeof(T),
10046124SN/A            pciToDma(descBase() + cachePnt * sizeof(T)),
10056124SN/A            curFetching * sizeof(T));
10066124SN/A    assert(curFetching);
10076124SN/A    igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
10086124SN/A                  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
10096124SN/A                  igbe->fetchCompDelay);
10106124SN/A}
10116124SN/A
10126124SN/Atemplate<class T>
10136124SN/Avoid
10146124SN/AIGbE::DescCache<T>::fetchComplete()
10156124SN/A{
10166124SN/A    T *newDesc;
10176124SN/A    igbe->anBegin(annSmFetch, "Fetch Complete");
10186124SN/A    for (int x = 0; x < curFetching; x++) {
10196124SN/A        newDesc = new T;
10206124SN/A        memcpy(newDesc, &fetchBuf[x], sizeof(T));
10216124SN/A        unusedCache.push_back(newDesc);
10226124SN/A        igbe->anDq(annSmFetch, annUnusedDescQ);
10236124SN/A        igbe->anQ(annSmFetch, annUnusedCacheQ);
10246124SN/A        igbe->anQ(annSmFetch, annDescQ);
10256124SN/A    }
10266124SN/A
10276124SN/A
10286124SN/A#ifndef NDEBUG
10296124SN/A    int oldCp = cachePnt;
10306124SN/A#endif
10316124SN/A
10326124SN/A    cachePnt += curFetching;
10336124SN/A    assert(cachePnt <= descLen());
10346124SN/A    if (cachePnt == descLen())
10356124SN/A        cachePnt = 0;
10366124SN/A
10376124SN/A    curFetching = 0;
10386124SN/A
10396124SN/A    DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
10406124SN/A            oldCp, cachePnt);
10416124SN/A
10426124SN/A    if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
10436124SN/A                                                             cachePnt)) == 0)
10446124SN/A    {
10456124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
10466124SN/A    } else if (!(size - usedCache.size() - unusedCache.size())) {
10476124SN/A        igbe->anWf(annSmFetch, annDescQ);
10486124SN/A    } else {
10496124SN/A        igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
10506124SN/A    }
10516124SN/A
10526124SN/A    enableSm();
10536124SN/A    igbe->checkDrain();
10546124SN/A}
10556124SN/A
10566124SN/Atemplate<class T>
10576124SN/Avoid
10586124SN/AIGbE::DescCache<T>::wbComplete()
10596124SN/A{
10606124SN/A
10616124SN/A    igbe->anBegin(annSmWb, "Finish Writeback");
10626124SN/A
10636124SN/A    long  curHead = descHead();
10646124SN/A#ifndef NDEBUG
10656124SN/A    long oldHead = curHead;
10666124SN/A#endif
106711320Ssteve.reinhardt@amd.com
10686124SN/A    for (int x = 0; x < wbOut; x++) {
10696124SN/A        assert(usedCache.size());
10706124SN/A        delete usedCache[0];
10716124SN/A        usedCache.pop_front();
10726124SN/A
10736124SN/A        igbe->anDq(annSmWb, annUsedCacheQ);
10746124SN/A        igbe->anDq(annSmWb, annDescQ);
10756124SN/A    }
10766124SN/A
10776124SN/A    curHead += wbOut;
10786124SN/A    wbOut = 0;
10796124SN/A
10806124SN/A    if (curHead >= descLen())
10816124SN/A        curHead -= descLen();
10826124SN/A
10836124SN/A    // Update the head
10846124SN/A    updateHead(curHead);
10856124SN/A
10866124SN/A    DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
10876124SN/A            oldHead, curHead);
10886124SN/A
10896124SN/A    // If we still have more to wb, call wb now
10906124SN/A    actionAfterWb();
10916124SN/A    if (moreToWb) {
10926124SN/A        moreToWb = false;
10936124SN/A        DPRINTF(EthernetDesc, "Writeback has more todo\n");
10946124SN/A        writeback(wbAlignment);
10956124SN/A    }
10966124SN/A
10976124SN/A    if (!wbOut) {
10986124SN/A        igbe->checkDrain();
10996124SN/A        if (usedCache.size())
11006124SN/A            igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
11016124SN/A        else
11026124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
11036124SN/A    }
11046124SN/A    fetchAfterWb();
11056124SN/A}
11066124SN/A
11076124SN/Atemplate<class T>
11086124SN/Avoid
11096124SN/AIGbE::DescCache<T>::reset()
11106124SN/A{
11116124SN/A    DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
11126228SN/A    for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
11136124SN/A        delete usedCache[x];
11146228SN/A    for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
11156124SN/A        delete unusedCache[x];
11166124SN/A
11176124SN/A    usedCache.clear();
11186124SN/A    unusedCache.clear();
11196124SN/A
11206124SN/A    cachePnt = 0;
11216124SN/A
11226124SN/A}
11236124SN/A
11246124SN/Atemplate<class T>
11256124SN/Avoid
112610905SN/AIGbE::DescCache<T>::serialize(CheckpointOut &cp) const
11276124SN/A{
11286124SN/A    SERIALIZE_SCALAR(cachePnt);
11296124SN/A    SERIALIZE_SCALAR(curFetching);
11306124SN/A    SERIALIZE_SCALAR(wbOut);
11316124SN/A    SERIALIZE_SCALAR(moreToWb);
11326124SN/A    SERIALIZE_SCALAR(wbAlignment);
11336124SN/A
11346228SN/A    typename CacheType::size_type usedCacheSize = usedCache.size();
11356124SN/A    SERIALIZE_SCALAR(usedCacheSize);
11366228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
113710905SN/A        arrayParamOut(cp, csprintf("usedCache_%d", x),
11386124SN/A                      (uint8_t*)usedCache[x],sizeof(T));
11396124SN/A    }
11406124SN/A
11416228SN/A    typename CacheType::size_type unusedCacheSize = unusedCache.size();
11426124SN/A    SERIALIZE_SCALAR(unusedCacheSize);
11436228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
114410905SN/A        arrayParamOut(cp, csprintf("unusedCache_%d", x),
11456124SN/A                      (uint8_t*)unusedCache[x],sizeof(T));
11466124SN/A    }
11476124SN/A
11486124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11496124SN/A    if (fetchDelayEvent.scheduled())
11506124SN/A        fetch_delay = fetchDelayEvent.when();
11516124SN/A    SERIALIZE_SCALAR(fetch_delay);
11526124SN/A    if (wbDelayEvent.scheduled())
11536124SN/A        wb_delay = wbDelayEvent.when();
11546124SN/A    SERIALIZE_SCALAR(wb_delay);
11556124SN/A
11566124SN/A
11576124SN/A}
11586124SN/A
11596124SN/Atemplate<class T>
11606124SN/Avoid
116110905SN/AIGbE::DescCache<T>::unserialize(CheckpointIn &cp)
11626124SN/A{
11636124SN/A    UNSERIALIZE_SCALAR(cachePnt);
11646124SN/A    UNSERIALIZE_SCALAR(curFetching);
11656124SN/A    UNSERIALIZE_SCALAR(wbOut);
11666124SN/A    UNSERIALIZE_SCALAR(moreToWb);
11676124SN/A    UNSERIALIZE_SCALAR(wbAlignment);
11686124SN/A
11696228SN/A    typename CacheType::size_type usedCacheSize;
11706124SN/A    UNSERIALIZE_SCALAR(usedCacheSize);
11716124SN/A    T *temp;
11726228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
11736124SN/A        temp = new T;
117410905SN/A        arrayParamIn(cp, csprintf("usedCache_%d", x),
11756124SN/A                     (uint8_t*)temp,sizeof(T));
11766124SN/A        usedCache.push_back(temp);
11776124SN/A    }
11786124SN/A
11796228SN/A    typename CacheType::size_type unusedCacheSize;
11806124SN/A    UNSERIALIZE_SCALAR(unusedCacheSize);
11816228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
11826124SN/A        temp = new T;
118310905SN/A        arrayParamIn(cp, csprintf("unusedCache_%d", x),
11846124SN/A                     (uint8_t*)temp,sizeof(T));
11856124SN/A        unusedCache.push_back(temp);
11866124SN/A    }
11876124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11886124SN/A    UNSERIALIZE_SCALAR(fetch_delay);
11896124SN/A    UNSERIALIZE_SCALAR(wb_delay);
11906124SN/A    if (fetch_delay)
11916124SN/A        igbe->schedule(fetchDelayEvent, fetch_delay);
11926124SN/A    if (wb_delay)
11936124SN/A        igbe->schedule(wbDelayEvent, wb_delay);
11946124SN/A
11956124SN/A
11966124SN/A}
11976124SN/A
11986124SN/A///////////////////////////// IGbE::RxDescCache //////////////////////////////
11994263SN/A
12004263SN/AIGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
120111320Ssteve.reinhardt@amd.com    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
120212087Sspwilson2@wisc.edu    pktEvent([this]{ pktComplete(); }, n),
120312087Sspwilson2@wisc.edu    pktHdrEvent([this]{ pktSplitDone(); }, n),
120412087Sspwilson2@wisc.edu    pktDataEvent([this]{ pktSplitDone(); }, n)
12054263SN/A
12064263SN/A{
12075954SN/A    annSmFetch = "RX Desc Fetch";
12085954SN/A    annSmWb = "RX Desc Writeback";
12095954SN/A    annUnusedDescQ = "RX Unused Descriptors";
12105954SN/A    annUnusedCacheQ = "RX Unused Descriptor Cache";
12115954SN/A    annUsedCacheQ = "RX Used Descriptor Cache";
12125954SN/A    annUsedDescQ = "RX Used Descriptors";
12135954SN/A    annDescQ = "RX Descriptors";
12144263SN/A}
12153116SN/A
12165339SN/Avoid
12175783SN/AIGbE::RxDescCache::pktSplitDone()
12185783SN/A{
12195783SN/A    splitCount++;
12206124SN/A    DPRINTF(EthernetDesc,
12216124SN/A            "Part of split packet done: splitcount now %d\n", splitCount);
12225783SN/A    assert(splitCount <= 2);
12235783SN/A    if (splitCount != 2)
12245783SN/A        return;
12255783SN/A    splitCount = 0;
12266124SN/A    DPRINTF(EthernetDesc,
12276124SN/A            "Part of split packet done: calling pktComplete()\n");
12285783SN/A    pktComplete();
12295783SN/A}
12305783SN/A
12315783SN/Aint
12325783SN/AIGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
12333116SN/A{
12346124SN/A    assert(unusedCache.size());
12355071SN/A    //if (!unusedCache.size())
12365071SN/A    //    return false;
12374263SN/A
12384263SN/A    pktPtr = packet;
12394452SN/A    pktDone = false;
12406227SN/A    unsigned buf_len, hdr_len;
12415763SN/A
12425763SN/A    RxDesc *desc = unusedCache.front();
12435763SN/A    switch (igbe->regs.srrctl.desctype()) {
12445763SN/A      case RXDT_LEGACY:
12455783SN/A        assert(pkt_offset == 0);
12465783SN/A        bytesCopied = packet->length;
12475763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
12486124SN/A                packet->length, igbe->regs.rctl.descSize());
12495763SN/A        assert(packet->length < igbe->regs.rctl.descSize());
12506124SN/A        igbe->dmaWrite(pciToDma(desc->legacy.buf),
12516124SN/A                       packet->length, &pktEvent, packet->data,
12526124SN/A                       igbe->rxWriteDelay);
12535763SN/A        break;
12545763SN/A      case RXDT_ADV_ONEBUF:
12555783SN/A        assert(pkt_offset == 0);
12565783SN/A        bytesCopied = packet->length;
12575763SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12586124SN/A            igbe->regs.rctl.descSize();
12595763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
12606124SN/A                packet->length, igbe->regs.srrctl(), buf_len);
12615763SN/A        assert(packet->length < buf_len);
12626124SN/A        igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
12636124SN/A                       packet->length, &pktEvent, packet->data,
12646124SN/A                       igbe->rxWriteDelay);
12655783SN/A        desc->adv_wb.header_len = htole(0);
12665783SN/A        desc->adv_wb.sph = htole(0);
12675783SN/A        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
12685783SN/A        break;
12695783SN/A      case RXDT_ADV_SPLIT_A:
12705783SN/A        int split_point;
127111320Ssteve.reinhardt@amd.com
12725783SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12736124SN/A            igbe->regs.rctl.descSize();
127411320Ssteve.reinhardt@amd.com        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
12756124SN/A        DPRINTF(EthernetDesc,
12766124SN/A                "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
12776124SN/A                "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
12786124SN/A                igbe->regs.rctl.lpe(), packet->length, pkt_offset,
12796124SN/A                igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
12806124SN/A                desc->adv_read.pkt, buf_len);
12815783SN/A
12825783SN/A        split_point = hsplit(pktPtr);
12835783SN/A
12845783SN/A        if (packet->length <= hdr_len) {
12855783SN/A            bytesCopied = packet->length;
12865783SN/A            assert(pkt_offset == 0);
12876124SN/A            DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
12886124SN/A            igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
12896124SN/A                           packet->length, &pktEvent, packet->data,
12906124SN/A                           igbe->rxWriteDelay);
12915783SN/A            desc->adv_wb.header_len = htole((uint16_t)packet->length);
12925783SN/A            desc->adv_wb.sph = htole(0);
12935783SN/A            desc->adv_wb.pkt_len = htole(0);
12945783SN/A        } else if (split_point) {
12955783SN/A            if (pkt_offset) {
12965783SN/A                // we are only copying some data, header/data has already been
12975783SN/A                // copied
12986124SN/A                int max_to_copy =
12996124SN/A                    std::min(packet->length - pkt_offset, buf_len);
13005783SN/A                bytesCopied += max_to_copy;
13016124SN/A                DPRINTF(EthernetDesc,
13026124SN/A                        "Hdr split: Continuing data buffer copy\n");
13036124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13046124SN/A                               max_to_copy, &pktEvent,
13056124SN/A                               packet->data + pkt_offset, igbe->rxWriteDelay);
13065783SN/A                desc->adv_wb.header_len = htole(0);
13075783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
13085783SN/A                desc->adv_wb.sph = htole(0);
13095783SN/A            } else {
13106124SN/A                int max_to_copy =
13116124SN/A                    std::min(packet->length - split_point, buf_len);
13125783SN/A                bytesCopied += max_to_copy + split_point;
131311320Ssteve.reinhardt@amd.com
13146124SN/A                DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
13155783SN/A                        split_point);
13166124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
13176124SN/A                               split_point, &pktHdrEvent,
13186124SN/A                               packet->data, igbe->rxWriteDelay);
13196124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13206124SN/A                               max_to_copy, &pktDataEvent,
13216124SN/A                               packet->data + split_point, igbe->rxWriteDelay);
13225783SN/A                desc->adv_wb.header_len = htole(split_point);
13235783SN/A                desc->adv_wb.sph = 1;
13245783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
13255783SN/A            }
13265783SN/A        } else {
13276124SN/A            panic("Header split not fitting within header buffer or "
13286124SN/A                  "undecodable packet not fitting in header unsupported\n");
13295783SN/A        }
13305763SN/A        break;
13315763SN/A      default:
13325763SN/A        panic("Unimplemnted RX receive buffer type: %d\n",
13336124SN/A              igbe->regs.srrctl.desctype());
13345763SN/A    }
13355783SN/A    return bytesCopied;
13365763SN/A
13373116SN/A}
13383116SN/A
13394263SN/Avoid
13404263SN/AIGbE::RxDescCache::pktComplete()
13414263SN/A{
13424263SN/A    assert(unusedCache.size());
13434263SN/A    RxDesc *desc;
13444263SN/A    desc = unusedCache.front();
13454263SN/A
13465954SN/A    igbe->anBegin("RXS", "Update Desc");
13475954SN/A
13484283SN/A    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
13496124SN/A    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
13506124SN/A            "stripcrc offset: %d value written: %d %d\n",
13515783SN/A            pktPtr->length, bytesCopied, crcfixup,
13524283SN/A            htole((uint16_t)(pktPtr->length + crcfixup)),
13534283SN/A            (uint16_t)(pktPtr->length + crcfixup));
13544283SN/A
13554263SN/A    // no support for anything but starting at 0
13564263SN/A    assert(igbe->regs.rxcsum.pcss() == 0);
13574263SN/A
13584291SN/A    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
13594263SN/A
13605783SN/A    uint16_t status = RXDS_DD;
13614263SN/A    uint8_t err = 0;
13625763SN/A    uint16_t ext_err = 0;
13635763SN/A    uint16_t csum = 0;
13645763SN/A    uint16_t ptype = 0;
13655763SN/A    uint16_t ip_id = 0;
13664452SN/A
13675783SN/A    assert(bytesCopied <= pktPtr->length);
13685783SN/A    if (bytesCopied == pktPtr->length)
13695783SN/A        status |= RXDS_EOP;
13705783SN/A
13714263SN/A    IpPtr ip(pktPtr);
137212963Streapking@google.com    Ip6Ptr ip6(pktPtr);
13734452SN/A
137412963Streapking@google.com    if (ip || ip6) {
137512963Streapking@google.com        if (ip) {
137612963Streapking@google.com            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
137712963Streapking@google.com                    ip->id());
137812963Streapking@google.com            ptype |= RXDP_IPV4;
137912963Streapking@google.com            ip_id = ip->id();
138012963Streapking@google.com        }
138112963Streapking@google.com        if (ip6)
138212963Streapking@google.com            ptype |= RXDP_IPV6;
13834452SN/A
138412963Streapking@google.com        if (ip && igbe->regs.rxcsum.ipofld()) {
13854291SN/A            DPRINTF(EthernetDesc, "Checking IP checksum\n");
13864263SN/A            status |= RXDS_IPCS;
13875763SN/A            csum = htole(cksum(ip));
13885485SN/A            igbe->rxIpChecksums++;
13894263SN/A            if (cksum(ip) != 0) {
13904263SN/A                err |= RXDE_IPE;
13915763SN/A                ext_err |= RXDEE_IPE;
13924291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
13934263SN/A            }
13944263SN/A        }
139512963Streapking@google.com        TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
13964263SN/A        if (tcp && igbe->regs.rxcsum.tuofld()) {
13974291SN/A            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
13984263SN/A            status |= RXDS_TCPCS;
13995763SN/A            ptype |= RXDP_TCP;
14005763SN/A            csum = htole(cksum(tcp));
14015485SN/A            igbe->rxTcpChecksums++;
14024263SN/A            if (cksum(tcp) != 0) {
14034291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
14044263SN/A                err |= RXDE_TCPE;
14055763SN/A                ext_err |= RXDEE_TCPE;
14064263SN/A            }
14074263SN/A        }
14084263SN/A
140912963Streapking@google.com        UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
14104263SN/A        if (udp && igbe->regs.rxcsum.tuofld()) {
14114291SN/A            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
14124263SN/A            status |= RXDS_UDPCS;
14135763SN/A            ptype |= RXDP_UDP;
14145763SN/A            csum = htole(cksum(udp));
14155485SN/A            igbe->rxUdpChecksums++;
14164421SN/A            if (cksum(udp) != 0) {
14174291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
14185763SN/A                ext_err |= RXDEE_TCPE;
14194263SN/A                err |= RXDE_TCPE;
14204263SN/A            }
14214263SN/A        }
14224452SN/A    } else { // if ip
14234452SN/A        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
14244452SN/A    }
14254452SN/A
14265763SN/A    switch (igbe->regs.srrctl.desctype()) {
14275763SN/A      case RXDT_LEGACY:
14285763SN/A        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
14295763SN/A        desc->legacy.status = htole(status);
14305763SN/A        desc->legacy.errors = htole(err);
14315763SN/A        // No vlan support at this point... just set it to 0
14325763SN/A        desc->legacy.vlan = 0;
14335763SN/A        break;
14345783SN/A      case RXDT_ADV_SPLIT_A:
14355763SN/A      case RXDT_ADV_ONEBUF:
14365763SN/A        desc->adv_wb.rss_type = htole(0);
14375763SN/A        desc->adv_wb.pkt_type = htole(ptype);
14385763SN/A        if (igbe->regs.rxcsum.pcsd()) {
14395763SN/A            // no rss support right now
14405763SN/A            desc->adv_wb.rss_hash = htole(0);
14415763SN/A        } else {
14425763SN/A            desc->adv_wb.id = htole(ip_id);
14435763SN/A            desc->adv_wb.csum = htole(csum);
14445763SN/A        }
14455763SN/A        desc->adv_wb.status = htole(status);
14465763SN/A        desc->adv_wb.errors = htole(ext_err);
14475763SN/A        // no vlan support
144811320Ssteve.reinhardt@amd.com        desc->adv_wb.vlan_tag = htole(0);
14495763SN/A        break;
14505763SN/A      default:
14515763SN/A        panic("Unimplemnted RX receive buffer type %d\n",
14526124SN/A              igbe->regs.srrctl.desctype());
14535763SN/A    }
14544263SN/A
14555783SN/A    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
14565783SN/A            desc->adv_read.pkt, desc->adv_read.hdr);
14574263SN/A
14585783SN/A    if (bytesCopied == pktPtr->length) {
14596124SN/A        DPRINTF(EthernetDesc,
14606124SN/A                "Packet completely written to descriptor buffers\n");
14615783SN/A        // Deal with the rx timer interrupts
14625783SN/A        if (igbe->regs.rdtr.delay()) {
14636124SN/A            Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
14646124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
14657823SN/A            igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
14665783SN/A        }
14675783SN/A
14685783SN/A        if (igbe->regs.radv.idv()) {
14696124SN/A            Tick delay = igbe->regs.radv.idv() * igbe->intClock();
14706124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
14715783SN/A            if (!igbe->radvEvent.scheduled()) {
14727823SN/A                igbe->schedule(igbe->radvEvent, curTick() + delay);
14735783SN/A            }
14745783SN/A        }
14755783SN/A
14765783SN/A        // if neither radv or rdtr, maybe itr is set...
14775783SN/A        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
14786124SN/A            DPRINTF(EthernetSM,
14796124SN/A                    "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
14805783SN/A            igbe->postInterrupt(IT_RXT);
14815783SN/A        }
14825783SN/A
14835783SN/A        // If the packet is small enough, interrupt appropriately
14845783SN/A        // I wonder if this is delayed or not?!
14855783SN/A        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
14866124SN/A            DPRINTF(EthernetSM,
14876124SN/A                    "RXS: Posting IT_SRPD beacuse small packet received\n");
14885783SN/A            igbe->postInterrupt(IT_SRPD);
14895783SN/A        }
14905783SN/A        bytesCopied = 0;
14914263SN/A    }
14924263SN/A
14935783SN/A    pktPtr = NULL;
14945783SN/A    igbe->checkDrain();
14955783SN/A    enableSm();
14965783SN/A    pktDone = true;
14974263SN/A
14985954SN/A    igbe->anBegin("RXS", "Done Updating Desc");
14994291SN/A    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
15005954SN/A    igbe->anDq("RXS", annUnusedCacheQ);
15014263SN/A    unusedCache.pop_front();
15025954SN/A    igbe->anQ("RXS", annUsedCacheQ);
15034263SN/A    usedCache.push_back(desc);
15044263SN/A}
15054263SN/A
15064263SN/Avoid
15074263SN/AIGbE::RxDescCache::enableSm()
15084263SN/A{
150910913SN/A    if (igbe->drainState() != DrainState::Draining) {
15105071SN/A        igbe->rxTick = true;
15115071SN/A        igbe->restartClock();
15125071SN/A    }
15134263SN/A}
15144263SN/A
15154263SN/Abool
15164263SN/AIGbE::RxDescCache::packetDone()
15174263SN/A{
15184263SN/A    if (pktDone) {
15194263SN/A        pktDone = false;
15204263SN/A        return true;
15214263SN/A    }
15224263SN/A    return false;
15234263SN/A}
15244263SN/A
15254294SN/Abool
15264294SN/AIGbE::RxDescCache::hasOutstandingEvents()
15274294SN/A{
15284294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
15295783SN/A        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
15305783SN/A        pktDataEvent.scheduled();
153111320Ssteve.reinhardt@amd.com
15324294SN/A}
15334294SN/A
15344294SN/Avoid
153510905SN/AIGbE::RxDescCache::serialize(CheckpointOut &cp) const
15364294SN/A{
153710905SN/A    DescCache<RxDesc>::serialize(cp);
15384294SN/A    SERIALIZE_SCALAR(pktDone);
15395783SN/A    SERIALIZE_SCALAR(splitCount);
15405783SN/A    SERIALIZE_SCALAR(bytesCopied);
15414294SN/A}
15424294SN/A
15434294SN/Avoid
154410905SN/AIGbE::RxDescCache::unserialize(CheckpointIn &cp)
15454294SN/A{
154610905SN/A    DescCache<RxDesc>::unserialize(cp);
15474294SN/A    UNSERIALIZE_SCALAR(pktDone);
15485783SN/A    UNSERIALIZE_SCALAR(splitCount);
15495783SN/A    UNSERIALIZE_SCALAR(bytesCopied);
15504294SN/A}
15514294SN/A
15524294SN/A
15536124SN/A///////////////////////////// IGbE::TxDescCache //////////////////////////////
15544263SN/A
15554263SN/AIGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
15566124SN/A    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
155710420SN/A      pktWaiting(false), pktMultiDesc(false),
155810420SN/A      completionAddress(0), completionEnabled(false),
15598553SN/A      useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
15608553SN/A      tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
15618553SN/A      tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
156212087Sspwilson2@wisc.edu    pktEvent([this]{ pktComplete(); }, n),
156312087Sspwilson2@wisc.edu    headerEvent([this]{ headerComplete(); }, n),
156412087Sspwilson2@wisc.edu    nullEvent([this]{ nullCallback(); }, n)
15654263SN/A{
15665954SN/A    annSmFetch = "TX Desc Fetch";
15675954SN/A    annSmWb = "TX Desc Writeback";
15685954SN/A    annUnusedDescQ = "TX Unused Descriptors";
15695954SN/A    annUnusedCacheQ = "TX Unused Descriptor Cache";
15705954SN/A    annUsedCacheQ = "TX Used Descriptor Cache";
15715954SN/A    annUsedDescQ = "TX Used Descriptors";
15725954SN/A    annDescQ = "TX Descriptors";
15734263SN/A}
15744263SN/A
15755762SN/Avoid
15765762SN/AIGbE::TxDescCache::processContextDesc()
15774263SN/A{
15784263SN/A    assert(unusedCache.size());
15795762SN/A    TxDesc *desc;
158011320Ssteve.reinhardt@amd.com
15815762SN/A    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
15824263SN/A
15836124SN/A    while (!useTso && unusedCache.size() &&
15846124SN/A           TxdOp::isContext(unusedCache.front())) {
15855762SN/A        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
15864263SN/A
15875762SN/A        desc = unusedCache.front();
158811320Ssteve.reinhardt@amd.com        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
15896124SN/A                desc->d1, desc->d2);
15904263SN/A
159111320Ssteve.reinhardt@amd.com
15924263SN/A        // is this going to be a tcp or udp packet?
15934263SN/A        isTcp = TxdOp::tcp(desc) ? true : false;
15944263SN/A
159511320Ssteve.reinhardt@amd.com        // setup all the TSO variables, they'll be ignored if we don't use
15965763SN/A        // tso for this connection
15975763SN/A        tsoHeaderLen = TxdOp::hdrlen(desc);
15985763SN/A        tsoMss  = TxdOp::mss(desc);
15995763SN/A
16005763SN/A        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
16016124SN/A            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
16026124SN/A                    "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
16036124SN/A                    TxdOp::mss(desc), TxdOp::getLen(desc));
16045762SN/A            useTso = true;
16055762SN/A            tsoTotalLen = TxdOp::getLen(desc);
16065762SN/A            tsoLoadedHeader = false;
16075762SN/A            tsoDescBytesUsed = 0;
16085762SN/A            tsoUsedLen = 0;
16095762SN/A            tsoPrevSeq = 0;
16105762SN/A            tsoPktHasHeader = false;
16115762SN/A            tsoPkts = 0;
16128553SN/A            tsoCopyBytes = 0;
16135762SN/A        }
16144263SN/A
16154263SN/A        TxdOp::setDd(desc);
16164263SN/A        unusedCache.pop_front();
16175954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
16184263SN/A        usedCache.push_back(desc);
16195954SN/A        igbe->anQ("TXS", annUsedCacheQ);
16204263SN/A    }
16214263SN/A
16224263SN/A    if (!unusedCache.size())
16235762SN/A        return;
16245762SN/A
16255763SN/A    desc = unusedCache.front();
162611320Ssteve.reinhardt@amd.com    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) &&
16276124SN/A        TxdOp::tse(desc)) {
16286124SN/A        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
162911320Ssteve.reinhardt@amd.com                "hdrlen: %d mss: %d paylen %d\n",
16305763SN/A                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
16315763SN/A        useTso = true;
16325763SN/A        tsoTotalLen = TxdOp::getTsoLen(desc);
16335763SN/A        tsoLoadedHeader = false;
16345763SN/A        tsoDescBytesUsed = 0;
16355763SN/A        tsoUsedLen = 0;
16365763SN/A        tsoPrevSeq = 0;
16375763SN/A        tsoPktHasHeader = false;
16385763SN/A        tsoPkts = 0;
16395763SN/A    }
16405763SN/A
16415762SN/A    if (useTso && !tsoLoadedHeader) {
16425762SN/A        // we need to fetch a header
16435762SN/A        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
16445762SN/A        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
16455762SN/A        pktWaiting = true;
16465762SN/A        assert(tsoHeaderLen <= 256);
16476124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
16486124SN/A                      tsoHeaderLen, &headerEvent, tsoHeader, 0);
16495762SN/A    }
16505762SN/A}
16515762SN/A
16525762SN/Avoid
16535762SN/AIGbE::TxDescCache::headerComplete()
16545762SN/A{
16555762SN/A    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
16565762SN/A    pktWaiting = false;
16575762SN/A
16585762SN/A    assert(unusedCache.size());
16595762SN/A    TxDesc *desc = unusedCache.front();
16605762SN/A    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
16615762SN/A            TxdOp::getLen(desc), tsoHeaderLen);
16625762SN/A
16635762SN/A    if (TxdOp::getLen(desc) == tsoHeaderLen) {
16645762SN/A        tsoDescBytesUsed = 0;
16655762SN/A        tsoLoadedHeader = true;
16665762SN/A        unusedCache.pop_front();
16675762SN/A        usedCache.push_back(desc);
16685762SN/A    } else {
16699189SN/A        DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
16709189SN/A        tsoDescBytesUsed = tsoHeaderLen;
16719189SN/A        tsoLoadedHeader = true;
16725762SN/A    }
16735762SN/A    enableSm();
16745762SN/A    igbe->checkDrain();
16755762SN/A}
16765762SN/A
16776227SN/Aunsigned
16785762SN/AIGbE::TxDescCache::getPacketSize(EthPacketPtr p)
16795762SN/A{
16805762SN/A    if (!unusedCache.size())
16816227SN/A        return 0;
168211320Ssteve.reinhardt@amd.com
16835762SN/A    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
16845762SN/A
16855762SN/A    assert(!useTso || tsoLoadedHeader);
16866227SN/A    TxDesc *desc = unusedCache.front();
16875762SN/A
16885762SN/A    if (useTso) {
16896124SN/A        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
16906124SN/A                "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
16916124SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
16926124SN/A                "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
16936124SN/A                tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
16948553SN/A
169511320Ssteve.reinhardt@amd.com        if (tsoPktHasHeader)
16966124SN/A            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length,
16978553SN/A                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16985762SN/A        else
16996124SN/A            tsoCopyBytes =  std::min(tsoMss,
170011320Ssteve.reinhardt@amd.com                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
17016227SN/A        unsigned pkt_size =
170211320Ssteve.reinhardt@amd.com            tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
17038553SN/A
17048553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
17058553SN/A                "this descLen: %d\n",
17068553SN/A                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
17078553SN/A        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
17085762SN/A        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
17095762SN/A        return pkt_size;
17105762SN/A    }
17114263SN/A
17124291SN/A    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
17136124SN/A            TxdOp::getLen(unusedCache.front()));
17145762SN/A    return TxdOp::getLen(desc);
17154263SN/A}
17164263SN/A
17174263SN/Avoid
17184263SN/AIGbE::TxDescCache::getPacketData(EthPacketPtr p)
17194263SN/A{
17204263SN/A    assert(unusedCache.size());
17214263SN/A
17224263SN/A    TxDesc *desc;
17234263SN/A    desc = unusedCache.front();
17244263SN/A
17256124SN/A    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
17266124SN/A            "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
17276124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17286124SN/A           TxdOp::getLen(desc));
17294263SN/A
17304263SN/A    pktPtr = p;
17314263SN/A
17324263SN/A    pktWaiting = true;
17334263SN/A
17345404SN/A    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
173511320Ssteve.reinhardt@amd.com
17365762SN/A    if (useTso) {
17375762SN/A        assert(tsoLoadedHeader);
17385762SN/A        if (!tsoPktHasHeader) {
17396124SN/A            DPRINTF(EthernetDesc,
17406124SN/A                    "Loading TSO header (%d bytes) into start of packet\n",
17416124SN/A                    tsoHeaderLen);
17425762SN/A            memcpy(p->data, &tsoHeader,tsoHeaderLen);
17435762SN/A            p->length +=tsoHeaderLen;
17445762SN/A            tsoPktHasHeader = true;
17455762SN/A        }
17465762SN/A    }
174711320Ssteve.reinhardt@amd.com
17485762SN/A    if (useTso) {
17496124SN/A        DPRINTF(EthernetDesc,
17506124SN/A                "Starting DMA of packet at offset %d length: %d\n",
17515762SN/A                p->length, tsoCopyBytes);
17526124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc))
17536124SN/A                      + tsoDescBytesUsed,
17546124SN/A                      tsoCopyBytes, &pktEvent, p->data + p->length,
17556124SN/A                      igbe->txReadDelay);
17568553SN/A        tsoDescBytesUsed += tsoCopyBytes;
17578553SN/A        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
17585762SN/A    } else {
17596124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
17606124SN/A                      TxdOp::getLen(desc), &pktEvent, p->data + p->length,
17616124SN/A                      igbe->txReadDelay);
17625762SN/A    }
17634263SN/A}
17644263SN/A
17654263SN/Avoid
17664263SN/AIGbE::TxDescCache::pktComplete()
17674263SN/A{
17684263SN/A
17694263SN/A    TxDesc *desc;
17704263SN/A    assert(unusedCache.size());
17714263SN/A    assert(pktPtr);
17724263SN/A
17735954SN/A    igbe->anBegin("TXS", "Update Desc");
17745954SN/A
17754291SN/A    DPRINTF(EthernetDesc, "DMA of packet complete\n");
17764263SN/A
17775339SN/A
17784263SN/A    desc = unusedCache.front();
17796124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17806124SN/A           TxdOp::getLen(desc));
17814263SN/A
17826124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
17836124SN/A            desc->d1, desc->d2);
17844283SN/A
17855762SN/A    // Set the length of the data in the EtherPacket
17865762SN/A    if (useTso) {
17878553SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
17888553SN/A            "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
17898553SN/A            tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
179011701Smichael.lebeane@amd.com        pktPtr->simLength += tsoCopyBytes;
17915762SN/A        pktPtr->length += tsoCopyBytes;
17925762SN/A        tsoUsedLen += tsoCopyBytes;
17938553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
17948553SN/A            tsoDescBytesUsed, tsoCopyBytes);
179511701Smichael.lebeane@amd.com    } else {
179611701Smichael.lebeane@amd.com        pktPtr->simLength += TxdOp::getLen(desc);
17975404SN/A        pktPtr->length += TxdOp::getLen(desc);
179811701Smichael.lebeane@amd.com    }
17995762SN/A
18005762SN/A
180111320Ssteve.reinhardt@amd.com
180211320Ssteve.reinhardt@amd.com    if ((!TxdOp::eop(desc) && !useTso) ||
18036124SN/A        (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
18046124SN/A         tsoTotalLen != tsoUsedLen && useTso)) {
18055762SN/A        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
18065954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
18074283SN/A        unusedCache.pop_front();
18085954SN/A        igbe->anQ("TXS", annUsedCacheQ);
18094283SN/A        usedCache.push_back(desc);
18105762SN/A
18115762SN/A        tsoDescBytesUsed = 0;
18124283SN/A        pktDone = true;
18134283SN/A        pktWaiting = false;
18145404SN/A        pktMultiDesc = true;
18155404SN/A
18165404SN/A        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
18175404SN/A                pktPtr->length);
18184283SN/A        pktPtr = NULL;
18194283SN/A
18204438SN/A        enableSm();
18215071SN/A        igbe->checkDrain();
18224283SN/A        return;
18234283SN/A    }
18245762SN/A
18255762SN/A
18265404SN/A    pktMultiDesc = false;
18274263SN/A    // no support for vlans
18284263SN/A    assert(!TxdOp::vle(desc));
18294263SN/A
18304263SN/A    // we only support single packet descriptors at this point
18315762SN/A    if (!useTso)
18325762SN/A        assert(TxdOp::eop(desc));
18334263SN/A
18344263SN/A    // set that this packet is done
18355762SN/A    if (TxdOp::rs(desc))
18365762SN/A        TxdOp::setDd(desc);
18374263SN/A
18386124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
18396124SN/A            desc->d1, desc->d2);
18404283SN/A
18415762SN/A    if (useTso) {
18425762SN/A        IpPtr ip(pktPtr);
184312963Streapking@google.com        Ip6Ptr ip6(pktPtr);
18445762SN/A        if (ip) {
18455762SN/A            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
18465762SN/A                    tsoPkts);
18475762SN/A            ip->id(ip->id() + tsoPkts++);
184811320Ssteve.reinhardt@amd.com            ip->len(pktPtr->length - EthPtr(pktPtr)->size());
184912963Streapking@google.com        }
185012963Streapking@google.com        if (ip6)
185112963Streapking@google.com            ip6->plen(pktPtr->length - EthPtr(pktPtr)->size());
185212963Streapking@google.com        TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
185312963Streapking@google.com        if (tcp) {
185412963Streapking@google.com            DPRINTF(EthernetDesc,
185512963Streapking@google.com                    "TSO: Modifying TCP header. old seq %d + %d\n",
185612963Streapking@google.com                    tcp->seq(), tsoPrevSeq);
185712963Streapking@google.com            tcp->seq(tcp->seq() + tsoPrevSeq);
185812963Streapking@google.com            if (tsoUsedLen != tsoTotalLen)
185912963Streapking@google.com                tcp->flags(tcp->flags() & ~9); // clear fin & psh
186012963Streapking@google.com        }
186112963Streapking@google.com        UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
186212963Streapking@google.com        if (udp) {
186312963Streapking@google.com            DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
186412963Streapking@google.com            udp->len(pktPtr->length - EthPtr(pktPtr)->size());
18655762SN/A        }
18665762SN/A        tsoPrevSeq = tsoUsedLen;
18675762SN/A    }
18685762SN/A
18694452SN/A    if (DTRACE(EthernetDesc)) {
18704452SN/A        IpPtr ip(pktPtr);
18714452SN/A        if (ip)
18724452SN/A            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
18734452SN/A                    ip->id());
18744452SN/A        else
18754452SN/A            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
18764452SN/A    }
18774452SN/A
18784263SN/A    // Checksums are only ofloaded for new descriptor types
187912963Streapking@google.com    if (TxdOp::isData(desc) && (TxdOp::ixsm(desc) || TxdOp::txsm(desc))) {
18804291SN/A        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
18814263SN/A        IpPtr ip(pktPtr);
188212963Streapking@google.com        Ip6Ptr ip6(pktPtr);
188312963Streapking@google.com        assert(ip || ip6);
188412963Streapking@google.com        if (ip && TxdOp::ixsm(desc)) {
18854263SN/A            ip->sum(0);
18864263SN/A            ip->sum(cksum(ip));
18875485SN/A            igbe->txIpChecksums++;
18884291SN/A            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
18894263SN/A        }
18904987SN/A        if (TxdOp::txsm(desc)) {
189112963Streapking@google.com            TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
189212963Streapking@google.com            UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
18934987SN/A            if (tcp) {
18946124SN/A                tcp->sum(0);
18956124SN/A                tcp->sum(cksum(tcp));
18966124SN/A                igbe->txTcpChecksums++;
18976124SN/A                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
18984987SN/A            } else if (udp) {
18996124SN/A                assert(udp);
19006124SN/A                udp->sum(0);
19016124SN/A                udp->sum(cksum(udp));
19026124SN/A                igbe->txUdpChecksums++;
19036124SN/A                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
19044987SN/A            } else {
19054987SN/A                panic("Told to checksum, but don't know how\n");
19064987SN/A            }
19074263SN/A        }
19084263SN/A    }
19094263SN/A
19104263SN/A    if (TxdOp::ide(desc)) {
19114263SN/A        // Deal with the rx timer interrupts
19124291SN/A        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
19134263SN/A        if (igbe->regs.tidv.idv()) {
19146124SN/A            Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
19154291SN/A            DPRINTF(EthernetDesc, "setting tidv\n");
19167823SN/A            igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
19174263SN/A        }
19184263SN/A
19194263SN/A        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
19206124SN/A            Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
19214291SN/A            DPRINTF(EthernetDesc, "setting tadv\n");
19224987SN/A            if (!igbe->tadvEvent.scheduled()) {
19237823SN/A                igbe->schedule(igbe->tadvEvent, curTick() + delay);
19244987SN/A            }
19254263SN/A        }
19264263SN/A    }
19274263SN/A
19284283SN/A
19295762SN/A    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
19305762SN/A        DPRINTF(EthernetDesc, "Descriptor Done\n");
19315954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
19325762SN/A        unusedCache.pop_front();
19335954SN/A        igbe->anQ("TXS", annUsedCacheQ);
19345762SN/A        usedCache.push_back(desc);
19355762SN/A        tsoDescBytesUsed = 0;
19365762SN/A    }
19374283SN/A
19385762SN/A    if (useTso && tsoUsedLen == tsoTotalLen)
19395762SN/A        useTso = false;
19405762SN/A
19415762SN/A
19426124SN/A    DPRINTF(EthernetDesc,
19436124SN/A            "------Packet of %d bytes ready for transmission-------\n",
19445762SN/A            pktPtr->length);
19454263SN/A    pktDone = true;
19464263SN/A    pktWaiting = false;
19474263SN/A    pktPtr = NULL;
19485762SN/A    tsoPktHasHeader = false;
19494283SN/A
19504283SN/A    if (igbe->regs.txdctl.wthresh() == 0) {
19515954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19524291SN/A        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
19534283SN/A        writeback(0);
19548984SN/A    } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
19556124SN/A               descInBlock(usedCache.size())) {
19565763SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19575954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19585763SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19598984SN/A    } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
19604291SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19615954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19624283SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19634283SN/A    }
19645763SN/A
19654438SN/A    enableSm();
19664294SN/A    igbe->checkDrain();
19674294SN/A}
19684283SN/A
19694294SN/Avoid
197011320Ssteve.reinhardt@amd.comIGbE::TxDescCache::actionAfterWb()
19715763SN/A{
19725763SN/A    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
19735763SN/A            completionEnabled);
19745763SN/A    igbe->postInterrupt(iGbReg::IT_TXDW);
197511320Ssteve.reinhardt@amd.com    if (completionEnabled) {
19765763SN/A        descEnd = igbe->regs.tdh();
19776124SN/A        DPRINTF(EthernetDesc,
19786124SN/A                "Completion writing back value: %d to addr: %#x\n", descEnd,
19795763SN/A                completionAddress);
19806124SN/A        igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)),
19816124SN/A                       sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
19825763SN/A    }
19835763SN/A}
19845763SN/A
19855763SN/Avoid
198610905SN/AIGbE::TxDescCache::serialize(CheckpointOut &cp) const
19874294SN/A{
198810905SN/A    DescCache<TxDesc>::serialize(cp);
198910905SN/A
19904294SN/A    SERIALIZE_SCALAR(pktDone);
19914294SN/A    SERIALIZE_SCALAR(isTcp);
19924294SN/A    SERIALIZE_SCALAR(pktWaiting);
19935404SN/A    SERIALIZE_SCALAR(pktMultiDesc);
19945762SN/A
19955762SN/A    SERIALIZE_SCALAR(useTso);
19965762SN/A    SERIALIZE_SCALAR(tsoHeaderLen);
19975762SN/A    SERIALIZE_SCALAR(tsoMss);
19985762SN/A    SERIALIZE_SCALAR(tsoTotalLen);
19995762SN/A    SERIALIZE_SCALAR(tsoUsedLen);
20005762SN/A    SERIALIZE_SCALAR(tsoPrevSeq);;
20015762SN/A    SERIALIZE_SCALAR(tsoPktPayloadBytes);
20025762SN/A    SERIALIZE_SCALAR(tsoLoadedHeader);
20035762SN/A    SERIALIZE_SCALAR(tsoPktHasHeader);
20045762SN/A    SERIALIZE_ARRAY(tsoHeader, 256);
20055762SN/A    SERIALIZE_SCALAR(tsoDescBytesUsed);
20065762SN/A    SERIALIZE_SCALAR(tsoCopyBytes);
20075762SN/A    SERIALIZE_SCALAR(tsoPkts);
20085762SN/A
20095763SN/A    SERIALIZE_SCALAR(completionAddress);
20105763SN/A    SERIALIZE_SCALAR(completionEnabled);
20115763SN/A    SERIALIZE_SCALAR(descEnd);
20124294SN/A}
20134294SN/A
20144294SN/Avoid
201510905SN/AIGbE::TxDescCache::unserialize(CheckpointIn &cp)
20164294SN/A{
201710905SN/A    DescCache<TxDesc>::unserialize(cp);
201810905SN/A
20194294SN/A    UNSERIALIZE_SCALAR(pktDone);
20204294SN/A    UNSERIALIZE_SCALAR(isTcp);
20214294SN/A    UNSERIALIZE_SCALAR(pktWaiting);
20225404SN/A    UNSERIALIZE_SCALAR(pktMultiDesc);
20235762SN/A
20245762SN/A    UNSERIALIZE_SCALAR(useTso);
20255762SN/A    UNSERIALIZE_SCALAR(tsoHeaderLen);
20265762SN/A    UNSERIALIZE_SCALAR(tsoMss);
20275762SN/A    UNSERIALIZE_SCALAR(tsoTotalLen);
20285762SN/A    UNSERIALIZE_SCALAR(tsoUsedLen);
20295762SN/A    UNSERIALIZE_SCALAR(tsoPrevSeq);;
20305762SN/A    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
20315762SN/A    UNSERIALIZE_SCALAR(tsoLoadedHeader);
20325762SN/A    UNSERIALIZE_SCALAR(tsoPktHasHeader);
20335762SN/A    UNSERIALIZE_ARRAY(tsoHeader, 256);
20345762SN/A    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
20355762SN/A    UNSERIALIZE_SCALAR(tsoCopyBytes);
20365762SN/A    UNSERIALIZE_SCALAR(tsoPkts);
20375763SN/A
20385763SN/A    UNSERIALIZE_SCALAR(completionAddress);
20395763SN/A    UNSERIALIZE_SCALAR(completionEnabled);
20405763SN/A    UNSERIALIZE_SCALAR(descEnd);
20414263SN/A}
20424263SN/A
20434263SN/Abool
20444263SN/AIGbE::TxDescCache::packetAvailable()
20454263SN/A{
20464263SN/A    if (pktDone) {
20474263SN/A        pktDone = false;
20484263SN/A        return true;
20494263SN/A    }
20504263SN/A    return false;
20514263SN/A}
20524263SN/A
20534263SN/Avoid
20544263SN/AIGbE::TxDescCache::enableSm()
20554263SN/A{
205610913SN/A    if (igbe->drainState() != DrainState::Draining) {
20575071SN/A        igbe->txTick = true;
20585071SN/A        igbe->restartClock();
20595071SN/A    }
20604263SN/A}
20614263SN/A
20624294SN/Abool
20634294SN/AIGbE::TxDescCache::hasOutstandingEvents()
20644294SN/A{
20654294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
20664294SN/A        fetchEvent.scheduled();
20674294SN/A}
20684263SN/A
20694263SN/A
20704263SN/A///////////////////////////////////// IGbE /////////////////////////////////
20714263SN/A
20724263SN/Avoid
20734283SN/AIGbE::restartClock()
20744283SN/A{
20755606SN/A    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
207610913SN/A        drainState() == DrainState::Running)
20779180SN/A        schedule(tickEvent, clockEdge(Cycles(1)));
20784283SN/A}
20794283SN/A
208010913SN/ADrainState
208110913SN/AIGbE::drain()
20824294SN/A{
208310912SN/A    unsigned int count(0);
20844294SN/A    if (rxDescCache.hasOutstandingEvents() ||
20856124SN/A        txDescCache.hasOutstandingEvents()) {
20864294SN/A        count++;
20874294SN/A    }
20884294SN/A
20894294SN/A    txFifoTick = false;
20904294SN/A    txTick = false;
20914294SN/A    rxTick = false;
20924294SN/A
20934294SN/A    if (tickEvent.scheduled())
20945606SN/A        deschedule(tickEvent);
20954294SN/A
20969152SN/A    if (count) {
20979152SN/A        DPRINTF(Drain, "IGbE not drained\n");
209810913SN/A        return DrainState::Draining;
20999152SN/A    } else
210010913SN/A        return DrainState::Drained;
21014294SN/A}
21024294SN/A
21034294SN/Avoid
21049342SN/AIGbE::drainResume()
21054294SN/A{
21069342SN/A    Drainable::drainResume();
21074294SN/A
21084294SN/A    txFifoTick = true;
21094294SN/A    txTick = true;
21104294SN/A    rxTick = true;
21114294SN/A
21124294SN/A    restartClock();
21135954SN/A    DPRINTF(EthernetSM, "resuming from drain");
21144294SN/A}
21154294SN/A
21164294SN/Avoid
21174294SN/AIGbE::checkDrain()
21184294SN/A{
211910913SN/A    if (drainState() != DrainState::Draining)
21204294SN/A        return;
21214294SN/A
21224987SN/A    txFifoTick = false;
21234987SN/A    txTick = false;
21244987SN/A    rxTick = false;
21254987SN/A    if (!rxDescCache.hasOutstandingEvents() &&
21266124SN/A        !txDescCache.hasOutstandingEvents()) {
21279152SN/A        DPRINTF(Drain, "IGbE done draining, processing drain event\n");
212810913SN/A        signalDrainDone();
21294294SN/A    }
21304294SN/A}
21314283SN/A
21324283SN/Avoid
21334263SN/AIGbE::txStateMachine()
21344263SN/A{
21354263SN/A    if (!regs.tctl.en()) {
21364263SN/A        txTick = false;
21374283SN/A        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
21384263SN/A        return;
21394263SN/A    }
21404263SN/A
21414283SN/A    // If we have a packet available and it's length is not 0 (meaning it's not
21424283SN/A    // a multidescriptor packet) put it in the fifo, otherwise an the next
21434283SN/A    // iteration we'll get the rest of the data
21445404SN/A    if (txPacket && txDescCache.packetAvailable()
21456124SN/A        && !txDescCache.packetMultiDesc() && txPacket->length) {
21465954SN/A        anQ("TXS", "TX FIFO Q");
21474263SN/A        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
21488641SN/A#ifndef NDEBUG
21498641SN/A        bool success =
21508641SN/A#endif
21518641SN/A            txFifo.push(txPacket);
215210913SN/A        txFifoTick = true && drainState() != DrainState::Draining;
21534263SN/A        assert(success);
21544263SN/A        txPacket = NULL;
21555954SN/A        anBegin("TXS", "Desc Writeback");
21564291SN/A        txDescCache.writeback((cacheBlockSize()-1)>>4);
21574263SN/A        return;
21584263SN/A    }
21594263SN/A
21604263SN/A    // Only support descriptor granularity
21616124SN/A    if (regs.txdctl.lwthresh() &&
21626124SN/A        txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
21634263SN/A        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
21644263SN/A        postInterrupt(IT_TXDLOW);
21654263SN/A    }
21664263SN/A
21674263SN/A    if (!txPacket) {
216810469SN/A        txPacket = std::make_shared<EthPacketData>(16384);
21694263SN/A    }
21704263SN/A
21714263SN/A    if (!txDescCache.packetWaiting()) {
21724263SN/A        if (txDescCache.descLeft() == 0) {
21734987SN/A            postInterrupt(IT_TXQE);
21745954SN/A            anBegin("TXS", "Desc Writeback");
21754987SN/A            txDescCache.writeback(0);
21765954SN/A            anBegin("TXS", "Desc Fetch");
21775954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21785071SN/A            txDescCache.fetchDescriptors();
21794283SN/A            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
21804283SN/A                    "writeback stopping ticking and posting TXQE\n");
21814263SN/A            txTick = false;
21824291SN/A            return;
21834263SN/A        }
21844263SN/A
21854283SN/A
21864263SN/A        if (!(txDescCache.descUnused())) {
21875954SN/A            anBegin("TXS", "Desc Fetch");
21885071SN/A            txDescCache.fetchDescriptors();
21895954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21906124SN/A            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
21916124SN/A                    "fetching and stopping ticking\n");
21924263SN/A            txTick = false;
21934263SN/A            return;
21944263SN/A        }
21955954SN/A        anPq("TXS", txDescCache.annUnusedCacheQ);
21964263SN/A
21975339SN/A
21985762SN/A        txDescCache.processContextDesc();
21995762SN/A        if (txDescCache.packetWaiting()) {
22006124SN/A            DPRINTF(EthernetSM,
22016124SN/A                    "TXS: Fetching TSO header, stopping ticking\n");
22025762SN/A            txTick = false;
22035762SN/A            return;
22045762SN/A        }
22055762SN/A
22066227SN/A        unsigned size = txDescCache.getPacketSize(txPacket);
22074283SN/A        if (size > 0 && txFifo.avail() > size) {
22085954SN/A            anRq("TXS", "TX FIFO Q");
22095954SN/A            anBegin("TXS", "DMA Packet");
22106124SN/A            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
22116124SN/A                    "beginning DMA of next packet\n", size);
22124283SN/A            txFifo.reserve(size);
22134263SN/A            txDescCache.getPacketData(txPacket);
22146227SN/A        } else if (size == 0) {
22154987SN/A            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
22166124SN/A            DPRINTF(EthernetSM,
22176124SN/A                    "TXS: No packets to get, writing back used descriptors\n");
22185954SN/A            anBegin("TXS", "Desc Writeback");
22194263SN/A            txDescCache.writeback(0);
22204291SN/A        } else {
22215954SN/A            anWf("TXS", "TX FIFO Q");
22224291SN/A            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
22234291SN/A                    "available in FIFO\n");
22244291SN/A            txTick = false;
22254263SN/A        }
22264263SN/A
22274291SN/A
22284263SN/A        return;
22294263SN/A    }
22304438SN/A    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
22314438SN/A    txTick = false;
22324263SN/A}
22334263SN/A
22344263SN/Abool
22354263SN/AIGbE::ethRxPkt(EthPacketPtr pkt)
22364263SN/A{
22375485SN/A    rxBytes += pkt->length;
22385485SN/A    rxPackets++;
22395485SN/A
22404263SN/A    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
22415954SN/A    anBegin("RXQ", "Wire Recv");
22425954SN/A
22434987SN/A
22444263SN/A    if (!regs.rctl.en()) {
22454263SN/A        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
22465954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22474263SN/A        return true;
22484263SN/A    }
22494263SN/A
22504263SN/A    // restart the state machines if they are stopped
225110913SN/A    rxTick = true && drainState() != DrainState::Draining;
22524263SN/A    if ((rxTick || txTick) && !tickEvent.scheduled()) {
22536124SN/A        DPRINTF(EthernetSM,
22546124SN/A                "RXS: received packet into fifo, starting ticking\n");
22554283SN/A        restartClock();
22564263SN/A    }
22574263SN/A
22584263SN/A    if (!rxFifo.push(pkt)) {
22594263SN/A        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
22604263SN/A        postInterrupt(IT_RXO, true);
22615954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22624263SN/A        return false;
22634263SN/A    }
22645339SN/A
22655954SN/A    if (CPA::available() && cpa->enabled()) {
22665954SN/A        assert(sys->numSystemsRunning <= 2);
22675954SN/A        System *other_sys;
22685954SN/A        if (sys->systemList[0] == sys)
22695954SN/A            other_sys = sys->systemList[1];
22705954SN/A        else
22715954SN/A            other_sys = sys->systemList[0];
22725954SN/A
22735954SN/A        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22745954SN/A        anQ("RXQ", "RX FIFO Q");
22755954SN/A        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22765954SN/A    }
22775954SN/A
22784263SN/A    return true;
22794263SN/A}
22804263SN/A
22814263SN/A
22824263SN/Avoid
22834263SN/AIGbE::rxStateMachine()
22844263SN/A{
22854263SN/A    if (!regs.rctl.en()) {
22864263SN/A        rxTick = false;
22874263SN/A        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
22884263SN/A        return;
22894263SN/A    }
22904263SN/A
22914263SN/A    // If the packet is done check for interrupts/descriptors/etc
22924263SN/A    if (rxDescCache.packetDone()) {
22934452SN/A        rxDmaPacket = false;
22944263SN/A        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
22954263SN/A        int descLeft = rxDescCache.descLeft();
22965783SN/A        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
22975783SN/A                descLeft, regs.rctl.rdmts(), regs.rdlen());
229812392Sjason@lowepower.com
229912392Sjason@lowepower.com        // rdmts 2->1/8, 1->1/4, 0->1/2
230012392Sjason@lowepower.com        int ratio = (1ULL << (regs.rctl.rdmts() + 1));
230112392Sjason@lowepower.com        if (descLeft * ratio <= regs.rdlen()) {
23026124SN/A            DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
23036124SN/A                    "because of descriptors left\n");
23046124SN/A            postInterrupt(IT_RXDMT);
23054263SN/A        }
23064263SN/A
23075783SN/A        if (rxFifo.empty())
23085783SN/A            rxDescCache.writeback(0);
23095783SN/A
23104263SN/A        if (descLeft == 0) {
23115954SN/A            anBegin("RXS", "Writeback Descriptors");
23124263SN/A            rxDescCache.writeback(0);
23135339SN/A            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
23145339SN/A                    " writeback and stopping ticking\n");
23154263SN/A            rxTick = false;
23164263SN/A        }
23174263SN/A
23184263SN/A        // only support descriptor granulaties
23194263SN/A        assert(regs.rxdctl.gran());
23204263SN/A
23214263SN/A        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
23226124SN/A            DPRINTF(EthernetSM,
23236124SN/A                    "RXS: Writing back because WTHRESH >= descUsed\n");
23245954SN/A            anBegin("RXS", "Writeback Descriptors");
23254283SN/A            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
23264283SN/A                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
23274283SN/A            else
23284283SN/A                rxDescCache.writeback((cacheBlockSize()-1)>>4);
23294263SN/A        }
23304263SN/A
23314263SN/A        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
23326124SN/A            ((rxDescCache.descLeft() - rxDescCache.descUnused()) >
23336124SN/A             regs.rxdctl.hthresh())) {
23346124SN/A            DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
23356124SN/A                    "descUnused < PTHRESH\n");
23365954SN/A            anBegin("RXS", "Fetch Descriptors");
23374263SN/A            rxDescCache.fetchDescriptors();
23384263SN/A        }
23394263SN/A
23404263SN/A        if (rxDescCache.descUnused() == 0) {
23415954SN/A            anBegin("RXS", "Fetch Descriptors");
23425071SN/A            rxDescCache.fetchDescriptors();
23435954SN/A            anWe("RXS", rxDescCache.annUnusedCacheQ);
23444291SN/A            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23454291SN/A                    "fetching descriptors and stopping ticking\n");
23464263SN/A            rxTick = false;
23474263SN/A        }
23484263SN/A        return;
23494263SN/A    }
23504263SN/A
23514452SN/A    if (rxDmaPacket) {
23526124SN/A        DPRINTF(EthernetSM,
23536124SN/A                "RXS: stopping ticking until packet DMA completes\n");
23544452SN/A        rxTick = false;
23554452SN/A        return;
23564452SN/A    }
23574452SN/A
23584263SN/A    if (!rxDescCache.descUnused()) {
23595954SN/A        anBegin("RXS", "Fetch Descriptors");
23605071SN/A        rxDescCache.fetchDescriptors();
23615954SN/A        anWe("RXS", rxDescCache.annUnusedCacheQ);
23626124SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23636124SN/A                "stopping ticking\n");
23644263SN/A        rxTick = false;
23654263SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
23664263SN/A        return;
23674263SN/A    }
23685954SN/A    anPq("RXS", rxDescCache.annUnusedCacheQ);
23694263SN/A
23704263SN/A    if (rxFifo.empty()) {
23715954SN/A        anWe("RXS", "RX FIFO Q");
23724263SN/A        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
23734263SN/A        rxTick = false;
23744263SN/A        return;
23754263SN/A    }
23765954SN/A    anPq("RXS", "RX FIFO Q");
23775954SN/A    anBegin("RXS", "Get Desc");
23784263SN/A
23794263SN/A    EthPacketPtr pkt;
23804263SN/A    pkt = rxFifo.front();
23814263SN/A
23825339SN/A
23835783SN/A    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
23844263SN/A    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
23855783SN/A    if (pktOffset == pkt->length) {
23865954SN/A        anBegin( "RXS", "FIFO Dequeue");
23875783SN/A        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
23885783SN/A        pktOffset = 0;
23895954SN/A        anDq("RXS", "RX FIFO Q");
23905783SN/A        rxFifo.pop();
23915783SN/A    }
23925783SN/A
23935339SN/A    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
23945339SN/A    rxTick = false;
23955339SN/A    rxDmaPacket = true;
23965954SN/A    anBegin("RXS", "DMA Packet");
23974263SN/A}
23984263SN/A
23994263SN/Avoid
24004263SN/AIGbE::txWire()
24014263SN/A{
240212064Sgabeblack@google.com    txFifoTick = false;
240312064Sgabeblack@google.com
24044263SN/A    if (txFifo.empty()) {
24055954SN/A        anWe("TXQ", "TX FIFO Q");
24064263SN/A        return;
24074263SN/A    }
24084263SN/A
24095339SN/A
24105954SN/A    anPq("TXQ", "TX FIFO Q");
24115339SN/A    if (etherInt->sendPacket(txFifo.front())) {
241210702SN/A        anQ("TXQ", "WireQ");
24134987SN/A        if (DTRACE(EthernetSM)) {
24144987SN/A            IpPtr ip(txFifo.front());
24154987SN/A            if (ip)
24164987SN/A                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
24174987SN/A                        ip->id());
24184987SN/A            else
24194987SN/A                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
24204987SN/A        }
24215954SN/A        anDq("TXQ", "TX FIFO Q");
24225954SN/A        anBegin("TXQ", "Wire Send");
24236124SN/A        DPRINTF(EthernetSM,
24246124SN/A                "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
24254263SN/A                txFifo.avail());
24265485SN/A
24275485SN/A        txBytes += txFifo.front()->length;
24285485SN/A        txPackets++;
24295485SN/A
24304263SN/A        txFifo.pop();
24314263SN/A    }
24324263SN/A}
24334263SN/A
24344263SN/Avoid
24354263SN/AIGbE::tick()
24364263SN/A{
24374283SN/A    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
24384263SN/A
243912064Sgabeblack@google.com    inTick = true;
244012064Sgabeblack@google.com
24414263SN/A    if (rxTick)
24424263SN/A        rxStateMachine();
24434263SN/A
24444291SN/A    if (txTick)
24454263SN/A        txStateMachine();
24464291SN/A
244712064Sgabeblack@google.com    // If txWire returns and txFifoTick is still set, that means the data we
244812064Sgabeblack@google.com    // sent to the other end was already accepted and we can send another
244912064Sgabeblack@google.com    // frame right away. This is consistent with the previous behavior which
245012064Sgabeblack@google.com    // would send another frame if one was ready in ethTxDone. This version
245112064Sgabeblack@google.com    // avoids growing the stack with each frame sent which can cause stack
245212064Sgabeblack@google.com    // overflow.
245312064Sgabeblack@google.com    while (txFifoTick)
24544263SN/A        txWire();
24554263SN/A
24564291SN/A    if (rxTick || txTick || txFifoTick)
24579179SN/A        schedule(tickEvent, curTick() + clockPeriod());
245812064Sgabeblack@google.com
245912064Sgabeblack@google.com    inTick = false;
24604263SN/A}
24613116SN/A
24623116SN/Avoid
24633116SN/AIGbE::ethTxDone()
24643116SN/A{
24655954SN/A    anBegin("TXQ", "Send Done");
24664291SN/A    // restart the tx state machines if they are stopped
24674291SN/A    // fifo to send another packet
24684291SN/A    // tx sm to put more data into the fifo
246910913SN/A    txFifoTick = true && drainState() != DrainState::Draining;
247010913SN/A    if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
24714987SN/A        txTick = true;
24724291SN/A
247312064Sgabeblack@google.com    if (!inTick)
247412064Sgabeblack@google.com        restartClock();
24754294SN/A    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
24763116SN/A}
24773116SN/A
24783116SN/Avoid
247910905SN/AIGbE::serialize(CheckpointOut &cp) const
24803116SN/A{
248110905SN/A    PciDevice::serialize(cp);
24824294SN/A
248310905SN/A    regs.serialize(cp);
24844294SN/A    SERIALIZE_SCALAR(eeOpBits);
24854294SN/A    SERIALIZE_SCALAR(eeAddrBits);
24864294SN/A    SERIALIZE_SCALAR(eeDataBits);
24874294SN/A    SERIALIZE_SCALAR(eeOpcode);
24884294SN/A    SERIALIZE_SCALAR(eeAddr);
24895500SN/A    SERIALIZE_SCALAR(lastInterrupt);
24904294SN/A    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
24914294SN/A
249210905SN/A    rxFifo.serialize("rxfifo", cp);
249310905SN/A    txFifo.serialize("txfifo", cp);
24944294SN/A
249510469SN/A    bool txPktExists = txPacket != nullptr;
24964294SN/A    SERIALIZE_SCALAR(txPktExists);
24974294SN/A    if (txPktExists)
249810905SN/A        txPacket->serialize("txpacket", cp);
24994294SN/A
25004294SN/A    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
25016124SN/A        inter_time = 0;
25024294SN/A
25034294SN/A    if (rdtrEvent.scheduled())
25046124SN/A        rdtr_time = rdtrEvent.when();
25054294SN/A    SERIALIZE_SCALAR(rdtr_time);
25064294SN/A
25074294SN/A    if (radvEvent.scheduled())
25086124SN/A        radv_time = radvEvent.when();
25094294SN/A    SERIALIZE_SCALAR(radv_time);
25104294SN/A
25114294SN/A    if (tidvEvent.scheduled())
25126124SN/A        tidv_time = tidvEvent.when();
25134294SN/A    SERIALIZE_SCALAR(tidv_time);
25144294SN/A
25154294SN/A    if (tadvEvent.scheduled())
25166124SN/A        tadv_time = tadvEvent.when();
25174294SN/A    SERIALIZE_SCALAR(tadv_time);
25184294SN/A
25194294SN/A    if (interEvent.scheduled())
25206124SN/A        inter_time = interEvent.when();
25214294SN/A    SERIALIZE_SCALAR(inter_time);
25224294SN/A
25235783SN/A    SERIALIZE_SCALAR(pktOffset);
25245783SN/A
252510905SN/A    txDescCache.serializeSection(cp, "TxDescCache");
252610905SN/A    rxDescCache.serializeSection(cp, "RxDescCache");
25273116SN/A}
25283116SN/A
25293116SN/Avoid
253010905SN/AIGbE::unserialize(CheckpointIn &cp)
25313116SN/A{
253210905SN/A    PciDevice::unserialize(cp);
25334294SN/A
253410905SN/A    regs.unserialize(cp);
25354294SN/A    UNSERIALIZE_SCALAR(eeOpBits);
25364294SN/A    UNSERIALIZE_SCALAR(eeAddrBits);
25374294SN/A    UNSERIALIZE_SCALAR(eeDataBits);
25384294SN/A    UNSERIALIZE_SCALAR(eeOpcode);
25394294SN/A    UNSERIALIZE_SCALAR(eeAddr);
25405500SN/A    UNSERIALIZE_SCALAR(lastInterrupt);
25414294SN/A    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
25424294SN/A
254310905SN/A    rxFifo.unserialize("rxfifo", cp);
254410905SN/A    txFifo.unserialize("txfifo", cp);
25454294SN/A
25464294SN/A    bool txPktExists;
25474294SN/A    UNSERIALIZE_SCALAR(txPktExists);
25484294SN/A    if (txPktExists) {
254911719Smichael.lebeane@amd.com        txPacket = std::make_shared<EthPacketData>(16384);
255010905SN/A        txPacket->unserialize("txpacket", cp);
25514294SN/A    }
25524294SN/A
25534294SN/A    rxTick = true;
25544294SN/A    txTick = true;
25554294SN/A    txFifoTick = true;
25564294SN/A
25574294SN/A    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
25584294SN/A    UNSERIALIZE_SCALAR(rdtr_time);
25594294SN/A    UNSERIALIZE_SCALAR(radv_time);
25604294SN/A    UNSERIALIZE_SCALAR(tidv_time);
25614294SN/A    UNSERIALIZE_SCALAR(tadv_time);
25624294SN/A    UNSERIALIZE_SCALAR(inter_time);
25634294SN/A
25644294SN/A    if (rdtr_time)
25655606SN/A        schedule(rdtrEvent, rdtr_time);
25664294SN/A
25674294SN/A    if (radv_time)
25685606SN/A        schedule(radvEvent, radv_time);
25694294SN/A
25704294SN/A    if (tidv_time)
25715606SN/A        schedule(tidvEvent, tidv_time);
25724294SN/A
25734294SN/A    if (tadv_time)
25745606SN/A        schedule(tadvEvent, tadv_time);
25754294SN/A
25764294SN/A    if (inter_time)
25775606SN/A        schedule(interEvent, inter_time);
25784294SN/A
25795783SN/A    UNSERIALIZE_SCALAR(pktOffset);
25805783SN/A
258110905SN/A    txDescCache.unserializeSection(cp, "TxDescCache");
258210905SN/A    rxDescCache.unserializeSection(cp, "RxDescCache");
25833116SN/A}
25843116SN/A
25854762SN/AIGbE *
25864762SN/AIGbEParams::create()
25873116SN/A{
25884762SN/A    return new IGbE(this);
25893116SN/A}
2590