i8254xGBe.cc revision 11810
13116SN/A/*
23116SN/A * Copyright (c) 2006 The Regents of The University of Michigan
33116SN/A * All rights reserved.
43116SN/A *
53116SN/A * Redistribution and use in source and binary forms, with or without
63116SN/A * modification, are permitted provided that the following conditions are
73116SN/A * met: redistributions of source code must retain the above copyright
83116SN/A * notice, this list of conditions and the following disclaimer;
93116SN/A * redistributions in binary form must reproduce the above copyright
103116SN/A * notice, this list of conditions and the following disclaimer in the
113116SN/A * documentation and/or other materials provided with the distribution;
123116SN/A * neither the name of the copyright holders nor the names of its
133116SN/A * contributors may be used to endorse or promote products derived from
143116SN/A * this software without specific prior written permission.
153116SN/A *
163116SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173116SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183116SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193116SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203116SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213116SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223116SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233116SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243116SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253116SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263116SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273116SN/A *
283116SN/A * Authors: Ali Saidi
293116SN/A */
303116SN/A
313116SN/A/* @file
323116SN/A * Device model for Intel's 8254x line of gigabit ethernet controllers.
333318SN/A * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
343318SN/A * fewest workarounds in the driver. It will probably work with most of the
353318SN/A * other MACs with slight modifications.
363116SN/A */
373116SN/A
3811263Sandreas.sandberg@arm.com#include "dev/net/i8254xGBe.hh"
394263SN/A
404263SN/A/*
414263SN/A * @todo really there are multiple dma engines.. we should implement them.
424263SN/A */
434263SN/A
444762SN/A#include <algorithm>
4510469SN/A#include <memory>
464762SN/A
473116SN/A#include "base/inet.hh"
484263SN/A#include "base/trace.hh"
499152SN/A#include "debug/Drain.hh"
508232SN/A#include "debug/EthernetAll.hh"
513116SN/A#include "mem/packet.hh"
523405SN/A#include "mem/packet_access.hh"
534762SN/A#include "params/IGbE.hh"
543116SN/A#include "sim/stats.hh"
553116SN/A#include "sim/system.hh"
563116SN/A
573318SN/Ausing namespace iGbReg;
584263SN/Ausing namespace Net;
593318SN/A
604981SN/AIGbE::IGbE(const Params *p)
6110913SN/A    : EtherDevice(p), etherInt(NULL), cpa(NULL),
624263SN/A      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
635783SN/A      txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
6411320Ssteve.reinhardt@amd.com      fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
6511320Ssteve.reinhardt@amd.com      fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
6611320Ssteve.reinhardt@amd.com      rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
675535SN/A      rdtrEvent(this), radvEvent(this),
684291SN/A      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
694283SN/A      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
705500SN/A      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
719157SN/A      lastInterrupt(0)
723116SN/A{
734981SN/A    etherInt = new IGbEInt(name() + ".int", this);
744981SN/A
753318SN/A    // Initialized internal registers per Intel documentation
764263SN/A    // All registers intialized to 0 by per register constructor
774218SN/A    regs.ctrl.fd(1);
784218SN/A    regs.ctrl.lrst(1);
794218SN/A    regs.ctrl.speed(2);
804218SN/A    regs.ctrl.frcspd(1);
814218SN/A    regs.sts.speed(3); // Say we're 1000Mbps
824218SN/A    regs.sts.fd(1); // full duplex
834283SN/A    regs.sts.lu(1); // link up
844218SN/A    regs.eecd.fwe(1);
854218SN/A    regs.eecd.ee_type(1);
864263SN/A    regs.imr = 0;
874263SN/A    regs.iam = 0;
884263SN/A    regs.rxdctl.gran(1);
894263SN/A    regs.rxdctl.wthresh(1);
904218SN/A    regs.fcrth(1);
915763SN/A    regs.tdwba = 0;
925763SN/A    regs.rlpml = 0;
935763SN/A    regs.sw_fw_sync = 0;
943116SN/A
954218SN/A    regs.pba.rxa(0x30);
964218SN/A    regs.pba.txa(0x10);
973405SN/A
983318SN/A    eeOpBits            = 0;
993318SN/A    eeAddrBits          = 0;
1003318SN/A    eeDataBits          = 0;
1013318SN/A    eeOpcode            = 0;
1023318SN/A
1033405SN/A    // clear all 64 16 bit words of the eeprom
1043405SN/A    memset(&flash, 0, EEPROM_SIZE*2);
1053405SN/A
1064283SN/A    // Set the MAC address
1074283SN/A    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
1084283SN/A    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
1094283SN/A        flash[x] = htobe(flash[x]);
1104218SN/A
1114218SN/A    uint16_t csum = 0;
1124218SN/A    for (int x = 0; x < EEPROM_SIZE; x++)
1134283SN/A        csum += htobe(flash[x]);
1144283SN/A
1154218SN/A
1163318SN/A    // Magic happy checksum value
1174218SN/A    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
1184263SN/A
1195954SN/A    // Store the MAC address as queue ID
1205954SN/A    macAddr = p->hardware_address;
1215954SN/A
1224263SN/A    rxFifo.clear();
1234263SN/A    txFifo.clear();
1243116SN/A}
1253116SN/A
1269086SN/AIGbE::~IGbE()
1279086SN/A{
1289086SN/A    delete etherInt;
1299086SN/A}
1309086SN/A
1315954SN/Avoid
1325954SN/AIGbE::init()
1335954SN/A{
1345954SN/A    cpa = CPA::cpa();
1359807SN/A    PciDevice::init();
1365954SN/A}
1375954SN/A
1384981SN/AEtherInt*
1394981SN/AIGbE::getEthPort(const std::string &if_name, int idx)
1404981SN/A{
1414981SN/A
1424987SN/A    if (if_name == "interface") {
1434981SN/A        if (etherInt->getPeer())
1444981SN/A            panic("Port already connected to\n");
1454981SN/A        return etherInt;
1464981SN/A    }
1474981SN/A    return NULL;
1484981SN/A}
1493116SN/A
1503116SN/ATick
1513349SN/AIGbE::writeConfig(PacketPtr pkt)
1523116SN/A{
1533116SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1543116SN/A    if (offset < PCI_DEVICE_SPECIFIC)
1559807SN/A        PciDevice::writeConfig(pkt);
1563116SN/A    else
1573116SN/A        panic("Device specific PCI config space not implemented.\n");
1583116SN/A
1596124SN/A    //
1606124SN/A    // Some work may need to be done here based for the pci COMMAND bits.
1616124SN/A    //
1623116SN/A
1639198SN/A    return configDelay;
1643116SN/A}
1653116SN/A
1666124SN/A// Handy macro for range-testing register access addresses
1676124SN/A#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
1686124SN/A
1693116SN/ATick
1703349SN/AIGbE::read(PacketPtr pkt)
1713116SN/A{
1723116SN/A    int bar;
1733116SN/A    Addr daddr;
1743116SN/A
1753116SN/A    if (!getBAR(pkt->getAddr(), bar, daddr))
1763116SN/A        panic("Invalid PCI memory access to unmapped memory.\n");
1773116SN/A
1783116SN/A    // Only Memory register BAR is allowed
1793116SN/A    assert(bar == 0);
1803116SN/A
1813318SN/A    // Only 32bit accesses allowed
1823318SN/A    assert(pkt->getSize() == 4);
1833318SN/A
1844283SN/A    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
1853116SN/A
1866124SN/A    //
1876124SN/A    // Handle read of register here
1886124SN/A    //
1893116SN/A
1903405SN/A
1913318SN/A    switch (daddr) {
1924218SN/A      case REG_CTRL:
1934218SN/A        pkt->set<uint32_t>(regs.ctrl());
1944218SN/A        break;
1954218SN/A      case REG_STATUS:
1964218SN/A        pkt->set<uint32_t>(regs.sts());
1974218SN/A        break;
1984218SN/A      case REG_EECD:
1994218SN/A        pkt->set<uint32_t>(regs.eecd());
2004218SN/A        break;
2014218SN/A      case REG_EERD:
2024218SN/A        pkt->set<uint32_t>(regs.eerd());
2034218SN/A        break;
2044218SN/A      case REG_CTRL_EXT:
2054218SN/A        pkt->set<uint32_t>(regs.ctrl_ext());
2064218SN/A        break;
2074218SN/A      case REG_MDIC:
2084218SN/A        pkt->set<uint32_t>(regs.mdic());
2094218SN/A        break;
2104218SN/A      case REG_ICR:
2116124SN/A        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
2126124SN/A                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
2134218SN/A        pkt->set<uint32_t>(regs.icr());
2144283SN/A        if (regs.icr.int_assert() || regs.imr == 0) {
2154283SN/A            regs.icr = regs.icr() & ~mask(30);
2164283SN/A            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
2174263SN/A        }
2184283SN/A        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
2194283SN/A            regs.imr &= ~regs.iam;
2204283SN/A        chkInterrupt();
2214218SN/A        break;
2225763SN/A      case REG_EICR:
2235763SN/A        // This is only useful for MSI, but the driver reads it every time
2245763SN/A        // Just don't do anything
2255763SN/A        pkt->set<uint32_t>(0);
2265763SN/A        break;
2274218SN/A      case REG_ITR:
2284218SN/A        pkt->set<uint32_t>(regs.itr());
2294218SN/A        break;
2304218SN/A      case REG_RCTL:
2314218SN/A        pkt->set<uint32_t>(regs.rctl());
2324218SN/A        break;
2334218SN/A      case REG_FCTTV:
2344218SN/A        pkt->set<uint32_t>(regs.fcttv());
2354218SN/A        break;
2364218SN/A      case REG_TCTL:
2374218SN/A        pkt->set<uint32_t>(regs.tctl());
2384218SN/A        break;
2394218SN/A      case REG_PBA:
2404218SN/A        pkt->set<uint32_t>(regs.pba());
2414218SN/A        break;
2424218SN/A      case REG_WUC:
24311810Sbaz21@cam.ac.uk      case REG_WUFC:
24411810Sbaz21@cam.ac.uk      case REG_WUS:
2454218SN/A      case REG_LEDCTL:
2464218SN/A        pkt->set<uint32_t>(0); // We don't care, so just return 0
2474218SN/A        break;
2484218SN/A      case REG_FCRTL:
2494218SN/A        pkt->set<uint32_t>(regs.fcrtl());
2504218SN/A        break;
2514218SN/A      case REG_FCRTH:
2524218SN/A        pkt->set<uint32_t>(regs.fcrth());
2534218SN/A        break;
2544218SN/A      case REG_RDBAL:
2554218SN/A        pkt->set<uint32_t>(regs.rdba.rdbal());
2564218SN/A        break;
2574218SN/A      case REG_RDBAH:
2584218SN/A        pkt->set<uint32_t>(regs.rdba.rdbah());
2594218SN/A        break;
2604218SN/A      case REG_RDLEN:
2614218SN/A        pkt->set<uint32_t>(regs.rdlen());
2624218SN/A        break;
2635763SN/A      case REG_SRRCTL:
2645763SN/A        pkt->set<uint32_t>(regs.srrctl());
2655763SN/A        break;
2664218SN/A      case REG_RDH:
2674218SN/A        pkt->set<uint32_t>(regs.rdh());
2684218SN/A        break;
2694218SN/A      case REG_RDT:
2704218SN/A        pkt->set<uint32_t>(regs.rdt());
2714218SN/A        break;
2724218SN/A      case REG_RDTR:
2734218SN/A        pkt->set<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:
2835763SN/A        pkt->set<uint32_t>(regs.rxdctl());
2845763SN/A        break;
2854218SN/A      case REG_RADV:
2864218SN/A        pkt->set<uint32_t>(regs.radv());
2874218SN/A        break;
2884218SN/A      case REG_TDBAL:
2894218SN/A        pkt->set<uint32_t>(regs.tdba.tdbal());
2904218SN/A        break;
2914218SN/A      case REG_TDBAH:
2924218SN/A        pkt->set<uint32_t>(regs.tdba.tdbah());
2934218SN/A        break;
2944218SN/A      case REG_TDLEN:
2954218SN/A        pkt->set<uint32_t>(regs.tdlen());
2964218SN/A        break;
2974218SN/A      case REG_TDH:
2984218SN/A        pkt->set<uint32_t>(regs.tdh());
2994218SN/A        break;
3005763SN/A      case REG_TXDCA_CTL:
3015763SN/A        pkt->set<uint32_t>(regs.txdca_ctl());
3025763SN/A        break;
3034218SN/A      case REG_TDT:
3044218SN/A        pkt->set<uint32_t>(regs.tdt());
3054218SN/A        break;
3064218SN/A      case REG_TIDV:
3074218SN/A        pkt->set<uint32_t>(regs.tidv());
3084218SN/A        break;
3094218SN/A      case REG_TXDCTL:
3104218SN/A        pkt->set<uint32_t>(regs.txdctl());
3114218SN/A        break;
3124218SN/A      case REG_TADV:
3134218SN/A        pkt->set<uint32_t>(regs.tadv());
3144218SN/A        break;
3155763SN/A      case REG_TDWBAL:
3165763SN/A        pkt->set<uint32_t>(regs.tdwba & mask(32));
3175763SN/A        break;
3185763SN/A      case REG_TDWBAH:
3195763SN/A        pkt->set<uint32_t>(regs.tdwba >> 32);
3205763SN/A        break;
3214218SN/A      case REG_RXCSUM:
3224218SN/A        pkt->set<uint32_t>(regs.rxcsum());
3234218SN/A        break;
3245763SN/A      case REG_RLPML:
3255763SN/A        pkt->set<uint32_t>(regs.rlpml);
3265763SN/A        break;
3275763SN/A      case REG_RFCTL:
3285763SN/A        pkt->set<uint32_t>(regs.rfctl());
3295763SN/A        break;
3304218SN/A      case REG_MANC:
3314218SN/A        pkt->set<uint32_t>(regs.manc());
3324218SN/A        break;
3335763SN/A      case REG_SWSM:
3345763SN/A        pkt->set<uint32_t>(regs.swsm());
3355763SN/A        regs.swsm.smbi(1);
3365763SN/A        break;
3375763SN/A      case REG_FWSM:
3385763SN/A        pkt->set<uint32_t>(regs.fwsm());
3395763SN/A        break;
3405763SN/A      case REG_SWFWSYNC:
3415763SN/A        pkt->set<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
3504218SN/A            pkt->set<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",
3746124SN/A            daddr, pkt->get<uint32_t>());
3753116SN/A
3766124SN/A    //
3776124SN/A    // Handle write of register here
3786124SN/A    //
3793318SN/A    uint32_t val = pkt->get<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),
82810420SN/A      wbDelayEvent(this), fetchDelayEvent(this), fetchEvent(this),
82910420SN/A      wbEvent(this)
8306124SN/A{
8316124SN/A    fetchBuf = new T[size];
8326124SN/A    wbBuf = new T[size];
8336124SN/A}
8346124SN/A
8356124SN/Atemplate<class T>
8366124SN/AIGbE::DescCache<T>::~DescCache()
8376124SN/A{
8386124SN/A    reset();
8399086SN/A    delete[] fetchBuf;
8409086SN/A    delete[] wbBuf;
8416124SN/A}
8426124SN/A
8436124SN/Atemplate<class T>
8446124SN/Avoid
8456124SN/AIGbE::DescCache<T>::areaChanged()
8466124SN/A{
8476124SN/A    if (usedCache.size() > 0 || curFetching || wbOut)
8486124SN/A        panic("Descriptor Address, Length or Head changed. Bad\n");
8496124SN/A    reset();
8506124SN/A
8514263SN/A}
8524263SN/A
8536124SN/Atemplate<class T>
8546124SN/Avoid
8556124SN/AIGbE::DescCache<T>::writeback(Addr aMask)
8566124SN/A{
8576124SN/A    int curHead = descHead();
8586124SN/A    int max_to_wb = usedCache.size();
8596124SN/A
8606124SN/A    // Check if this writeback is less restrictive that the previous
8616124SN/A    // and if so setup another one immediately following it
8626124SN/A    if (wbOut) {
8636124SN/A        if (aMask < wbAlignment) {
8646124SN/A            moreToWb = true;
8656124SN/A            wbAlignment = aMask;
8666124SN/A        }
8676124SN/A        DPRINTF(EthernetDesc,
8686124SN/A                "Writing back already in process, returning\n");
8696124SN/A        return;
8706124SN/A    }
8716124SN/A
8726124SN/A    moreToWb = false;
8736124SN/A    wbAlignment = aMask;
87411320Ssteve.reinhardt@amd.com
8756124SN/A
8766124SN/A    DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
8776124SN/A            "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
8786124SN/A            curHead, descTail(), descLen(), cachePnt, max_to_wb,
8796124SN/A            descLeft());
8806124SN/A
8816124SN/A    if (max_to_wb + curHead >= descLen()) {
8826124SN/A        max_to_wb = descLen() - curHead;
8836124SN/A        moreToWb = true;
8846124SN/A        // this is by definition aligned correctly
8856124SN/A    } else if (wbAlignment != 0) {
8866124SN/A        // align the wb point to the mask
8876124SN/A        max_to_wb = max_to_wb & ~wbAlignment;
8886124SN/A    }
8896124SN/A
8906124SN/A    DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
8916124SN/A
8926124SN/A    if (max_to_wb <= 0) {
8936124SN/A        if (usedCache.size())
8946124SN/A            igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
8956124SN/A        else
8966124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
8976124SN/A        return;
8986124SN/A    }
8996124SN/A
9006124SN/A    wbOut = max_to_wb;
9016124SN/A
90211320Ssteve.reinhardt@amd.com    assert(!wbDelayEvent.scheduled());
9037823SN/A    igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9046124SN/A    igbe->anBegin(annSmWb, "Prepare Writeback Desc");
9056124SN/A}
90611320Ssteve.reinhardt@amd.com
9076124SN/Atemplate<class T>
9086124SN/Avoid
9096124SN/AIGbE::DescCache<T>::writeback1()
9106124SN/A{
9116124SN/A    // If we're draining delay issuing this DMA
91210913SN/A    if (igbe->drainState() != DrainState::Running) {
9137823SN/A        igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
9146124SN/A        return;
9156124SN/A    }
9166124SN/A
9176124SN/A    DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
91811320Ssteve.reinhardt@amd.com
9196124SN/A    for (int x = 0; x < wbOut; x++) {
9206124SN/A        assert(usedCache.size());
9216124SN/A        memcpy(&wbBuf[x], usedCache[x], sizeof(T));
9226124SN/A        igbe->anPq(annSmWb, annUsedCacheQ);
9236124SN/A        igbe->anPq(annSmWb, annDescQ);
9246124SN/A        igbe->anQ(annSmWb, annUsedDescQ);
9256124SN/A    }
9266124SN/A
92711320Ssteve.reinhardt@amd.com
9286124SN/A    igbe->anBegin(annSmWb, "Writeback Desc DMA");
9296124SN/A
9306124SN/A    assert(wbOut);
9316124SN/A    igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
9326124SN/A                   wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
9336124SN/A                   igbe->wbCompDelay);
9346124SN/A}
9356124SN/A
9366124SN/Atemplate<class T>
9376124SN/Avoid
9386124SN/AIGbE::DescCache<T>::fetchDescriptors()
9396124SN/A{
9406124SN/A    size_t max_to_fetch;
9416124SN/A
9426124SN/A    if (curFetching) {
9436124SN/A        DPRINTF(EthernetDesc,
9446124SN/A                "Currently fetching %d descriptors, returning\n",
9456124SN/A                curFetching);
9466124SN/A        return;
9476124SN/A    }
9486124SN/A
9496124SN/A    if (descTail() >= cachePnt)
9506124SN/A        max_to_fetch = descTail() - cachePnt;
9516124SN/A    else
9526124SN/A        max_to_fetch = descLen() - cachePnt;
9536124SN/A
9546124SN/A    size_t free_cache = size - usedCache.size() - unusedCache.size();
9556124SN/A
9566124SN/A    if (!max_to_fetch)
9576124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
9586124SN/A    else
9596124SN/A        igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
9606124SN/A
9616124SN/A    if (max_to_fetch) {
9626124SN/A        if (!free_cache)
9636124SN/A            igbe->anWf(annSmFetch, annDescQ);
9646124SN/A        else
9656124SN/A            igbe->anRq(annSmFetch, annDescQ, free_cache);
9666124SN/A    }
9676124SN/A
9686124SN/A    max_to_fetch = std::min(max_to_fetch, free_cache);
96911320Ssteve.reinhardt@amd.com
9706124SN/A
9716124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
9726124SN/A            "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
9736124SN/A            descHead(), descTail(), descLen(), cachePnt,
9746124SN/A            max_to_fetch, descLeft());
9756124SN/A
9766124SN/A    // Nothing to do
9776124SN/A    if (max_to_fetch == 0)
9786124SN/A        return;
97911320Ssteve.reinhardt@amd.com
9806124SN/A    // So we don't have two descriptor fetches going on at once
9816124SN/A    curFetching = max_to_fetch;
9826124SN/A
9836124SN/A    assert(!fetchDelayEvent.scheduled());
9847823SN/A    igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9856124SN/A    igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
9866124SN/A}
9876124SN/A
9886124SN/Atemplate<class T>
9896124SN/Avoid
9906124SN/AIGbE::DescCache<T>::fetchDescriptors1()
9916124SN/A{
9926124SN/A    // If we're draining delay issuing this DMA
99310913SN/A    if (igbe->drainState() != DrainState::Running) {
9947823SN/A        igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
9956124SN/A        return;
9966124SN/A    }
9976124SN/A
9986124SN/A    igbe->anBegin(annSmFetch, "Fetch Desc");
9996124SN/A
10006124SN/A    DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
10016124SN/A            descBase() + cachePnt * sizeof(T),
10026124SN/A            pciToDma(descBase() + cachePnt * sizeof(T)),
10036124SN/A            curFetching * sizeof(T));
10046124SN/A    assert(curFetching);
10056124SN/A    igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
10066124SN/A                  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
10076124SN/A                  igbe->fetchCompDelay);
10086124SN/A}
10096124SN/A
10106124SN/Atemplate<class T>
10116124SN/Avoid
10126124SN/AIGbE::DescCache<T>::fetchComplete()
10136124SN/A{
10146124SN/A    T *newDesc;
10156124SN/A    igbe->anBegin(annSmFetch, "Fetch Complete");
10166124SN/A    for (int x = 0; x < curFetching; x++) {
10176124SN/A        newDesc = new T;
10186124SN/A        memcpy(newDesc, &fetchBuf[x], sizeof(T));
10196124SN/A        unusedCache.push_back(newDesc);
10206124SN/A        igbe->anDq(annSmFetch, annUnusedDescQ);
10216124SN/A        igbe->anQ(annSmFetch, annUnusedCacheQ);
10226124SN/A        igbe->anQ(annSmFetch, annDescQ);
10236124SN/A    }
10246124SN/A
10256124SN/A
10266124SN/A#ifndef NDEBUG
10276124SN/A    int oldCp = cachePnt;
10286124SN/A#endif
10296124SN/A
10306124SN/A    cachePnt += curFetching;
10316124SN/A    assert(cachePnt <= descLen());
10326124SN/A    if (cachePnt == descLen())
10336124SN/A        cachePnt = 0;
10346124SN/A
10356124SN/A    curFetching = 0;
10366124SN/A
10376124SN/A    DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
10386124SN/A            oldCp, cachePnt);
10396124SN/A
10406124SN/A    if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
10416124SN/A                                                             cachePnt)) == 0)
10426124SN/A    {
10436124SN/A        igbe->anWe(annSmFetch, annUnusedDescQ);
10446124SN/A    } else if (!(size - usedCache.size() - unusedCache.size())) {
10456124SN/A        igbe->anWf(annSmFetch, annDescQ);
10466124SN/A    } else {
10476124SN/A        igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
10486124SN/A    }
10496124SN/A
10506124SN/A    enableSm();
10516124SN/A    igbe->checkDrain();
10526124SN/A}
10536124SN/A
10546124SN/Atemplate<class T>
10556124SN/Avoid
10566124SN/AIGbE::DescCache<T>::wbComplete()
10576124SN/A{
10586124SN/A
10596124SN/A    igbe->anBegin(annSmWb, "Finish Writeback");
10606124SN/A
10616124SN/A    long  curHead = descHead();
10626124SN/A#ifndef NDEBUG
10636124SN/A    long oldHead = curHead;
10646124SN/A#endif
106511320Ssteve.reinhardt@amd.com
10666124SN/A    for (int x = 0; x < wbOut; x++) {
10676124SN/A        assert(usedCache.size());
10686124SN/A        delete usedCache[0];
10696124SN/A        usedCache.pop_front();
10706124SN/A
10716124SN/A        igbe->anDq(annSmWb, annUsedCacheQ);
10726124SN/A        igbe->anDq(annSmWb, annDescQ);
10736124SN/A    }
10746124SN/A
10756124SN/A    curHead += wbOut;
10766124SN/A    wbOut = 0;
10776124SN/A
10786124SN/A    if (curHead >= descLen())
10796124SN/A        curHead -= descLen();
10806124SN/A
10816124SN/A    // Update the head
10826124SN/A    updateHead(curHead);
10836124SN/A
10846124SN/A    DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
10856124SN/A            oldHead, curHead);
10866124SN/A
10876124SN/A    // If we still have more to wb, call wb now
10886124SN/A    actionAfterWb();
10896124SN/A    if (moreToWb) {
10906124SN/A        moreToWb = false;
10916124SN/A        DPRINTF(EthernetDesc, "Writeback has more todo\n");
10926124SN/A        writeback(wbAlignment);
10936124SN/A    }
10946124SN/A
10956124SN/A    if (!wbOut) {
10966124SN/A        igbe->checkDrain();
10976124SN/A        if (usedCache.size())
10986124SN/A            igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
10996124SN/A        else
11006124SN/A            igbe->anWe(annSmWb, annUsedCacheQ);
11016124SN/A    }
11026124SN/A    fetchAfterWb();
11036124SN/A}
11046124SN/A
11056124SN/Atemplate<class T>
11066124SN/Avoid
11076124SN/AIGbE::DescCache<T>::reset()
11086124SN/A{
11096124SN/A    DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
11106228SN/A    for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
11116124SN/A        delete usedCache[x];
11126228SN/A    for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
11136124SN/A        delete unusedCache[x];
11146124SN/A
11156124SN/A    usedCache.clear();
11166124SN/A    unusedCache.clear();
11176124SN/A
11186124SN/A    cachePnt = 0;
11196124SN/A
11206124SN/A}
11216124SN/A
11226124SN/Atemplate<class T>
11236124SN/Avoid
112410905SN/AIGbE::DescCache<T>::serialize(CheckpointOut &cp) const
11256124SN/A{
11266124SN/A    SERIALIZE_SCALAR(cachePnt);
11276124SN/A    SERIALIZE_SCALAR(curFetching);
11286124SN/A    SERIALIZE_SCALAR(wbOut);
11296124SN/A    SERIALIZE_SCALAR(moreToWb);
11306124SN/A    SERIALIZE_SCALAR(wbAlignment);
11316124SN/A
11326228SN/A    typename CacheType::size_type usedCacheSize = usedCache.size();
11336124SN/A    SERIALIZE_SCALAR(usedCacheSize);
11346228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
113510905SN/A        arrayParamOut(cp, csprintf("usedCache_%d", x),
11366124SN/A                      (uint8_t*)usedCache[x],sizeof(T));
11376124SN/A    }
11386124SN/A
11396228SN/A    typename CacheType::size_type unusedCacheSize = unusedCache.size();
11406124SN/A    SERIALIZE_SCALAR(unusedCacheSize);
11416228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
114210905SN/A        arrayParamOut(cp, csprintf("unusedCache_%d", x),
11436124SN/A                      (uint8_t*)unusedCache[x],sizeof(T));
11446124SN/A    }
11456124SN/A
11466124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11476124SN/A    if (fetchDelayEvent.scheduled())
11486124SN/A        fetch_delay = fetchDelayEvent.when();
11496124SN/A    SERIALIZE_SCALAR(fetch_delay);
11506124SN/A    if (wbDelayEvent.scheduled())
11516124SN/A        wb_delay = wbDelayEvent.when();
11526124SN/A    SERIALIZE_SCALAR(wb_delay);
11536124SN/A
11546124SN/A
11556124SN/A}
11566124SN/A
11576124SN/Atemplate<class T>
11586124SN/Avoid
115910905SN/AIGbE::DescCache<T>::unserialize(CheckpointIn &cp)
11606124SN/A{
11616124SN/A    UNSERIALIZE_SCALAR(cachePnt);
11626124SN/A    UNSERIALIZE_SCALAR(curFetching);
11636124SN/A    UNSERIALIZE_SCALAR(wbOut);
11646124SN/A    UNSERIALIZE_SCALAR(moreToWb);
11656124SN/A    UNSERIALIZE_SCALAR(wbAlignment);
11666124SN/A
11676228SN/A    typename CacheType::size_type usedCacheSize;
11686124SN/A    UNSERIALIZE_SCALAR(usedCacheSize);
11696124SN/A    T *temp;
11706228SN/A    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
11716124SN/A        temp = new T;
117210905SN/A        arrayParamIn(cp, csprintf("usedCache_%d", x),
11736124SN/A                     (uint8_t*)temp,sizeof(T));
11746124SN/A        usedCache.push_back(temp);
11756124SN/A    }
11766124SN/A
11776228SN/A    typename CacheType::size_type unusedCacheSize;
11786124SN/A    UNSERIALIZE_SCALAR(unusedCacheSize);
11796228SN/A    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
11806124SN/A        temp = new T;
118110905SN/A        arrayParamIn(cp, csprintf("unusedCache_%d", x),
11826124SN/A                     (uint8_t*)temp,sizeof(T));
11836124SN/A        unusedCache.push_back(temp);
11846124SN/A    }
11856124SN/A    Tick fetch_delay = 0, wb_delay = 0;
11866124SN/A    UNSERIALIZE_SCALAR(fetch_delay);
11876124SN/A    UNSERIALIZE_SCALAR(wb_delay);
11886124SN/A    if (fetch_delay)
11896124SN/A        igbe->schedule(fetchDelayEvent, fetch_delay);
11906124SN/A    if (wb_delay)
11916124SN/A        igbe->schedule(wbDelayEvent, wb_delay);
11926124SN/A
11936124SN/A
11946124SN/A}
11956124SN/A
11966124SN/A///////////////////////////// IGbE::RxDescCache //////////////////////////////
11974263SN/A
11984263SN/AIGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
119911320Ssteve.reinhardt@amd.com    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
12005783SN/A      pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
12014263SN/A
12024263SN/A{
12035954SN/A    annSmFetch = "RX Desc Fetch";
12045954SN/A    annSmWb = "RX Desc Writeback";
12055954SN/A    annUnusedDescQ = "RX Unused Descriptors";
12065954SN/A    annUnusedCacheQ = "RX Unused Descriptor Cache";
12075954SN/A    annUsedCacheQ = "RX Used Descriptor Cache";
12085954SN/A    annUsedDescQ = "RX Used Descriptors";
12095954SN/A    annDescQ = "RX Descriptors";
12104263SN/A}
12113116SN/A
12125339SN/Avoid
12135783SN/AIGbE::RxDescCache::pktSplitDone()
12145783SN/A{
12155783SN/A    splitCount++;
12166124SN/A    DPRINTF(EthernetDesc,
12176124SN/A            "Part of split packet done: splitcount now %d\n", splitCount);
12185783SN/A    assert(splitCount <= 2);
12195783SN/A    if (splitCount != 2)
12205783SN/A        return;
12215783SN/A    splitCount = 0;
12226124SN/A    DPRINTF(EthernetDesc,
12236124SN/A            "Part of split packet done: calling pktComplete()\n");
12245783SN/A    pktComplete();
12255783SN/A}
12265783SN/A
12275783SN/Aint
12285783SN/AIGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
12293116SN/A{
12306124SN/A    assert(unusedCache.size());
12315071SN/A    //if (!unusedCache.size())
12325071SN/A    //    return false;
12334263SN/A
12344263SN/A    pktPtr = packet;
12354452SN/A    pktDone = false;
12366227SN/A    unsigned buf_len, hdr_len;
12375763SN/A
12385763SN/A    RxDesc *desc = unusedCache.front();
12395763SN/A    switch (igbe->regs.srrctl.desctype()) {
12405763SN/A      case RXDT_LEGACY:
12415783SN/A        assert(pkt_offset == 0);
12425783SN/A        bytesCopied = packet->length;
12435763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
12446124SN/A                packet->length, igbe->regs.rctl.descSize());
12455763SN/A        assert(packet->length < igbe->regs.rctl.descSize());
12466124SN/A        igbe->dmaWrite(pciToDma(desc->legacy.buf),
12476124SN/A                       packet->length, &pktEvent, packet->data,
12486124SN/A                       igbe->rxWriteDelay);
12495763SN/A        break;
12505763SN/A      case RXDT_ADV_ONEBUF:
12515783SN/A        assert(pkt_offset == 0);
12525783SN/A        bytesCopied = packet->length;
12535763SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12546124SN/A            igbe->regs.rctl.descSize();
12555763SN/A        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
12566124SN/A                packet->length, igbe->regs.srrctl(), buf_len);
12575763SN/A        assert(packet->length < buf_len);
12586124SN/A        igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
12596124SN/A                       packet->length, &pktEvent, packet->data,
12606124SN/A                       igbe->rxWriteDelay);
12615783SN/A        desc->adv_wb.header_len = htole(0);
12625783SN/A        desc->adv_wb.sph = htole(0);
12635783SN/A        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
12645783SN/A        break;
12655783SN/A      case RXDT_ADV_SPLIT_A:
12665783SN/A        int split_point;
126711320Ssteve.reinhardt@amd.com
12685783SN/A        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
12696124SN/A            igbe->regs.rctl.descSize();
127011320Ssteve.reinhardt@amd.com        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
12716124SN/A        DPRINTF(EthernetDesc,
12726124SN/A                "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
12736124SN/A                "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
12746124SN/A                igbe->regs.rctl.lpe(), packet->length, pkt_offset,
12756124SN/A                igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
12766124SN/A                desc->adv_read.pkt, buf_len);
12775783SN/A
12785783SN/A        split_point = hsplit(pktPtr);
12795783SN/A
12805783SN/A        if (packet->length <= hdr_len) {
12815783SN/A            bytesCopied = packet->length;
12825783SN/A            assert(pkt_offset == 0);
12836124SN/A            DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
12846124SN/A            igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
12856124SN/A                           packet->length, &pktEvent, packet->data,
12866124SN/A                           igbe->rxWriteDelay);
12875783SN/A            desc->adv_wb.header_len = htole((uint16_t)packet->length);
12885783SN/A            desc->adv_wb.sph = htole(0);
12895783SN/A            desc->adv_wb.pkt_len = htole(0);
12905783SN/A        } else if (split_point) {
12915783SN/A            if (pkt_offset) {
12925783SN/A                // we are only copying some data, header/data has already been
12935783SN/A                // copied
12946124SN/A                int max_to_copy =
12956124SN/A                    std::min(packet->length - pkt_offset, buf_len);
12965783SN/A                bytesCopied += max_to_copy;
12976124SN/A                DPRINTF(EthernetDesc,
12986124SN/A                        "Hdr split: Continuing data buffer copy\n");
12996124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13006124SN/A                               max_to_copy, &pktEvent,
13016124SN/A                               packet->data + pkt_offset, igbe->rxWriteDelay);
13025783SN/A                desc->adv_wb.header_len = htole(0);
13035783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
13045783SN/A                desc->adv_wb.sph = htole(0);
13055783SN/A            } else {
13066124SN/A                int max_to_copy =
13076124SN/A                    std::min(packet->length - split_point, buf_len);
13085783SN/A                bytesCopied += max_to_copy + split_point;
130911320Ssteve.reinhardt@amd.com
13106124SN/A                DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
13115783SN/A                        split_point);
13126124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
13136124SN/A                               split_point, &pktHdrEvent,
13146124SN/A                               packet->data, igbe->rxWriteDelay);
13156124SN/A                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
13166124SN/A                               max_to_copy, &pktDataEvent,
13176124SN/A                               packet->data + split_point, igbe->rxWriteDelay);
13185783SN/A                desc->adv_wb.header_len = htole(split_point);
13195783SN/A                desc->adv_wb.sph = 1;
13205783SN/A                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
13215783SN/A            }
13225783SN/A        } else {
13236124SN/A            panic("Header split not fitting within header buffer or "
13246124SN/A                  "undecodable packet not fitting in header unsupported\n");
13255783SN/A        }
13265763SN/A        break;
13275763SN/A      default:
13285763SN/A        panic("Unimplemnted RX receive buffer type: %d\n",
13296124SN/A              igbe->regs.srrctl.desctype());
13305763SN/A    }
13315783SN/A    return bytesCopied;
13325763SN/A
13333116SN/A}
13343116SN/A
13354263SN/Avoid
13364263SN/AIGbE::RxDescCache::pktComplete()
13374263SN/A{
13384263SN/A    assert(unusedCache.size());
13394263SN/A    RxDesc *desc;
13404263SN/A    desc = unusedCache.front();
13414263SN/A
13425954SN/A    igbe->anBegin("RXS", "Update Desc");
13435954SN/A
13444283SN/A    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
13456124SN/A    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
13466124SN/A            "stripcrc offset: %d value written: %d %d\n",
13475783SN/A            pktPtr->length, bytesCopied, crcfixup,
13484283SN/A            htole((uint16_t)(pktPtr->length + crcfixup)),
13494283SN/A            (uint16_t)(pktPtr->length + crcfixup));
13504283SN/A
13514263SN/A    // no support for anything but starting at 0
13524263SN/A    assert(igbe->regs.rxcsum.pcss() == 0);
13534263SN/A
13544291SN/A    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
13554263SN/A
13565783SN/A    uint16_t status = RXDS_DD;
13574263SN/A    uint8_t err = 0;
13585763SN/A    uint16_t ext_err = 0;
13595763SN/A    uint16_t csum = 0;
13605763SN/A    uint16_t ptype = 0;
13615763SN/A    uint16_t ip_id = 0;
13624452SN/A
13635783SN/A    assert(bytesCopied <= pktPtr->length);
13645783SN/A    if (bytesCopied == pktPtr->length)
13655783SN/A        status |= RXDS_EOP;
13665783SN/A
13674263SN/A    IpPtr ip(pktPtr);
13684452SN/A
13694263SN/A    if (ip) {
13704452SN/A        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
13715763SN/A        ptype |= RXDP_IPV4;
13725763SN/A        ip_id = ip->id();
13734452SN/A
13744263SN/A        if (igbe->regs.rxcsum.ipofld()) {
13754291SN/A            DPRINTF(EthernetDesc, "Checking IP checksum\n");
13764263SN/A            status |= RXDS_IPCS;
13775763SN/A            csum = htole(cksum(ip));
13785485SN/A            igbe->rxIpChecksums++;
13794263SN/A            if (cksum(ip) != 0) {
13804263SN/A                err |= RXDE_IPE;
13815763SN/A                ext_err |= RXDEE_IPE;
13824291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
13834263SN/A            }
13844263SN/A        }
13854263SN/A        TcpPtr tcp(ip);
13864263SN/A        if (tcp && igbe->regs.rxcsum.tuofld()) {
13874291SN/A            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
13884263SN/A            status |= RXDS_TCPCS;
13895763SN/A            ptype |= RXDP_TCP;
13905763SN/A            csum = htole(cksum(tcp));
13915485SN/A            igbe->rxTcpChecksums++;
13924263SN/A            if (cksum(tcp) != 0) {
13934291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
13944263SN/A                err |= RXDE_TCPE;
13955763SN/A                ext_err |= RXDEE_TCPE;
13964263SN/A            }
13974263SN/A        }
13984263SN/A
13994263SN/A        UdpPtr udp(ip);
14004263SN/A        if (udp && igbe->regs.rxcsum.tuofld()) {
14014291SN/A            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
14024263SN/A            status |= RXDS_UDPCS;
14035763SN/A            ptype |= RXDP_UDP;
14045763SN/A            csum = htole(cksum(udp));
14055485SN/A            igbe->rxUdpChecksums++;
14064421SN/A            if (cksum(udp) != 0) {
14074291SN/A                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
14085763SN/A                ext_err |= RXDEE_TCPE;
14094263SN/A                err |= RXDE_TCPE;
14104263SN/A            }
14114263SN/A        }
14124452SN/A    } else { // if ip
14134452SN/A        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
14144452SN/A    }
14154452SN/A
14165763SN/A    switch (igbe->regs.srrctl.desctype()) {
14175763SN/A      case RXDT_LEGACY:
14185763SN/A        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
14195763SN/A        desc->legacy.status = htole(status);
14205763SN/A        desc->legacy.errors = htole(err);
14215763SN/A        // No vlan support at this point... just set it to 0
14225763SN/A        desc->legacy.vlan = 0;
14235763SN/A        break;
14245783SN/A      case RXDT_ADV_SPLIT_A:
14255763SN/A      case RXDT_ADV_ONEBUF:
14265763SN/A        desc->adv_wb.rss_type = htole(0);
14275763SN/A        desc->adv_wb.pkt_type = htole(ptype);
14285763SN/A        if (igbe->regs.rxcsum.pcsd()) {
14295763SN/A            // no rss support right now
14305763SN/A            desc->adv_wb.rss_hash = htole(0);
14315763SN/A        } else {
14325763SN/A            desc->adv_wb.id = htole(ip_id);
14335763SN/A            desc->adv_wb.csum = htole(csum);
14345763SN/A        }
14355763SN/A        desc->adv_wb.status = htole(status);
14365763SN/A        desc->adv_wb.errors = htole(ext_err);
14375763SN/A        // no vlan support
143811320Ssteve.reinhardt@amd.com        desc->adv_wb.vlan_tag = htole(0);
14395763SN/A        break;
14405763SN/A      default:
14415763SN/A        panic("Unimplemnted RX receive buffer type %d\n",
14426124SN/A              igbe->regs.srrctl.desctype());
14435763SN/A    }
14444263SN/A
14455783SN/A    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
14465783SN/A            desc->adv_read.pkt, desc->adv_read.hdr);
14474263SN/A
14485783SN/A    if (bytesCopied == pktPtr->length) {
14496124SN/A        DPRINTF(EthernetDesc,
14506124SN/A                "Packet completely written to descriptor buffers\n");
14515783SN/A        // Deal with the rx timer interrupts
14525783SN/A        if (igbe->regs.rdtr.delay()) {
14536124SN/A            Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
14546124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
14557823SN/A            igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
14565783SN/A        }
14575783SN/A
14585783SN/A        if (igbe->regs.radv.idv()) {
14596124SN/A            Tick delay = igbe->regs.radv.idv() * igbe->intClock();
14606124SN/A            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
14615783SN/A            if (!igbe->radvEvent.scheduled()) {
14627823SN/A                igbe->schedule(igbe->radvEvent, curTick() + delay);
14635783SN/A            }
14645783SN/A        }
14655783SN/A
14665783SN/A        // if neither radv or rdtr, maybe itr is set...
14675783SN/A        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
14686124SN/A            DPRINTF(EthernetSM,
14696124SN/A                    "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
14705783SN/A            igbe->postInterrupt(IT_RXT);
14715783SN/A        }
14725783SN/A
14735783SN/A        // If the packet is small enough, interrupt appropriately
14745783SN/A        // I wonder if this is delayed or not?!
14755783SN/A        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
14766124SN/A            DPRINTF(EthernetSM,
14776124SN/A                    "RXS: Posting IT_SRPD beacuse small packet received\n");
14785783SN/A            igbe->postInterrupt(IT_SRPD);
14795783SN/A        }
14805783SN/A        bytesCopied = 0;
14814263SN/A    }
14824263SN/A
14835783SN/A    pktPtr = NULL;
14845783SN/A    igbe->checkDrain();
14855783SN/A    enableSm();
14865783SN/A    pktDone = true;
14874263SN/A
14885954SN/A    igbe->anBegin("RXS", "Done Updating Desc");
14894291SN/A    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
14905954SN/A    igbe->anDq("RXS", annUnusedCacheQ);
14914263SN/A    unusedCache.pop_front();
14925954SN/A    igbe->anQ("RXS", annUsedCacheQ);
14934263SN/A    usedCache.push_back(desc);
14944263SN/A}
14954263SN/A
14964263SN/Avoid
14974263SN/AIGbE::RxDescCache::enableSm()
14984263SN/A{
149910913SN/A    if (igbe->drainState() != DrainState::Draining) {
15005071SN/A        igbe->rxTick = true;
15015071SN/A        igbe->restartClock();
15025071SN/A    }
15034263SN/A}
15044263SN/A
15054263SN/Abool
15064263SN/AIGbE::RxDescCache::packetDone()
15074263SN/A{
15084263SN/A    if (pktDone) {
15094263SN/A        pktDone = false;
15104263SN/A        return true;
15114263SN/A    }
15124263SN/A    return false;
15134263SN/A}
15144263SN/A
15154294SN/Abool
15164294SN/AIGbE::RxDescCache::hasOutstandingEvents()
15174294SN/A{
15184294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
15195783SN/A        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
15205783SN/A        pktDataEvent.scheduled();
152111320Ssteve.reinhardt@amd.com
15224294SN/A}
15234294SN/A
15244294SN/Avoid
152510905SN/AIGbE::RxDescCache::serialize(CheckpointOut &cp) const
15264294SN/A{
152710905SN/A    DescCache<RxDesc>::serialize(cp);
15284294SN/A    SERIALIZE_SCALAR(pktDone);
15295783SN/A    SERIALIZE_SCALAR(splitCount);
15305783SN/A    SERIALIZE_SCALAR(bytesCopied);
15314294SN/A}
15324294SN/A
15334294SN/Avoid
153410905SN/AIGbE::RxDescCache::unserialize(CheckpointIn &cp)
15354294SN/A{
153610905SN/A    DescCache<RxDesc>::unserialize(cp);
15374294SN/A    UNSERIALIZE_SCALAR(pktDone);
15385783SN/A    UNSERIALIZE_SCALAR(splitCount);
15395783SN/A    UNSERIALIZE_SCALAR(bytesCopied);
15404294SN/A}
15414294SN/A
15424294SN/A
15436124SN/A///////////////////////////// IGbE::TxDescCache //////////////////////////////
15444263SN/A
15454263SN/AIGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
15466124SN/A    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
154710420SN/A      pktWaiting(false), pktMultiDesc(false),
154810420SN/A      completionAddress(0), completionEnabled(false),
15498553SN/A      useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
15508553SN/A      tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
15518553SN/A      tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
15528553SN/A      pktEvent(this), headerEvent(this), nullEvent(this)
15534263SN/A{
15545954SN/A    annSmFetch = "TX Desc Fetch";
15555954SN/A    annSmWb = "TX Desc Writeback";
15565954SN/A    annUnusedDescQ = "TX Unused Descriptors";
15575954SN/A    annUnusedCacheQ = "TX Unused Descriptor Cache";
15585954SN/A    annUsedCacheQ = "TX Used Descriptor Cache";
15595954SN/A    annUsedDescQ = "TX Used Descriptors";
15605954SN/A    annDescQ = "TX Descriptors";
15614263SN/A}
15624263SN/A
15635762SN/Avoid
15645762SN/AIGbE::TxDescCache::processContextDesc()
15654263SN/A{
15664263SN/A    assert(unusedCache.size());
15675762SN/A    TxDesc *desc;
156811320Ssteve.reinhardt@amd.com
15695762SN/A    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
15704263SN/A
15716124SN/A    while (!useTso && unusedCache.size() &&
15726124SN/A           TxdOp::isContext(unusedCache.front())) {
15735762SN/A        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
15744263SN/A
15755762SN/A        desc = unusedCache.front();
157611320Ssteve.reinhardt@amd.com        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
15776124SN/A                desc->d1, desc->d2);
15784263SN/A
157911320Ssteve.reinhardt@amd.com
15804263SN/A        // is this going to be a tcp or udp packet?
15814263SN/A        isTcp = TxdOp::tcp(desc) ? true : false;
15824263SN/A
158311320Ssteve.reinhardt@amd.com        // setup all the TSO variables, they'll be ignored if we don't use
15845763SN/A        // tso for this connection
15855763SN/A        tsoHeaderLen = TxdOp::hdrlen(desc);
15865763SN/A        tsoMss  = TxdOp::mss(desc);
15875763SN/A
15885763SN/A        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
15896124SN/A            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
15906124SN/A                    "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
15916124SN/A                    TxdOp::mss(desc), TxdOp::getLen(desc));
15925762SN/A            useTso = true;
15935762SN/A            tsoTotalLen = TxdOp::getLen(desc);
15945762SN/A            tsoLoadedHeader = false;
15955762SN/A            tsoDescBytesUsed = 0;
15965762SN/A            tsoUsedLen = 0;
15975762SN/A            tsoPrevSeq = 0;
15985762SN/A            tsoPktHasHeader = false;
15995762SN/A            tsoPkts = 0;
16008553SN/A            tsoCopyBytes = 0;
16015762SN/A        }
16024263SN/A
16034263SN/A        TxdOp::setDd(desc);
16044263SN/A        unusedCache.pop_front();
16055954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
16064263SN/A        usedCache.push_back(desc);
16075954SN/A        igbe->anQ("TXS", annUsedCacheQ);
16084263SN/A    }
16094263SN/A
16104263SN/A    if (!unusedCache.size())
16115762SN/A        return;
16125762SN/A
16135763SN/A    desc = unusedCache.front();
161411320Ssteve.reinhardt@amd.com    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) &&
16156124SN/A        TxdOp::tse(desc)) {
16166124SN/A        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
161711320Ssteve.reinhardt@amd.com                "hdrlen: %d mss: %d paylen %d\n",
16185763SN/A                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
16195763SN/A        useTso = true;
16205763SN/A        tsoTotalLen = TxdOp::getTsoLen(desc);
16215763SN/A        tsoLoadedHeader = false;
16225763SN/A        tsoDescBytesUsed = 0;
16235763SN/A        tsoUsedLen = 0;
16245763SN/A        tsoPrevSeq = 0;
16255763SN/A        tsoPktHasHeader = false;
16265763SN/A        tsoPkts = 0;
16275763SN/A    }
16285763SN/A
16295762SN/A    if (useTso && !tsoLoadedHeader) {
16305762SN/A        // we need to fetch a header
16315762SN/A        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
16325762SN/A        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
16335762SN/A        pktWaiting = true;
16345762SN/A        assert(tsoHeaderLen <= 256);
16356124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
16366124SN/A                      tsoHeaderLen, &headerEvent, tsoHeader, 0);
16375762SN/A    }
16385762SN/A}
16395762SN/A
16405762SN/Avoid
16415762SN/AIGbE::TxDescCache::headerComplete()
16425762SN/A{
16435762SN/A    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
16445762SN/A    pktWaiting = false;
16455762SN/A
16465762SN/A    assert(unusedCache.size());
16475762SN/A    TxDesc *desc = unusedCache.front();
16485762SN/A    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
16495762SN/A            TxdOp::getLen(desc), tsoHeaderLen);
16505762SN/A
16515762SN/A    if (TxdOp::getLen(desc) == tsoHeaderLen) {
16525762SN/A        tsoDescBytesUsed = 0;
16535762SN/A        tsoLoadedHeader = true;
16545762SN/A        unusedCache.pop_front();
16555762SN/A        usedCache.push_back(desc);
16565762SN/A    } else {
16579189SN/A        DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
16589189SN/A        tsoDescBytesUsed = tsoHeaderLen;
16599189SN/A        tsoLoadedHeader = true;
16605762SN/A    }
16615762SN/A    enableSm();
16625762SN/A    igbe->checkDrain();
16635762SN/A}
16645762SN/A
16656227SN/Aunsigned
16665762SN/AIGbE::TxDescCache::getPacketSize(EthPacketPtr p)
16675762SN/A{
16685762SN/A    if (!unusedCache.size())
16696227SN/A        return 0;
167011320Ssteve.reinhardt@amd.com
16715762SN/A    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
16725762SN/A
16735762SN/A    assert(!useTso || tsoLoadedHeader);
16746227SN/A    TxDesc *desc = unusedCache.front();
16755762SN/A
16765762SN/A    if (useTso) {
16776124SN/A        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
16786124SN/A                "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
16796124SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
16806124SN/A                "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
16816124SN/A                tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
16828553SN/A
168311320Ssteve.reinhardt@amd.com        if (tsoPktHasHeader)
16846124SN/A            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length,
16858553SN/A                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16865762SN/A        else
16876124SN/A            tsoCopyBytes =  std::min(tsoMss,
168811320Ssteve.reinhardt@amd.com                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
16896227SN/A        unsigned pkt_size =
169011320Ssteve.reinhardt@amd.com            tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
16918553SN/A
16928553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
16938553SN/A                "this descLen: %d\n",
16948553SN/A                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
16958553SN/A        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
16965762SN/A        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
16975762SN/A        return pkt_size;
16985762SN/A    }
16994263SN/A
17004291SN/A    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
17016124SN/A            TxdOp::getLen(unusedCache.front()));
17025762SN/A    return TxdOp::getLen(desc);
17034263SN/A}
17044263SN/A
17054263SN/Avoid
17064263SN/AIGbE::TxDescCache::getPacketData(EthPacketPtr p)
17074263SN/A{
17084263SN/A    assert(unusedCache.size());
17094263SN/A
17104263SN/A    TxDesc *desc;
17114263SN/A    desc = unusedCache.front();
17124263SN/A
17136124SN/A    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
17146124SN/A            "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
17156124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17166124SN/A           TxdOp::getLen(desc));
17174263SN/A
17184263SN/A    pktPtr = p;
17194263SN/A
17204263SN/A    pktWaiting = true;
17214263SN/A
17225404SN/A    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
172311320Ssteve.reinhardt@amd.com
17245762SN/A    if (useTso) {
17255762SN/A        assert(tsoLoadedHeader);
17265762SN/A        if (!tsoPktHasHeader) {
17276124SN/A            DPRINTF(EthernetDesc,
17286124SN/A                    "Loading TSO header (%d bytes) into start of packet\n",
17296124SN/A                    tsoHeaderLen);
17305762SN/A            memcpy(p->data, &tsoHeader,tsoHeaderLen);
17315762SN/A            p->length +=tsoHeaderLen;
17325762SN/A            tsoPktHasHeader = true;
17335762SN/A        }
17345762SN/A    }
173511320Ssteve.reinhardt@amd.com
17365762SN/A    if (useTso) {
17376124SN/A        DPRINTF(EthernetDesc,
17386124SN/A                "Starting DMA of packet at offset %d length: %d\n",
17395762SN/A                p->length, tsoCopyBytes);
17406124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc))
17416124SN/A                      + tsoDescBytesUsed,
17426124SN/A                      tsoCopyBytes, &pktEvent, p->data + p->length,
17436124SN/A                      igbe->txReadDelay);
17448553SN/A        tsoDescBytesUsed += tsoCopyBytes;
17458553SN/A        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
17465762SN/A    } else {
17476124SN/A        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
17486124SN/A                      TxdOp::getLen(desc), &pktEvent, p->data + p->length,
17496124SN/A                      igbe->txReadDelay);
17505762SN/A    }
17514263SN/A}
17524263SN/A
17534263SN/Avoid
17544263SN/AIGbE::TxDescCache::pktComplete()
17554263SN/A{
17564263SN/A
17574263SN/A    TxDesc *desc;
17584263SN/A    assert(unusedCache.size());
17594263SN/A    assert(pktPtr);
17604263SN/A
17615954SN/A    igbe->anBegin("TXS", "Update Desc");
17625954SN/A
17634291SN/A    DPRINTF(EthernetDesc, "DMA of packet complete\n");
17644263SN/A
17655339SN/A
17664263SN/A    desc = unusedCache.front();
17676124SN/A    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
17686124SN/A           TxdOp::getLen(desc));
17694263SN/A
17706124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
17716124SN/A            desc->d1, desc->d2);
17724283SN/A
17735762SN/A    // Set the length of the data in the EtherPacket
17745762SN/A    if (useTso) {
17758553SN/A        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
17768553SN/A            "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
17778553SN/A            tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
177811701Smichael.lebeane@amd.com        pktPtr->simLength += tsoCopyBytes;
17795762SN/A        pktPtr->length += tsoCopyBytes;
17805762SN/A        tsoUsedLen += tsoCopyBytes;
17818553SN/A        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
17828553SN/A            tsoDescBytesUsed, tsoCopyBytes);
178311701Smichael.lebeane@amd.com    } else {
178411701Smichael.lebeane@amd.com        pktPtr->simLength += TxdOp::getLen(desc);
17855404SN/A        pktPtr->length += TxdOp::getLen(desc);
178611701Smichael.lebeane@amd.com    }
17875762SN/A
17885762SN/A
178911320Ssteve.reinhardt@amd.com
179011320Ssteve.reinhardt@amd.com    if ((!TxdOp::eop(desc) && !useTso) ||
17916124SN/A        (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
17926124SN/A         tsoTotalLen != tsoUsedLen && useTso)) {
17935762SN/A        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
17945954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
17954283SN/A        unusedCache.pop_front();
17965954SN/A        igbe->anQ("TXS", annUsedCacheQ);
17974283SN/A        usedCache.push_back(desc);
17985762SN/A
17995762SN/A        tsoDescBytesUsed = 0;
18004283SN/A        pktDone = true;
18014283SN/A        pktWaiting = false;
18025404SN/A        pktMultiDesc = true;
18035404SN/A
18045404SN/A        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
18055404SN/A                pktPtr->length);
18064283SN/A        pktPtr = NULL;
18074283SN/A
18084438SN/A        enableSm();
18095071SN/A        igbe->checkDrain();
18104283SN/A        return;
18114283SN/A    }
18125762SN/A
18135762SN/A
18145404SN/A    pktMultiDesc = false;
18154263SN/A    // no support for vlans
18164263SN/A    assert(!TxdOp::vle(desc));
18174263SN/A
18184263SN/A    // we only support single packet descriptors at this point
18195762SN/A    if (!useTso)
18205762SN/A        assert(TxdOp::eop(desc));
18214263SN/A
18224263SN/A    // set that this packet is done
18235762SN/A    if (TxdOp::rs(desc))
18245762SN/A        TxdOp::setDd(desc);
18254263SN/A
18266124SN/A    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
18276124SN/A            desc->d1, desc->d2);
18284283SN/A
18295762SN/A    if (useTso) {
18305762SN/A        IpPtr ip(pktPtr);
18315762SN/A        if (ip) {
18325762SN/A            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
18335762SN/A                    tsoPkts);
18345762SN/A            ip->id(ip->id() + tsoPkts++);
183511320Ssteve.reinhardt@amd.com            ip->len(pktPtr->length - EthPtr(pktPtr)->size());
183611320Ssteve.reinhardt@amd.com
18375762SN/A            TcpPtr tcp(ip);
18385762SN/A            if (tcp) {
18396124SN/A                DPRINTF(EthernetDesc,
18406124SN/A                        "TSO: Modifying TCP header. old seq %d + %d\n",
18416124SN/A                        tcp->seq(), tsoPrevSeq);
18425762SN/A                tcp->seq(tcp->seq() + tsoPrevSeq);
18435762SN/A                if (tsoUsedLen != tsoTotalLen)
18445762SN/A                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
18455762SN/A            }
18465762SN/A            UdpPtr udp(ip);
18475762SN/A            if (udp) {
18485762SN/A                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
18495762SN/A                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
18505762SN/A            }
18515762SN/A        }
18525762SN/A        tsoPrevSeq = tsoUsedLen;
18535762SN/A    }
18545762SN/A
18554452SN/A    if (DTRACE(EthernetDesc)) {
18564452SN/A        IpPtr ip(pktPtr);
18574452SN/A        if (ip)
18584452SN/A            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
18594452SN/A                    ip->id());
18604452SN/A        else
18614452SN/A            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
18624452SN/A    }
18634452SN/A
18644263SN/A    // Checksums are only ofloaded for new descriptor types
18654263SN/A    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
18664291SN/A        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
18674263SN/A        IpPtr ip(pktPtr);
18685404SN/A        assert(ip);
18694263SN/A        if (TxdOp::ixsm(desc)) {
18704263SN/A            ip->sum(0);
18714263SN/A            ip->sum(cksum(ip));
18725485SN/A            igbe->txIpChecksums++;
18734291SN/A            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
18744263SN/A        }
18754987SN/A        if (TxdOp::txsm(desc)) {
18764987SN/A            TcpPtr tcp(ip);
18774987SN/A            UdpPtr udp(ip);
18784987SN/A            if (tcp) {
18796124SN/A                tcp->sum(0);
18806124SN/A                tcp->sum(cksum(tcp));
18816124SN/A                igbe->txTcpChecksums++;
18826124SN/A                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
18834987SN/A            } else if (udp) {
18846124SN/A                assert(udp);
18856124SN/A                udp->sum(0);
18866124SN/A                udp->sum(cksum(udp));
18876124SN/A                igbe->txUdpChecksums++;
18886124SN/A                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
18894987SN/A            } else {
18904987SN/A                panic("Told to checksum, but don't know how\n");
18914987SN/A            }
18924263SN/A        }
18934263SN/A    }
18944263SN/A
18954263SN/A    if (TxdOp::ide(desc)) {
18964263SN/A        // Deal with the rx timer interrupts
18974291SN/A        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
18984263SN/A        if (igbe->regs.tidv.idv()) {
18996124SN/A            Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
19004291SN/A            DPRINTF(EthernetDesc, "setting tidv\n");
19017823SN/A            igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
19024263SN/A        }
19034263SN/A
19044263SN/A        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
19056124SN/A            Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
19064291SN/A            DPRINTF(EthernetDesc, "setting tadv\n");
19074987SN/A            if (!igbe->tadvEvent.scheduled()) {
19087823SN/A                igbe->schedule(igbe->tadvEvent, curTick() + delay);
19094987SN/A            }
19104263SN/A        }
19114263SN/A    }
19124263SN/A
19134283SN/A
19145762SN/A    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
19155762SN/A        DPRINTF(EthernetDesc, "Descriptor Done\n");
19165954SN/A        igbe->anDq("TXS", annUnusedCacheQ);
19175762SN/A        unusedCache.pop_front();
19185954SN/A        igbe->anQ("TXS", annUsedCacheQ);
19195762SN/A        usedCache.push_back(desc);
19205762SN/A        tsoDescBytesUsed = 0;
19215762SN/A    }
19224283SN/A
19235762SN/A    if (useTso && tsoUsedLen == tsoTotalLen)
19245762SN/A        useTso = false;
19255762SN/A
19265762SN/A
19276124SN/A    DPRINTF(EthernetDesc,
19286124SN/A            "------Packet of %d bytes ready for transmission-------\n",
19295762SN/A            pktPtr->length);
19304263SN/A    pktDone = true;
19314263SN/A    pktWaiting = false;
19324263SN/A    pktPtr = NULL;
19335762SN/A    tsoPktHasHeader = false;
19344283SN/A
19354283SN/A    if (igbe->regs.txdctl.wthresh() == 0) {
19365954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19374291SN/A        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
19384283SN/A        writeback(0);
19398984SN/A    } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
19406124SN/A               descInBlock(usedCache.size())) {
19415763SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19425954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19435763SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19448984SN/A    } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
19454291SN/A        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
19465954SN/A        igbe->anBegin("TXS", "Desc Writeback");
19474283SN/A        writeback((igbe->cacheBlockSize()-1)>>4);
19484283SN/A    }
19495763SN/A
19504438SN/A    enableSm();
19514294SN/A    igbe->checkDrain();
19524294SN/A}
19534283SN/A
19544294SN/Avoid
195511320Ssteve.reinhardt@amd.comIGbE::TxDescCache::actionAfterWb()
19565763SN/A{
19575763SN/A    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
19585763SN/A            completionEnabled);
19595763SN/A    igbe->postInterrupt(iGbReg::IT_TXDW);
196011320Ssteve.reinhardt@amd.com    if (completionEnabled) {
19615763SN/A        descEnd = igbe->regs.tdh();
19626124SN/A        DPRINTF(EthernetDesc,
19636124SN/A                "Completion writing back value: %d to addr: %#x\n", descEnd,
19645763SN/A                completionAddress);
19656124SN/A        igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)),
19666124SN/A                       sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
19675763SN/A    }
19685763SN/A}
19695763SN/A
19705763SN/Avoid
197110905SN/AIGbE::TxDescCache::serialize(CheckpointOut &cp) const
19724294SN/A{
197310905SN/A    DescCache<TxDesc>::serialize(cp);
197410905SN/A
19754294SN/A    SERIALIZE_SCALAR(pktDone);
19764294SN/A    SERIALIZE_SCALAR(isTcp);
19774294SN/A    SERIALIZE_SCALAR(pktWaiting);
19785404SN/A    SERIALIZE_SCALAR(pktMultiDesc);
19795762SN/A
19805762SN/A    SERIALIZE_SCALAR(useTso);
19815762SN/A    SERIALIZE_SCALAR(tsoHeaderLen);
19825762SN/A    SERIALIZE_SCALAR(tsoMss);
19835762SN/A    SERIALIZE_SCALAR(tsoTotalLen);
19845762SN/A    SERIALIZE_SCALAR(tsoUsedLen);
19855762SN/A    SERIALIZE_SCALAR(tsoPrevSeq);;
19865762SN/A    SERIALIZE_SCALAR(tsoPktPayloadBytes);
19875762SN/A    SERIALIZE_SCALAR(tsoLoadedHeader);
19885762SN/A    SERIALIZE_SCALAR(tsoPktHasHeader);
19895762SN/A    SERIALIZE_ARRAY(tsoHeader, 256);
19905762SN/A    SERIALIZE_SCALAR(tsoDescBytesUsed);
19915762SN/A    SERIALIZE_SCALAR(tsoCopyBytes);
19925762SN/A    SERIALIZE_SCALAR(tsoPkts);
19935762SN/A
19945763SN/A    SERIALIZE_SCALAR(completionAddress);
19955763SN/A    SERIALIZE_SCALAR(completionEnabled);
19965763SN/A    SERIALIZE_SCALAR(descEnd);
19974294SN/A}
19984294SN/A
19994294SN/Avoid
200010905SN/AIGbE::TxDescCache::unserialize(CheckpointIn &cp)
20014294SN/A{
200210905SN/A    DescCache<TxDesc>::unserialize(cp);
200310905SN/A
20044294SN/A    UNSERIALIZE_SCALAR(pktDone);
20054294SN/A    UNSERIALIZE_SCALAR(isTcp);
20064294SN/A    UNSERIALIZE_SCALAR(pktWaiting);
20075404SN/A    UNSERIALIZE_SCALAR(pktMultiDesc);
20085762SN/A
20095762SN/A    UNSERIALIZE_SCALAR(useTso);
20105762SN/A    UNSERIALIZE_SCALAR(tsoHeaderLen);
20115762SN/A    UNSERIALIZE_SCALAR(tsoMss);
20125762SN/A    UNSERIALIZE_SCALAR(tsoTotalLen);
20135762SN/A    UNSERIALIZE_SCALAR(tsoUsedLen);
20145762SN/A    UNSERIALIZE_SCALAR(tsoPrevSeq);;
20155762SN/A    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
20165762SN/A    UNSERIALIZE_SCALAR(tsoLoadedHeader);
20175762SN/A    UNSERIALIZE_SCALAR(tsoPktHasHeader);
20185762SN/A    UNSERIALIZE_ARRAY(tsoHeader, 256);
20195762SN/A    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
20205762SN/A    UNSERIALIZE_SCALAR(tsoCopyBytes);
20215762SN/A    UNSERIALIZE_SCALAR(tsoPkts);
20225763SN/A
20235763SN/A    UNSERIALIZE_SCALAR(completionAddress);
20245763SN/A    UNSERIALIZE_SCALAR(completionEnabled);
20255763SN/A    UNSERIALIZE_SCALAR(descEnd);
20264263SN/A}
20274263SN/A
20284263SN/Abool
20294263SN/AIGbE::TxDescCache::packetAvailable()
20304263SN/A{
20314263SN/A    if (pktDone) {
20324263SN/A        pktDone = false;
20334263SN/A        return true;
20344263SN/A    }
20354263SN/A    return false;
20364263SN/A}
20374263SN/A
20384263SN/Avoid
20394263SN/AIGbE::TxDescCache::enableSm()
20404263SN/A{
204110913SN/A    if (igbe->drainState() != DrainState::Draining) {
20425071SN/A        igbe->txTick = true;
20435071SN/A        igbe->restartClock();
20445071SN/A    }
20454263SN/A}
20464263SN/A
20474294SN/Abool
20484294SN/AIGbE::TxDescCache::hasOutstandingEvents()
20494294SN/A{
20504294SN/A    return pktEvent.scheduled() || wbEvent.scheduled() ||
20514294SN/A        fetchEvent.scheduled();
20524294SN/A}
20534263SN/A
20544263SN/A
20554263SN/A///////////////////////////////////// IGbE /////////////////////////////////
20564263SN/A
20574263SN/Avoid
20584283SN/AIGbE::restartClock()
20594283SN/A{
20605606SN/A    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
206110913SN/A        drainState() == DrainState::Running)
20629180SN/A        schedule(tickEvent, clockEdge(Cycles(1)));
20634283SN/A}
20644283SN/A
206510913SN/ADrainState
206610913SN/AIGbE::drain()
20674294SN/A{
206810912SN/A    unsigned int count(0);
20694294SN/A    if (rxDescCache.hasOutstandingEvents() ||
20706124SN/A        txDescCache.hasOutstandingEvents()) {
20714294SN/A        count++;
20724294SN/A    }
20734294SN/A
20744294SN/A    txFifoTick = false;
20754294SN/A    txTick = false;
20764294SN/A    rxTick = false;
20774294SN/A
20784294SN/A    if (tickEvent.scheduled())
20795606SN/A        deschedule(tickEvent);
20804294SN/A
20819152SN/A    if (count) {
20829152SN/A        DPRINTF(Drain, "IGbE not drained\n");
208310913SN/A        return DrainState::Draining;
20849152SN/A    } else
208510913SN/A        return DrainState::Drained;
20864294SN/A}
20874294SN/A
20884294SN/Avoid
20899342SN/AIGbE::drainResume()
20904294SN/A{
20919342SN/A    Drainable::drainResume();
20924294SN/A
20934294SN/A    txFifoTick = true;
20944294SN/A    txTick = true;
20954294SN/A    rxTick = true;
20964294SN/A
20974294SN/A    restartClock();
20985954SN/A    DPRINTF(EthernetSM, "resuming from drain");
20994294SN/A}
21004294SN/A
21014294SN/Avoid
21024294SN/AIGbE::checkDrain()
21034294SN/A{
210410913SN/A    if (drainState() != DrainState::Draining)
21054294SN/A        return;
21064294SN/A
21074987SN/A    txFifoTick = false;
21084987SN/A    txTick = false;
21094987SN/A    rxTick = false;
21104987SN/A    if (!rxDescCache.hasOutstandingEvents() &&
21116124SN/A        !txDescCache.hasOutstandingEvents()) {
21129152SN/A        DPRINTF(Drain, "IGbE done draining, processing drain event\n");
211310913SN/A        signalDrainDone();
21144294SN/A    }
21154294SN/A}
21164283SN/A
21174283SN/Avoid
21184263SN/AIGbE::txStateMachine()
21194263SN/A{
21204263SN/A    if (!regs.tctl.en()) {
21214263SN/A        txTick = false;
21224283SN/A        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
21234263SN/A        return;
21244263SN/A    }
21254263SN/A
21264283SN/A    // If we have a packet available and it's length is not 0 (meaning it's not
21274283SN/A    // a multidescriptor packet) put it in the fifo, otherwise an the next
21284283SN/A    // iteration we'll get the rest of the data
21295404SN/A    if (txPacket && txDescCache.packetAvailable()
21306124SN/A        && !txDescCache.packetMultiDesc() && txPacket->length) {
21315954SN/A        anQ("TXS", "TX FIFO Q");
21324263SN/A        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
21338641SN/A#ifndef NDEBUG
21348641SN/A        bool success =
21358641SN/A#endif
21368641SN/A            txFifo.push(txPacket);
213710913SN/A        txFifoTick = true && drainState() != DrainState::Draining;
21384263SN/A        assert(success);
21394263SN/A        txPacket = NULL;
21405954SN/A        anBegin("TXS", "Desc Writeback");
21414291SN/A        txDescCache.writeback((cacheBlockSize()-1)>>4);
21424263SN/A        return;
21434263SN/A    }
21444263SN/A
21454263SN/A    // Only support descriptor granularity
21466124SN/A    if (regs.txdctl.lwthresh() &&
21476124SN/A        txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
21484263SN/A        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
21494263SN/A        postInterrupt(IT_TXDLOW);
21504263SN/A    }
21514263SN/A
21524263SN/A    if (!txPacket) {
215310469SN/A        txPacket = std::make_shared<EthPacketData>(16384);
21544263SN/A    }
21554263SN/A
21564263SN/A    if (!txDescCache.packetWaiting()) {
21574263SN/A        if (txDescCache.descLeft() == 0) {
21584987SN/A            postInterrupt(IT_TXQE);
21595954SN/A            anBegin("TXS", "Desc Writeback");
21604987SN/A            txDescCache.writeback(0);
21615954SN/A            anBegin("TXS", "Desc Fetch");
21625954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21635071SN/A            txDescCache.fetchDescriptors();
21644283SN/A            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
21654283SN/A                    "writeback stopping ticking and posting TXQE\n");
21664263SN/A            txTick = false;
21674291SN/A            return;
21684263SN/A        }
21694263SN/A
21704283SN/A
21714263SN/A        if (!(txDescCache.descUnused())) {
21725954SN/A            anBegin("TXS", "Desc Fetch");
21735071SN/A            txDescCache.fetchDescriptors();
21745954SN/A            anWe("TXS", txDescCache.annUnusedCacheQ);
21756124SN/A            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
21766124SN/A                    "fetching and stopping ticking\n");
21774263SN/A            txTick = false;
21784263SN/A            return;
21794263SN/A        }
21805954SN/A        anPq("TXS", txDescCache.annUnusedCacheQ);
21814263SN/A
21825339SN/A
21835762SN/A        txDescCache.processContextDesc();
21845762SN/A        if (txDescCache.packetWaiting()) {
21856124SN/A            DPRINTF(EthernetSM,
21866124SN/A                    "TXS: Fetching TSO header, stopping ticking\n");
21875762SN/A            txTick = false;
21885762SN/A            return;
21895762SN/A        }
21905762SN/A
21916227SN/A        unsigned size = txDescCache.getPacketSize(txPacket);
21924283SN/A        if (size > 0 && txFifo.avail() > size) {
21935954SN/A            anRq("TXS", "TX FIFO Q");
21945954SN/A            anBegin("TXS", "DMA Packet");
21956124SN/A            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
21966124SN/A                    "beginning DMA of next packet\n", size);
21974283SN/A            txFifo.reserve(size);
21984263SN/A            txDescCache.getPacketData(txPacket);
21996227SN/A        } else if (size == 0) {
22004987SN/A            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
22016124SN/A            DPRINTF(EthernetSM,
22026124SN/A                    "TXS: No packets to get, writing back used descriptors\n");
22035954SN/A            anBegin("TXS", "Desc Writeback");
22044263SN/A            txDescCache.writeback(0);
22054291SN/A        } else {
22065954SN/A            anWf("TXS", "TX FIFO Q");
22074291SN/A            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
22084291SN/A                    "available in FIFO\n");
22094291SN/A            txTick = false;
22104263SN/A        }
22114263SN/A
22124291SN/A
22134263SN/A        return;
22144263SN/A    }
22154438SN/A    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
22164438SN/A    txTick = false;
22174263SN/A}
22184263SN/A
22194263SN/Abool
22204263SN/AIGbE::ethRxPkt(EthPacketPtr pkt)
22214263SN/A{
22225485SN/A    rxBytes += pkt->length;
22235485SN/A    rxPackets++;
22245485SN/A
22254263SN/A    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
22265954SN/A    anBegin("RXQ", "Wire Recv");
22275954SN/A
22284987SN/A
22294263SN/A    if (!regs.rctl.en()) {
22304263SN/A        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
22315954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22324263SN/A        return true;
22334263SN/A    }
22344263SN/A
22354263SN/A    // restart the state machines if they are stopped
223610913SN/A    rxTick = true && drainState() != DrainState::Draining;
22374263SN/A    if ((rxTick || txTick) && !tickEvent.scheduled()) {
22386124SN/A        DPRINTF(EthernetSM,
22396124SN/A                "RXS: received packet into fifo, starting ticking\n");
22404283SN/A        restartClock();
22414263SN/A    }
22424263SN/A
22434263SN/A    if (!rxFifo.push(pkt)) {
22444263SN/A        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
22454263SN/A        postInterrupt(IT_RXO, true);
22465954SN/A        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
22474263SN/A        return false;
22484263SN/A    }
22495339SN/A
22505954SN/A    if (CPA::available() && cpa->enabled()) {
22515954SN/A        assert(sys->numSystemsRunning <= 2);
22525954SN/A        System *other_sys;
22535954SN/A        if (sys->systemList[0] == sys)
22545954SN/A            other_sys = sys->systemList[1];
22555954SN/A        else
22565954SN/A            other_sys = sys->systemList[0];
22575954SN/A
22585954SN/A        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22595954SN/A        anQ("RXQ", "RX FIFO Q");
22605954SN/A        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
22615954SN/A    }
22625954SN/A
22634263SN/A    return true;
22644263SN/A}
22654263SN/A
22664263SN/A
22674263SN/Avoid
22684263SN/AIGbE::rxStateMachine()
22694263SN/A{
22704263SN/A    if (!regs.rctl.en()) {
22714263SN/A        rxTick = false;
22724263SN/A        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
22734263SN/A        return;
22744263SN/A    }
22754263SN/A
22764263SN/A    // If the packet is done check for interrupts/descriptors/etc
22774263SN/A    if (rxDescCache.packetDone()) {
22784452SN/A        rxDmaPacket = false;
22794263SN/A        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
22804263SN/A        int descLeft = rxDescCache.descLeft();
22815783SN/A        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
22825783SN/A                descLeft, regs.rctl.rdmts(), regs.rdlen());
22834263SN/A        switch (regs.rctl.rdmts()) {
22846124SN/A          case 2: if (descLeft > .125 * regs.rdlen()) break;
22856124SN/A          case 1: if (descLeft > .250 * regs.rdlen()) break;
22866124SN/A          case 0: if (descLeft > .500 * regs.rdlen())  break;
22876124SN/A            DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
22886124SN/A                    "because of descriptors left\n");
22896124SN/A            postInterrupt(IT_RXDMT);
22906124SN/A            break;
22914263SN/A        }
22924263SN/A
22935783SN/A        if (rxFifo.empty())
22945783SN/A            rxDescCache.writeback(0);
22955783SN/A
22964263SN/A        if (descLeft == 0) {
22975954SN/A            anBegin("RXS", "Writeback Descriptors");
22984263SN/A            rxDescCache.writeback(0);
22995339SN/A            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
23005339SN/A                    " writeback and stopping ticking\n");
23014263SN/A            rxTick = false;
23024263SN/A        }
23034263SN/A
23044263SN/A        // only support descriptor granulaties
23054263SN/A        assert(regs.rxdctl.gran());
23064263SN/A
23074263SN/A        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
23086124SN/A            DPRINTF(EthernetSM,
23096124SN/A                    "RXS: Writing back because WTHRESH >= descUsed\n");
23105954SN/A            anBegin("RXS", "Writeback Descriptors");
23114283SN/A            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
23124283SN/A                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
23134283SN/A            else
23144283SN/A                rxDescCache.writeback((cacheBlockSize()-1)>>4);
23154263SN/A        }
23164263SN/A
23174263SN/A        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
23186124SN/A            ((rxDescCache.descLeft() - rxDescCache.descUnused()) >
23196124SN/A             regs.rxdctl.hthresh())) {
23206124SN/A            DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
23216124SN/A                    "descUnused < PTHRESH\n");
23225954SN/A            anBegin("RXS", "Fetch Descriptors");
23234263SN/A            rxDescCache.fetchDescriptors();
23244263SN/A        }
23254263SN/A
23264263SN/A        if (rxDescCache.descUnused() == 0) {
23275954SN/A            anBegin("RXS", "Fetch Descriptors");
23285071SN/A            rxDescCache.fetchDescriptors();
23295954SN/A            anWe("RXS", rxDescCache.annUnusedCacheQ);
23304291SN/A            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23314291SN/A                    "fetching descriptors and stopping ticking\n");
23324263SN/A            rxTick = false;
23334263SN/A        }
23344263SN/A        return;
23354263SN/A    }
23364263SN/A
23374452SN/A    if (rxDmaPacket) {
23386124SN/A        DPRINTF(EthernetSM,
23396124SN/A                "RXS: stopping ticking until packet DMA completes\n");
23404452SN/A        rxTick = false;
23414452SN/A        return;
23424452SN/A    }
23434452SN/A
23444263SN/A    if (!rxDescCache.descUnused()) {
23455954SN/A        anBegin("RXS", "Fetch Descriptors");
23465071SN/A        rxDescCache.fetchDescriptors();
23475954SN/A        anWe("RXS", rxDescCache.annUnusedCacheQ);
23486124SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
23496124SN/A                "stopping ticking\n");
23504263SN/A        rxTick = false;
23514263SN/A        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
23524263SN/A        return;
23534263SN/A    }
23545954SN/A    anPq("RXS", rxDescCache.annUnusedCacheQ);
23554263SN/A
23564263SN/A    if (rxFifo.empty()) {
23575954SN/A        anWe("RXS", "RX FIFO Q");
23584263SN/A        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
23594263SN/A        rxTick = false;
23604263SN/A        return;
23614263SN/A    }
23625954SN/A    anPq("RXS", "RX FIFO Q");
23635954SN/A    anBegin("RXS", "Get Desc");
23644263SN/A
23654263SN/A    EthPacketPtr pkt;
23664263SN/A    pkt = rxFifo.front();
23674263SN/A
23685339SN/A
23695783SN/A    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
23704263SN/A    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
23715783SN/A    if (pktOffset == pkt->length) {
23725954SN/A        anBegin( "RXS", "FIFO Dequeue");
23735783SN/A        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
23745783SN/A        pktOffset = 0;
23755954SN/A        anDq("RXS", "RX FIFO Q");
23765783SN/A        rxFifo.pop();
23775783SN/A    }
23785783SN/A
23795339SN/A    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
23805339SN/A    rxTick = false;
23815339SN/A    rxDmaPacket = true;
23825954SN/A    anBegin("RXS", "DMA Packet");
23834263SN/A}
23844263SN/A
23854263SN/Avoid
23864263SN/AIGbE::txWire()
23874263SN/A{
23884263SN/A    if (txFifo.empty()) {
23895954SN/A        anWe("TXQ", "TX FIFO Q");
23904291SN/A        txFifoTick = false;
23914263SN/A        return;
23924263SN/A    }
23934263SN/A
23945339SN/A
23955954SN/A    anPq("TXQ", "TX FIFO Q");
23965339SN/A    if (etherInt->sendPacket(txFifo.front())) {
239710702SN/A        anQ("TXQ", "WireQ");
23984987SN/A        if (DTRACE(EthernetSM)) {
23994987SN/A            IpPtr ip(txFifo.front());
24004987SN/A            if (ip)
24014987SN/A                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
24024987SN/A                        ip->id());
24034987SN/A            else
24044987SN/A                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
24054987SN/A        }
24065954SN/A        anDq("TXQ", "TX FIFO Q");
24075954SN/A        anBegin("TXQ", "Wire Send");
24086124SN/A        DPRINTF(EthernetSM,
24096124SN/A                "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
24104263SN/A                txFifo.avail());
24115485SN/A
24125485SN/A        txBytes += txFifo.front()->length;
24135485SN/A        txPackets++;
24145538SN/A        txFifoTick = false;
24155485SN/A
24164263SN/A        txFifo.pop();
24175339SN/A    } else {
24185339SN/A        // We'll get woken up when the packet ethTxDone() gets called
24195339SN/A        txFifoTick = false;
24204263SN/A    }
24214263SN/A}
24224263SN/A
24234263SN/Avoid
24244263SN/AIGbE::tick()
24254263SN/A{
24264283SN/A    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
24274263SN/A
24284263SN/A    if (rxTick)
24294263SN/A        rxStateMachine();
24304263SN/A
24314291SN/A    if (txTick)
24324263SN/A        txStateMachine();
24334291SN/A
24344291SN/A    if (txFifoTick)
24354263SN/A        txWire();
24364263SN/A
24374291SN/A
24384291SN/A    if (rxTick || txTick || txFifoTick)
24399179SN/A        schedule(tickEvent, curTick() + clockPeriod());
24404263SN/A}
24413116SN/A
24423116SN/Avoid
24433116SN/AIGbE::ethTxDone()
24443116SN/A{
24455954SN/A    anBegin("TXQ", "Send Done");
24464291SN/A    // restart the tx state machines if they are stopped
24474291SN/A    // fifo to send another packet
24484291SN/A    // tx sm to put more data into the fifo
244910913SN/A    txFifoTick = true && drainState() != DrainState::Draining;
245010913SN/A    if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
24514987SN/A        txTick = true;
24524291SN/A
24534283SN/A    restartClock();
24545395SN/A    txWire();
24554294SN/A    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
24563116SN/A}
24573116SN/A
24583116SN/Avoid
245910905SN/AIGbE::serialize(CheckpointOut &cp) const
24603116SN/A{
246110905SN/A    PciDevice::serialize(cp);
24624294SN/A
246310905SN/A    regs.serialize(cp);
24644294SN/A    SERIALIZE_SCALAR(eeOpBits);
24654294SN/A    SERIALIZE_SCALAR(eeAddrBits);
24664294SN/A    SERIALIZE_SCALAR(eeDataBits);
24674294SN/A    SERIALIZE_SCALAR(eeOpcode);
24684294SN/A    SERIALIZE_SCALAR(eeAddr);
24695500SN/A    SERIALIZE_SCALAR(lastInterrupt);
24704294SN/A    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
24714294SN/A
247210905SN/A    rxFifo.serialize("rxfifo", cp);
247310905SN/A    txFifo.serialize("txfifo", cp);
24744294SN/A
247510469SN/A    bool txPktExists = txPacket != nullptr;
24764294SN/A    SERIALIZE_SCALAR(txPktExists);
24774294SN/A    if (txPktExists)
247810905SN/A        txPacket->serialize("txpacket", cp);
24794294SN/A
24804294SN/A    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
24816124SN/A        inter_time = 0;
24824294SN/A
24834294SN/A    if (rdtrEvent.scheduled())
24846124SN/A        rdtr_time = rdtrEvent.when();
24854294SN/A    SERIALIZE_SCALAR(rdtr_time);
24864294SN/A
24874294SN/A    if (radvEvent.scheduled())
24886124SN/A        radv_time = radvEvent.when();
24894294SN/A    SERIALIZE_SCALAR(radv_time);
24904294SN/A
24914294SN/A    if (tidvEvent.scheduled())
24926124SN/A        tidv_time = tidvEvent.when();
24934294SN/A    SERIALIZE_SCALAR(tidv_time);
24944294SN/A
24954294SN/A    if (tadvEvent.scheduled())
24966124SN/A        tadv_time = tadvEvent.when();
24974294SN/A    SERIALIZE_SCALAR(tadv_time);
24984294SN/A
24994294SN/A    if (interEvent.scheduled())
25006124SN/A        inter_time = interEvent.when();
25014294SN/A    SERIALIZE_SCALAR(inter_time);
25024294SN/A
25035783SN/A    SERIALIZE_SCALAR(pktOffset);
25045783SN/A
250510905SN/A    txDescCache.serializeSection(cp, "TxDescCache");
250610905SN/A    rxDescCache.serializeSection(cp, "RxDescCache");
25073116SN/A}
25083116SN/A
25093116SN/Avoid
251010905SN/AIGbE::unserialize(CheckpointIn &cp)
25113116SN/A{
251210905SN/A    PciDevice::unserialize(cp);
25134294SN/A
251410905SN/A    regs.unserialize(cp);
25154294SN/A    UNSERIALIZE_SCALAR(eeOpBits);
25164294SN/A    UNSERIALIZE_SCALAR(eeAddrBits);
25174294SN/A    UNSERIALIZE_SCALAR(eeDataBits);
25184294SN/A    UNSERIALIZE_SCALAR(eeOpcode);
25194294SN/A    UNSERIALIZE_SCALAR(eeAddr);
25205500SN/A    UNSERIALIZE_SCALAR(lastInterrupt);
25214294SN/A    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
25224294SN/A
252310905SN/A    rxFifo.unserialize("rxfifo", cp);
252410905SN/A    txFifo.unserialize("txfifo", cp);
25254294SN/A
25264294SN/A    bool txPktExists;
25274294SN/A    UNSERIALIZE_SCALAR(txPktExists);
25284294SN/A    if (txPktExists) {
252911719Smichael.lebeane@amd.com        txPacket = std::make_shared<EthPacketData>(16384);
253010905SN/A        txPacket->unserialize("txpacket", cp);
25314294SN/A    }
25324294SN/A
25334294SN/A    rxTick = true;
25344294SN/A    txTick = true;
25354294SN/A    txFifoTick = true;
25364294SN/A
25374294SN/A    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
25384294SN/A    UNSERIALIZE_SCALAR(rdtr_time);
25394294SN/A    UNSERIALIZE_SCALAR(radv_time);
25404294SN/A    UNSERIALIZE_SCALAR(tidv_time);
25414294SN/A    UNSERIALIZE_SCALAR(tadv_time);
25424294SN/A    UNSERIALIZE_SCALAR(inter_time);
25434294SN/A
25444294SN/A    if (rdtr_time)
25455606SN/A        schedule(rdtrEvent, rdtr_time);
25464294SN/A
25474294SN/A    if (radv_time)
25485606SN/A        schedule(radvEvent, radv_time);
25494294SN/A
25504294SN/A    if (tidv_time)
25515606SN/A        schedule(tidvEvent, tidv_time);
25524294SN/A
25534294SN/A    if (tadv_time)
25545606SN/A        schedule(tadvEvent, tadv_time);
25554294SN/A
25564294SN/A    if (inter_time)
25575606SN/A        schedule(interEvent, inter_time);
25584294SN/A
25595783SN/A    UNSERIALIZE_SCALAR(pktOffset);
25605783SN/A
256110905SN/A    txDescCache.unserializeSection(cp, "TxDescCache");
256210905SN/A    rxDescCache.unserializeSection(cp, "RxDescCache");
25633116SN/A}
25643116SN/A
25654762SN/AIGbE *
25664762SN/AIGbEParams::create()
25673116SN/A{
25684762SN/A    return new IGbE(this);
25693116SN/A}
2570