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