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