coherent_xbar.cc revision 5197
16145SN/A/* 28683SN/A * Copyright (c) 2006 The Regents of The University of Michigan 310973Sdavid.hashe@amd.com * All rights reserved. 46145SN/A * 56145SN/A * Redistribution and use in source and binary forms, with or without 66145SN/A * modification, are permitted provided that the following conditions are 76145SN/A * met: redistributions of source code must retain the above copyright 86145SN/A * notice, this list of conditions and the following disclaimer; 96145SN/A * redistributions in binary form must reproduce the above copyright 106145SN/A * notice, this list of conditions and the following disclaimer in the 116145SN/A * documentation and/or other materials provided with the distribution; 126145SN/A * neither the name of the copyright holders nor the names of its 136145SN/A * contributors may be used to endorse or promote products derived from 146145SN/A * this software without specific prior written permission. 156145SN/A * 166145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276145SN/A * 286145SN/A * Authors: Ali Saidi 296145SN/A */ 3010441Snilay@cs.wisc.edu 3110441Snilay@cs.wisc.edu/** 326145SN/A * @file 337055SN/A * Definition of a bus object. 346145SN/A */ 356145SN/A 367039SN/A#include <algorithm> 379104SN/A#include <limits> 3810301Snilay@cs.wisc.edu 399105SN/A#include "base/misc.hh" 408174SN/A#include "base/trace.hh" 417039SN/A#include "mem/bus.hh" 427039SN/A 437039SN/APort * 4410970Sdavid.hashe@amd.comBus::getPort(const std::string &if_name, int idx) 4510301Snilay@cs.wisc.edu{ 4610301Snilay@cs.wisc.edu if (if_name == "default") { 477039SN/A if (defaultPort == NULL) { 487039SN/A defaultPort = new BusPort(csprintf("%s-default",name()), this, 496145SN/A defaultId); 507039SN/A cachedBlockSizeValid = false; 517039SN/A return defaultPort; 527039SN/A } else 536876SN/A fatal("Default port already set\n"); 547039SN/A } 557039SN/A int id; 566145SN/A if (if_name == "functional") { 577039SN/A if (!funcPort) { 586145SN/A id = maxId++; 597039SN/A funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id); 607039SN/A funcPortId = id; 618165SN/A interfaces[id] = funcPort; 627039SN/A } 636145SN/A return funcPort; 647039SN/A } 658165SN/A 667039SN/A // if_name ignored? forced to be empty? 676145SN/A id = maxId++; 687039SN/A assert(maxId < std::numeric_limits<typeof(maxId)>::max()); 697039SN/A BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); 706145SN/A interfaces[id] = bp; 717039SN/A cachedBlockSizeValid = false; 727039SN/A return bp; 737039SN/A} 747039SN/A 756145SN/Avoid 767039SN/ABus::deletePortRefs(Port *p) 777839SN/A{ 788193SN/A 798193SN/A BusPort *bp = dynamic_cast<BusPort*>(p); 808193SN/A if (bp == NULL) 818193SN/A panic("Couldn't convert Port* to BusPort*\n"); 826145SN/A // If this is our one functional port 837039SN/A if (funcPort == bp) 847039SN/A return; 856145SN/A interfaces.erase(bp->getId()); 867039SN/A clearBusCache(); 877039SN/A delete bp; 886145SN/A} 897039SN/A 907839SN/A/** Get the ranges of anyone other buses that we are connected to. */ 917839SN/Avoid 926145SN/ABus::init() 939499SN/A{ 9410969Sdavid.hashe@amd.com m5::hash_map<short,BusPort*>::iterator intIter; 9510969Sdavid.hashe@amd.com 9610969Sdavid.hashe@amd.com for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 976285SN/A intIter->second->sendStatusChange(Port::RangeChange); 987039SN/A} 998683SN/A 1006145SN/ABus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) 1017039SN/A{} 1027039SN/A 1036145SN/Avoid Bus::BusFreeEvent::process() 1047039SN/A{ 1057039SN/A bus->recvRetry(-1); 1067039SN/A} 1079692SN/A 1087039SN/Aconst char * Bus::BusFreeEvent::description() 1097055SN/A{ 1107055SN/A return "bus became available"; 1116145SN/A} 1129692SN/A 1139692SN/Avoid Bus::occupyBus(PacketPtr pkt) 1149692SN/A{ 1156374SN/A //Bring tickNextIdle up to the present tick 1169692SN/A //There is some potential ambiguity where a cycle starts, which might make 1179692SN/A //a difference when devices are acting right around a cycle boundary. Using 1189692SN/A //a < allows things which happen exactly on a cycle boundary to take up 1199692SN/A //only the following cycle. Anything that happens later will have to "wait" 1209692SN/A //for the end of that cycle, and then start using the bus after that. 1219692SN/A if (tickNextIdle < curTick) { 1229692SN/A tickNextIdle = curTick; 1239692SN/A if (tickNextIdle % clock != 0) 1249692SN/A tickNextIdle = curTick - (curTick % clock) + clock; 1259692SN/A } 1269104SN/A 1279104SN/A // The packet will be sent. Figure out how long it occupies the bus, and 1289104SN/A // how much of that time is for the first "word", aka bus width. 1299104SN/A int numCycles = 0; 1309104SN/A // Requests need one cycle to send an address 1319104SN/A if (pkt->isRequest()) 1329105SN/A numCycles++; 1339105SN/A else if (pkt->isResponse() || pkt->hasData()) { 1349692SN/A // If a packet has data, it needs ceil(size/width) cycles to send it 13510973Sdavid.hashe@amd.com // We're using the "adding instead of dividing" trick again here 13610973Sdavid.hashe@amd.com if (pkt->hasData()) { 13710973Sdavid.hashe@amd.com int dataSize = pkt->getSize(); 13810973Sdavid.hashe@amd.com numCycles += dataSize/width; 1397039SN/A if (dataSize % width) 1407039SN/A numCycles++; 14110314Snilay@cs.wisc.edu } else { 1426145SN/A // If the packet didn't have data, it must have been a response. 1437039SN/A // Those use the bus for one cycle to send their data. 1447039SN/A numCycles++; 14510314Snilay@cs.wisc.edu } 14610314Snilay@cs.wisc.edu } 1477039SN/A 1486145SN/A // The first word will be delivered after the current tick, the delivery 1497039SN/A // of the address if any, and one bus cycle to deliver the data 1507039SN/A pkt->firstWordTime = tickNextIdle + (pkt->isRequest() ? clock : 0) + clock; 1517039SN/A 1526145SN/A //Advance it numCycles bus cycles. 1537039SN/A //XXX Should this use the repeated addition trick as well? 1549499SN/A tickNextIdle += (numCycles * clock); 1556145SN/A if (!busIdle.scheduled()) { 1567039SN/A busIdle.schedule(tickNextIdle); 1577039SN/A } else { 1586285SN/A busIdle.reschedule(tickNextIdle); 1597039SN/A } 1607039SN/A DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1617039SN/A curTick, tickNextIdle); 1627454SN/A 1636145SN/A // The bus will become idle once the current packet is delivered. 1647039SN/A pkt->finishTime = tickNextIdle; 1656145SN/A} 1669105SN/A 1679105SN/A/** Function called by the port when the bus is receiving a Timing 1689105SN/A * transaction.*/ 1697039SN/Abool 1707039SN/ABus::recvTiming(PacketPtr pkt) 1717039SN/A{ 1727039SN/A short src = pkt->getSrc(); 1737564SN/A 1749105SN/A BusPort *src_port; 1756145SN/A if (src == defaultId) 1766145SN/A src_port = defaultPort; 1779554SN/A else { 1789554SN/A src_port = checkBusCache(src); 17910441Snilay@cs.wisc.edu 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