etherlink.cc (11263:8dcc6b40f164) etherlink.cc (11701:5e7599457b97)
1/*
2 * Copyright (c) 2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Nathan Binkert
41 * Ron Dreslinski
42 */
43
44/* @file
45 * Device module for modelling a fixed bandwidth full duplex ethernet link
46 */
47
48#include "dev/net/etherlink.hh"
49
50#include <cmath>
51#include <deque>
52#include <string>
53#include <vector>
54
55#include "base/random.hh"
56#include "base/trace.hh"
57#include "debug/Ethernet.hh"
58#include "debug/EthernetData.hh"
59#include "dev/net/etherdump.hh"
60#include "dev/net/etherint.hh"
61#include "dev/net/etherpkt.hh"
62#include "params/EtherLink.hh"
63#include "sim/core.hh"
64#include "sim/serialize.hh"
65#include "sim/system.hh"
66
67using namespace std;
68
69EtherLink::EtherLink(const Params *p)
70 : EtherObject(p)
71{
72 link[0] = new Link(name() + ".link0", this, 0, p->speed,
73 p->delay, p->delay_var, p->dump);
74 link[1] = new Link(name() + ".link1", this, 1, p->speed,
75 p->delay, p->delay_var, p->dump);
76
77 interface[0] = new Interface(name() + ".int0", link[0], link[1]);
78 interface[1] = new Interface(name() + ".int1", link[1], link[0]);
79}
80
81
82EtherLink::~EtherLink()
83{
84 delete link[0];
85 delete link[1];
86
87 delete interface[0];
88 delete interface[1];
89}
90
91EtherInt*
92EtherLink::getEthPort(const std::string &if_name, int idx)
93{
94 Interface *i;
95 if (if_name == "int0")
96 i = interface[0];
97 else if (if_name == "int1")
98 i = interface[1];
99 else
100 return NULL;
101 if (i->getPeer())
102 panic("interface already connected to\n");
103
104 return i;
105}
106
107
108EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
109 : EtherInt(name), txlink(tx)
110{
111 tx->setTxInt(this);
112 rx->setRxInt(this);
113}
114
115EtherLink::Link::Link(const string &name, EtherLink *p, int num,
116 double rate, Tick delay, Tick delay_var, EtherDump *d)
117 : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
118 ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
119 doneEvent(this), txQueueEvent(this)
120{ }
121
122void
123EtherLink::serialize(CheckpointOut &cp) const
124{
125 link[0]->serialize("link0", cp);
126 link[1]->serialize("link1", cp);
127}
128
129void
130EtherLink::unserialize(CheckpointIn &cp)
131{
132 link[0]->unserialize("link0", cp);
133 link[1]->unserialize("link1", cp);
134}
135
136void
137EtherLink::Link::txComplete(EthPacketPtr packet)
138{
139 DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
140 DDUMP(EthernetData, packet->data, packet->length);
141 rxint->sendPacket(packet);
142}
143
144void
145EtherLink::Link::txDone()
146{
147 if (dump)
148 dump->dump(packet);
149
150 if (linkDelay > 0) {
151 DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
152 txQueue.emplace_back(std::make_pair(curTick() + linkDelay, packet));
153 if (!txQueueEvent.scheduled())
154 parent->schedule(txQueueEvent, txQueue.front().first);
155 } else {
156 assert(txQueue.empty());
157 txComplete(packet);
158 }
159
160 packet = 0;
161 assert(!busy());
162
163 txint->sendDone();
164}
165
166void
167EtherLink::Link::processTxQueue()
168{
169 auto cur(txQueue.front());
170 txQueue.pop_front();
171
172 // Schedule a new event to process the next packet in the queue.
173 if (!txQueue.empty()) {
174 auto next(txQueue.front());
175 assert(next.first > curTick());
176 parent->schedule(txQueueEvent, next.first);
177 }
178
179 assert(cur.first == curTick());
180 txComplete(cur.second);
181}
182
183bool
184EtherLink::Link::transmit(EthPacketPtr pkt)
185{
186 if (busy()) {
187 DPRINTF(Ethernet, "packet not sent, link busy\n");
188 return false;
189 }
190
191 DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
192 DDUMP(EthernetData, pkt->data, pkt->length);
193
194 packet = pkt;
1/*
2 * Copyright (c) 2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Nathan Binkert
41 * Ron Dreslinski
42 */
43
44/* @file
45 * Device module for modelling a fixed bandwidth full duplex ethernet link
46 */
47
48#include "dev/net/etherlink.hh"
49
50#include <cmath>
51#include <deque>
52#include <string>
53#include <vector>
54
55#include "base/random.hh"
56#include "base/trace.hh"
57#include "debug/Ethernet.hh"
58#include "debug/EthernetData.hh"
59#include "dev/net/etherdump.hh"
60#include "dev/net/etherint.hh"
61#include "dev/net/etherpkt.hh"
62#include "params/EtherLink.hh"
63#include "sim/core.hh"
64#include "sim/serialize.hh"
65#include "sim/system.hh"
66
67using namespace std;
68
69EtherLink::EtherLink(const Params *p)
70 : EtherObject(p)
71{
72 link[0] = new Link(name() + ".link0", this, 0, p->speed,
73 p->delay, p->delay_var, p->dump);
74 link[1] = new Link(name() + ".link1", this, 1, p->speed,
75 p->delay, p->delay_var, p->dump);
76
77 interface[0] = new Interface(name() + ".int0", link[0], link[1]);
78 interface[1] = new Interface(name() + ".int1", link[1], link[0]);
79}
80
81
82EtherLink::~EtherLink()
83{
84 delete link[0];
85 delete link[1];
86
87 delete interface[0];
88 delete interface[1];
89}
90
91EtherInt*
92EtherLink::getEthPort(const std::string &if_name, int idx)
93{
94 Interface *i;
95 if (if_name == "int0")
96 i = interface[0];
97 else if (if_name == "int1")
98 i = interface[1];
99 else
100 return NULL;
101 if (i->getPeer())
102 panic("interface already connected to\n");
103
104 return i;
105}
106
107
108EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
109 : EtherInt(name), txlink(tx)
110{
111 tx->setTxInt(this);
112 rx->setRxInt(this);
113}
114
115EtherLink::Link::Link(const string &name, EtherLink *p, int num,
116 double rate, Tick delay, Tick delay_var, EtherDump *d)
117 : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
118 ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
119 doneEvent(this), txQueueEvent(this)
120{ }
121
122void
123EtherLink::serialize(CheckpointOut &cp) const
124{
125 link[0]->serialize("link0", cp);
126 link[1]->serialize("link1", cp);
127}
128
129void
130EtherLink::unserialize(CheckpointIn &cp)
131{
132 link[0]->unserialize("link0", cp);
133 link[1]->unserialize("link1", cp);
134}
135
136void
137EtherLink::Link::txComplete(EthPacketPtr packet)
138{
139 DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
140 DDUMP(EthernetData, packet->data, packet->length);
141 rxint->sendPacket(packet);
142}
143
144void
145EtherLink::Link::txDone()
146{
147 if (dump)
148 dump->dump(packet);
149
150 if (linkDelay > 0) {
151 DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
152 txQueue.emplace_back(std::make_pair(curTick() + linkDelay, packet));
153 if (!txQueueEvent.scheduled())
154 parent->schedule(txQueueEvent, txQueue.front().first);
155 } else {
156 assert(txQueue.empty());
157 txComplete(packet);
158 }
159
160 packet = 0;
161 assert(!busy());
162
163 txint->sendDone();
164}
165
166void
167EtherLink::Link::processTxQueue()
168{
169 auto cur(txQueue.front());
170 txQueue.pop_front();
171
172 // Schedule a new event to process the next packet in the queue.
173 if (!txQueue.empty()) {
174 auto next(txQueue.front());
175 assert(next.first > curTick());
176 parent->schedule(txQueueEvent, next.first);
177 }
178
179 assert(cur.first == curTick());
180 txComplete(cur.second);
181}
182
183bool
184EtherLink::Link::transmit(EthPacketPtr pkt)
185{
186 if (busy()) {
187 DPRINTF(Ethernet, "packet not sent, link busy\n");
188 return false;
189 }
190
191 DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
192 DDUMP(EthernetData, pkt->data, pkt->length);
193
194 packet = pkt;
195 Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
195 Tick delay = (Tick)ceil(((double)pkt->simLength * ticksPerByte) + 1.0);
196 if (delayVar != 0)
197 delay += random_mt.random<Tick>(0, delayVar);
198
199 DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
200 delay, ticksPerByte);
201 parent->schedule(doneEvent, curTick() + delay);
202
203 return true;
204}
205
206void
207EtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
208{
209 bool packet_exists = packet != nullptr;
210 paramOut(cp, base + ".packet_exists", packet_exists);
211 if (packet_exists)
212 packet->serialize(base + ".packet", cp);
213
214 bool event_scheduled = doneEvent.scheduled();
215 paramOut(cp, base + ".event_scheduled", event_scheduled);
216 if (event_scheduled) {
217 Tick event_time = doneEvent.when();
218 paramOut(cp, base + ".event_time", event_time);
219 }
220
221 const size_t tx_queue_size(txQueue.size());
222 paramOut(cp, base + ".tx_queue_size", tx_queue_size);
223 unsigned idx(0);
224 for (const auto &pe : txQueue) {
225 paramOut(cp, csprintf("%s.txQueue[%i].tick", base, idx), pe.first);
226 pe.second->serialize(csprintf("%s.txQueue[%i].packet", base, idx), cp);
227
228 ++idx;
229 }
230}
231
232void
233EtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
234{
235 bool packet_exists;
236 paramIn(cp, base + ".packet_exists", packet_exists);
237 if (packet_exists) {
196 if (delayVar != 0)
197 delay += random_mt.random<Tick>(0, delayVar);
198
199 DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
200 delay, ticksPerByte);
201 parent->schedule(doneEvent, curTick() + delay);
202
203 return true;
204}
205
206void
207EtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
208{
209 bool packet_exists = packet != nullptr;
210 paramOut(cp, base + ".packet_exists", packet_exists);
211 if (packet_exists)
212 packet->serialize(base + ".packet", cp);
213
214 bool event_scheduled = doneEvent.scheduled();
215 paramOut(cp, base + ".event_scheduled", event_scheduled);
216 if (event_scheduled) {
217 Tick event_time = doneEvent.when();
218 paramOut(cp, base + ".event_time", event_time);
219 }
220
221 const size_t tx_queue_size(txQueue.size());
222 paramOut(cp, base + ".tx_queue_size", tx_queue_size);
223 unsigned idx(0);
224 for (const auto &pe : txQueue) {
225 paramOut(cp, csprintf("%s.txQueue[%i].tick", base, idx), pe.first);
226 pe.second->serialize(csprintf("%s.txQueue[%i].packet", base, idx), cp);
227
228 ++idx;
229 }
230}
231
232void
233EtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
234{
235 bool packet_exists;
236 paramIn(cp, base + ".packet_exists", packet_exists);
237 if (packet_exists) {
238 packet = make_shared<EthPacketData>(16384);
238 packet = make_shared();
239 packet->unserialize(base + ".packet", cp);
240 }
241
242 bool event_scheduled;
243 paramIn(cp, base + ".event_scheduled", event_scheduled);
244 if (event_scheduled) {
245 Tick event_time;
246 paramIn(cp, base + ".event_time", event_time);
247 parent->schedule(doneEvent, event_time);
248 }
249
250 size_t tx_queue_size;
251 if (optParamIn(cp, base + ".tx_queue_size", tx_queue_size)) {
252 for (size_t idx = 0; idx < tx_queue_size; ++idx) {
253 Tick tick;
239 packet->unserialize(base + ".packet", cp);
240 }
241
242 bool event_scheduled;
243 paramIn(cp, base + ".event_scheduled", event_scheduled);
244 if (event_scheduled) {
245 Tick event_time;
246 paramIn(cp, base + ".event_time", event_time);
247 parent->schedule(doneEvent, event_time);
248 }
249
250 size_t tx_queue_size;
251 if (optParamIn(cp, base + ".tx_queue_size", tx_queue_size)) {
252 for (size_t idx = 0; idx < tx_queue_size; ++idx) {
253 Tick tick;
254 EthPacketPtr delayed_packet = make_shared<EthPacketData>(16384);
254 EthPacketPtr delayed_packet = make_shared();
255
256 paramIn(cp, csprintf("%s.txQueue[%i].tick", base, idx), tick);
257 delayed_packet->unserialize(
258 csprintf("%s.txQueue[%i].packet", base, idx), cp);
259
260 fatal_if(!txQueue.empty() && txQueue.back().first > tick,
261 "Invalid txQueue packet order in EtherLink!\n");
262 txQueue.emplace_back(std::make_pair(tick, delayed_packet));
263 }
264
265 if (!txQueue.empty())
266 parent->schedule(txQueueEvent, txQueue.front().first);
267 } else {
268 // We can't reliably convert in-flight packets from old
269 // checkpoints. In fact, gem5 hasn't been able to load these
270 // packets for at least two years before the format change.
271 warn("Old-style EtherLink serialization format detected, "
272 "in-flight packets may have been dropped.\n");
273 }
274}
275
276EtherLink *
277EtherLinkParams::create()
278{
279 return new EtherLink(this);
280}
255
256 paramIn(cp, csprintf("%s.txQueue[%i].tick", base, idx), tick);
257 delayed_packet->unserialize(
258 csprintf("%s.txQueue[%i].packet", base, idx), cp);
259
260 fatal_if(!txQueue.empty() && txQueue.back().first > tick,
261 "Invalid txQueue packet order in EtherLink!\n");
262 txQueue.emplace_back(std::make_pair(tick, delayed_packet));
263 }
264
265 if (!txQueue.empty())
266 parent->schedule(txQueueEvent, txQueue.front().first);
267 } else {
268 // We can't reliably convert in-flight packets from old
269 // checkpoints. In fact, gem5 hasn't been able to load these
270 // packets for at least two years before the format change.
271 warn("Old-style EtherLink serialization format detected, "
272 "in-flight packets may have been dropped.\n");
273 }
274}
275
276EtherLink *
277EtherLinkParams::create()
278{
279 return new EtherLink(this);
280}