i8254xGBe.cc revision 5606
13569Sgblack@eecs.umich.edu/*
23569Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
33569Sgblack@eecs.umich.edu * All rights reserved.
43569Sgblack@eecs.umich.edu *
53569Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
63569Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
73569Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
83569Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
93569Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
103569Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
113569Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
123569Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
133569Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
143569Sgblack@eecs.umich.edu * this software without specific prior written permission.
153569Sgblack@eecs.umich.edu *
163569Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173569Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183569Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193569Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203569Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213569Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223569Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233569Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243569Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253569Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263569Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273569Sgblack@eecs.umich.edu *
283804Ssaidi@eecs.umich.edu * Authors: Ali Saidi
293569Sgblack@eecs.umich.edu */
303569Sgblack@eecs.umich.edu
313918Ssaidi@eecs.umich.edu/* @file
323918Ssaidi@eecs.umich.edu * Device model for Intel's 8254x line of gigabit ethernet controllers.
333804Ssaidi@eecs.umich.edu * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
343811Ssaidi@eecs.umich.edu * fewest workarounds in the driver. It will probably work with most of the
353569Sgblack@eecs.umich.edu * other MACs with slight modifications.
363824Ssaidi@eecs.umich.edu */
373811Ssaidi@eecs.umich.edu
383811Ssaidi@eecs.umich.edu
393823Ssaidi@eecs.umich.edu/*
403823Ssaidi@eecs.umich.edu * @todo really there are multiple dma engines.. we should implement them.
413823Ssaidi@eecs.umich.edu */
424103Ssaidi@eecs.umich.edu
433569Sgblack@eecs.umich.edu#include <algorithm>
443804Ssaidi@eecs.umich.edu
453804Ssaidi@eecs.umich.edu#include "base/inet.hh"
464088Sbinkertn@umich.edu#include "base/trace.hh"
473569Sgblack@eecs.umich.edu#include "dev/i8254xGBe.hh"
485034Smilesck@eecs.umich.edu#include "mem/packet.hh"
495034Smilesck@eecs.umich.edu#include "mem/packet_access.hh"
503881Ssaidi@eecs.umich.edu#include "params/IGbE.hh"
513804Ssaidi@eecs.umich.edu#include "sim/stats.hh"
523804Ssaidi@eecs.umich.edu#include "sim/system.hh"
533804Ssaidi@eecs.umich.edu
543804Ssaidi@eecs.umich.eduusing namespace iGbReg;
553569Sgblack@eecs.umich.eduusing namespace Net;
563804Ssaidi@eecs.umich.edu
573918Ssaidi@eecs.umich.eduIGbE::IGbE(const Params *p)
583881Ssaidi@eecs.umich.edu    : EtherDevice(p), etherInt(NULL),  drainEvent(NULL), useFlowControl(p->use_flow_control),
593881Ssaidi@eecs.umich.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
603881Ssaidi@eecs.umich.edu      txTick(false), txFifoTick(false), rxDmaPacket(false),
614990Sgblack@eecs.umich.edu      fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
624990Sgblack@eecs.umich.edu      fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
634990Sgblack@eecs.umich.edu      rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
644990Sgblack@eecs.umich.edu      rdtrEvent(this), radvEvent(this),
654990Sgblack@eecs.umich.edu      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
664990Sgblack@eecs.umich.edu      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
674990Sgblack@eecs.umich.edu      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
684990Sgblack@eecs.umich.edu      clock(p->clock), lastInterrupt(0)
694990Sgblack@eecs.umich.edu{
703804Ssaidi@eecs.umich.edu    etherInt = new IGbEInt(name() + ".int", this);
713569Sgblack@eecs.umich.edu
723804Ssaidi@eecs.umich.edu    // Initialized internal registers per Intel documentation
733804Ssaidi@eecs.umich.edu    // All registers intialized to 0 by per register constructor
743804Ssaidi@eecs.umich.edu    regs.ctrl.fd(1);
753804Ssaidi@eecs.umich.edu    regs.ctrl.lrst(1);
763881Ssaidi@eecs.umich.edu    regs.ctrl.speed(2);
773804Ssaidi@eecs.umich.edu    regs.ctrl.frcspd(1);
783804Ssaidi@eecs.umich.edu    regs.sts.speed(3); // Say we're 1000Mbps
793804Ssaidi@eecs.umich.edu    regs.sts.fd(1); // full duplex
803804Ssaidi@eecs.umich.edu    regs.sts.lu(1); // link up
813804Ssaidi@eecs.umich.edu    regs.eecd.fwe(1);
823804Ssaidi@eecs.umich.edu    regs.eecd.ee_type(1);
833804Ssaidi@eecs.umich.edu    regs.imr = 0;
843569Sgblack@eecs.umich.edu    regs.iam = 0;
853569Sgblack@eecs.umich.edu    regs.rxdctl.gran(1);
863804Ssaidi@eecs.umich.edu    regs.rxdctl.wthresh(1);
873804Ssaidi@eecs.umich.edu    regs.fcrth(1);
883826Ssaidi@eecs.umich.edu
893804Ssaidi@eecs.umich.edu    regs.pba.rxa(0x30);
903569Sgblack@eecs.umich.edu    regs.pba.txa(0x10);
913569Sgblack@eecs.umich.edu
923804Ssaidi@eecs.umich.edu    eeOpBits            = 0;
933826Ssaidi@eecs.umich.edu    eeAddrBits          = 0;
943907Ssaidi@eecs.umich.edu    eeDataBits          = 0;
953826Ssaidi@eecs.umich.edu    eeOpcode            = 0;
963811Ssaidi@eecs.umich.edu
973836Ssaidi@eecs.umich.edu    // clear all 64 16 bit words of the eeprom
983915Ssaidi@eecs.umich.edu    memset(&flash, 0, EEPROM_SIZE*2);
993907Ssaidi@eecs.umich.edu
1003881Ssaidi@eecs.umich.edu    // Set the MAC address
1013881Ssaidi@eecs.umich.edu    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
1023881Ssaidi@eecs.umich.edu    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
1033881Ssaidi@eecs.umich.edu        flash[x] = htobe(flash[x]);
1043907Ssaidi@eecs.umich.edu
1053881Ssaidi@eecs.umich.edu    uint16_t csum = 0;
1063881Ssaidi@eecs.umich.edu    for (int x = 0; x < EEPROM_SIZE; x++)
1073881Ssaidi@eecs.umich.edu        csum += htobe(flash[x]);
1083881Ssaidi@eecs.umich.edu
1093881Ssaidi@eecs.umich.edu
1103907Ssaidi@eecs.umich.edu    // Magic happy checksum value
1113907Ssaidi@eecs.umich.edu    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
1123907Ssaidi@eecs.umich.edu
1133907Ssaidi@eecs.umich.edu    rxFifo.clear();
1143907Ssaidi@eecs.umich.edu    txFifo.clear();
1153907Ssaidi@eecs.umich.edu}
1163907Ssaidi@eecs.umich.edu
1173907Ssaidi@eecs.umich.eduEtherInt*
1183907Ssaidi@eecs.umich.eduIGbE::getEthPort(const std::string &if_name, int idx)
1193907Ssaidi@eecs.umich.edu{
1203907Ssaidi@eecs.umich.edu
1213907Ssaidi@eecs.umich.edu    if (if_name == "interface") {
1223907Ssaidi@eecs.umich.edu        if (etherInt->getPeer())
1233907Ssaidi@eecs.umich.edu            panic("Port already connected to\n");
1243907Ssaidi@eecs.umich.edu        return etherInt;
1253907Ssaidi@eecs.umich.edu    }
1263907Ssaidi@eecs.umich.edu    return NULL;
1273907Ssaidi@eecs.umich.edu}
1283907Ssaidi@eecs.umich.edu
1293907Ssaidi@eecs.umich.eduTick
1303907Ssaidi@eecs.umich.eduIGbE::writeConfig(PacketPtr pkt)
1313907Ssaidi@eecs.umich.edu{
1323907Ssaidi@eecs.umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1333881Ssaidi@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
1343881Ssaidi@eecs.umich.edu        PciDev::writeConfig(pkt);
1353881Ssaidi@eecs.umich.edu    else
1363881Ssaidi@eecs.umich.edu        panic("Device specific PCI config space not implemented.\n");
1373881Ssaidi@eecs.umich.edu
1383881Ssaidi@eecs.umich.edu    ///
1393881Ssaidi@eecs.umich.edu    /// Some work may need to be done here based for the pci COMMAND bits.
1403881Ssaidi@eecs.umich.edu    ///
1413881Ssaidi@eecs.umich.edu
1423881Ssaidi@eecs.umich.edu    return pioDelay;
1433881Ssaidi@eecs.umich.edu}
1443881Ssaidi@eecs.umich.edu
1453907Ssaidi@eecs.umich.eduTick
1463811Ssaidi@eecs.umich.eduIGbE::read(PacketPtr pkt)
1473826Ssaidi@eecs.umich.edu{
1483826Ssaidi@eecs.umich.edu    int bar;
1493826Ssaidi@eecs.umich.edu    Addr daddr;
1503826Ssaidi@eecs.umich.edu
1513881Ssaidi@eecs.umich.edu    if (!getBAR(pkt->getAddr(), bar, daddr))
1523881Ssaidi@eecs.umich.edu        panic("Invalid PCI memory access to unmapped memory.\n");
1533881Ssaidi@eecs.umich.edu
1543881Ssaidi@eecs.umich.edu    // Only Memory register BAR is allowed
1553881Ssaidi@eecs.umich.edu    assert(bar == 0);
1563881Ssaidi@eecs.umich.edu
1573881Ssaidi@eecs.umich.edu    // Only 32bit accesses allowed
1583881Ssaidi@eecs.umich.edu    assert(pkt->getSize() == 4);
1593881Ssaidi@eecs.umich.edu
1603881Ssaidi@eecs.umich.edu    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
1613881Ssaidi@eecs.umich.edu
1623881Ssaidi@eecs.umich.edu    pkt->allocate();
1633881Ssaidi@eecs.umich.edu
1643881Ssaidi@eecs.umich.edu    ///
1653881Ssaidi@eecs.umich.edu    /// Handle read of register here
1663826Ssaidi@eecs.umich.edu    ///
1673826Ssaidi@eecs.umich.edu
1683826Ssaidi@eecs.umich.edu
1693826Ssaidi@eecs.umich.edu    switch (daddr) {
1703826Ssaidi@eecs.umich.edu      case REG_CTRL:
1713881Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.ctrl());
1723569Sgblack@eecs.umich.edu        break;
1733569Sgblack@eecs.umich.edu      case REG_STATUS:
1743881Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.sts());
1753804Ssaidi@eecs.umich.edu        break;
1763881Ssaidi@eecs.umich.edu      case REG_EECD:
1773826Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.eecd());
1783881Ssaidi@eecs.umich.edu        break;
1793881Ssaidi@eecs.umich.edu      case REG_EERD:
1803881Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.eerd());
1813907Ssaidi@eecs.umich.edu        break;
1823907Ssaidi@eecs.umich.edu      case REG_CTRL_EXT:
1833929Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.ctrl_ext());
1843929Ssaidi@eecs.umich.edu        break;
1853907Ssaidi@eecs.umich.edu      case REG_MDIC:
1863907Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.mdic());
1873804Ssaidi@eecs.umich.edu        break;
1883804Ssaidi@eecs.umich.edu      case REG_ICR:
1893881Ssaidi@eecs.umich.edu        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
1903804Ssaidi@eecs.umich.edu                regs.imr, regs.iam, regs.ctrl_ext.iame());
1913804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.icr());
1923804Ssaidi@eecs.umich.edu        if (regs.icr.int_assert() || regs.imr == 0) {
1933804Ssaidi@eecs.umich.edu            regs.icr = regs.icr() & ~mask(30);
1943804Ssaidi@eecs.umich.edu            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
1953804Ssaidi@eecs.umich.edu        }
1963804Ssaidi@eecs.umich.edu        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
1973569Sgblack@eecs.umich.edu            regs.imr &= ~regs.iam;
1983569Sgblack@eecs.umich.edu        chkInterrupt();
1993569Sgblack@eecs.umich.edu        break;
2003863Ssaidi@eecs.umich.edu      case REG_ITR:
2013863Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.itr());
2023804Ssaidi@eecs.umich.edu        break;
2033804Ssaidi@eecs.umich.edu      case REG_RCTL:
2043804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rctl());
2053804Ssaidi@eecs.umich.edu        break;
2063804Ssaidi@eecs.umich.edu      case REG_FCTTV:
2073804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.fcttv());
2083804Ssaidi@eecs.umich.edu        break;
2093804Ssaidi@eecs.umich.edu      case REG_TCTL:
2103804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tctl());
2113569Sgblack@eecs.umich.edu        break;
2123804Ssaidi@eecs.umich.edu      case REG_PBA:
2133804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.pba());
2143804Ssaidi@eecs.umich.edu        break;
2154070Ssaidi@eecs.umich.edu      case REG_WUC:
2164070Ssaidi@eecs.umich.edu      case REG_LEDCTL:
2173804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(0); // We don't care, so just return 0
2183804Ssaidi@eecs.umich.edu        break;
2193804Ssaidi@eecs.umich.edu      case REG_FCRTL:
2203804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.fcrtl());
2213804Ssaidi@eecs.umich.edu        break;
2223811Ssaidi@eecs.umich.edu      case REG_FCRTH:
2233811Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.fcrth());
2243804Ssaidi@eecs.umich.edu        break;
2253804Ssaidi@eecs.umich.edu      case REG_RDBAL:
2263863Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rdba.rdbal());
2273804Ssaidi@eecs.umich.edu        break;
2283804Ssaidi@eecs.umich.edu      case REG_RDBAH:
2293804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rdba.rdbah());
2303804Ssaidi@eecs.umich.edu        break;
2313804Ssaidi@eecs.umich.edu      case REG_RDLEN:
2323804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rdlen());
2333804Ssaidi@eecs.umich.edu        break;
2343811Ssaidi@eecs.umich.edu      case REG_RDH:
2353804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rdh());
2363804Ssaidi@eecs.umich.edu        break;
2373804Ssaidi@eecs.umich.edu      case REG_RDT:
2383804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rdt());
2393804Ssaidi@eecs.umich.edu        break;
2403826Ssaidi@eecs.umich.edu      case REG_RDTR:
2413826Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rdtr());
2424070Ssaidi@eecs.umich.edu        if (regs.rdtr.fpd()) {
2434070Ssaidi@eecs.umich.edu            rxDescCache.writeback(0);
2444070Ssaidi@eecs.umich.edu            DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n");
2454070Ssaidi@eecs.umich.edu            postInterrupt(IT_RXT);
2463804Ssaidi@eecs.umich.edu            regs.rdtr.fpd(0);
2473804Ssaidi@eecs.umich.edu        }
2483804Ssaidi@eecs.umich.edu        break;
2493804Ssaidi@eecs.umich.edu      case REG_RADV:
2503804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.radv());
2513804Ssaidi@eecs.umich.edu        break;
2523804Ssaidi@eecs.umich.edu      case REG_TDBAL:
2533804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tdba.tdbal());
2543804Ssaidi@eecs.umich.edu        break;
2553804Ssaidi@eecs.umich.edu      case REG_TDBAH:
2563804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tdba.tdbah());
2573804Ssaidi@eecs.umich.edu        break;
2583826Ssaidi@eecs.umich.edu      case REG_TDLEN:
2593826Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tdlen());
2603826Ssaidi@eecs.umich.edu        break;
2613863Ssaidi@eecs.umich.edu      case REG_TDH:
2623826Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tdh());
2633826Ssaidi@eecs.umich.edu        break;
2643826Ssaidi@eecs.umich.edu      case REG_TDT:
2653826Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tdt());
2663826Ssaidi@eecs.umich.edu        break;
2673826Ssaidi@eecs.umich.edu      case REG_TIDV:
2683826Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tidv());
2693826Ssaidi@eecs.umich.edu        break;
2703826Ssaidi@eecs.umich.edu      case REG_TXDCTL:
2713804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.txdctl());
2723804Ssaidi@eecs.umich.edu        break;
2733804Ssaidi@eecs.umich.edu      case REG_TADV:
2743804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.tadv());
2753804Ssaidi@eecs.umich.edu        break;
2763804Ssaidi@eecs.umich.edu      case REG_RXCSUM:
2773804Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.rxcsum());
2783863Ssaidi@eecs.umich.edu        break;
2793863Ssaidi@eecs.umich.edu      case REG_MANC:
2803863Ssaidi@eecs.umich.edu        pkt->set<uint32_t>(regs.manc());
2813836Ssaidi@eecs.umich.edu        break;
2823836Ssaidi@eecs.umich.edu      default:
2833804Ssaidi@eecs.umich.edu        if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
2843804Ssaidi@eecs.umich.edu            !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
2853863Ssaidi@eecs.umich.edu            !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) &&
2863804Ssaidi@eecs.umich.edu            !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE)))
2873804Ssaidi@eecs.umich.edu            panic("Read request to unknown register number: %#x\n", daddr);
2883804Ssaidi@eecs.umich.edu        else
2893804Ssaidi@eecs.umich.edu            pkt->set<uint32_t>(0);
2903804Ssaidi@eecs.umich.edu    };
2913804Ssaidi@eecs.umich.edu
2923804Ssaidi@eecs.umich.edu    pkt->makeAtomicResponse();
2933863Ssaidi@eecs.umich.edu    return pioDelay;
2943804Ssaidi@eecs.umich.edu}
2953804Ssaidi@eecs.umich.edu
2963804Ssaidi@eecs.umich.eduTick
2973804Ssaidi@eecs.umich.eduIGbE::write(PacketPtr pkt)
2983804Ssaidi@eecs.umich.edu{
2993881Ssaidi@eecs.umich.edu    int bar;
3003804Ssaidi@eecs.umich.edu    Addr daddr;
3013804Ssaidi@eecs.umich.edu
3023804Ssaidi@eecs.umich.edu
3033804Ssaidi@eecs.umich.edu    if (!getBAR(pkt->getAddr(), bar, daddr))
3043804Ssaidi@eecs.umich.edu        panic("Invalid PCI memory access to unmapped memory.\n");
3053804Ssaidi@eecs.umich.edu
3063804Ssaidi@eecs.umich.edu    // Only Memory register BAR is allowed
3073804Ssaidi@eecs.umich.edu    assert(bar == 0);
3083863Ssaidi@eecs.umich.edu
3093863Ssaidi@eecs.umich.edu    // Only 32bit accesses allowed
3103836Ssaidi@eecs.umich.edu    assert(pkt->getSize() == sizeof(uint32_t));
3113804Ssaidi@eecs.umich.edu
3123804Ssaidi@eecs.umich.edu    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
3133804Ssaidi@eecs.umich.edu
3143881Ssaidi@eecs.umich.edu    ///
3153881Ssaidi@eecs.umich.edu    /// Handle write of register here
3163881Ssaidi@eecs.umich.edu    ///
3173804Ssaidi@eecs.umich.edu    uint32_t val = pkt->get<uint32_t>();
3183804Ssaidi@eecs.umich.edu
3193804Ssaidi@eecs.umich.edu    Regs::RCTL oldrctl;
3203804Ssaidi@eecs.umich.edu    Regs::TCTL oldtctl;
3213804Ssaidi@eecs.umich.edu
3223804Ssaidi@eecs.umich.edu    switch (daddr) {
3233804Ssaidi@eecs.umich.edu      case REG_CTRL:
3243804Ssaidi@eecs.umich.edu        regs.ctrl = val;
3253804Ssaidi@eecs.umich.edu        if (regs.ctrl.tfce())
3263804Ssaidi@eecs.umich.edu            warn("TX Flow control enabled, should implement\n");
3273804Ssaidi@eecs.umich.edu        if (regs.ctrl.rfce())
3283804Ssaidi@eecs.umich.edu            warn("RX Flow control enabled, should implement\n");
3293804Ssaidi@eecs.umich.edu        break;
3303804Ssaidi@eecs.umich.edu      case REG_CTRL_EXT:
3313863Ssaidi@eecs.umich.edu        regs.ctrl_ext = val;
3323836Ssaidi@eecs.umich.edu        break;
3333804Ssaidi@eecs.umich.edu      case REG_STATUS:
3343804Ssaidi@eecs.umich.edu        regs.sts = val;
3353881Ssaidi@eecs.umich.edu        break;
3363881Ssaidi@eecs.umich.edu      case REG_EECD:
3373881Ssaidi@eecs.umich.edu        int oldClk;
3383804Ssaidi@eecs.umich.edu        oldClk = regs.eecd.sk();
3393804Ssaidi@eecs.umich.edu        regs.eecd = val;
3403804Ssaidi@eecs.umich.edu        // See if this is a eeprom access and emulate accordingly
3413804Ssaidi@eecs.umich.edu        if (!oldClk && regs.eecd.sk()) {
3423804Ssaidi@eecs.umich.edu            if (eeOpBits < 8) {
3433804Ssaidi@eecs.umich.edu                eeOpcode = eeOpcode << 1 | regs.eecd.din();
3443804Ssaidi@eecs.umich.edu                eeOpBits++;
3453804Ssaidi@eecs.umich.edu            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
3463804Ssaidi@eecs.umich.edu                eeAddr = eeAddr << 1 | regs.eecd.din();
3473804Ssaidi@eecs.umich.edu                eeAddrBits++;
3483804Ssaidi@eecs.umich.edu            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
3493804Ssaidi@eecs.umich.edu                assert(eeAddr>>1 < EEPROM_SIZE);
3503804Ssaidi@eecs.umich.edu                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
3513804Ssaidi@eecs.umich.edu                        flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]);
3523836Ssaidi@eecs.umich.edu                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
3533836Ssaidi@eecs.umich.edu                eeDataBits++;
3543881Ssaidi@eecs.umich.edu            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
3553907Ssaidi@eecs.umich.edu                regs.eecd.dout(0);
3563804Ssaidi@eecs.umich.edu                eeDataBits++;
3573881Ssaidi@eecs.umich.edu            } else
3583881Ssaidi@eecs.umich.edu                panic("What's going on with eeprom interface? opcode:"
3593804Ssaidi@eecs.umich.edu                       " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
3603907Ssaidi@eecs.umich.edu                       (uint32_t)eeOpBits, (uint32_t)eeAddr,
3613804Ssaidi@eecs.umich.edu                       (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
3623804Ssaidi@eecs.umich.edu
3633804Ssaidi@eecs.umich.edu            // Reset everything for the next command
3643804Ssaidi@eecs.umich.edu            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
3653804Ssaidi@eecs.umich.edu               (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
3663804Ssaidi@eecs.umich.edu                eeOpBits = 0;
3673881Ssaidi@eecs.umich.edu                eeAddrBits = 0;
3683881Ssaidi@eecs.umich.edu                eeDataBits = 0;
3693881Ssaidi@eecs.umich.edu               eeOpcode = 0;
3703804Ssaidi@eecs.umich.edu                eeAddr = 0;
3713881Ssaidi@eecs.umich.edu            }
3723881Ssaidi@eecs.umich.edu
3733881Ssaidi@eecs.umich.edu           DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
3743881Ssaidi@eecs.umich.edu                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
3753804Ssaidi@eecs.umich.edu                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
3763804Ssaidi@eecs.umich.edu           if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
3773804Ssaidi@eecs.umich.edu                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
3783804Ssaidi@eecs.umich.edu                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
3793804Ssaidi@eecs.umich.edu                        (uint32_t)eeOpBits);
3803804Ssaidi@eecs.umich.edu
3813881Ssaidi@eecs.umich.edu
3823881Ssaidi@eecs.umich.edu        }
3833804Ssaidi@eecs.umich.edu        // If driver requests eeprom access, immediately give it to it
3843881Ssaidi@eecs.umich.edu        regs.eecd.ee_gnt(regs.eecd.ee_req());
3853881Ssaidi@eecs.umich.edu        break;
3863881Ssaidi@eecs.umich.edu      case REG_EERD:
3873804Ssaidi@eecs.umich.edu        regs.eerd = val;
3883804Ssaidi@eecs.umich.edu        break;
3893804Ssaidi@eecs.umich.edu      case REG_MDIC:
3903804Ssaidi@eecs.umich.edu        regs.mdic = val;
3913804Ssaidi@eecs.umich.edu        if (regs.mdic.i())
3923804Ssaidi@eecs.umich.edu            panic("No support for interrupt on mdic complete\n");
3933804Ssaidi@eecs.umich.edu        if (regs.mdic.phyadd() != 1)
3943804Ssaidi@eecs.umich.edu            panic("No support for reading anything but phy\n");
3953804Ssaidi@eecs.umich.edu        DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing"
3963804Ssaidi@eecs.umich.edu                : "Reading", regs.mdic.regadd());
3973804Ssaidi@eecs.umich.edu        switch (regs.mdic.regadd()) {
3983804Ssaidi@eecs.umich.edu            case PHY_PSTATUS:
3993804Ssaidi@eecs.umich.edu                regs.mdic.data(0x796D); // link up
4003804Ssaidi@eecs.umich.edu                break;
4013804Ssaidi@eecs.umich.edu            case PHY_PID:
4023804Ssaidi@eecs.umich.edu                regs.mdic.data(0x02A8);
4034990Sgblack@eecs.umich.edu                break;
4043804Ssaidi@eecs.umich.edu            case PHY_EPID:
4053804Ssaidi@eecs.umich.edu                regs.mdic.data(0x0380);
4063804Ssaidi@eecs.umich.edu                break;
4073804Ssaidi@eecs.umich.edu            case PHY_GSTATUS:
4083804Ssaidi@eecs.umich.edu                regs.mdic.data(0x7C00);
4093804Ssaidi@eecs.umich.edu                break;
4103804Ssaidi@eecs.umich.edu            case PHY_EPSTATUS:
4113804Ssaidi@eecs.umich.edu                regs.mdic.data(0x3000);
4123804Ssaidi@eecs.umich.edu                break;
4133804Ssaidi@eecs.umich.edu            case PHY_AGC:
4143804Ssaidi@eecs.umich.edu                regs.mdic.data(0x180); // some random length
4153804Ssaidi@eecs.umich.edu                break;
4163804Ssaidi@eecs.umich.edu            default:
4173804Ssaidi@eecs.umich.edu                regs.mdic.data(0);
4183804Ssaidi@eecs.umich.edu        }
4193826Ssaidi@eecs.umich.edu        regs.mdic.r(1);
4204990Sgblack@eecs.umich.edu        break;
4213826Ssaidi@eecs.umich.edu      case REG_ICR:
4223916Ssaidi@eecs.umich.edu        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
4233916Ssaidi@eecs.umich.edu                regs.imr, regs.iam, regs.ctrl_ext.iame());
4243916Ssaidi@eecs.umich.edu        if (regs.ctrl_ext.iame())
4254990Sgblack@eecs.umich.edu            regs.imr &= ~regs.iam;
4263826Ssaidi@eecs.umich.edu        regs.icr = ~bits(val,30,0) & regs.icr();
4273804Ssaidi@eecs.umich.edu        chkInterrupt();
4283804Ssaidi@eecs.umich.edu        break;
4294990Sgblack@eecs.umich.edu      case REG_ITR:
4303804Ssaidi@eecs.umich.edu        regs.itr = val;
4313811Ssaidi@eecs.umich.edu        break;
4323811Ssaidi@eecs.umich.edu      case REG_ICS:
4334990Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
4343804Ssaidi@eecs.umich.edu        postInterrupt((IntTypes)val);
4353804Ssaidi@eecs.umich.edu        break;
4363804Ssaidi@eecs.umich.edu       case REG_IMS:
4374990Sgblack@eecs.umich.edu        regs.imr |= val;
4383804Ssaidi@eecs.umich.edu        chkInterrupt();
4393804Ssaidi@eecs.umich.edu        break;
4403811Ssaidi@eecs.umich.edu      case REG_IMC:
4413811Ssaidi@eecs.umich.edu        regs.imr &= ~val;
4424990Sgblack@eecs.umich.edu        chkInterrupt();
4434990Sgblack@eecs.umich.edu        break;
4443804Ssaidi@eecs.umich.edu      case REG_IAM:
4453804Ssaidi@eecs.umich.edu        regs.iam = val;
4463804Ssaidi@eecs.umich.edu        break;
4473804Ssaidi@eecs.umich.edu      case REG_RCTL:
4483804Ssaidi@eecs.umich.edu        oldrctl = regs.rctl;
4494172Ssaidi@eecs.umich.edu        regs.rctl = val;
4503833Ssaidi@eecs.umich.edu        if (regs.rctl.rst()) {
4513836Ssaidi@eecs.umich.edu            rxDescCache.reset();
4523836Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
4533836Ssaidi@eecs.umich.edu            rxFifo.clear();
4543836Ssaidi@eecs.umich.edu            regs.rctl.rst(0);
4553836Ssaidi@eecs.umich.edu        }
4563836Ssaidi@eecs.umich.edu        if (regs.rctl.en())
4573836Ssaidi@eecs.umich.edu            rxTick = true;
4583836Ssaidi@eecs.umich.edu        restartClock();
4593836Ssaidi@eecs.umich.edu        break;
4603836Ssaidi@eecs.umich.edu      case REG_FCTTV:
4613836Ssaidi@eecs.umich.edu        regs.fcttv = val;
4623836Ssaidi@eecs.umich.edu        break;
4633836Ssaidi@eecs.umich.edu      case REG_TCTL:
4643836Ssaidi@eecs.umich.edu        regs.tctl = val;
4653836Ssaidi@eecs.umich.edu        oldtctl = regs.tctl;
4663836Ssaidi@eecs.umich.edu        regs.tctl = val;
4673836Ssaidi@eecs.umich.edu        if (regs.tctl.en())
4683836Ssaidi@eecs.umich.edu           txTick = true;
4693836Ssaidi@eecs.umich.edu        restartClock();
4703836Ssaidi@eecs.umich.edu        if (regs.tctl.en() && !oldtctl.en()) {
4713836Ssaidi@eecs.umich.edu            txDescCache.reset();
4723836Ssaidi@eecs.umich.edu        }
4733836Ssaidi@eecs.umich.edu         break;
4743833Ssaidi@eecs.umich.edu      case REG_PBA:
4753833Ssaidi@eecs.umich.edu        regs.pba.rxa(val);
4763833Ssaidi@eecs.umich.edu        regs.pba.txa(64 - regs.pba.rxa());
4773833Ssaidi@eecs.umich.edu        break;
4783833Ssaidi@eecs.umich.edu      case REG_WUC:
4793833Ssaidi@eecs.umich.edu      case REG_LEDCTL:
4803833Ssaidi@eecs.umich.edu      case REG_FCAL:
4813833Ssaidi@eecs.umich.edu      case REG_FCAH:
4823833Ssaidi@eecs.umich.edu      case REG_FCT:
4833804Ssaidi@eecs.umich.edu      case REG_VET:
4843804Ssaidi@eecs.umich.edu      case REG_AIFS:
4853804Ssaidi@eecs.umich.edu      case REG_TIPG:
4863804Ssaidi@eecs.umich.edu        ; // We don't care, so don't store anything
4873804Ssaidi@eecs.umich.edu        break;
4883833Ssaidi@eecs.umich.edu      case REG_FCRTL:
4893833Ssaidi@eecs.umich.edu        regs.fcrtl = val;
4903811Ssaidi@eecs.umich.edu        break;
4913804Ssaidi@eecs.umich.edu      case REG_FCRTH:
4923804Ssaidi@eecs.umich.edu        regs.fcrth = val;
4933804Ssaidi@eecs.umich.edu        break;
4943804Ssaidi@eecs.umich.edu      case REG_RDBAL:
4953804Ssaidi@eecs.umich.edu        regs.rdba.rdbal( val & ~mask(4));
4963804Ssaidi@eecs.umich.edu        rxDescCache.areaChanged();
4973804Ssaidi@eecs.umich.edu        break;
4983833Ssaidi@eecs.umich.edu      case REG_RDBAH:
4993804Ssaidi@eecs.umich.edu        regs.rdba.rdbah(val);
5003804Ssaidi@eecs.umich.edu        rxDescCache.areaChanged();
5013833Ssaidi@eecs.umich.edu        break;
5023836Ssaidi@eecs.umich.edu      case REG_RDLEN:
5033836Ssaidi@eecs.umich.edu        regs.rdlen = val & ~mask(7);
5043836Ssaidi@eecs.umich.edu        rxDescCache.areaChanged();
5053836Ssaidi@eecs.umich.edu        break;
5063804Ssaidi@eecs.umich.edu      case REG_RDH:
5073804Ssaidi@eecs.umich.edu        regs.rdh = val;
5083804Ssaidi@eecs.umich.edu        rxDescCache.areaChanged();
5093836Ssaidi@eecs.umich.edu        break;
5103836Ssaidi@eecs.umich.edu      case REG_RDT:
5114990Sgblack@eecs.umich.edu        regs.rdt = val;
5123804Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
5133804Ssaidi@eecs.umich.edu        if (getState() == SimObject::Running) {
5143804Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
5153804Ssaidi@eecs.umich.edu            rxDescCache.fetchDescriptors();
5163804Ssaidi@eecs.umich.edu        } else {
5173804Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
5183804Ssaidi@eecs.umich.edu        }
5194990Sgblack@eecs.umich.edu        break;
5203804Ssaidi@eecs.umich.edu      case REG_RDTR:
5213804Ssaidi@eecs.umich.edu        regs.rdtr = val;
5223804Ssaidi@eecs.umich.edu        break;
5233833Ssaidi@eecs.umich.edu      case REG_RADV:
5243836Ssaidi@eecs.umich.edu        regs.radv = val;
5253804Ssaidi@eecs.umich.edu        break;
5263804Ssaidi@eecs.umich.edu      case REG_TDBAL:
5273804Ssaidi@eecs.umich.edu        regs.tdba.tdbal( val & ~mask(4));
5283804Ssaidi@eecs.umich.edu        txDescCache.areaChanged();
5293804Ssaidi@eecs.umich.edu        break;
5303804Ssaidi@eecs.umich.edu      case REG_TDBAH:
5313804Ssaidi@eecs.umich.edu        regs.tdba.tdbah(val);
5324990Sgblack@eecs.umich.edu        txDescCache.areaChanged();
5333804Ssaidi@eecs.umich.edu        break;
5343804Ssaidi@eecs.umich.edu      case REG_TDLEN:
5353804Ssaidi@eecs.umich.edu        regs.tdlen = val & ~mask(7);
5364997Sgblack@eecs.umich.edu        txDescCache.areaChanged();
5373804Ssaidi@eecs.umich.edu        break;
5384997Sgblack@eecs.umich.edu      case REG_TDH:
5394997Sgblack@eecs.umich.edu        regs.tdh = val;
5404997Sgblack@eecs.umich.edu        txDescCache.areaChanged();
5413804Ssaidi@eecs.umich.edu        break;
5423804Ssaidi@eecs.umich.edu      case REG_TDT:
5433804Ssaidi@eecs.umich.edu        regs.tdt = val;
5443804Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
5454990Sgblack@eecs.umich.edu        if (getState() == SimObject::Running) {
5464990Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
5473804Ssaidi@eecs.umich.edu            txDescCache.fetchDescriptors();
5483804Ssaidi@eecs.umich.edu        } else {
5493804Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
5503836Ssaidi@eecs.umich.edu        }
5513836Ssaidi@eecs.umich.edu        break;
5523836Ssaidi@eecs.umich.edu      case REG_TIDV:
5533836Ssaidi@eecs.umich.edu        regs.tidv = val;
5543836Ssaidi@eecs.umich.edu        break;
5553826Ssaidi@eecs.umich.edu      case REG_TXDCTL:
5563836Ssaidi@eecs.umich.edu        regs.txdctl = val;
5573836Ssaidi@eecs.umich.edu        break;
5583804Ssaidi@eecs.umich.edu      case REG_TADV:
5593804Ssaidi@eecs.umich.edu        regs.tadv = val;
5603804Ssaidi@eecs.umich.edu        break;
5613804Ssaidi@eecs.umich.edu      case REG_RXCSUM:
5623804Ssaidi@eecs.umich.edu        regs.rxcsum = val;
5633804Ssaidi@eecs.umich.edu        break;
5643804Ssaidi@eecs.umich.edu      case REG_MANC:
5653804Ssaidi@eecs.umich.edu        regs.manc = val;
5663804Ssaidi@eecs.umich.edu        break;
5674172Ssaidi@eecs.umich.edu      default:
5683836Ssaidi@eecs.umich.edu       if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
5693836Ssaidi@eecs.umich.edu           !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
5703836Ssaidi@eecs.umich.edu           !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)))
5713836Ssaidi@eecs.umich.edu           panic("Write request to unknown register number: %#x\n", daddr);
5723836Ssaidi@eecs.umich.edu    };
5733836Ssaidi@eecs.umich.edu
5744996Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
5753833Ssaidi@eecs.umich.edu    return pioDelay;
5763836Ssaidi@eecs.umich.edu}
5773836Ssaidi@eecs.umich.edu
5783836Ssaidi@eecs.umich.eduvoid
5793929Ssaidi@eecs.umich.eduIGbE::postInterrupt(IntTypes t, bool now)
5803929Ssaidi@eecs.umich.edu{
5813929Ssaidi@eecs.umich.edu    assert(t);
5823836Ssaidi@eecs.umich.edu
5833836Ssaidi@eecs.umich.edu    // Interrupt is already pending
5843836Ssaidi@eecs.umich.edu    if (t & regs.icr() && !now)
5854996Sgblack@eecs.umich.edu        return;
5864996Sgblack@eecs.umich.edu
5874996Sgblack@eecs.umich.edu    regs.icr = regs.icr() | t;
5884996Sgblack@eecs.umich.edu
5894996Sgblack@eecs.umich.edu    Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval();
5904996Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n",
5914996Sgblack@eecs.umich.edu            curTick, regs.itr.interval(), itr_interval);
5924996Sgblack@eecs.umich.edu
5934996Sgblack@eecs.umich.edu    if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) {
5944996Sgblack@eecs.umich.edu        if (interEvent.scheduled()) {
5954996Sgblack@eecs.umich.edu            deschedule(interEvent);
5964996Sgblack@eecs.umich.edu        }
5974996Sgblack@eecs.umich.edu        cpuPostInt();
5984996Sgblack@eecs.umich.edu    } else {
5994996Sgblack@eecs.umich.edu       Tick int_time = lastInterrupt + itr_interval;
6004996Sgblack@eecs.umich.edu       assert(int_time > 0);
6014996Sgblack@eecs.umich.edu       DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
6024996Sgblack@eecs.umich.edu                int_time);
6034996Sgblack@eecs.umich.edu       if (!interEvent.scheduled()) {
6044996Sgblack@eecs.umich.edu           schedule(interEvent, int_time);
6054996Sgblack@eecs.umich.edu       }
6064996Sgblack@eecs.umich.edu    }
6074996Sgblack@eecs.umich.edu}
6084996Sgblack@eecs.umich.edu
6094996Sgblack@eecs.umich.eduvoid
6104996Sgblack@eecs.umich.eduIGbE::delayIntEvent()
6114996Sgblack@eecs.umich.edu{
6124996Sgblack@eecs.umich.edu    cpuPostInt();
6134996Sgblack@eecs.umich.edu}
6144996Sgblack@eecs.umich.edu
6154996Sgblack@eecs.umich.edu
6164996Sgblack@eecs.umich.eduvoid
6174996Sgblack@eecs.umich.eduIGbE::cpuPostInt()
6184996Sgblack@eecs.umich.edu{
6194996Sgblack@eecs.umich.edu
6204996Sgblack@eecs.umich.edu    postedInterrupts++;
6214996Sgblack@eecs.umich.edu
6224996Sgblack@eecs.umich.edu    if (!(regs.icr() & regs.imr)) {
6234996Sgblack@eecs.umich.edu        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
6244996Sgblack@eecs.umich.edu        return;
6253836Ssaidi@eecs.umich.edu    }
6263836Ssaidi@eecs.umich.edu
6273833Ssaidi@eecs.umich.edu    DPRINTF(Ethernet, "Posting Interrupt\n");
6283833Ssaidi@eecs.umich.edu
6293833Ssaidi@eecs.umich.edu
6303833Ssaidi@eecs.umich.edu    if (interEvent.scheduled()) {
6313833Ssaidi@eecs.umich.edu        deschedule(interEvent);
6323833Ssaidi@eecs.umich.edu    }
6333833Ssaidi@eecs.umich.edu
6343833Ssaidi@eecs.umich.edu    if (rdtrEvent.scheduled()) {
6353916Ssaidi@eecs.umich.edu        regs.icr.rxt0(1);
6363833Ssaidi@eecs.umich.edu        deschedule(rdtrEvent);
6373804Ssaidi@eecs.umich.edu    }
6383832Ssaidi@eecs.umich.edu    if (radvEvent.scheduled()) {
6393832Ssaidi@eecs.umich.edu        regs.icr.rxt0(1);
6403804Ssaidi@eecs.umich.edu        deschedule(radvEvent);
6413804Ssaidi@eecs.umich.edu    }
6423804Ssaidi@eecs.umich.edu    if (tadvEvent.scheduled()) {
6433833Ssaidi@eecs.umich.edu        regs.icr.txdw(1);
6443833Ssaidi@eecs.umich.edu        deschedule(tadvEvent);
6453804Ssaidi@eecs.umich.edu    }
6463804Ssaidi@eecs.umich.edu    if (tidvEvent.scheduled()) {
6473804Ssaidi@eecs.umich.edu        regs.icr.txdw(1);
6483804Ssaidi@eecs.umich.edu        deschedule(tidvEvent);
6493804Ssaidi@eecs.umich.edu    }
6503804Ssaidi@eecs.umich.edu
6513804Ssaidi@eecs.umich.edu    regs.icr.int_assert(1);
6523804Ssaidi@eecs.umich.edu    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
6533804Ssaidi@eecs.umich.edu            regs.icr());
6543833Ssaidi@eecs.umich.edu
6553804Ssaidi@eecs.umich.edu    intrPost();
6563910Ssaidi@eecs.umich.edu
6573804Ssaidi@eecs.umich.edu    lastInterrupt = curTick;
6583910Ssaidi@eecs.umich.edu}
6593804Ssaidi@eecs.umich.edu
6604990Sgblack@eecs.umich.eduvoid
6613804Ssaidi@eecs.umich.eduIGbE::cpuClearInt()
6623804Ssaidi@eecs.umich.edu{
6633910Ssaidi@eecs.umich.edu    if (regs.icr.int_assert()) {
6643910Ssaidi@eecs.umich.edu        regs.icr.int_assert(0);
6654990Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
6663804Ssaidi@eecs.umich.edu                regs.icr());
6673804Ssaidi@eecs.umich.edu        intrClear();
6683804Ssaidi@eecs.umich.edu    }
6693910Ssaidi@eecs.umich.edu}
6703910Ssaidi@eecs.umich.edu
6713910Ssaidi@eecs.umich.eduvoid
6723910Ssaidi@eecs.umich.eduIGbE::chkInterrupt()
6733910Ssaidi@eecs.umich.edu{
6743910Ssaidi@eecs.umich.edu    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
6753910Ssaidi@eecs.umich.edu            regs.imr);
6763910Ssaidi@eecs.umich.edu    // Check if we need to clear the cpu interrupt
6773910Ssaidi@eecs.umich.edu    if (!(regs.icr() & regs.imr)) {
6783910Ssaidi@eecs.umich.edu        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
6793910Ssaidi@eecs.umich.edu        if (interEvent.scheduled())
6803910Ssaidi@eecs.umich.edu           deschedule(interEvent);
6813910Ssaidi@eecs.umich.edu        if (regs.icr.int_assert())
6823902Ssaidi@eecs.umich.edu            cpuClearInt();
6833804Ssaidi@eecs.umich.edu    }
6843926Ssaidi@eecs.umich.edu    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval());
6853804Ssaidi@eecs.umich.edu
6863804Ssaidi@eecs.umich.edu    if (regs.icr() & regs.imr) {
6874989Sgblack@eecs.umich.edu        if (regs.itr.interval() == 0)  {
6884989Sgblack@eecs.umich.edu            cpuPostInt();
6894989Sgblack@eecs.umich.edu        } else {
6904989Sgblack@eecs.umich.edu            DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n");
6914989Sgblack@eecs.umich.edu            if (!interEvent.scheduled()) {
6924989Sgblack@eecs.umich.edu               DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns
6933856Ssaidi@eecs.umich.edu                       * 256 * regs.itr.interval());
6943804Ssaidi@eecs.umich.edu               schedule(interEvent,
6953804Ssaidi@eecs.umich.edu                   curTick + Clock::Int::ns * 256 * regs.itr.interval());
6964103Ssaidi@eecs.umich.edu            }
6974191Ssaidi@eecs.umich.edu        }
6984191Ssaidi@eecs.umich.edu    }
6994191Ssaidi@eecs.umich.edu
7003824Ssaidi@eecs.umich.edu
7014103Ssaidi@eecs.umich.edu}
7023804Ssaidi@eecs.umich.edu
7033804Ssaidi@eecs.umich.edu
7043804Ssaidi@eecs.umich.eduIGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
7053804Ssaidi@eecs.umich.edu    : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
7063824Ssaidi@eecs.umich.edu
7073824Ssaidi@eecs.umich.edu{
7083825Ssaidi@eecs.umich.edu}
7093825Ssaidi@eecs.umich.edu
7103823Ssaidi@eecs.umich.eduvoid
7113926Ssaidi@eecs.umich.eduIGbE::RxDescCache::writePacket(EthPacketPtr packet)
7124989Sgblack@eecs.umich.edu{
7133823Ssaidi@eecs.umich.edu    // We shouldn't have to deal with any of these yet
7143804Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
7153804Ssaidi@eecs.umich.edu            packet->length, igbe->regs.rctl.descSize());
7163826Ssaidi@eecs.umich.edu    assert(packet->length < igbe->regs.rctl.descSize());
7174996Sgblack@eecs.umich.edu
7184990Sgblack@eecs.umich.edu    assert(unusedCache.size());
7193826Ssaidi@eecs.umich.edu    //if (!unusedCache.size())
7203826Ssaidi@eecs.umich.edu    //    return false;
7213826Ssaidi@eecs.umich.edu
7223826Ssaidi@eecs.umich.edu    pktPtr = packet;
7233826Ssaidi@eecs.umich.edu    pktDone = false;
7243826Ssaidi@eecs.umich.edu    igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
7253826Ssaidi@eecs.umich.edu            packet->length, &pktEvent, packet->data, igbe->rxWriteDelay);
7264990Sgblack@eecs.umich.edu}
7273826Ssaidi@eecs.umich.edu
7283826Ssaidi@eecs.umich.eduvoid
7293826Ssaidi@eecs.umich.eduIGbE::RxDescCache::pktComplete()
7303826Ssaidi@eecs.umich.edu{
7313910Ssaidi@eecs.umich.edu    assert(unusedCache.size());
7323804Ssaidi@eecs.umich.edu    RxDesc *desc;
7333804Ssaidi@eecs.umich.edu    desc = unusedCache.front();
7343804Ssaidi@eecs.umich.edu
7353804Ssaidi@eecs.umich.edu    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
7363804Ssaidi@eecs.umich.edu    desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
7373836Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
7383804Ssaidi@eecs.umich.edu            pktPtr->length, crcfixup,
7393804Ssaidi@eecs.umich.edu            htole((uint16_t)(pktPtr->length + crcfixup)),
7403804Ssaidi@eecs.umich.edu            (uint16_t)(pktPtr->length + crcfixup));
7413836Ssaidi@eecs.umich.edu
7423804Ssaidi@eecs.umich.edu    // no support for anything but starting at 0
7433804Ssaidi@eecs.umich.edu    assert(igbe->regs.rxcsum.pcss() == 0);
7444990Sgblack@eecs.umich.edu
7453811Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
7463804Ssaidi@eecs.umich.edu
7473804Ssaidi@eecs.umich.edu    uint8_t status = RXDS_DD | RXDS_EOP;
7483804Ssaidi@eecs.umich.edu    uint8_t err = 0;
7494997Sgblack@eecs.umich.edu
7503804Ssaidi@eecs.umich.edu    IpPtr ip(pktPtr);
7514997Sgblack@eecs.umich.edu
7524997Sgblack@eecs.umich.edu    if (ip) {
7534997Sgblack@eecs.umich.edu        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
7543804Ssaidi@eecs.umich.edu
7553804Ssaidi@eecs.umich.edu        if (igbe->regs.rxcsum.ipofld()) {
7563804Ssaidi@eecs.umich.edu            DPRINTF(EthernetDesc, "Checking IP checksum\n");
7573928Ssaidi@eecs.umich.edu            status |= RXDS_IPCS;
7584990Sgblack@eecs.umich.edu            desc->csum = htole(cksum(ip));
7594990Sgblack@eecs.umich.edu            igbe->rxIpChecksums++;
7603928Ssaidi@eecs.umich.edu            if (cksum(ip) != 0) {
7613928Ssaidi@eecs.umich.edu                err |= RXDE_IPE;
7623804Ssaidi@eecs.umich.edu                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
7633804Ssaidi@eecs.umich.edu            }
7644990Sgblack@eecs.umich.edu        }
7654990Sgblack@eecs.umich.edu        TcpPtr tcp(ip);
7663804Ssaidi@eecs.umich.edu        if (tcp && igbe->regs.rxcsum.tuofld()) {
7673804Ssaidi@eecs.umich.edu            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
7683804Ssaidi@eecs.umich.edu            status |= RXDS_TCPCS;
7693804Ssaidi@eecs.umich.edu            desc->csum = htole(cksum(tcp));
7704990Sgblack@eecs.umich.edu            igbe->rxTcpChecksums++;
7714990Sgblack@eecs.umich.edu            if (cksum(tcp) != 0) {
7723804Ssaidi@eecs.umich.edu                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
7733804Ssaidi@eecs.umich.edu                err |= RXDE_TCPE;
7743804Ssaidi@eecs.umich.edu            }
7753928Ssaidi@eecs.umich.edu        }
7764990Sgblack@eecs.umich.edu
7774990Sgblack@eecs.umich.edu        UdpPtr udp(ip);
7783928Ssaidi@eecs.umich.edu        if (udp && igbe->regs.rxcsum.tuofld()) {
7793928Ssaidi@eecs.umich.edu            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
7803928Ssaidi@eecs.umich.edu            status |= RXDS_UDPCS;
7813928Ssaidi@eecs.umich.edu            desc->csum = htole(cksum(udp));
7824090Ssaidi@eecs.umich.edu            igbe->rxUdpChecksums++;
7833804Ssaidi@eecs.umich.edu            if (cksum(udp) != 0) {
7843804Ssaidi@eecs.umich.edu                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
7853836Ssaidi@eecs.umich.edu                err |= RXDE_TCPE;
7863836Ssaidi@eecs.umich.edu            }
7873881Ssaidi@eecs.umich.edu        }
7883881Ssaidi@eecs.umich.edu    } else { // if ip
7893881Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
7903881Ssaidi@eecs.umich.edu    }
7913881Ssaidi@eecs.umich.edu
7923836Ssaidi@eecs.umich.edu
7933836Ssaidi@eecs.umich.edu    desc->status = htole(status);
7943836Ssaidi@eecs.umich.edu    desc->errors = htole(err);
7953836Ssaidi@eecs.umich.edu
7963836Ssaidi@eecs.umich.edu    // No vlan support at this point... just set it to 0
7973836Ssaidi@eecs.umich.edu    desc->vlan = 0;
7983836Ssaidi@eecs.umich.edu
7993836Ssaidi@eecs.umich.edu    // Deal with the rx timer interrupts
8003881Ssaidi@eecs.umich.edu    if (igbe->regs.rdtr.delay()) {
8013826Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
8023836Ssaidi@eecs.umich.edu                igbe->regs.rdtr.delay() * igbe->intClock());
8033836Ssaidi@eecs.umich.edu        igbe->reschedule(igbe->rdtrEvent,
8043804Ssaidi@eecs.umich.edu            curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true);
8054103Ssaidi@eecs.umich.edu    }
8063806Ssaidi@eecs.umich.edu
8074103Ssaidi@eecs.umich.edu    if (igbe->regs.radv.idv()) {
8084103Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
8094990Sgblack@eecs.umich.edu                igbe->regs.radv.idv() * igbe->intClock());
8104103Ssaidi@eecs.umich.edu        if (!igbe->radvEvent.scheduled()) {
8114103Ssaidi@eecs.umich.edu            igbe->schedule(igbe->radvEvent,
8124103Ssaidi@eecs.umich.edu                curTick + igbe->regs.radv.idv() * igbe->intClock());
8134103Ssaidi@eecs.umich.edu        }
8144103Ssaidi@eecs.umich.edu    }
8154103Ssaidi@eecs.umich.edu
8164103Ssaidi@eecs.umich.edu    // if neither radv or rdtr, maybe itr is set...
8174103Ssaidi@eecs.umich.edu    if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
8184990Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
8194103Ssaidi@eecs.umich.edu        igbe->postInterrupt(IT_RXT);
8204103Ssaidi@eecs.umich.edu    }
8214103Ssaidi@eecs.umich.edu
8224103Ssaidi@eecs.umich.edu    // If the packet is small enough, interrupt appropriately
8234103Ssaidi@eecs.umich.edu    // I wonder if this is delayed or not?!
8243804Ssaidi@eecs.umich.edu    if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
8253806Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
8263806Ssaidi@eecs.umich.edu        igbe->postInterrupt(IT_SRPD);
8274990Sgblack@eecs.umich.edu    }
8283806Ssaidi@eecs.umich.edu
8293806Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
8303824Ssaidi@eecs.umich.edu    unusedCache.pop_front();
8313824Ssaidi@eecs.umich.edu    usedCache.push_back(desc);
8323824Ssaidi@eecs.umich.edu
8333824Ssaidi@eecs.umich.edu
8344990Sgblack@eecs.umich.edu    pktPtr = NULL;
8353824Ssaidi@eecs.umich.edu    enableSm();
8363824Ssaidi@eecs.umich.edu    pktDone = true;
8373881Ssaidi@eecs.umich.edu    igbe->checkDrain();
8384990Sgblack@eecs.umich.edu
8393824Ssaidi@eecs.umich.edu}
8403824Ssaidi@eecs.umich.edu
8413824Ssaidi@eecs.umich.eduvoid
8423824Ssaidi@eecs.umich.eduIGbE::RxDescCache::enableSm()
8433825Ssaidi@eecs.umich.edu{
8443825Ssaidi@eecs.umich.edu    if (!igbe->drainEvent) {
8454990Sgblack@eecs.umich.edu        igbe->rxTick = true;
8464070Ssaidi@eecs.umich.edu        igbe->restartClock();
8473825Ssaidi@eecs.umich.edu    }
8484070Ssaidi@eecs.umich.edu}
8493825Ssaidi@eecs.umich.edu
8503825Ssaidi@eecs.umich.edubool
8513825Ssaidi@eecs.umich.eduIGbE::RxDescCache::packetDone()
8523825Ssaidi@eecs.umich.edu{
8533825Ssaidi@eecs.umich.edu    if (pktDone) {
8543824Ssaidi@eecs.umich.edu        pktDone = false;
8553804Ssaidi@eecs.umich.edu        return true;
8563811Ssaidi@eecs.umich.edu    }
8573806Ssaidi@eecs.umich.edu    return false;
8583806Ssaidi@eecs.umich.edu}
8593806Ssaidi@eecs.umich.edu
8603804Ssaidi@eecs.umich.edubool
8613804Ssaidi@eecs.umich.eduIGbE::RxDescCache::hasOutstandingEvents()
8624997Sgblack@eecs.umich.edu{
8634997Sgblack@eecs.umich.edu    return pktEvent.scheduled() || wbEvent.scheduled() ||
8643806Ssaidi@eecs.umich.edu        fetchEvent.scheduled();
8653806Ssaidi@eecs.umich.edu}
8663806Ssaidi@eecs.umich.edu
8673823Ssaidi@eecs.umich.eduvoid
8683823Ssaidi@eecs.umich.eduIGbE::RxDescCache::serialize(std::ostream &os)
8694070Ssaidi@eecs.umich.edu{
8703823Ssaidi@eecs.umich.edu    DescCache<RxDesc>::serialize(os);
8713823Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(pktDone);
8723823Ssaidi@eecs.umich.edu}
8733823Ssaidi@eecs.umich.edu
8744990Sgblack@eecs.umich.eduvoid
8754990Sgblack@eecs.umich.eduIGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
8763823Ssaidi@eecs.umich.edu{
8773823Ssaidi@eecs.umich.edu    DescCache<RxDesc>::unserialize(cp, section);
8783823Ssaidi@eecs.umich.edu    UNSERIALIZE_SCALAR(pktDone);
8794172Ssaidi@eecs.umich.edu}
8803823Ssaidi@eecs.umich.edu
8813823Ssaidi@eecs.umich.edu
8823823Ssaidi@eecs.umich.edu///////////////////////////////////// IGbE::TxDesc /////////////////////////////////
8833823Ssaidi@eecs.umich.edu
8844172Ssaidi@eecs.umich.eduIGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
8853823Ssaidi@eecs.umich.edu    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
8863823Ssaidi@eecs.umich.edu       pktEvent(this)
8874172Ssaidi@eecs.umich.edu
8883823Ssaidi@eecs.umich.edu{
8893823Ssaidi@eecs.umich.edu}
8903823Ssaidi@eecs.umich.edu
8913823Ssaidi@eecs.umich.eduint
8923823Ssaidi@eecs.umich.eduIGbE::TxDescCache::getPacketSize()
8933824Ssaidi@eecs.umich.edu{
8944172Ssaidi@eecs.umich.edu    assert(unusedCache.size());
8953824Ssaidi@eecs.umich.edu
8963824Ssaidi@eecs.umich.edu    TxDesc *desc;
8973823Ssaidi@eecs.umich.edu
8983823Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
8994990Sgblack@eecs.umich.edu
9003823Ssaidi@eecs.umich.edu    while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
9013823Ssaidi@eecs.umich.edu        DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n");
9023823Ssaidi@eecs.umich.edu
9034990Sgblack@eecs.umich.edu        // I think we can just ignore these for now?
9043823Ssaidi@eecs.umich.edu        desc = unusedCache.front();
9053823Ssaidi@eecs.umich.edu        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", desc->d1,
9063823Ssaidi@eecs.umich.edu                desc->d2);
9074990Sgblack@eecs.umich.edu        // is this going to be a tcp or udp packet?
9083823Ssaidi@eecs.umich.edu        isTcp = TxdOp::tcp(desc) ? true : false;
9093823Ssaidi@eecs.umich.edu
9103823Ssaidi@eecs.umich.edu        // make sure it's ipv4
9114990Sgblack@eecs.umich.edu        //assert(TxdOp::ip(desc));
9123823Ssaidi@eecs.umich.edu
9133823Ssaidi@eecs.umich.edu        TxdOp::setDd(desc);
9143823Ssaidi@eecs.umich.edu        unusedCache.pop_front();
9154990Sgblack@eecs.umich.edu        usedCache.push_back(desc);
9163823Ssaidi@eecs.umich.edu    }
9173823Ssaidi@eecs.umich.edu
9183823Ssaidi@eecs.umich.edu    if (!unusedCache.size())
9194990Sgblack@eecs.umich.edu        return -1;
9203823Ssaidi@eecs.umich.edu
9213823Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
9223823Ssaidi@eecs.umich.edu            TxdOp::getLen(unusedCache.front()));
9234990Sgblack@eecs.umich.edu
9243823Ssaidi@eecs.umich.edu    return TxdOp::getLen(unusedCache.front());
9253823Ssaidi@eecs.umich.edu}
9263823Ssaidi@eecs.umich.edu
9274990Sgblack@eecs.umich.eduvoid
9283823Ssaidi@eecs.umich.eduIGbE::TxDescCache::getPacketData(EthPacketPtr p)
9293823Ssaidi@eecs.umich.edu{
9303823Ssaidi@eecs.umich.edu    assert(unusedCache.size());
9314990Sgblack@eecs.umich.edu
9323823Ssaidi@eecs.umich.edu    TxDesc *desc;
9333823Ssaidi@eecs.umich.edu    desc = unusedCache.front();
9343823Ssaidi@eecs.umich.edu
9354990Sgblack@eecs.umich.edu    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
9363823Ssaidi@eecs.umich.edu
9373823Ssaidi@eecs.umich.edu    pktPtr = p;
9383823Ssaidi@eecs.umich.edu
9394990Sgblack@eecs.umich.edu    pktWaiting = true;
9403823Ssaidi@eecs.umich.edu
9413823Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
9423823Ssaidi@eecs.umich.edu    igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
9434990Sgblack@eecs.umich.edu            TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay);
9443823Ssaidi@eecs.umich.edu
9453826Ssaidi@eecs.umich.edu
9463912Ssaidi@eecs.umich.edu}
9473826Ssaidi@eecs.umich.edu
9483823Ssaidi@eecs.umich.eduvoid
9493823Ssaidi@eecs.umich.eduIGbE::TxDescCache::pktComplete()
9504172Ssaidi@eecs.umich.edu{
9513823Ssaidi@eecs.umich.edu
9523826Ssaidi@eecs.umich.edu    TxDesc *desc;
9533826Ssaidi@eecs.umich.edu    assert(unusedCache.size());
9543833Ssaidi@eecs.umich.edu    assert(pktPtr);
9554990Sgblack@eecs.umich.edu
9563833Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "DMA of packet complete\n");
9573833Ssaidi@eecs.umich.edu
9583906Ssaidi@eecs.umich.edu
9594990Sgblack@eecs.umich.edu    desc = unusedCache.front();
9603906Ssaidi@eecs.umich.edu    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
9613826Ssaidi@eecs.umich.edu
9624990Sgblack@eecs.umich.edu    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
9633826Ssaidi@eecs.umich.edu
9643826Ssaidi@eecs.umich.edu    if (!TxdOp::eop(desc)) {
9653826Ssaidi@eecs.umich.edu        pktPtr->length += TxdOp::getLen(desc);
9663826Ssaidi@eecs.umich.edu        unusedCache.pop_front();
9673826Ssaidi@eecs.umich.edu        usedCache.push_back(desc);
9683823Ssaidi@eecs.umich.edu        pktDone = true;
9693823Ssaidi@eecs.umich.edu        pktWaiting = false;
9703833Ssaidi@eecs.umich.edu        pktMultiDesc = true;
9714990Sgblack@eecs.umich.edu
9723833Ssaidi@eecs.umich.edu        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
9733833Ssaidi@eecs.umich.edu                pktPtr->length);
9743906Ssaidi@eecs.umich.edu        pktPtr = NULL;
9754990Sgblack@eecs.umich.edu
9763906Ssaidi@eecs.umich.edu        enableSm();
9773906Ssaidi@eecs.umich.edu        igbe->checkDrain();
9784990Sgblack@eecs.umich.edu        return;
9793906Ssaidi@eecs.umich.edu    }
9803826Ssaidi@eecs.umich.edu    pktMultiDesc = false;
9814990Sgblack@eecs.umich.edu
9823826Ssaidi@eecs.umich.edu    // Set the length of the data in the EtherPacket
9833823Ssaidi@eecs.umich.edu    pktPtr->length += TxdOp::getLen(desc);
9844172Ssaidi@eecs.umich.edu
9853823Ssaidi@eecs.umich.edu    // no support for vlans
9863823Ssaidi@eecs.umich.edu    assert(!TxdOp::vle(desc));
9873823Ssaidi@eecs.umich.edu
9883823Ssaidi@eecs.umich.edu    // we alway report status
9893823Ssaidi@eecs.umich.edu    assert(TxdOp::rs(desc));
9903833Ssaidi@eecs.umich.edu
9914070Ssaidi@eecs.umich.edu    // we only support single packet descriptors at this point
9924990Sgblack@eecs.umich.edu    assert(TxdOp::eop(desc));
9934990Sgblack@eecs.umich.edu
9944990Sgblack@eecs.umich.edu    // set that this packet is done
9954990Sgblack@eecs.umich.edu    TxdOp::setDd(desc);
9964990Sgblack@eecs.umich.edu
9973833Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
9983833Ssaidi@eecs.umich.edu
9994070Ssaidi@eecs.umich.edu    if (DTRACE(EthernetDesc)) {
10004990Sgblack@eecs.umich.edu        IpPtr ip(pktPtr);
10014990Sgblack@eecs.umich.edu        if (ip)
10024990Sgblack@eecs.umich.edu            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
10034990Sgblack@eecs.umich.edu                    ip->id());
10044990Sgblack@eecs.umich.edu        else
10053833Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
10063899Ssaidi@eecs.umich.edu    }
10074070Ssaidi@eecs.umich.edu
10084990Sgblack@eecs.umich.edu    // Checksums are only ofloaded for new descriptor types
10094990Sgblack@eecs.umich.edu    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
10104990Sgblack@eecs.umich.edu        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
10114990Sgblack@eecs.umich.edu        IpPtr ip(pktPtr);
10124990Sgblack@eecs.umich.edu        assert(ip);
10133899Ssaidi@eecs.umich.edu        if (TxdOp::ixsm(desc)) {
10143899Ssaidi@eecs.umich.edu            ip->sum(0);
10154070Ssaidi@eecs.umich.edu            ip->sum(cksum(ip));
10164990Sgblack@eecs.umich.edu            igbe->txIpChecksums++;
10174990Sgblack@eecs.umich.edu            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
10184990Sgblack@eecs.umich.edu        }
10194990Sgblack@eecs.umich.edu        if (TxdOp::txsm(desc)) {
10204990Sgblack@eecs.umich.edu            TcpPtr tcp(ip);
10213899Ssaidi@eecs.umich.edu            UdpPtr udp(ip);
10224103Ssaidi@eecs.umich.edu            if (tcp) {
10234103Ssaidi@eecs.umich.edu                 tcp->sum(0);
10244103Ssaidi@eecs.umich.edu                 tcp->sum(cksum(tcp));
10254103Ssaidi@eecs.umich.edu                 igbe->txTcpChecksums++;
10264103Ssaidi@eecs.umich.edu                 DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
10274103Ssaidi@eecs.umich.edu            } else if (udp) {
10284103Ssaidi@eecs.umich.edu                 assert(udp);
10294103Ssaidi@eecs.umich.edu                 udp->sum(0);
10303823Ssaidi@eecs.umich.edu                 udp->sum(cksum(udp));
10313823Ssaidi@eecs.umich.edu                 igbe->txUdpChecksums++;
10323823Ssaidi@eecs.umich.edu                 DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
10333823Ssaidi@eecs.umich.edu            } else {
10343823Ssaidi@eecs.umich.edu                panic("Told to checksum, but don't know how\n");
10354870Sstever@eecs.umich.edu            }
10363823Ssaidi@eecs.umich.edu        }
10373806Ssaidi@eecs.umich.edu    }
10383806Ssaidi@eecs.umich.edu
10393806Ssaidi@eecs.umich.edu    if (TxdOp::ide(desc)) {
10403806Ssaidi@eecs.umich.edu        // Deal with the rx timer interrupts
10413806Ssaidi@eecs.umich.edu        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
10423823Ssaidi@eecs.umich.edu        if (igbe->regs.tidv.idv()) {
10433823Ssaidi@eecs.umich.edu            DPRINTF(EthernetDesc, "setting tidv\n");
10443823Ssaidi@eecs.umich.edu            igbe->reschedule(igbe->tidvEvent,
10453823Ssaidi@eecs.umich.edu                curTick + igbe->regs.tidv.idv() * igbe->intClock(), true);
10463826Ssaidi@eecs.umich.edu        }
10473826Ssaidi@eecs.umich.edu
10483826Ssaidi@eecs.umich.edu        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
10493826Ssaidi@eecs.umich.edu            DPRINTF(EthernetDesc, "setting tadv\n");
10503826Ssaidi@eecs.umich.edu            if (!igbe->tadvEvent.scheduled()) {
10513826Ssaidi@eecs.umich.edu                igbe->schedule(igbe->tadvEvent,
10523863Ssaidi@eecs.umich.edu                    curTick + igbe->regs.tadv.idv() * igbe->intClock());
10533863Ssaidi@eecs.umich.edu            }
10543863Ssaidi@eecs.umich.edu        }
10553826Ssaidi@eecs.umich.edu    }
10563826Ssaidi@eecs.umich.edu
10573825Ssaidi@eecs.umich.edu
10583823Ssaidi@eecs.umich.edu
10593823Ssaidi@eecs.umich.edu    unusedCache.pop_front();
10604990Sgblack@eecs.umich.edu    usedCache.push_back(desc);
10614990Sgblack@eecs.umich.edu    pktDone = true;
10623823Ssaidi@eecs.umich.edu    pktWaiting = false;
10633823Ssaidi@eecs.umich.edu    pktPtr = NULL;
10643823Ssaidi@eecs.umich.edu
10654172Ssaidi@eecs.umich.edu    DPRINTF(EthernetDesc, "Descriptor Done\n");
10663823Ssaidi@eecs.umich.edu
10673823Ssaidi@eecs.umich.edu    if (igbe->regs.txdctl.wthresh() == 0) {
10683823Ssaidi@eecs.umich.edu        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
10693823Ssaidi@eecs.umich.edu        writeback(0);
10704172Ssaidi@eecs.umich.edu    } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
10713823Ssaidi@eecs.umich.edu        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
10723823Ssaidi@eecs.umich.edu        writeback((igbe->cacheBlockSize()-1)>>4);
10734172Ssaidi@eecs.umich.edu    }
10743823Ssaidi@eecs.umich.edu    enableSm();
10753823Ssaidi@eecs.umich.edu    igbe->checkDrain();
10763823Ssaidi@eecs.umich.edu}
10773823Ssaidi@eecs.umich.edu
10783823Ssaidi@eecs.umich.eduvoid
10793824Ssaidi@eecs.umich.eduIGbE::TxDescCache::serialize(std::ostream &os)
10803825Ssaidi@eecs.umich.edu{
10814172Ssaidi@eecs.umich.edu    DescCache<TxDesc>::serialize(os);
10823824Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(pktDone);
10833824Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(isTcp);
10843823Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(pktWaiting);
10853823Ssaidi@eecs.umich.edu    SERIALIZE_SCALAR(pktMultiDesc);
10864990Sgblack@eecs.umich.edu}
10873823Ssaidi@eecs.umich.edu
10883823Ssaidi@eecs.umich.eduvoid
10893823Ssaidi@eecs.umich.eduIGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
10904990Sgblack@eecs.umich.edu{
10913823Ssaidi@eecs.umich.edu    DescCache<TxDesc>::unserialize(cp, section);
10923823Ssaidi@eecs.umich.edu    UNSERIALIZE_SCALAR(pktDone);
10933823Ssaidi@eecs.umich.edu    UNSERIALIZE_SCALAR(isTcp);
10944990Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(pktWaiting);
10953823Ssaidi@eecs.umich.edu    UNSERIALIZE_SCALAR(pktMultiDesc);
10963823Ssaidi@eecs.umich.edu}
10973823Ssaidi@eecs.umich.edu
10984990Sgblack@eecs.umich.edubool
10993823Ssaidi@eecs.umich.eduIGbE::TxDescCache::packetAvailable()
11003823Ssaidi@eecs.umich.edu{
11013823Ssaidi@eecs.umich.edu    if (pktDone) {
11024990Sgblack@eecs.umich.edu        pktDone = false;
11033823Ssaidi@eecs.umich.edu        return true;
11043823Ssaidi@eecs.umich.edu    }
11053823Ssaidi@eecs.umich.edu    return false;
11064990Sgblack@eecs.umich.edu}
11073823Ssaidi@eecs.umich.edu
11083823Ssaidi@eecs.umich.eduvoid
11093823Ssaidi@eecs.umich.eduIGbE::TxDescCache::enableSm()
11104990Sgblack@eecs.umich.edu{
11113823Ssaidi@eecs.umich.edu    if (!igbe->drainEvent) {
11123823Ssaidi@eecs.umich.edu        igbe->txTick = true;
11133823Ssaidi@eecs.umich.edu        igbe->restartClock();
11144990Sgblack@eecs.umich.edu    }
11153823Ssaidi@eecs.umich.edu}
11163823Ssaidi@eecs.umich.edu
11173823Ssaidi@eecs.umich.edubool
11184990Sgblack@eecs.umich.eduIGbE::TxDescCache::hasOutstandingEvents()
11193823Ssaidi@eecs.umich.edu{
11203823Ssaidi@eecs.umich.edu    return pktEvent.scheduled() || wbEvent.scheduled() ||
11213823Ssaidi@eecs.umich.edu        fetchEvent.scheduled();
11224990Sgblack@eecs.umich.edu}
11233823Ssaidi@eecs.umich.edu
11243823Ssaidi@eecs.umich.edu
11253823Ssaidi@eecs.umich.edu///////////////////////////////////// IGbE /////////////////////////////////
11264990Sgblack@eecs.umich.edu
11273823Ssaidi@eecs.umich.eduvoid
11283823Ssaidi@eecs.umich.eduIGbE::restartClock()
11293823Ssaidi@eecs.umich.edu{
11304990Sgblack@eecs.umich.edu    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
11313823Ssaidi@eecs.umich.edu        getState() == SimObject::Running)
11323825Ssaidi@eecs.umich.edu        schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1));
11333825Ssaidi@eecs.umich.edu}
11343825Ssaidi@eecs.umich.edu
11353825Ssaidi@eecs.umich.eduunsigned int
11363823Ssaidi@eecs.umich.eduIGbE::drain(Event *de)
11373823Ssaidi@eecs.umich.edu{
11384172Ssaidi@eecs.umich.edu    unsigned int count;
11393823Ssaidi@eecs.umich.edu    count = pioPort->drain(de) + dmaPort->drain(de);
11403826Ssaidi@eecs.umich.edu    if (rxDescCache.hasOutstandingEvents() ||
11413826Ssaidi@eecs.umich.edu            txDescCache.hasOutstandingEvents()) {
11423906Ssaidi@eecs.umich.edu        count++;
11434990Sgblack@eecs.umich.edu        drainEvent = de;
11443906Ssaidi@eecs.umich.edu    }
11453826Ssaidi@eecs.umich.edu
11463916Ssaidi@eecs.umich.edu    txFifoTick = false;
11474990Sgblack@eecs.umich.edu    txTick = false;
11483826Ssaidi@eecs.umich.edu    rxTick = false;
11493826Ssaidi@eecs.umich.edu
11503826Ssaidi@eecs.umich.edu    if (tickEvent.scheduled())
11513826Ssaidi@eecs.umich.edu        deschedule(tickEvent);
11523826Ssaidi@eecs.umich.edu
11533826Ssaidi@eecs.umich.edu    if (count)
11543826Ssaidi@eecs.umich.edu        changeState(Draining);
11553826Ssaidi@eecs.umich.edu    else
11563826Ssaidi@eecs.umich.edu        changeState(Drained);
11574990Sgblack@eecs.umich.edu
11583826Ssaidi@eecs.umich.edu    return count;
11593826Ssaidi@eecs.umich.edu}
11604172Ssaidi@eecs.umich.edu
11613826Ssaidi@eecs.umich.eduvoid
11623826Ssaidi@eecs.umich.eduIGbE::resume()
11633826Ssaidi@eecs.umich.edu{
11643826Ssaidi@eecs.umich.edu    SimObject::resume();
11653826Ssaidi@eecs.umich.edu
11663826Ssaidi@eecs.umich.edu    txFifoTick = true;
11673826Ssaidi@eecs.umich.edu    txTick = true;
11683826Ssaidi@eecs.umich.edu    rxTick = true;
11693826Ssaidi@eecs.umich.edu
11703826Ssaidi@eecs.umich.edu    restartClock();
11714990Sgblack@eecs.umich.edu}
11723826Ssaidi@eecs.umich.edu
11733826Ssaidi@eecs.umich.eduvoid
11744172Ssaidi@eecs.umich.eduIGbE::checkDrain()
11753826Ssaidi@eecs.umich.edu{
11763826Ssaidi@eecs.umich.edu    if (!drainEvent)
11773826Ssaidi@eecs.umich.edu        return;
11783826Ssaidi@eecs.umich.edu
11793826Ssaidi@eecs.umich.edu    txFifoTick = false;
11803863Ssaidi@eecs.umich.edu    txTick = false;
11813863Ssaidi@eecs.umich.edu    rxTick = false;
11823863Ssaidi@eecs.umich.edu    if (!rxDescCache.hasOutstandingEvents() &&
11834172Ssaidi@eecs.umich.edu            !txDescCache.hasOutstandingEvents()) {
11843863Ssaidi@eecs.umich.edu        drainEvent->process();
11853863Ssaidi@eecs.umich.edu        drainEvent = NULL;
11864172Ssaidi@eecs.umich.edu    }
11873863Ssaidi@eecs.umich.edu}
11883863Ssaidi@eecs.umich.edu
11893863Ssaidi@eecs.umich.eduvoid
11903863Ssaidi@eecs.umich.eduIGbE::txStateMachine()
11913863Ssaidi@eecs.umich.edu{
11923863Ssaidi@eecs.umich.edu    if (!regs.tctl.en()) {
11933863Ssaidi@eecs.umich.edu        txTick = false;
11943863Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
11953863Ssaidi@eecs.umich.edu        return;
11963863Ssaidi@eecs.umich.edu    }
11973863Ssaidi@eecs.umich.edu
11983863Ssaidi@eecs.umich.edu    // If we have a packet available and it's length is not 0 (meaning it's not
11993863Ssaidi@eecs.umich.edu    // a multidescriptor packet) put it in the fifo, otherwise an the next
12003863Ssaidi@eecs.umich.edu    // iteration we'll get the rest of the data
12013863Ssaidi@eecs.umich.edu    if (txPacket && txDescCache.packetAvailable()
12023863Ssaidi@eecs.umich.edu                 && !txDescCache.packetMultiDesc() && txPacket->length) {
12033863Ssaidi@eecs.umich.edu        bool success;
12043863Ssaidi@eecs.umich.edu
12053863Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
12063863Ssaidi@eecs.umich.edu        success = txFifo.push(txPacket);
12073863Ssaidi@eecs.umich.edu        txFifoTick = true && !drainEvent;
12083863Ssaidi@eecs.umich.edu        assert(success);
12093863Ssaidi@eecs.umich.edu        txPacket = NULL;
12103863Ssaidi@eecs.umich.edu        txDescCache.writeback((cacheBlockSize()-1)>>4);
12113863Ssaidi@eecs.umich.edu        return;
12123863Ssaidi@eecs.umich.edu    }
12133863Ssaidi@eecs.umich.edu
12143863Ssaidi@eecs.umich.edu    // Only support descriptor granularity
12153823Ssaidi@eecs.umich.edu    assert(regs.txdctl.gran());
12163823Ssaidi@eecs.umich.edu    if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
12173906Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
12184990Sgblack@eecs.umich.edu        postInterrupt(IT_TXDLOW);
12193906Ssaidi@eecs.umich.edu    }
12203826Ssaidi@eecs.umich.edu
12213916Ssaidi@eecs.umich.edu    if (!txPacket) {
12224990Sgblack@eecs.umich.edu        txPacket = new EthPacketData(16384);
12233826Ssaidi@eecs.umich.edu    }
12243823Ssaidi@eecs.umich.edu
12254172Ssaidi@eecs.umich.edu    if (!txDescCache.packetWaiting()) {
12263823Ssaidi@eecs.umich.edu        if (txDescCache.descLeft() == 0) {
12273823Ssaidi@eecs.umich.edu            postInterrupt(IT_TXQE);
12283823Ssaidi@eecs.umich.edu            txDescCache.writeback(0);
12293823Ssaidi@eecs.umich.edu            txDescCache.fetchDescriptors();
12303823Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
12313863Ssaidi@eecs.umich.edu                    "writeback stopping ticking and posting TXQE\n");
12323863Ssaidi@eecs.umich.edu            txTick = false;
12333863Ssaidi@eecs.umich.edu            return;
12344172Ssaidi@eecs.umich.edu        }
12353863Ssaidi@eecs.umich.edu
12363863Ssaidi@eecs.umich.edu
12374172Ssaidi@eecs.umich.edu        if (!(txDescCache.descUnused())) {
12383863Ssaidi@eecs.umich.edu            txDescCache.fetchDescriptors();
12393863Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
12404172Ssaidi@eecs.umich.edu            txTick = false;
12413863Ssaidi@eecs.umich.edu            return;
12423863Ssaidi@eecs.umich.edu        }
12433863Ssaidi@eecs.umich.edu
12443863Ssaidi@eecs.umich.edu
12453863Ssaidi@eecs.umich.edu        int size;
12463863Ssaidi@eecs.umich.edu        size = txDescCache.getPacketSize();
12473863Ssaidi@eecs.umich.edu        if (size > 0 && txFifo.avail() > size) {
12483863Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
12493863Ssaidi@eecs.umich.edu                    "DMA of next packet\n", size);
12503863Ssaidi@eecs.umich.edu            txFifo.reserve(size);
12513863Ssaidi@eecs.umich.edu            txDescCache.getPacketData(txPacket);
12523863Ssaidi@eecs.umich.edu        } else if (size <= 0) {
12533863Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
12543863Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
12553863Ssaidi@eecs.umich.edu            txDescCache.writeback(0);
12563863Ssaidi@eecs.umich.edu        } else {
12573863Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
12583863Ssaidi@eecs.umich.edu                    "available in FIFO\n");
12593863Ssaidi@eecs.umich.edu            txTick = false;
12603863Ssaidi@eecs.umich.edu        }
12613863Ssaidi@eecs.umich.edu
12623863Ssaidi@eecs.umich.edu
12633863Ssaidi@eecs.umich.edu        return;
12643863Ssaidi@eecs.umich.edu    }
12654103Ssaidi@eecs.umich.edu    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
12664103Ssaidi@eecs.umich.edu    txTick = false;
12674103Ssaidi@eecs.umich.edu}
12684103Ssaidi@eecs.umich.edu
12694103Ssaidi@eecs.umich.edubool
12704103Ssaidi@eecs.umich.eduIGbE::ethRxPkt(EthPacketPtr pkt)
12714103Ssaidi@eecs.umich.edu{
12724103Ssaidi@eecs.umich.edu    rxBytes += pkt->length;
12734103Ssaidi@eecs.umich.edu    rxPackets++;
12744103Ssaidi@eecs.umich.edu
12754103Ssaidi@eecs.umich.edu    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
12764103Ssaidi@eecs.umich.edu
12774103Ssaidi@eecs.umich.edu    if (!regs.rctl.en()) {
12783823Ssaidi@eecs.umich.edu        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
12793823Ssaidi@eecs.umich.edu        return true;
12803823Ssaidi@eecs.umich.edu    }
12813823Ssaidi@eecs.umich.edu
12824870Sstever@eecs.umich.edu    // restart the state machines if they are stopped
12833823Ssaidi@eecs.umich.edu    rxTick = true && !drainEvent;
12843806Ssaidi@eecs.umich.edu    if ((rxTick || txTick) && !tickEvent.scheduled()) {
12853806Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
12864997Sgblack@eecs.umich.edu        restartClock();
12874997Sgblack@eecs.umich.edu    }
12883804Ssaidi@eecs.umich.edu
12894070Ssaidi@eecs.umich.edu    if (!rxFifo.push(pkt)) {
12904070Ssaidi@eecs.umich.edu        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
12914070Ssaidi@eecs.umich.edu        postInterrupt(IT_RXO, true);
12924990Sgblack@eecs.umich.edu        return false;
12934070Ssaidi@eecs.umich.edu    }
12944990Sgblack@eecs.umich.edu
12954990Sgblack@eecs.umich.edu    return true;
12964990Sgblack@eecs.umich.edu}
12974990Sgblack@eecs.umich.edu
12984070Ssaidi@eecs.umich.edu
12994990Sgblack@eecs.umich.eduvoid
13004990Sgblack@eecs.umich.eduIGbE::rxStateMachine()
13014990Sgblack@eecs.umich.edu{
13024990Sgblack@eecs.umich.edu    if (!regs.rctl.en()) {
13034070Ssaidi@eecs.umich.edu        rxTick = false;
13044990Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
13054990Sgblack@eecs.umich.edu        return;
13064990Sgblack@eecs.umich.edu    }
13074990Sgblack@eecs.umich.edu
13084070Ssaidi@eecs.umich.edu    // If the packet is done check for interrupts/descriptors/etc
13094990Sgblack@eecs.umich.edu    if (rxDescCache.packetDone()) {
13104990Sgblack@eecs.umich.edu        rxDmaPacket = false;
13114990Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
13124990Sgblack@eecs.umich.edu        int descLeft = rxDescCache.descLeft();
13134070Ssaidi@eecs.umich.edu        switch (regs.rctl.rdmts()) {
13144070Ssaidi@eecs.umich.edu            case 2: if (descLeft > .125 * regs.rdlen()) break;
13154070Ssaidi@eecs.umich.edu            case 1: if (descLeft > .250 * regs.rdlen()) break;
13164070Ssaidi@eecs.umich.edu            case 0: if (descLeft > .500 * regs.rdlen())  break;
13174070Ssaidi@eecs.umich.edu                DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n");
13184070Ssaidi@eecs.umich.edu                postInterrupt(IT_RXDMT);
13194070Ssaidi@eecs.umich.edu                break;
13204070Ssaidi@eecs.umich.edu        }
13214070Ssaidi@eecs.umich.edu
13224070Ssaidi@eecs.umich.edu        if (descLeft == 0) {
13234070Ssaidi@eecs.umich.edu            rxDescCache.writeback(0);
13244070Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
13254070Ssaidi@eecs.umich.edu                    " writeback and stopping ticking\n");
13264070Ssaidi@eecs.umich.edu            rxTick = false;
13274070Ssaidi@eecs.umich.edu        }
13284070Ssaidi@eecs.umich.edu
13294070Ssaidi@eecs.umich.edu        // only support descriptor granulaties
13304070Ssaidi@eecs.umich.edu        assert(regs.rxdctl.gran());
13314070Ssaidi@eecs.umich.edu
13324070Ssaidi@eecs.umich.edu        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
13334070Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
13344070Ssaidi@eecs.umich.edu            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
13354070Ssaidi@eecs.umich.edu                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
13364070Ssaidi@eecs.umich.edu            else
13374070Ssaidi@eecs.umich.edu                rxDescCache.writeback((cacheBlockSize()-1)>>4);
13384070Ssaidi@eecs.umich.edu        }
13394070Ssaidi@eecs.umich.edu
13404070Ssaidi@eecs.umich.edu        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
13414070Ssaidi@eecs.umich.edu             ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
13424070Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
13434070Ssaidi@eecs.umich.edu            rxDescCache.fetchDescriptors();
13444070Ssaidi@eecs.umich.edu        }
13454070Ssaidi@eecs.umich.edu
13464070Ssaidi@eecs.umich.edu        if (rxDescCache.descUnused() == 0) {
13474070Ssaidi@eecs.umich.edu            rxDescCache.fetchDescriptors();
13483804Ssaidi@eecs.umich.edu            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
13493804Ssaidi@eecs.umich.edu                    "fetching descriptors and stopping ticking\n");
13504000Ssaidi@eecs.umich.edu            rxTick = false;
13514000Ssaidi@eecs.umich.edu        }
13524000Ssaidi@eecs.umich.edu        return;
13534000Ssaidi@eecs.umich.edu    }
13544000Ssaidi@eecs.umich.edu
13554000Ssaidi@eecs.umich.edu    if (rxDmaPacket) {
13564000Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
13574000Ssaidi@eecs.umich.edu        rxTick = false;
13584000Ssaidi@eecs.umich.edu        return;
13594000Ssaidi@eecs.umich.edu    }
13604000Ssaidi@eecs.umich.edu
13614000Ssaidi@eecs.umich.edu    if (!rxDescCache.descUnused()) {
13624000Ssaidi@eecs.umich.edu        rxDescCache.fetchDescriptors();
13634000Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
13644000Ssaidi@eecs.umich.edu        rxTick = false;
13654000Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
13664000Ssaidi@eecs.umich.edu        return;
13674000Ssaidi@eecs.umich.edu    }
13684000Ssaidi@eecs.umich.edu
13694000Ssaidi@eecs.umich.edu    if (rxFifo.empty()) {
13704990Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
13714990Sgblack@eecs.umich.edu        rxTick = false;
13724990Sgblack@eecs.umich.edu        return;
13734990Sgblack@eecs.umich.edu    }
13744990Sgblack@eecs.umich.edu
13754990Sgblack@eecs.umich.edu    EthPacketPtr pkt;
13764990Sgblack@eecs.umich.edu    pkt = rxFifo.front();
13774990Sgblack@eecs.umich.edu
13784990Sgblack@eecs.umich.edu
13793804Ssaidi@eecs.umich.edu    rxDescCache.writePacket(pkt);
13803804Ssaidi@eecs.umich.edu    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
13813804Ssaidi@eecs.umich.edu    DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
13823804Ssaidi@eecs.umich.edu    rxFifo.pop();
13833804Ssaidi@eecs.umich.edu    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
13844000Ssaidi@eecs.umich.edu    rxTick = false;
13854000Ssaidi@eecs.umich.edu    rxDmaPacket = true;
13864000Ssaidi@eecs.umich.edu}
13874000Ssaidi@eecs.umich.edu
13884000Ssaidi@eecs.umich.eduvoid
13894000Ssaidi@eecs.umich.eduIGbE::txWire()
13904000Ssaidi@eecs.umich.edu{
13914000Ssaidi@eecs.umich.edu    if (txFifo.empty()) {
13924000Ssaidi@eecs.umich.edu        txFifoTick = false;
13934000Ssaidi@eecs.umich.edu        return;
13944000Ssaidi@eecs.umich.edu    }
13954000Ssaidi@eecs.umich.edu
13964000Ssaidi@eecs.umich.edu
13974000Ssaidi@eecs.umich.edu    if (etherInt->sendPacket(txFifo.front())) {
13984000Ssaidi@eecs.umich.edu        if (DTRACE(EthernetSM)) {
13994000Ssaidi@eecs.umich.edu            IpPtr ip(txFifo.front());
14004000Ssaidi@eecs.umich.edu            if (ip)
14014000Ssaidi@eecs.umich.edu                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
14024000Ssaidi@eecs.umich.edu                        ip->id());
14034000Ssaidi@eecs.umich.edu            else
14044000Ssaidi@eecs.umich.edu                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
14054000Ssaidi@eecs.umich.edu        }
14064000Ssaidi@eecs.umich.edu        DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
14074000Ssaidi@eecs.umich.edu                txFifo.avail());
14084990Sgblack@eecs.umich.edu
14094990Sgblack@eecs.umich.edu        txBytes += txFifo.front()->length;
14104990Sgblack@eecs.umich.edu        txPackets++;
14114990Sgblack@eecs.umich.edu        txFifoTick = false;
14124990Sgblack@eecs.umich.edu
14134990Sgblack@eecs.umich.edu        txFifo.pop();
14144990Sgblack@eecs.umich.edu    } else {
14154990Sgblack@eecs.umich.edu        // We'll get woken up when the packet ethTxDone() gets called
14164990Sgblack@eecs.umich.edu        txFifoTick = false;
14174990Sgblack@eecs.umich.edu    }
14184990Sgblack@eecs.umich.edu}
14194990Sgblack@eecs.umich.edu
14204990Sgblack@eecs.umich.eduvoid
14214990Sgblack@eecs.umich.eduIGbE::tick()
14224990Sgblack@eecs.umich.edu{
14234990Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
14244990Sgblack@eecs.umich.edu
14254990Sgblack@eecs.umich.edu    if (rxTick)
14264990Sgblack@eecs.umich.edu        rxStateMachine();
14274990Sgblack@eecs.umich.edu
14284990Sgblack@eecs.umich.edu    if (txTick)
14294990Sgblack@eecs.umich.edu        txStateMachine();
14304990Sgblack@eecs.umich.edu
14313804Ssaidi@eecs.umich.edu    if (txFifoTick)
14323804Ssaidi@eecs.umich.edu        txWire();
14334088Sbinkertn@umich.edu
14344088Sbinkertn@umich.edu
14354762Snate@binkert.org    if (rxTick || txTick || txFifoTick)
14364762Snate@binkert.org        schedule(tickEvent, curTick + ticks(1));
14373804Ssaidi@eecs.umich.edu}
14385034Smilesck@eecs.umich.edu
14393804Ssaidi@eecs.umich.eduvoid
14403804Ssaidi@eecs.umich.eduIGbE::ethTxDone()
14414762Snate@binkert.org{
14424762Snate@binkert.org    // restart the tx state machines if they are stopped
14433804Ssaidi@eecs.umich.edu    // fifo to send another packet
14445034Smilesck@eecs.umich.edu    // tx sm to put more data into the fifo
14453804Ssaidi@eecs.umich.edu    txFifoTick = true && !drainEvent;
1446    if (txDescCache.descLeft() != 0 && !drainEvent)
1447        txTick = true;
1448
1449    restartClock();
1450    txWire();
1451    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
1452}
1453
1454void
1455IGbE::serialize(std::ostream &os)
1456{
1457    PciDev::serialize(os);
1458
1459    regs.serialize(os);
1460    SERIALIZE_SCALAR(eeOpBits);
1461    SERIALIZE_SCALAR(eeAddrBits);
1462    SERIALIZE_SCALAR(eeDataBits);
1463    SERIALIZE_SCALAR(eeOpcode);
1464    SERIALIZE_SCALAR(eeAddr);
1465    SERIALIZE_SCALAR(lastInterrupt);
1466    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
1467
1468    rxFifo.serialize("rxfifo", os);
1469    txFifo.serialize("txfifo", os);
1470
1471    bool txPktExists = txPacket;
1472    SERIALIZE_SCALAR(txPktExists);
1473    if (txPktExists)
1474        txPacket->serialize("txpacket", os);
1475
1476    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
1477         inter_time = 0;
1478
1479    if (rdtrEvent.scheduled())
1480       rdtr_time = rdtrEvent.when();
1481    SERIALIZE_SCALAR(rdtr_time);
1482
1483    if (radvEvent.scheduled())
1484       radv_time = radvEvent.when();
1485    SERIALIZE_SCALAR(radv_time);
1486
1487    if (tidvEvent.scheduled())
1488       tidv_time = tidvEvent.when();
1489    SERIALIZE_SCALAR(tidv_time);
1490
1491    if (tadvEvent.scheduled())
1492       tadv_time = tadvEvent.when();
1493    SERIALIZE_SCALAR(tadv_time);
1494
1495    if (interEvent.scheduled())
1496       inter_time = interEvent.when();
1497    SERIALIZE_SCALAR(inter_time);
1498
1499    nameOut(os, csprintf("%s.TxDescCache", name()));
1500    txDescCache.serialize(os);
1501
1502    nameOut(os, csprintf("%s.RxDescCache", name()));
1503    rxDescCache.serialize(os);
1504}
1505
1506void
1507IGbE::unserialize(Checkpoint *cp, const std::string &section)
1508{
1509    PciDev::unserialize(cp, section);
1510
1511    regs.unserialize(cp, section);
1512    UNSERIALIZE_SCALAR(eeOpBits);
1513    UNSERIALIZE_SCALAR(eeAddrBits);
1514    UNSERIALIZE_SCALAR(eeDataBits);
1515    UNSERIALIZE_SCALAR(eeOpcode);
1516    UNSERIALIZE_SCALAR(eeAddr);
1517    UNSERIALIZE_SCALAR(lastInterrupt);
1518    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
1519
1520    rxFifo.unserialize("rxfifo", cp, section);
1521    txFifo.unserialize("txfifo", cp, section);
1522
1523    bool txPktExists;
1524    UNSERIALIZE_SCALAR(txPktExists);
1525    if (txPktExists) {
1526        txPacket = new EthPacketData(16384);
1527        txPacket->unserialize("txpacket", cp, section);
1528    }
1529
1530    rxTick = true;
1531    txTick = true;
1532    txFifoTick = true;
1533
1534    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
1535    UNSERIALIZE_SCALAR(rdtr_time);
1536    UNSERIALIZE_SCALAR(radv_time);
1537    UNSERIALIZE_SCALAR(tidv_time);
1538    UNSERIALIZE_SCALAR(tadv_time);
1539    UNSERIALIZE_SCALAR(inter_time);
1540
1541    if (rdtr_time)
1542        schedule(rdtrEvent, rdtr_time);
1543
1544    if (radv_time)
1545        schedule(radvEvent, radv_time);
1546
1547    if (tidv_time)
1548        schedule(tidvEvent, tidv_time);
1549
1550    if (tadv_time)
1551        schedule(tadvEvent, tadv_time);
1552
1553    if (inter_time)
1554        schedule(interEvent, inter_time);
1555
1556    txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));
1557
1558    rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section));
1559}
1560
1561IGbE *
1562IGbEParams::create()
1563{
1564    return new IGbE(this);
1565}
1566