xbar.cc revision 8711
18292SN/A/* 28292SN/A * Copyright (c) 2011 ARM Limited 38292SN/A * All rights reserved 48292SN/A * 58292SN/A * The license below extends only to copyright in the software and shall 68292SN/A * not be construed as granting a license to any other intellectual 78292SN/A * property including but not limited to intellectual property relating 88292SN/A * to a hardware implementation of the functionality of the software 98292SN/A * licensed hereunder. You may use the software subject to the license 108292SN/A * terms below provided that you ensure that this notice is replicated 118292SN/A * unmodified and in its entirety in all distributions of the software, 128292SN/A * modified or unmodified, in source code or in binary form. 138292SN/A * 148292SN/A * Copyright (c) 2006 The Regents of The University of Michigan 158292SN/A * All rights reserved. 168292SN/A * 178292SN/A * Redistribution and use in source and binary forms, with or without 188292SN/A * modification, are permitted provided that the following conditions are 198292SN/A * met: redistributions of source code must retain the above copyright 208292SN/A * notice, this list of conditions and the following disclaimer; 218292SN/A * redistributions in binary form must reproduce the above copyright 228292SN/A * notice, this list of conditions and the following disclaimer in the 238292SN/A * documentation and/or other materials provided with the distribution; 248292SN/A * neither the name of the copyright holders nor the names of its 258292SN/A * contributors may be used to endorse or promote products derived from 268292SN/A * this software without specific prior written permission. 278292SN/A * 288292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 298292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 308292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3113774Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3213774Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3313774Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 348292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 358292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 368292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3713774Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 389100SBrad.Beckmann@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 399148Spowerjg@cs.wisc.edu * 408292SN/A * Authors: Ali Saidi 418292SN/A */ 429100SBrad.Beckmann@amd.com 439100SBrad.Beckmann@amd.com/** 448292SN/A * @file 459862Snilay@cs.wisc.edu * Definition of a bus object. 469100SBrad.Beckmann@amd.com */ 479862Snilay@cs.wisc.edu 4811666Stushar@ece.gatech.edu#include <algorithm> 4911666Stushar@ece.gatech.edu#include <limits> 5011666Stushar@ece.gatech.edu 5111666Stushar@ece.gatech.edu#include "base/misc.hh" 5211666Stushar@ece.gatech.edu#include "base/trace.hh" 5311666Stushar@ece.gatech.edu#include "debug/Bus.hh" 5411666Stushar@ece.gatech.edu#include "debug/BusAddrRanges.hh" 5511666Stushar@ece.gatech.edu#include "debug/MMU.hh" 5611666Stushar@ece.gatech.edu#include "mem/bus.hh" 5711666Stushar@ece.gatech.edu 5811666Stushar@ece.gatech.eduBus::Bus(const BusParams *p) 5911666Stushar@ece.gatech.edu : MemObject(p), busId(p->bus_id), clock(p->clock), 609862Snilay@cs.wisc.edu headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 618292SN/A drainEvent(NULL), busIdle(this), inRetry(false), maxId(0), 6211666Stushar@ece.gatech.edu defaultPort(NULL), funcPort(NULL), funcPortId(-4), 6311666Stushar@ece.gatech.edu useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size), 649100SBrad.Beckmann@amd.com cachedBlockSize(0), cachedBlockSizeValid(false) 659862Snilay@cs.wisc.edu{ 669862Snilay@cs.wisc.edu //width, clock period, and header cycles must be positive 679100SBrad.Beckmann@amd.com if (width <= 0) 689100SBrad.Beckmann@amd.com fatal("Bus width must be positive\n"); 6913731Sandreas.sandberg@arm.com if (clock <= 0) 7013731Sandreas.sandberg@arm.com fatal("Bus clock period must be positive\n"); 719100SBrad.Beckmann@amd.com if (headerCycles <= 0) 729100SBrad.Beckmann@amd.com fatal("Number of header cycles must be positive\n"); 739100SBrad.Beckmann@amd.com clearBusCache(); 7411663Stushar@ece.gatech.edu clearPortCache(); 7511666Stushar@ece.gatech.edu} 7611666Stushar@ece.gatech.edu 779100SBrad.Beckmann@amd.comPort * 789862Snilay@cs.wisc.eduBus::getPort(const std::string &if_name, int idx) 79{ 80 if (if_name == "default") { 81 if (defaultPort == NULL) { 82 defaultPort = new BusPort(csprintf("%s-default",name()), this, 83 defaultId); 84 cachedBlockSizeValid = false; 85 return defaultPort; 86 } else 87 fatal("Default port already set\n"); 88 } 89 int id; 90 if (if_name == "functional") { 91 if (!funcPort) { 92 id = maxId++; 93 funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 94 funcPortId = id; 95 interfaces[id] = funcPort; 96 } 97 return funcPort; 98 } 99 100 // if_name ignored? forced to be empty? 101 id = maxId++; 102 assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 103 BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 104 interfaces[id] = bp; 105 cachedBlockSizeValid = false; 106 return bp; 107} 108 109void 110Bus::init() 111{ 112 m5::hash_map<short,BusPort*>::iterator intIter; 113 114 // iterate over our interfaces and determine which of our neighbours 115 // are snooping and add them as snoopers 116 for (intIter = interfaces.begin(); intIter != interfaces.end(); 117 intIter++) { 118 if (intIter->second->getPeer()->isSnooping()) { 119 DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", 120 intIter->second->getPeer()->name()); 121 snoopPorts.push_back(intIter->second); 122 } 123 } 124} 125 126Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) 127 : bus(_bus) 128{} 129 130void 131Bus::BusFreeEvent::process() 132{ 133 bus->recvRetry(-1); 134} 135 136const char * 137Bus::BusFreeEvent::description() const 138{ 139 return "bus became available"; 140} 141 142Tick 143Bus::calcPacketTiming(PacketPtr pkt) 144{ 145 // Bring tickNextIdle up to the present tick. 146 // There is some potential ambiguity where a cycle starts, which 147 // might make a difference when devices are acting right around a 148 // cycle boundary. Using a < allows things which happen exactly on 149 // a cycle boundary to take up only the following cycle. Anything 150 // that happens later will have to "wait" for the end of that 151 // cycle, and then start using the bus after that. 152 if (tickNextIdle < curTick()) { 153 tickNextIdle = curTick(); 154 if (tickNextIdle % clock != 0) 155 tickNextIdle = curTick() - (curTick() % clock) + clock; 156 } 157 158 Tick headerTime = tickNextIdle + headerCycles * clock; 159 160 // The packet will be sent. Figure out how long it occupies the bus, and 161 // how much of that time is for the first "word", aka bus width. 162 int numCycles = 0; 163 if (pkt->hasData()) { 164 // If a packet has data, it needs ceil(size/width) cycles to send it 165 int dataSize = pkt->getSize(); 166 numCycles += dataSize/width; 167 if (dataSize % width) 168 numCycles++; 169 } 170 171 // The first word will be delivered after the current tick, the delivery 172 // of the address if any, and one bus cycle to deliver the data 173 pkt->firstWordTime = headerTime + clock; 174 175 pkt->finishTime = headerTime + numCycles * clock; 176 177 return headerTime; 178} 179 180void Bus::occupyBus(Tick until) 181{ 182 if (until == 0) { 183 // shortcut for express snoop packets 184 return; 185 } 186 187 tickNextIdle = until; 188 reschedule(busIdle, tickNextIdle, true); 189 190 DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 191 curTick(), tickNextIdle); 192} 193 194/** Function called by the port when the bus is receiving a Timing 195 * transaction.*/ 196bool 197Bus::recvTiming(PacketPtr pkt) 198{ 199 short src = pkt->getSrc(); 200 201 BusPort *src_port; 202 if (src == defaultId) 203 src_port = defaultPort; 204 else { 205 src_port = checkBusCache(src); 206 if (src_port == NULL) { 207 src_port = interfaces[src]; 208 updateBusCache(src, src_port); 209 } 210 } 211 212 // If the bus is busy, or other devices are in line ahead of the current 213 // one, put this device on the retry list. 214 if (!pkt->isExpressSnoop() && 215 (tickNextIdle > curTick() || 216 (retryList.size() && (!inRetry || src_port != retryList.front())))) 217 { 218 addToRetryList(src_port); 219 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n", 220 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 221 return false; 222 } 223 224 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", 225 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 226 227 Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); 228 Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; 229 230 short dest = pkt->getDest(); 231 int dest_port_id; 232 Port *dest_port; 233 234 if (dest == Packet::Broadcast) { 235 dest_port_id = findPort(pkt->getAddr()); 236 dest_port = (dest_port_id == defaultId) ? 237 defaultPort : interfaces[dest_port_id]; 238 SnoopIter s_end = snoopPorts.end(); 239 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 240 BusPort *p = *s_iter; 241 if (p != dest_port && p != src_port) { 242 // cache is not allowed to refuse snoop 243 bool success M5_VAR_USED = p->sendTiming(pkt); 244 assert(success); 245 } 246 } 247 } else { 248 assert(dest < maxId); 249 assert(dest != src); // catch infinite loops 250 dest_port_id = dest; 251 if (dest_port_id == defaultId) 252 dest_port = defaultPort; 253 else { 254 dest_port = checkBusCache(dest); 255 if (dest_port == NULL) { 256 dest_port = interfaces[dest_port_id]; 257 // updateBusCache(dest_port_id, dest_port); 258 } 259 } 260 dest_port = (dest_port_id == defaultId) ? 261 defaultPort : interfaces[dest_port_id]; 262 } 263 264 if (dest_port_id == src) { 265 // Must be forwarded snoop up from below... 266 assert(dest == Packet::Broadcast); 267 } else { 268 // send to actual target 269 if (!dest_port->sendTiming(pkt)) { 270 // Packet not successfully sent. Leave or put it on the retry list. 271 // illegal to block responses... can lead to deadlock 272 assert(!pkt->isResponse()); 273 // It's also illegal to force a transaction to retry after 274 // someone else has committed to respond. 275 assert(!pkt->memInhibitAsserted()); 276 DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 277 src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 278 addToRetryList(src_port); 279 occupyBus(headerFinishTime); 280 return false; 281 } 282 // send OK, fall through... pkt may have been deleted by 283 // target at this point, so it should *not* be referenced 284 // again. We'll set it to NULL here just to be safe. 285 pkt = NULL; 286 } 287 288 occupyBus(packetFinishTime); 289 290 // Packet was successfully sent. 291 // Also take care of retries 292 if (inRetry) { 293 DPRINTF(Bus, "Remove retry from list %d\n", src); 294 retryList.front()->onRetryList(false); 295 retryList.pop_front(); 296 inRetry = false; 297 } 298 return true; 299} 300 301void 302Bus::recvRetry(int id) 303{ 304 // If there's anything waiting, and the bus isn't busy... 305 if (retryList.size() && curTick() >= tickNextIdle) { 306 //retryingPort = retryList.front(); 307 inRetry = true; 308 DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 309 retryList.front()->sendRetry(); 310 // If inRetry is still true, sendTiming wasn't called 311 if (inRetry) 312 { 313 retryList.front()->onRetryList(false); 314 retryList.pop_front(); 315 inRetry = false; 316 317 //Bring tickNextIdle up to the present 318 while (tickNextIdle < curTick()) 319 tickNextIdle += clock; 320 321 //Burn a cycle for the missed grant. 322 tickNextIdle += clock; 323 324 reschedule(busIdle, tickNextIdle, true); 325 } 326 } 327 //If we weren't able to drain before, we might be able to now. 328 if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) { 329 drainEvent->process(); 330 // Clear the drain event once we're done with it. 331 drainEvent = NULL; 332 } 333} 334 335int 336Bus::findPort(Addr addr) 337{ 338 /* An interval tree would be a better way to do this. --ali. */ 339 int dest_id; 340 341 dest_id = checkPortCache(addr); 342 if (dest_id != -1) 343 return dest_id; 344 345 // Check normal port ranges 346 PortIter i = portMap.find(RangeSize(addr,1)); 347 if (i != portMap.end()) { 348 dest_id = i->second; 349 updatePortCache(dest_id, i->first.start, i->first.end); 350 return dest_id; 351 } 352 353 // Check if this matches the default range 354 if (useDefaultRange) { 355 AddrRangeIter a_end = defaultRange.end(); 356 for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 357 if (*i == addr) { 358 DPRINTF(Bus, " found addr %#llx on default\n", addr); 359 return defaultId; 360 } 361 } 362 363 panic("Unable to find destination for addr %#llx\n", addr); 364 } 365 366 DPRINTF(Bus, "Unable to find destination for addr %#llx, " 367 "will use default port\n", addr); 368 return defaultId; 369} 370 371 372/** Function called by the port when the bus is receiving a Atomic 373 * transaction.*/ 374Tick 375Bus::recvAtomic(PacketPtr pkt) 376{ 377 DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 378 pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 379 assert(pkt->getDest() == Packet::Broadcast); 380 assert(pkt->isRequest()); 381 382 // Variables for recording original command and snoop response (if 383 // any)... if a snooper respondes, we will need to restore 384 // original command so that additional snoops can take place 385 // properly 386 MemCmd orig_cmd = pkt->cmd; 387 MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 388 Tick snoop_response_latency = 0; 389 int orig_src = pkt->getSrc(); 390 391 int target_port_id = findPort(pkt->getAddr()); 392 BusPort *target_port; 393 if (target_port_id == defaultId) 394 target_port = defaultPort; 395 else { 396 target_port = checkBusCache(target_port_id); 397 if (target_port == NULL) { 398 target_port = interfaces[target_port_id]; 399 updateBusCache(target_port_id, target_port); 400 } 401 } 402 403 SnoopIter s_end = snoopPorts.end(); 404 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 405 BusPort *p = *s_iter; 406 // same port should not have both target addresses and snooping 407 assert(p != target_port); 408 if (p->getId() != pkt->getSrc()) { 409 Tick latency = p->sendAtomic(pkt); 410 if (pkt->isResponse()) { 411 // response from snoop agent 412 assert(pkt->cmd != orig_cmd); 413 assert(pkt->memInhibitAsserted()); 414 // should only happen once 415 assert(snoop_response_cmd == MemCmd::InvalidCmd); 416 // save response state 417 snoop_response_cmd = pkt->cmd; 418 snoop_response_latency = latency; 419 // restore original packet state for remaining snoopers 420 pkt->cmd = orig_cmd; 421 pkt->setSrc(orig_src); 422 pkt->setDest(Packet::Broadcast); 423 } 424 } 425 } 426 427 Tick response_latency = 0; 428 429 // we can get requests sent up from the memory side of the bus for 430 // snooping... don't send them back down! 431 if (target_port_id != pkt->getSrc()) { 432 response_latency = target_port->sendAtomic(pkt); 433 } 434 435 // if we got a response from a snooper, restore it here 436 if (snoop_response_cmd != MemCmd::InvalidCmd) { 437 // no one else should have responded 438 assert(!pkt->isResponse()); 439 assert(pkt->cmd == orig_cmd); 440 pkt->cmd = snoop_response_cmd; 441 response_latency = snoop_response_latency; 442 } 443 444 // why do we have this packet field and the return value both??? 445 pkt->finishTime = curTick() + response_latency; 446 return response_latency; 447} 448 449/** Function called by the port when the bus is receiving a Functional 450 * transaction.*/ 451void 452Bus::recvFunctional(PacketPtr pkt) 453{ 454 assert(pkt->getDest() == Packet::Broadcast); 455 456 int port_id = findPort(pkt->getAddr()); 457 Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id]; 458 // The packet may be changed by another bus on snoops, restore the 459 // id after each 460 int src_id = pkt->getSrc(); 461 462 if (!pkt->isPrint()) { 463 // don't do DPRINTFs on PrintReq as it clutters up the output 464 DPRINTF(Bus, 465 "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 466 src_id, port_id, pkt->getAddr(), 467 pkt->cmdString()); 468 } 469 470 assert(pkt->isRequest()); // hasn't already been satisfied 471 472 SnoopIter s_end = snoopPorts.end(); 473 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 474 BusPort *p = *s_iter; 475 if (p != port && p->getId() != src_id) { 476 p->sendFunctional(pkt); 477 } 478 if (pkt->isResponse()) { 479 break; 480 } 481 pkt->setSrc(src_id); 482 } 483 484 // If the snooping hasn't found what we were looking for, keep going. 485 if (!pkt->isResponse() && port_id != pkt->getSrc()) { 486 port->sendFunctional(pkt); 487 } 488} 489 490/** Function called by the port when the bus is receiving a range change.*/ 491void 492Bus::recvRangeChange(int id) 493{ 494 AddrRangeList ranges; 495 AddrRangeIter iter; 496 497 if (inRecvRangeChange.count(id)) 498 return; 499 inRecvRangeChange.insert(id); 500 501 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 502 503 clearPortCache(); 504 if (id == defaultId) { 505 defaultRange.clear(); 506 // Only try to update these ranges if the user set a default responder. 507 if (useDefaultRange) { 508 AddrRangeList ranges = defaultPort->getPeer()->getAddrRanges(); 509 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 510 defaultRange.push_back(*iter); 511 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 512 iter->start, iter->end); 513 } 514 } 515 } else { 516 517 assert((id < maxId && id >= 0) || id == defaultId); 518 BusPort *port = interfaces[id]; 519 520 // Clean out any previously existent ids 521 for (PortIter portIter = portMap.begin(); 522 portIter != portMap.end(); ) { 523 if (portIter->second == id) 524 portMap.erase(portIter++); 525 else 526 portIter++; 527 } 528 529 ranges = port->getPeer()->getAddrRanges(); 530 531 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 532 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 533 iter->start, iter->end, id); 534 if (portMap.insert(*iter, id) == portMap.end()) { 535 int conflict_id = portMap.find(*iter)->second; 536 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 537 name(), interfaces[id]->getPeer()->name(), 538 interfaces[conflict_id]->getPeer()->name()); 539 } 540 } 541 } 542 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 543 544 // tell all our peers that our address range has changed. 545 // Don't tell the device that caused this change, it already knows 546 m5::hash_map<short,BusPort*>::iterator intIter; 547 548 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 549 if (intIter->first != id && intIter->first != funcPortId) 550 intIter->second->sendRangeChange(); 551 552 if (id != defaultId && defaultPort) 553 defaultPort->sendRangeChange(); 554 inRecvRangeChange.erase(id); 555} 556 557AddrRangeList 558Bus::getAddrRanges(int id) 559{ 560 AddrRangeList ranges; 561 562 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 563 564 for (AddrRangeIter dflt_iter = defaultRange.begin(); 565 dflt_iter != defaultRange.end(); dflt_iter++) { 566 ranges.push_back(*dflt_iter); 567 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 568 dflt_iter->end); 569 } 570 for (PortIter portIter = portMap.begin(); 571 portIter != portMap.end(); portIter++) { 572 bool subset = false; 573 for (AddrRangeIter dflt_iter = defaultRange.begin(); 574 dflt_iter != defaultRange.end(); dflt_iter++) { 575 if ((portIter->first.start < dflt_iter->start && 576 portIter->first.end >= dflt_iter->start) || 577 (portIter->first.start < dflt_iter->end && 578 portIter->first.end >= dflt_iter->end)) 579 fatal("Devices can not set ranges that itersect the default set\ 580 but are not a subset of the default set.\n"); 581 if (portIter->first.start >= dflt_iter->start && 582 portIter->first.end <= dflt_iter->end) { 583 subset = true; 584 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 585 portIter->first.start, portIter->first.end); 586 } 587 } 588 if (portIter->second != id && !subset) { 589 ranges.push_back(portIter->first); 590 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 591 portIter->first.start, portIter->first.end); 592 } 593 } 594 595 return ranges; 596} 597 598bool 599Bus::isSnooping(int id) 600{ 601 // in essence, answer the question if there are other snooping 602 // ports rather than the port that is asking 603 bool snoop = false; 604 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 605 s_iter++) { 606 if ((*s_iter)->getId() != id) { 607 snoop = true; 608 break; 609 } 610 } 611 return snoop; 612} 613 614unsigned 615Bus::findBlockSize(int id) 616{ 617 if (cachedBlockSizeValid) 618 return cachedBlockSize; 619 620 unsigned max_bs = 0; 621 622 PortIter p_end = portMap.end(); 623 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 624 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 625 if (tmp_bs > max_bs) 626 max_bs = tmp_bs; 627 } 628 SnoopIter s_end = snoopPorts.end(); 629 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 630 unsigned tmp_bs = (*s_iter)->peerBlockSize(); 631 if (tmp_bs > max_bs) 632 max_bs = tmp_bs; 633 } 634 if (max_bs == 0) 635 max_bs = defaultBlockSize; 636 637 if (max_bs != 64) 638 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 639 cachedBlockSize = max_bs; 640 cachedBlockSizeValid = true; 641 return max_bs; 642} 643 644 645unsigned int 646Bus::drain(Event * de) 647{ 648 //We should check that we're not "doing" anything, and that noone is 649 //waiting. We might be idle but have someone waiting if the device we 650 //contacted for a retry didn't actually retry. 651 if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) { 652 drainEvent = de; 653 return 1; 654 } 655 return 0; 656} 657 658void 659Bus::startup() 660{ 661 if (tickNextIdle < curTick()) 662 tickNextIdle = (curTick() / clock) * clock + clock; 663} 664 665Bus * 666BusParams::create() 667{ 668 return new Bus(this); 669} 670