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