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