xbar.cc revision 5490
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 */ 30 31/** 32 * @file 33 * Definition of a bus object. 34 */ 35 36#include <algorithm> 37#include <limits> 38 39#include "base/misc.hh" 40#include "base/trace.hh" 41#include "mem/bus.hh" 42 43Port * 44Bus::getPort(const std::string &if_name, int idx) 45{ 46 if (if_name == "default") { 47 if (defaultPort == NULL) { 48 defaultPort = new BusPort(csprintf("%s-default",name()), this, 49 defaultId); 50 cachedBlockSizeValid = false; 51 return defaultPort; 52 } else 53 fatal("Default port already set\n"); 54 } 55 int id; 56 if (if_name == "functional") { 57 if (!funcPort) { 58 id = maxId++; 59 funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 60 funcPortId = id; 61 interfaces[id] = funcPort; 62 } 63 return funcPort; 64 } 65 66 // if_name ignored? forced to be empty? 67 id = maxId++; 68 assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 69 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 70 interfaces[id] = bp; 71 cachedBlockSizeValid = false; 72 return bp; 73} 74 75bool 76Bus::deletePort(Port *p) 77{ 78 79 BusPort *bp = dynamic_cast<BusPort*>(p); 80 if (bp == NULL) 81 panic("Couldn't convert Port* to BusPort*\n"); 82 // If this is our one functional port 83 if (funcPort == bp) 84 return false; 85 interfaces.erase(bp->getId()); 86 clearBusCache(); 87 delete bp; 88 return true; 89} 90 91/** Get the ranges of anyone other buses that we are connected to. */ 92void 93Bus::init() 94{ 95 m5::hash_map<short,BusPort*>::iterator intIter; 96 97 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 98 intIter->second->sendStatusChange(Port::RangeChange); 99} 100 101Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 102{} 103 104void Bus::BusFreeEvent::process() 105{ 106 bus->recvRetry(-1); 107} 108 109const char * Bus::BusFreeEvent::description() const 110{ 111 return "bus became available"; 112} 113 114Tick Bus::calcPacketTiming(PacketPtr pkt) 115{ 116 // Bring tickNextIdle up to the present tick. 117 // There is some potential ambiguity where a cycle starts, which 118 // might make a difference when devices are acting right around a 119 // cycle boundary. Using a < allows things which happen exactly on 120 // a cycle boundary to take up only the following cycle. Anything 121 // that happens later will have to "wait" for the end of that 122 // cycle, and then start using the bus after that. 123 if (tickNextIdle < curTick) { 124 tickNextIdle = curTick; 125 if (tickNextIdle % clock != 0) 126 tickNextIdle = curTick - (curTick % clock) + clock; 127 } 128 129 Tick headerTime = tickNextIdle + headerCycles * clock; 130 131 // The packet will be sent. Figure out how long it occupies the bus, and 132 // how much of that time is for the first "word", aka bus width. 133 int numCycles = 0; 134 if (pkt->hasData()) { 135 // If a packet has data, it needs ceil(size/width) cycles to send it 136 int dataSize = pkt->getSize(); 137 numCycles += dataSize/width; 138 if (dataSize % width) 139 numCycles++; 140 } 141 142 // The first word will be delivered after the current tick, the delivery 143 // of the address if any, and one bus cycle to deliver the data 144 pkt->firstWordTime = headerTime + clock; 145 146 pkt->finishTime = headerTime + numCycles * clock; 147 148 return headerTime; 149} 150 151void Bus::occupyBus(Tick until) 152{ 153 if (until == 0) { 154 // shortcut for express snoop packets 155 return; 156 } 157 158 tickNextIdle = until; 159 160 if (!busIdle.scheduled()) { 161 busIdle.schedule(tickNextIdle); 162 } else { 163 busIdle.reschedule(tickNextIdle); 164 } 165 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 166 curTick, tickNextIdle); 167} 168 169/** Function called by the port when the bus is receiving a Timing 170 * transaction.*/ 171bool 172Bus::recvTiming(PacketPtr pkt) 173{ 174 short src = pkt->getSrc(); 175 176 BusPort *src_port; 177 if (src == defaultId) 178 src_port = defaultPort; 179 else { 180 src_port = checkBusCache(src); 181 if (src_port == NULL) { 182 src_port = interfaces[src]; 183 updateBusCache(src, src_port); 184 } 185 } 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 = (dest_port_id == defaultId) ? 212 defaultPort : 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 >= 0 && dest < maxId); 224 assert(dest != src); // catch infinite loops 225 dest_port_id = dest; 226 if (dest_port_id == defaultId) 227 dest_port = defaultPort; 228 else { 229 dest_port = checkBusCache(dest); 230 if (dest_port == NULL) { 231 dest_port = interfaces[dest_port_id]; 232 // updateBusCache(dest_port_id, dest_port); 233 } 234 } 235 dest_port = (dest_port_id == defaultId) ? 236 defaultPort : interfaces[dest_port_id]; 237 } 238 239 if (dest_port_id == src) { 240 // Must be forwarded snoop up from below... 241 assert(dest == Packet::Broadcast); 242 assert(src != defaultId); // catch infinite loops 243 } else { 244 // send to actual target 245 if (!dest_port->sendTiming(pkt)) { 246 // Packet not successfully sent. Leave or put it on the retry list. 247 // illegal to block responses... can lead to deadlock 248 assert(!pkt->isResponse()); 249 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 250 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 251 addToRetryList(src_port); 252 occupyBus(headerFinishTime); 253 return false; 254 } 255 // send OK, fall through... pkt may have been deleted by 256 // target at this point, so it should *not* be referenced 257 // again. We'll set it to NULL here just to be safe. 258 pkt = NULL; 259 } 260 261 occupyBus(packetFinishTime); 262 263 // Packet was successfully sent. 264 // Also take care of retries 265 if (inRetry) { 266 DPRINTF(Bus, "Remove retry from list %d\n", src); 267 retryList.front()->onRetryList(false); 268 retryList.pop_front(); 269 inRetry = false; 270 } 271 return true; 272} 273 274void 275Bus::recvRetry(int id) 276{ 277 // If there's anything waiting, and the bus isn't busy... 278 if (retryList.size() && curTick >= tickNextIdle) { 279 //retryingPort = retryList.front(); 280 inRetry = true; 281 DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 282 retryList.front()->sendRetry(); 283 // If inRetry is still true, sendTiming wasn't called 284 if (inRetry) 285 { 286 retryList.front()->onRetryList(false); 287 retryList.pop_front(); 288 inRetry = false; 289 290 //Bring tickNextIdle up to the present 291 while (tickNextIdle < curTick) 292 tickNextIdle += clock; 293 294 //Burn a cycle for the missed grant. 295 tickNextIdle += clock; 296 297 busIdle.reschedule(tickNextIdle, true); 298 } 299 } 300 //If we weren't able to drain before, we might be able to now. 301 if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) { 302 drainEvent->process(); 303 // Clear the drain event once we're done with it. 304 drainEvent = NULL; 305 } 306} 307 308int 309Bus::findPort(Addr addr) 310{ 311 /* An interval tree would be a better way to do this. --ali. */ 312 int dest_id = -1; 313 314 dest_id = checkPortCache(addr); 315 if (dest_id == -1) { 316 PortIter i = portMap.find(RangeSize(addr,1)); 317 if (i != portMap.end()) { 318 dest_id = i->second; 319 updatePortCache(dest_id, i->first.start, i->first.end); 320 } 321 } 322 323 // Check if this matches the default range 324 if (dest_id == -1) { 325 AddrRangeIter a_end = defaultRange.end(); 326 for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 327 if (*i == addr) { 328 DPRINTF(Bus, " found addr %#llx on default\n", addr); 329 return defaultId; 330 } 331 } 332 333 if (responderSet) { 334 panic("Unable to find destination for addr (user set default " 335 "responder): %#llx", addr); 336 } else { 337 DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use " 338 "default port", addr); 339 340 return defaultId; 341 } 342 } 343 344 return dest_id; 345} 346 347 348/** Function called by the port when the bus is receiving a Atomic 349 * transaction.*/ 350Tick 351Bus::recvAtomic(PacketPtr pkt) 352{ 353 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 354 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 355 assert(pkt->getDest() == Packet::Broadcast); 356 assert(pkt->isRequest()); 357 358 // Variables for recording original command and snoop response (if 359 // any)... if a snooper respondes, we will need to restore 360 // original command so that additional snoops can take place 361 // properly 362 MemCmd orig_cmd = pkt->cmd; 363 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 364 Tick snoop_response_latency = 0; 365 int orig_src = pkt->getSrc(); 366 367 int target_port_id = findPort(pkt->getAddr()); 368 BusPort *target_port; 369 if (target_port_id == defaultId) 370 target_port = defaultPort; 371 else { 372 target_port = checkBusCache(target_port_id); 373 if (target_port == NULL) { 374 target_port = interfaces[target_port_id]; 375 updateBusCache(target_port_id, target_port); 376 } 377 } 378 379 SnoopIter s_end = snoopPorts.end(); 380 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 381 BusPort *p = *s_iter; 382 // same port should not have both target addresses and snooping 383 assert(p != target_port); 384 if (p->getId() != pkt->getSrc()) { 385 Tick latency = p->sendAtomic(pkt); 386 if (pkt->isResponse()) { 387 // response from snoop agent 388 assert(pkt->cmd != orig_cmd); 389 assert(pkt->memInhibitAsserted()); 390 // should only happen once 391 assert(snoop_response_cmd == MemCmd::InvalidCmd); 392 // save response state 393 snoop_response_cmd = pkt->cmd; 394 snoop_response_latency = latency; 395 // restore original packet state for remaining snoopers 396 pkt->cmd = orig_cmd; 397 pkt->setSrc(orig_src); 398 pkt->setDest(Packet::Broadcast); 399 } 400 } 401 } 402 403 Tick response_latency = 0; 404 405 // we can get requests sent up from the memory side of the bus for 406 // snooping... don't send them back down! 407 if (target_port_id != pkt->getSrc()) { 408 response_latency = target_port->sendAtomic(pkt); 409 } 410 411 // if we got a response from a snooper, restore it here 412 if (snoop_response_cmd != MemCmd::InvalidCmd) { 413 // no one else should have responded 414 assert(!pkt->isResponse()); 415 assert(pkt->cmd == orig_cmd); 416 pkt->cmd = snoop_response_cmd; 417 response_latency = snoop_response_latency; 418 } 419 420 // why do we have this packet field and the return value both??? 421 pkt->finishTime = curTick + response_latency; 422 return response_latency; 423} 424 425/** Function called by the port when the bus is receiving a Functional 426 * transaction.*/ 427void 428Bus::recvFunctional(PacketPtr pkt) 429{ 430 if (!pkt->isPrint()) { 431 // don't do DPRINTFs on PrintReq as it clutters up the output 432 DPRINTF(Bus, 433 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 434 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), 435 pkt->cmdString()); 436 } 437 assert(pkt->getDest() == Packet::Broadcast); 438 439 int port_id = findPort(pkt->getAddr()); 440 Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id]; 441 // The packet may be changed by another bus on snoops, restore the 442 // id after each 443 int src_id = pkt->getSrc(); 444 445 assert(pkt->isRequest()); // hasn't already been satisfied 446 447 SnoopIter s_end = snoopPorts.end(); 448 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 449 BusPort *p = *s_iter; 450 if (p != port && p->getId() != src_id) { 451 p->sendFunctional(pkt); 452 } 453 if (pkt->isResponse()) { 454 break; 455 } 456 pkt->setSrc(src_id); 457 } 458 459 // If the snooping hasn't found what we were looking for, keep going. 460 if (!pkt->isResponse() && port_id != pkt->getSrc()) { 461 port->sendFunctional(pkt); 462 } 463} 464 465/** Function called by the port when the bus is receiving a status change.*/ 466void 467Bus::recvStatusChange(Port::Status status, int id) 468{ 469 AddrRangeList ranges; 470 bool snoops; 471 AddrRangeIter iter; 472 473 if (inRecvStatusChange.count(id)) 474 return; 475 inRecvStatusChange.insert(id); 476 477 assert(status == Port::RangeChange && 478 "The other statuses need to be implemented."); 479 480 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 481 482 clearPortCache(); 483 if (id == defaultId) { 484 defaultRange.clear(); 485 // Only try to update these ranges if the user set a default responder. 486 if (responderSet) { 487 defaultPort->getPeerAddressRanges(ranges, snoops); 488 assert(snoops == false); 489 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 490 defaultRange.push_back(*iter); 491 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 492 iter->start, iter->end); 493 } 494 } 495 } else { 496 497 assert((id < maxId && id >= 0) || id == defaultId); 498 BusPort *port = interfaces[id]; 499 500 // Clean out any previously existent ids 501 for (PortIter portIter = portMap.begin(); 502 portIter != portMap.end(); ) { 503 if (portIter->second == id) 504 portMap.erase(portIter++); 505 else 506 portIter++; 507 } 508 509 for (SnoopIter s_iter = snoopPorts.begin(); 510 s_iter != snoopPorts.end(); ) { 511 if ((*s_iter)->getId() == id) 512 s_iter = snoopPorts.erase(s_iter); 513 else 514 s_iter++; 515 } 516 517 port->getPeerAddressRanges(ranges, snoops); 518 519 if (snoops) { 520 DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id); 521 snoopPorts.push_back(port); 522 } 523 524 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 525 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 526 iter->start, iter->end, id); 527 if (portMap.insert(*iter, id) == portMap.end()) { 528 int conflict_id = portMap.find(*iter)->second; 529 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 530 name(), interfaces[id]->getPeer()->name(), 531 interfaces[conflict_id]->getPeer()->name()); 532 } 533 } 534 } 535 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 536 537 // tell all our peers that our address range has changed. 538 // Don't tell the device that caused this change, it already knows 539 m5::hash_map<short,BusPort*>::iterator intIter; 540 541 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 542 if (intIter->first != id && intIter->first != funcPortId) 543 intIter->second->sendStatusChange(Port::RangeChange); 544 545 if (id != defaultId && defaultPort) 546 defaultPort->sendStatusChange(Port::RangeChange); 547 inRecvStatusChange.erase(id); 548} 549 550void 551Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id) 552{ 553 resp.clear(); 554 snoop = false; 555 556 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 557 558 for (AddrRangeIter dflt_iter = defaultRange.begin(); 559 dflt_iter != defaultRange.end(); dflt_iter++) { 560 resp.push_back(*dflt_iter); 561 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 562 dflt_iter->end); 563 } 564 for (PortIter portIter = portMap.begin(); 565 portIter != portMap.end(); portIter++) { 566 bool subset = false; 567 for (AddrRangeIter dflt_iter = defaultRange.begin(); 568 dflt_iter != defaultRange.end(); dflt_iter++) { 569 if ((portIter->first.start < dflt_iter->start && 570 portIter->first.end >= dflt_iter->start) || 571 (portIter->first.start < dflt_iter->end && 572 portIter->first.end >= dflt_iter->end)) 573 fatal("Devices can not set ranges that itersect the default set\ 574 but are not a subset of the default set.\n"); 575 if (portIter->first.start >= dflt_iter->start && 576 portIter->first.end <= dflt_iter->end) { 577 subset = true; 578 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 579 portIter->first.start, portIter->first.end); 580 } 581 } 582 if (portIter->second != id && !subset) { 583 resp.push_back(portIter->first); 584 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 585 portIter->first.start, portIter->first.end); 586 } 587 } 588 589 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 590 s_iter++) { 591 if ((*s_iter)->getId() != id) { 592 snoop = true; 593 break; 594 } 595 } 596} 597 598int 599Bus::findBlockSize(int id) 600{ 601 if (cachedBlockSizeValid) 602 return cachedBlockSize; 603 604 int max_bs = -1; 605 606 PortIter p_end = portMap.end(); 607 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 608 int tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 609 if (tmp_bs > max_bs) 610 max_bs = tmp_bs; 611 } 612 SnoopIter s_end = snoopPorts.end(); 613 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 614 int tmp_bs = (*s_iter)->peerBlockSize(); 615 if (tmp_bs > max_bs) 616 max_bs = tmp_bs; 617 } 618 if (max_bs <= 0) 619 max_bs = defaultBlockSize; 620 621 if (max_bs != 64) 622 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 623 cachedBlockSize = max_bs; 624 cachedBlockSizeValid = true; 625 return max_bs; 626} 627 628 629unsigned int 630Bus::drain(Event * de) 631{ 632 //We should check that we're not "doing" anything, and that noone is 633 //waiting. We might be idle but have someone waiting if the device we 634 //contacted for a retry didn't actually retry. 635 if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) { 636 drainEvent = de; 637 return 1; 638 } 639 return 0; 640} 641 642void 643Bus::startup() 644{ 645 if (tickNextIdle < curTick) 646 tickNextIdle = (curTick / clock) * clock + clock; 647} 648 649Bus * 650BusParams::create() 651{ 652 return new Bus(this); 653} 654