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