MEM: Separate queries for snooping and address ranges
[gem5.git] / src / mem / bus.cc
1 /*
2 * Copyright (c) 2011 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) 2006 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: Ali Saidi
41 */
42
43 /**
44 * @file
45 * Definition of a bus object.
46 */
47
48 #include <algorithm>
49 #include <limits>
50
51 #include "base/misc.hh"
52 #include "base/trace.hh"
53 #include "debug/Bus.hh"
54 #include "debug/BusAddrRanges.hh"
55 #include "debug/MMU.hh"
56 #include "mem/bus.hh"
57
58 Bus::Bus(const BusParams *p)
59 : MemObject(p), busId(p->bus_id), clock(p->clock),
60 headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
61 drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
62 defaultPort(NULL), funcPort(NULL), funcPortId(-4),
63 useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
64 cachedBlockSize(0), cachedBlockSizeValid(false)
65 {
66 //width, clock period, and header cycles must be positive
67 if (width <= 0)
68 fatal("Bus width must be positive\n");
69 if (clock <= 0)
70 fatal("Bus clock period must be positive\n");
71 if (headerCycles <= 0)
72 fatal("Number of header cycles must be positive\n");
73 clearBusCache();
74 clearPortCache();
75 }
76
77 Port *
78 Bus::getPort(const std::string &if_name, int idx)
79 {
80 if (if_name == "default") {
81 if (defaultPort == NULL) {
82 defaultPort = new BusPort(csprintf("%s-default",name()), this,
83 defaultId);
84 cachedBlockSizeValid = false;
85 return defaultPort;
86 } else
87 fatal("Default port already set\n");
88 }
89 int id;
90 if (if_name == "functional") {
91 if (!funcPort) {
92 id = maxId++;
93 funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);
94 funcPortId = id;
95 interfaces[id] = funcPort;
96 }
97 return funcPort;
98 }
99
100 // if_name ignored? forced to be empty?
101 id = maxId++;
102 assert(maxId < std::numeric_limits<typeof(maxId)>::max());
103 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
104 interfaces[id] = bp;
105 cachedBlockSizeValid = false;
106 return bp;
107 }
108
109 void
110 Bus::init()
111 {
112 m5::hash_map<short,BusPort*>::iterator intIter;
113
114 // iterate over our interfaces and determine which of our neighbours
115 // are snooping and add them as snoopers
116 for (intIter = interfaces.begin(); intIter != interfaces.end();
117 intIter++) {
118 if (intIter->second->getPeer()->isSnooping()) {
119 DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
120 intIter->second->getPeer()->name());
121 snoopPorts.push_back(intIter->second);
122 }
123 }
124 }
125
126 Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
127 : bus(_bus)
128 {}
129
130 void
131 Bus::BusFreeEvent::process()
132 {
133 bus->recvRetry(-1);
134 }
135
136 const char *
137 Bus::BusFreeEvent::description() const
138 {
139 return "bus became available";
140 }
141
142 Tick
143 Bus::calcPacketTiming(PacketPtr pkt)
144 {
145 // Bring tickNextIdle up to the present tick.
146 // There is some potential ambiguity where a cycle starts, which
147 // might make a difference when devices are acting right around a
148 // cycle boundary. Using a < allows things which happen exactly on
149 // a cycle boundary to take up only the following cycle. Anything
150 // that happens later will have to "wait" for the end of that
151 // cycle, and then start using the bus after that.
152 if (tickNextIdle < curTick()) {
153 tickNextIdle = curTick();
154 if (tickNextIdle % clock != 0)
155 tickNextIdle = curTick() - (curTick() % clock) + clock;
156 }
157
158 Tick headerTime = tickNextIdle + headerCycles * clock;
159
160 // The packet will be sent. Figure out how long it occupies the bus, and
161 // how much of that time is for the first "word", aka bus width.
162 int numCycles = 0;
163 if (pkt->hasData()) {
164 // If a packet has data, it needs ceil(size/width) cycles to send it
165 int dataSize = pkt->getSize();
166 numCycles += dataSize/width;
167 if (dataSize % width)
168 numCycles++;
169 }
170
171 // The first word will be delivered after the current tick, the delivery
172 // of the address if any, and one bus cycle to deliver the data
173 pkt->firstWordTime = headerTime + clock;
174
175 pkt->finishTime = headerTime + numCycles * clock;
176
177 return headerTime;
178 }
179
180 void Bus::occupyBus(Tick until)
181 {
182 if (until == 0) {
183 // shortcut for express snoop packets
184 return;
185 }
186
187 tickNextIdle = until;
188 reschedule(busIdle, tickNextIdle, true);
189
190 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
191 curTick(), tickNextIdle);
192 }
193
194 /** Function called by the port when the bus is receiving a Timing
195 * transaction.*/
196 bool
197 Bus::recvTiming(PacketPtr pkt)
198 {
199 short src = pkt->getSrc();
200
201 BusPort *src_port;
202 if (src == defaultId)
203 src_port = defaultPort;
204 else {
205 src_port = checkBusCache(src);
206 if (src_port == NULL) {
207 src_port = interfaces[src];
208 updateBusCache(src, src_port);
209 }
210 }
211
212 // If the bus is busy, or other devices are in line ahead of the current
213 // one, put this device on the retry list.
214 if (!pkt->isExpressSnoop() &&
215 (tickNextIdle > curTick() ||
216 (retryList.size() && (!inRetry || src_port != retryList.front()))))
217 {
218 addToRetryList(src_port);
219 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
220 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
221 return false;
222 }
223
224 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
225 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
226
227 Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
228 Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
229
230 short dest = pkt->getDest();
231 int dest_port_id;
232 Port *dest_port;
233
234 if (dest == Packet::Broadcast) {
235 dest_port_id = findPort(pkt->getAddr());
236 dest_port = (dest_port_id == defaultId) ?
237 defaultPort : interfaces[dest_port_id];
238 SnoopIter s_end = snoopPorts.end();
239 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
240 BusPort *p = *s_iter;
241 if (p != dest_port && p != src_port) {
242 // cache is not allowed to refuse snoop
243 bool success M5_VAR_USED = p->sendTiming(pkt);
244 assert(success);
245 }
246 }
247 } else {
248 assert(dest < maxId);
249 assert(dest != src); // catch infinite loops
250 dest_port_id = dest;
251 if (dest_port_id == defaultId)
252 dest_port = defaultPort;
253 else {
254 dest_port = checkBusCache(dest);
255 if (dest_port == NULL) {
256 dest_port = interfaces[dest_port_id];
257 // updateBusCache(dest_port_id, dest_port);
258 }
259 }
260 dest_port = (dest_port_id == defaultId) ?
261 defaultPort : interfaces[dest_port_id];
262 }
263
264 if (dest_port_id == src) {
265 // Must be forwarded snoop up from below...
266 assert(dest == Packet::Broadcast);
267 } else {
268 // send to actual target
269 if (!dest_port->sendTiming(pkt)) {
270 // Packet not successfully sent. Leave or put it on the retry list.
271 // illegal to block responses... can lead to deadlock
272 assert(!pkt->isResponse());
273 // It's also illegal to force a transaction to retry after
274 // someone else has committed to respond.
275 assert(!pkt->memInhibitAsserted());
276 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
277 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
278 addToRetryList(src_port);
279 occupyBus(headerFinishTime);
280 return false;
281 }
282 // send OK, fall through... pkt may have been deleted by
283 // target at this point, so it should *not* be referenced
284 // again. We'll set it to NULL here just to be safe.
285 pkt = NULL;
286 }
287
288 occupyBus(packetFinishTime);
289
290 // Packet was successfully sent.
291 // Also take care of retries
292 if (inRetry) {
293 DPRINTF(Bus, "Remove retry from list %d\n", src);
294 retryList.front()->onRetryList(false);
295 retryList.pop_front();
296 inRetry = false;
297 }
298 return true;
299 }
300
301 void
302 Bus::recvRetry(int id)
303 {
304 // If there's anything waiting, and the bus isn't busy...
305 if (retryList.size() && curTick() >= tickNextIdle) {
306 //retryingPort = retryList.front();
307 inRetry = true;
308 DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
309 retryList.front()->sendRetry();
310 // If inRetry is still true, sendTiming wasn't called
311 if (inRetry)
312 {
313 retryList.front()->onRetryList(false);
314 retryList.pop_front();
315 inRetry = false;
316
317 //Bring tickNextIdle up to the present
318 while (tickNextIdle < curTick())
319 tickNextIdle += clock;
320
321 //Burn a cycle for the missed grant.
322 tickNextIdle += clock;
323
324 reschedule(busIdle, tickNextIdle, true);
325 }
326 }
327 //If we weren't able to drain before, we might be able to now.
328 if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) {
329 drainEvent->process();
330 // Clear the drain event once we're done with it.
331 drainEvent = NULL;
332 }
333 }
334
335 int
336 Bus::findPort(Addr addr)
337 {
338 /* An interval tree would be a better way to do this. --ali. */
339 int dest_id;
340
341 dest_id = checkPortCache(addr);
342 if (dest_id != -1)
343 return dest_id;
344
345 // Check normal port ranges
346 PortIter i = portMap.find(RangeSize(addr,1));
347 if (i != portMap.end()) {
348 dest_id = i->second;
349 updatePortCache(dest_id, i->first.start, i->first.end);
350 return dest_id;
351 }
352
353 // Check if this matches the default range
354 if (useDefaultRange) {
355 AddrRangeIter a_end = defaultRange.end();
356 for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
357 if (*i == addr) {
358 DPRINTF(Bus, " found addr %#llx on default\n", addr);
359 return defaultId;
360 }
361 }
362
363 panic("Unable to find destination for addr %#llx\n", addr);
364 }
365
366 DPRINTF(Bus, "Unable to find destination for addr %#llx, "
367 "will use default port\n", addr);
368 return defaultId;
369 }
370
371
372 /** Function called by the port when the bus is receiving a Atomic
373 * transaction.*/
374 Tick
375 Bus::recvAtomic(PacketPtr pkt)
376 {
377 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
378 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
379 assert(pkt->getDest() == Packet::Broadcast);
380 assert(pkt->isRequest());
381
382 // Variables for recording original command and snoop response (if
383 // any)... if a snooper respondes, we will need to restore
384 // original command so that additional snoops can take place
385 // properly
386 MemCmd orig_cmd = pkt->cmd;
387 MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
388 Tick snoop_response_latency = 0;
389 int orig_src = pkt->getSrc();
390
391 int target_port_id = findPort(pkt->getAddr());
392 BusPort *target_port;
393 if (target_port_id == defaultId)
394 target_port = defaultPort;
395 else {
396 target_port = checkBusCache(target_port_id);
397 if (target_port == NULL) {
398 target_port = interfaces[target_port_id];
399 updateBusCache(target_port_id, target_port);
400 }
401 }
402
403 SnoopIter s_end = snoopPorts.end();
404 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
405 BusPort *p = *s_iter;
406 // same port should not have both target addresses and snooping
407 assert(p != target_port);
408 if (p->getId() != pkt->getSrc()) {
409 Tick latency = p->sendAtomic(pkt);
410 if (pkt->isResponse()) {
411 // response from snoop agent
412 assert(pkt->cmd != orig_cmd);
413 assert(pkt->memInhibitAsserted());
414 // should only happen once
415 assert(snoop_response_cmd == MemCmd::InvalidCmd);
416 // save response state
417 snoop_response_cmd = pkt->cmd;
418 snoop_response_latency = latency;
419 // restore original packet state for remaining snoopers
420 pkt->cmd = orig_cmd;
421 pkt->setSrc(orig_src);
422 pkt->setDest(Packet::Broadcast);
423 }
424 }
425 }
426
427 Tick response_latency = 0;
428
429 // we can get requests sent up from the memory side of the bus for
430 // snooping... don't send them back down!
431 if (target_port_id != pkt->getSrc()) {
432 response_latency = target_port->sendAtomic(pkt);
433 }
434
435 // if we got a response from a snooper, restore it here
436 if (snoop_response_cmd != MemCmd::InvalidCmd) {
437 // no one else should have responded
438 assert(!pkt->isResponse());
439 assert(pkt->cmd == orig_cmd);
440 pkt->cmd = snoop_response_cmd;
441 response_latency = snoop_response_latency;
442 }
443
444 // why do we have this packet field and the return value both???
445 pkt->finishTime = curTick() + response_latency;
446 return response_latency;
447 }
448
449 /** Function called by the port when the bus is receiving a Functional
450 * transaction.*/
451 void
452 Bus::recvFunctional(PacketPtr pkt)
453 {
454 assert(pkt->getDest() == Packet::Broadcast);
455
456 int port_id = findPort(pkt->getAddr());
457 Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
458 // The packet may be changed by another bus on snoops, restore the
459 // id after each
460 int src_id = pkt->getSrc();
461
462 if (!pkt->isPrint()) {
463 // don't do DPRINTFs on PrintReq as it clutters up the output
464 DPRINTF(Bus,
465 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
466 src_id, port_id, pkt->getAddr(),
467 pkt->cmdString());
468 }
469
470 assert(pkt->isRequest()); // hasn't already been satisfied
471
472 SnoopIter s_end = snoopPorts.end();
473 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
474 BusPort *p = *s_iter;
475 if (p != port && p->getId() != src_id) {
476 p->sendFunctional(pkt);
477 }
478 if (pkt->isResponse()) {
479 break;
480 }
481 pkt->setSrc(src_id);
482 }
483
484 // If the snooping hasn't found what we were looking for, keep going.
485 if (!pkt->isResponse() && port_id != pkt->getSrc()) {
486 port->sendFunctional(pkt);
487 }
488 }
489
490 /** Function called by the port when the bus is receiving a range change.*/
491 void
492 Bus::recvRangeChange(int id)
493 {
494 AddrRangeList ranges;
495 AddrRangeIter iter;
496
497 if (inRecvRangeChange.count(id))
498 return;
499 inRecvRangeChange.insert(id);
500
501 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
502
503 clearPortCache();
504 if (id == defaultId) {
505 defaultRange.clear();
506 // Only try to update these ranges if the user set a default responder.
507 if (useDefaultRange) {
508 AddrRangeList ranges = defaultPort->getPeer()->getAddrRanges();
509 for(iter = ranges.begin(); iter != ranges.end(); iter++) {
510 defaultRange.push_back(*iter);
511 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
512 iter->start, iter->end);
513 }
514 }
515 } else {
516
517 assert((id < maxId && id >= 0) || id == defaultId);
518 BusPort *port = interfaces[id];
519
520 // Clean out any previously existent ids
521 for (PortIter portIter = portMap.begin();
522 portIter != portMap.end(); ) {
523 if (portIter->second == id)
524 portMap.erase(portIter++);
525 else
526 portIter++;
527 }
528
529 ranges = port->getPeer()->getAddrRanges();
530
531 for (iter = ranges.begin(); iter != ranges.end(); iter++) {
532 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
533 iter->start, iter->end, id);
534 if (portMap.insert(*iter, id) == portMap.end()) {
535 int conflict_id = portMap.find(*iter)->second;
536 fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
537 name(), interfaces[id]->getPeer()->name(),
538 interfaces[conflict_id]->getPeer()->name());
539 }
540 }
541 }
542 DPRINTF(MMU, "port list has %d entries\n", portMap.size());
543
544 // tell all our peers that our address range has changed.
545 // Don't tell the device that caused this change, it already knows
546 m5::hash_map<short,BusPort*>::iterator intIter;
547
548 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
549 if (intIter->first != id && intIter->first != funcPortId)
550 intIter->second->sendRangeChange();
551
552 if (id != defaultId && defaultPort)
553 defaultPort->sendRangeChange();
554 inRecvRangeChange.erase(id);
555 }
556
557 AddrRangeList
558 Bus::getAddrRanges(int id)
559 {
560 AddrRangeList ranges;
561
562 DPRINTF(BusAddrRanges, "received address range request, returning:\n");
563
564 for (AddrRangeIter dflt_iter = defaultRange.begin();
565 dflt_iter != defaultRange.end(); dflt_iter++) {
566 ranges.push_back(*dflt_iter);
567 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start,
568 dflt_iter->end);
569 }
570 for (PortIter portIter = portMap.begin();
571 portIter != portMap.end(); portIter++) {
572 bool subset = false;
573 for (AddrRangeIter dflt_iter = defaultRange.begin();
574 dflt_iter != defaultRange.end(); dflt_iter++) {
575 if ((portIter->first.start < dflt_iter->start &&
576 portIter->first.end >= dflt_iter->start) ||
577 (portIter->first.start < dflt_iter->end &&
578 portIter->first.end >= dflt_iter->end))
579 fatal("Devices can not set ranges that itersect the default set\
580 but are not a subset of the default set.\n");
581 if (portIter->first.start >= dflt_iter->start &&
582 portIter->first.end <= dflt_iter->end) {
583 subset = true;
584 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n",
585 portIter->first.start, portIter->first.end);
586 }
587 }
588 if (portIter->second != id && !subset) {
589 ranges.push_back(portIter->first);
590 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",
591 portIter->first.start, portIter->first.end);
592 }
593 }
594
595 return ranges;
596 }
597
598 bool
599 Bus::isSnooping(int id)
600 {
601 // in essence, answer the question if there are other snooping
602 // ports rather than the port that is asking
603 bool snoop = false;
604 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
605 s_iter++) {
606 if ((*s_iter)->getId() != id) {
607 snoop = true;
608 break;
609 }
610 }
611 return snoop;
612 }
613
614 unsigned
615 Bus::findBlockSize(int id)
616 {
617 if (cachedBlockSizeValid)
618 return cachedBlockSize;
619
620 unsigned max_bs = 0;
621
622 PortIter p_end = portMap.end();
623 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
624 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
625 if (tmp_bs > max_bs)
626 max_bs = tmp_bs;
627 }
628 SnoopIter s_end = snoopPorts.end();
629 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
630 unsigned tmp_bs = (*s_iter)->peerBlockSize();
631 if (tmp_bs > max_bs)
632 max_bs = tmp_bs;
633 }
634 if (max_bs == 0)
635 max_bs = defaultBlockSize;
636
637 if (max_bs != 64)
638 warn_once("Blocksize found to not be 64... hmm... probably not.\n");
639 cachedBlockSize = max_bs;
640 cachedBlockSizeValid = true;
641 return max_bs;
642 }
643
644
645 unsigned int
646 Bus::drain(Event * de)
647 {
648 //We should check that we're not "doing" anything, and that noone is
649 //waiting. We might be idle but have someone waiting if the device we
650 //contacted for a retry didn't actually retry.
651 if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) {
652 drainEvent = de;
653 return 1;
654 }
655 return 0;
656 }
657
658 void
659 Bus::startup()
660 {
661 if (tickNextIdle < curTick())
662 tickNextIdle = (curTick() / clock) * clock + clock;
663 }
664
665 Bus *
666 BusParams::create()
667 {
668 return new Bus(this);
669 }