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