etherlink.cc revision 13766:4ecebdee8da4
13536SN/A/*
27752SWilliam.Wang@arm.com * Copyright (c) 2015 ARM Limited
37752SWilliam.Wang@arm.com * All rights reserved
47752SWilliam.Wang@arm.com *
57752SWilliam.Wang@arm.com * The license below extends only to copyright in the software and shall
67752SWilliam.Wang@arm.com * not be construed as granting a license to any other intellectual
77752SWilliam.Wang@arm.com * property including but not limited to intellectual property relating
87752SWilliam.Wang@arm.com * to a hardware implementation of the functionality of the software
97752SWilliam.Wang@arm.com * licensed hereunder.  You may use the software subject to the license
107752SWilliam.Wang@arm.com * terms below provided that you ensure that this notice is replicated
117752SWilliam.Wang@arm.com * unmodified and in its entirety in all distributions of the software,
127752SWilliam.Wang@arm.com * modified or unmodified, in source code or in binary form.
137752SWilliam.Wang@arm.com *
143536SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
153536SN/A * All rights reserved.
163536SN/A *
173536SN/A * Redistribution and use in source and binary forms, with or without
183536SN/A * modification, are permitted provided that the following conditions are
193536SN/A * met: redistributions of source code must retain the above copyright
203536SN/A * notice, this list of conditions and the following disclaimer;
213536SN/A * redistributions in binary form must reproduce the above copyright
223536SN/A * notice, this list of conditions and the following disclaimer in the
233536SN/A * documentation and/or other materials provided with the distribution;
243536SN/A * neither the name of the copyright holders nor the names of its
253536SN/A * contributors may be used to endorse or promote products derived from
263536SN/A * this software without specific prior written permission.
273536SN/A *
283536SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293536SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303536SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313536SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323536SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333536SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343536SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353536SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363536SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373536SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383536SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393536SN/A *
403536SN/A * Authors: Nathan Binkert
417752SWilliam.Wang@arm.com *          Ron Dreslinski
423536SN/A */
433536SN/A
443536SN/A/* @file
458332Snate@binkert.org * Device module for modelling a fixed bandwidth full duplex ethernet link
468332Snate@binkert.org */
473536SN/A
483536SN/A#include "dev/net/etherlink.hh"
493536SN/A
503536SN/A#include <cmath>
513536SN/A#include <deque>
523536SN/A#include <string>
533536SN/A#include <vector>
545543SN/A
555543SN/A#include "base/random.hh"
563536SN/A#include "base/trace.hh"
573536SN/A#include "debug/Ethernet.hh"
583536SN/A#include "debug/EthernetData.hh"
593536SN/A#include "dev/net/etherdump.hh"
603536SN/A#include "dev/net/etherint.hh"
613536SN/A#include "dev/net/etherpkt.hh"
623536SN/A#include "params/EtherLink.hh"
633536SN/A#include "sim/core.hh"
643536SN/A#include "sim/serialize.hh"
653536SN/A#include "sim/system.hh"
663536SN/A
675543SN/Ausing namespace std;
685543SN/A
693536SN/AEtherLink::EtherLink(const Params *p)
703536SN/A    : SimObject(p)
713536SN/A{
723536SN/A    link[0] = new Link(name() + ".link0", this, 0, p->speed,
733536SN/A                       p->delay, p->delay_var, p->dump);
743536SN/A    link[1] = new Link(name() + ".link1", this, 1, p->speed,
753536SN/A                       p->delay, p->delay_var, p->dump);
763536SN/A
773536SN/A    interface[0] = new Interface(name() + ".int0", link[0], link[1]);
783536SN/A    interface[1] = new Interface(name() + ".int1", link[1], link[0]);
793536SN/A}
803536SN/A
813536SN/A
823536SN/AEtherLink::~EtherLink()
833536SN/A{
843536SN/A    delete link[0];
855543SN/A    delete link[1];
863536SN/A
873536SN/A    delete interface[0];
883536SN/A    delete interface[1];
893536SN/A}
903536SN/A
913536SN/AEtherInt*
923536SN/AEtherLink::getEthPort(const std::string &if_name, int idx)
933536SN/A{
943536SN/A    Interface *i;
953536SN/A    if (if_name == "int0")
963536SN/A        i = interface[0];
973536SN/A    else if (if_name == "int1")
983536SN/A        i = interface[1];
993536SN/A    else
1003536SN/A        return NULL;
1013536SN/A    if (i->getPeer())
1023536SN/A        panic("interface already connected to\n");
1033536SN/A
1043536SN/A    return i;
1055543SN/A}
1065543SN/A
1073536SN/A
1083536SN/AEtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
1093536SN/A    : EtherInt(name), txlink(tx)
1103536SN/A{
1113536SN/A    tx->setTxInt(this);
1123536SN/A    rx->setRxInt(this);
1133536SN/A}
1143536SN/A
1153536SN/AEtherLink::Link::Link(const string &name, EtherLink *p, int num,
1163536SN/A                      double rate, Tick delay, Tick delay_var, EtherDump *d)
1173536SN/A    : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
1183536SN/A      ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
1193536SN/A      doneEvent([this]{ txDone(); }, name),
1203536SN/A      txQueueEvent([this]{ processTxQueue(); }, name)
1213536SN/A{ }
1223536SN/A
1233536SN/Avoid
1243536SN/AEtherLink::serialize(CheckpointOut &cp) const
1253536SN/A{
1263536SN/A    link[0]->serialize("link0", cp);
1273536SN/A    link[1]->serialize("link1", cp);
1283536SN/A}
1293536SN/A
1303536SN/Avoid
1313536SN/AEtherLink::unserialize(CheckpointIn &cp)
1323536SN/A{
1335569SN/A    link[0]->unserialize("link0", cp);
1343536SN/A    link[1]->unserialize("link1", cp);
1353536SN/A}
1363536SN/A
1379020Sgblack@eecs.umich.eduvoid
1388229Snate@binkert.orgEtherLink::Link::txComplete(EthPacketPtr packet)
1398229Snate@binkert.org{
1408229Snate@binkert.org    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
1417752SWilliam.Wang@arm.com    DDUMP(EthernetData, packet->data, packet->length);
1427752SWilliam.Wang@arm.com    rxint->sendPacket(packet);
1433536SN/A}
1443536SN/A
1453536SN/Avoid
1463536SN/AEtherLink::Link::txDone()
1478229Snate@binkert.org{
1483536SN/A    if (dump)
1497752SWilliam.Wang@arm.com        dump->dump(packet);
1508232Snate@binkert.org
1518232Snate@binkert.org    if (linkDelay > 0) {
1528229Snate@binkert.org        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
1533536SN/A        txQueue.emplace_back(std::make_pair(curTick() + linkDelay, packet));
1543536SN/A        if (!txQueueEvent.scheduled())
1558782Sgblack@eecs.umich.edu            parent->schedule(txQueueEvent, txQueue.front().first);
1563536SN/A    } else {
1573536SN/A        assert(txQueue.empty());
1583536SN/A        txComplete(packet);
1597752SWilliam.Wang@arm.com    }
1603536SN/A
1615569SN/A    packet = 0;
1627752SWilliam.Wang@arm.com    assert(!busy());
1633536SN/A
1643536SN/A    txint->sendDone();
1653536SN/A}
1665569SN/A
1675569SN/Avoid
1685569SN/AEtherLink::Link::processTxQueue()
1693536SN/A{
1703536SN/A    auto cur(txQueue.front());
1713536SN/A    txQueue.pop_front();
1728782Sgblack@eecs.umich.edu
1738782Sgblack@eecs.umich.edu    // Schedule a new event to process the next packet in the queue.
1748782Sgblack@eecs.umich.edu    if (!txQueue.empty()) {
1758782Sgblack@eecs.umich.edu        auto next(txQueue.front());
1763536SN/A        assert(next.first > curTick());
1778782Sgblack@eecs.umich.edu        parent->schedule(txQueueEvent, next.first);
1788782Sgblack@eecs.umich.edu    }
1798782Sgblack@eecs.umich.edu
1808782Sgblack@eecs.umich.edu    assert(cur.first == curTick());
1818782Sgblack@eecs.umich.edu    txComplete(cur.second);
1828782Sgblack@eecs.umich.edu}
1838782Sgblack@eecs.umich.edu
1848782Sgblack@eecs.umich.edubool
1858782Sgblack@eecs.umich.eduEtherLink::Link::transmit(EthPacketPtr pkt)
1868782Sgblack@eecs.umich.edu{
1878782Sgblack@eecs.umich.edu    if (busy()) {
1888782Sgblack@eecs.umich.edu        DPRINTF(Ethernet, "packet not sent, link busy\n");
1898782Sgblack@eecs.umich.edu        return false;
1908782Sgblack@eecs.umich.edu    }
1913536SN/A
1928782Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
1938782Sgblack@eecs.umich.edu    DDUMP(EthernetData, pkt->data, pkt->length);
1943536SN/A
1953536SN/A    packet = pkt;
1965569SN/A    Tick delay = (Tick)ceil(((double)pkt->simLength * ticksPerByte) + 1.0);
1975569SN/A    if (delayVar != 0)
1985569SN/A        delay += random_mt.random<Tick>(0, delayVar);
1995569SN/A
2003536SN/A    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
2013536SN/A            delay, ticksPerByte);
2023536SN/A    parent->schedule(doneEvent, curTick() + delay);
2037752SWilliam.Wang@arm.com
2047752SWilliam.Wang@arm.com    return true;
2053579SN/A}
2063536SN/A
2077752SWilliam.Wang@arm.comvoid
2087752SWilliam.Wang@arm.comEtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
2097752SWilliam.Wang@arm.com{
2107752SWilliam.Wang@arm.com    bool packet_exists = packet != nullptr;
2117752SWilliam.Wang@arm.com    paramOut(cp, base + ".packet_exists", packet_exists);
2127752SWilliam.Wang@arm.com    if (packet_exists)
2137752SWilliam.Wang@arm.com        packet->serialize(base + ".packet", cp);
2147752SWilliam.Wang@arm.com
2157752SWilliam.Wang@arm.com    bool event_scheduled = doneEvent.scheduled();
2167752SWilliam.Wang@arm.com    paramOut(cp, base + ".event_scheduled", event_scheduled);
2177752SWilliam.Wang@arm.com    if (event_scheduled) {
2187752SWilliam.Wang@arm.com        Tick event_time = doneEvent.when();
2197752SWilliam.Wang@arm.com        paramOut(cp, base + ".event_time", event_time);
2207752SWilliam.Wang@arm.com    }
2217752SWilliam.Wang@arm.com
2227752SWilliam.Wang@arm.com    const size_t tx_queue_size(txQueue.size());
2237752SWilliam.Wang@arm.com    paramOut(cp, base + ".tx_queue_size", tx_queue_size);
2247752SWilliam.Wang@arm.com    unsigned idx(0);
2257752SWilliam.Wang@arm.com    for (const auto &pe : txQueue) {
2263536SN/A        paramOut(cp, csprintf("%s.txQueue[%i].tick", base, idx), pe.first);
2277752SWilliam.Wang@arm.com        pe.second->serialize(csprintf("%s.txQueue[%i].packet", base, idx), cp);
2287752SWilliam.Wang@arm.com
2297752SWilliam.Wang@arm.com        ++idx;
2307752SWilliam.Wang@arm.com    }
2317752SWilliam.Wang@arm.com}
2327752SWilliam.Wang@arm.com
2337752SWilliam.Wang@arm.comvoid
2347752SWilliam.Wang@arm.comEtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
2357752SWilliam.Wang@arm.com{
2367752SWilliam.Wang@arm.com    bool packet_exists;
2377752SWilliam.Wang@arm.com    paramIn(cp, base + ".packet_exists", packet_exists);
2387752SWilliam.Wang@arm.com    if (packet_exists) {
2397752SWilliam.Wang@arm.com        packet = make_shared<EthPacketData>();
2403536SN/A        packet->unserialize(base + ".packet", cp);
2413536SN/A    }
2427752SWilliam.Wang@arm.com
2437752SWilliam.Wang@arm.com    bool event_scheduled;
2447752SWilliam.Wang@arm.com    paramIn(cp, base + ".event_scheduled", event_scheduled);
2457752SWilliam.Wang@arm.com    if (event_scheduled) {
2463536SN/A        Tick event_time;
2473536SN/A        paramIn(cp, base + ".event_time", event_time);
2485569SN/A        parent->schedule(doneEvent, event_time);
2495569SN/A    }
2505569SN/A
2515569SN/A    size_t tx_queue_size;
2523536SN/A    if (optParamIn(cp, base + ".tx_queue_size", tx_queue_size)) {
2533536SN/A        for (size_t idx = 0; idx < tx_queue_size; ++idx) {
2543536SN/A            Tick tick;
2557752SWilliam.Wang@arm.com            EthPacketPtr delayed_packet = make_shared<EthPacketData>();
2567752SWilliam.Wang@arm.com
2577752SWilliam.Wang@arm.com            paramIn(cp, csprintf("%s.txQueue[%i].tick", base, idx), tick);
2587752SWilliam.Wang@arm.com            delayed_packet->unserialize(
2597752SWilliam.Wang@arm.com                csprintf("%s.txQueue[%i].packet", base, idx), cp);
2607752SWilliam.Wang@arm.com
2617752SWilliam.Wang@arm.com            fatal_if(!txQueue.empty() && txQueue.back().first > tick,
2627752SWilliam.Wang@arm.com                     "Invalid txQueue packet order in EtherLink!\n");
2637752SWilliam.Wang@arm.com            txQueue.emplace_back(std::make_pair(tick, delayed_packet));
2647752SWilliam.Wang@arm.com        }
2657752SWilliam.Wang@arm.com
2667752SWilliam.Wang@arm.com        if (!txQueue.empty())
2677752SWilliam.Wang@arm.com            parent->schedule(txQueueEvent, txQueue.front().first);
2687752SWilliam.Wang@arm.com    } else {
2697752SWilliam.Wang@arm.com        // We can't reliably convert in-flight packets from old
2707752SWilliam.Wang@arm.com        // checkpoints. In fact, gem5 hasn't been able to load these
2717752SWilliam.Wang@arm.com        // packets for at least two years before the format change.
2727752SWilliam.Wang@arm.com        warn("Old-style EtherLink serialization format detected, "
2737752SWilliam.Wang@arm.com             "in-flight packets may have been dropped.\n");
2747752SWilliam.Wang@arm.com    }
2757752SWilliam.Wang@arm.com}
2767752SWilliam.Wang@arm.com
2777752SWilliam.Wang@arm.comEtherLink *
2787752SWilliam.Wang@arm.comEtherLinkParams::create()
2797752SWilliam.Wang@arm.com{
2807752SWilliam.Wang@arm.com    return new EtherLink(this);
2817752SWilliam.Wang@arm.com}
2827752SWilliam.Wang@arm.com