xbar.cc revision 10405
1/* 2 * Copyright (c) 2011-2014 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 crossbar object. 48 */ 49 50#include "base/misc.hh" 51#include "base/trace.hh" 52#include "debug/AddrRanges.hh" 53#include "debug/Drain.hh" 54#include "debug/XBar.hh" 55#include "mem/xbar.hh" 56 57BaseXBar::BaseXBar(const BaseXBarParams *p) 58 : MemObject(p), 59 headerCycles(p->header_cycles), width(p->width), 60 gotAddrRanges(p->port_default_connection_count + 61 p->port_master_connection_count, false), 62 gotAllAddrRanges(false), defaultPortID(InvalidPortID), 63 useDefaultRange(p->use_default_range) 64{} 65 66BaseXBar::~BaseXBar() 67{ 68 for (auto m: masterPorts) 69 delete m; 70 71 for (auto s: slavePorts) 72 delete s; 73} 74 75void 76BaseXBar::init() 77{ 78} 79 80BaseMasterPort & 81BaseXBar::getMasterPort(const std::string &if_name, PortID idx) 82{ 83 if (if_name == "master" && idx < masterPorts.size()) { 84 // the master port index translates directly to the vector position 85 return *masterPorts[idx]; 86 } else if (if_name == "default") { 87 return *masterPorts[defaultPortID]; 88 } else { 89 return MemObject::getMasterPort(if_name, idx); 90 } 91} 92 93BaseSlavePort & 94BaseXBar::getSlavePort(const std::string &if_name, PortID idx) 95{ 96 if (if_name == "slave" && idx < slavePorts.size()) { 97 // the slave port index translates directly to the vector position 98 return *slavePorts[idx]; 99 } else { 100 return MemObject::getSlavePort(if_name, idx); 101 } 102} 103 104void 105BaseXBar::calcPacketTiming(PacketPtr pkt) 106{ 107 // the crossbar will be called at a time that is not necessarily 108 // coinciding with its own clock, so start by determining how long 109 // until the next clock edge (could be zero) 110 Tick offset = clockEdge() - curTick(); 111 112 // determine how many cycles are needed to send the data 113 unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0; 114 115 // before setting the bus delay fields of the packet, ensure that 116 // the delay from any previous crossbar has been accounted for 117 if (pkt->firstWordDelay != 0 || pkt->lastWordDelay != 0) 118 panic("Packet %s already has delay (%d, %d) that should be " 119 "accounted for.\n", pkt->cmdString(), pkt->firstWordDelay, 120 pkt->lastWordDelay); 121 122 // The first word will be delivered on the cycle after the header. 123 pkt->firstWordDelay = (headerCycles + 1) * clockPeriod() + offset; 124 125 // Note that currently lastWordDelay can be smaller than 126 // firstWordDelay if the packet has no data 127 pkt->lastWordDelay = (headerCycles + dataCycles) * clockPeriod() + 128 offset; 129} 130 131template <typename SrcType, typename DstType> 132BaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar, 133 const std::string& _name) : 134 port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL), 135 waitingForPeer(NULL), releaseEvent(this) 136{ 137} 138 139template <typename SrcType, typename DstType> 140void BaseXBar::Layer<SrcType,DstType>::occupyLayer(Tick until) 141{ 142 // ensure the state is busy at this point, as the layer should 143 // transition from idle as soon as it has decided to forward the 144 // packet to prevent any follow-on calls to sendTiming seeing an 145 // unoccupied layer 146 assert(state == BUSY); 147 148 // until should never be 0 as express snoops never occupy the layer 149 assert(until != 0); 150 xbar.schedule(releaseEvent, until); 151 152 // account for the occupied ticks 153 occupancy += until - curTick(); 154 155 DPRINTF(BaseXBar, "The crossbar layer is now busy from tick %d to %d\n", 156 curTick(), until); 157} 158 159template <typename SrcType, typename DstType> 160bool 161BaseXBar::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) 162{ 163 // if we are in the retry state, we will not see anything but the 164 // retrying port (or in the case of the snoop ports the snoop 165 // response port that mirrors the actual slave port) as we leave 166 // this state again in zero time if the peer does not immediately 167 // call the layer when receiving the retry 168 169 // first we see if the layer is busy, next we check if the 170 // destination port is already engaged in a transaction waiting 171 // for a retry from the peer 172 if (state == BUSY || waitingForPeer != NULL) { 173 // the port should not be waiting already 174 assert(std::find(waitingForLayer.begin(), waitingForLayer.end(), 175 src_port) == waitingForLayer.end()); 176 177 // put the port at the end of the retry list waiting for the 178 // layer to be freed up (and in the case of a busy peer, for 179 // that transaction to go through, and then the layer to free 180 // up) 181 waitingForLayer.push_back(src_port); 182 return false; 183 } 184 185 state = BUSY; 186 187 return true; 188} 189 190template <typename SrcType, typename DstType> 191void 192BaseXBar::Layer<SrcType,DstType>::succeededTiming(Tick busy_time) 193{ 194 // we should have gone from idle or retry to busy in the tryTiming 195 // test 196 assert(state == BUSY); 197 198 // occupy the layer accordingly 199 occupyLayer(busy_time); 200} 201 202template <typename SrcType, typename DstType> 203void 204BaseXBar::Layer<SrcType,DstType>::failedTiming(SrcType* src_port, 205 Tick busy_time) 206{ 207 // ensure no one got in between and tried to send something to 208 // this port 209 assert(waitingForPeer == NULL); 210 211 // if the source port is the current retrying one or not, we have 212 // failed in forwarding and should track that we are now waiting 213 // for the peer to send a retry 214 waitingForPeer = src_port; 215 216 // we should have gone from idle or retry to busy in the tryTiming 217 // test 218 assert(state == BUSY); 219 220 // occupy the bus accordingly 221 occupyLayer(busy_time); 222} 223 224template <typename SrcType, typename DstType> 225void 226BaseXBar::Layer<SrcType,DstType>::releaseLayer() 227{ 228 // releasing the bus means we should now be idle 229 assert(state == BUSY); 230 assert(!releaseEvent.scheduled()); 231 232 // update the state 233 state = IDLE; 234 235 // bus layer is now idle, so if someone is waiting we can retry 236 if (!waitingForLayer.empty()) { 237 // there is no point in sending a retry if someone is still 238 // waiting for the peer 239 if (waitingForPeer == NULL) 240 retryWaiting(); 241 } else if (waitingForPeer == NULL && drainManager) { 242 DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n"); 243 //If we weren't able to drain before, do it now. 244 drainManager->signalDrainDone(); 245 // Clear the drain event once we're done with it. 246 drainManager = NULL; 247 } 248} 249 250template <typename SrcType, typename DstType> 251void 252BaseXBar::Layer<SrcType,DstType>::retryWaiting() 253{ 254 // this should never be called with no one waiting 255 assert(!waitingForLayer.empty()); 256 257 // we always go to retrying from idle 258 assert(state == IDLE); 259 260 // update the state 261 state = RETRY; 262 263 // set the retrying port to the front of the retry list and pop it 264 // off the list 265 SrcType* retryingPort = waitingForLayer.front(); 266 waitingForLayer.pop_front(); 267 268 // tell the port to retry, which in some cases ends up calling the 269 // layer again 270 retryingPort->sendRetry(); 271 272 // If the layer is still in the retry state, sendTiming wasn't 273 // called in zero time (e.g. the cache does this), burn a cycle 274 if (state == RETRY) { 275 // update the state to busy and reset the retrying port, we 276 // have done our bit and sent the retry 277 state = BUSY; 278 279 // occupy the crossbar layer until the next cycle ends 280 occupyLayer(xbar.clockEdge(Cycles(1))); 281 } 282} 283 284template <typename SrcType, typename DstType> 285void 286BaseXBar::Layer<SrcType,DstType>::recvRetry() 287{ 288 // we should never get a retry without having failed to forward 289 // something to this port 290 assert(waitingForPeer != NULL); 291 292 // add the port where the failed packet originated to the front of 293 // the waiting ports for the layer, this allows us to call retry 294 // on the port immediately if the crossbar layer is idle 295 waitingForLayer.push_front(waitingForPeer); 296 297 // we are no longer waiting for the peer 298 waitingForPeer = NULL; 299 300 // if the layer is idle, retry this port straight away, if we 301 // are busy, then simply let the port wait for its turn 302 if (state == IDLE) { 303 retryWaiting(); 304 } else { 305 assert(state == BUSY); 306 } 307} 308 309PortID 310BaseXBar::findPort(Addr addr) 311{ 312 // we should never see any address lookups before we've got the 313 // ranges of all connected slave modules 314 assert(gotAllAddrRanges); 315 316 // Check the cache 317 PortID dest_id = checkPortCache(addr); 318 if (dest_id != InvalidPortID) 319 return dest_id; 320 321 // Check the address map interval tree 322 auto i = portMap.find(addr); 323 if (i != portMap.end()) { 324 dest_id = i->second; 325 updatePortCache(dest_id, i->first); 326 return dest_id; 327 } 328 329 // Check if this matches the default range 330 if (useDefaultRange) { 331 if (defaultRange.contains(addr)) { 332 DPRINTF(AddrRanges, " found addr %#llx on default\n", 333 addr); 334 return defaultPortID; 335 } 336 } else if (defaultPortID != InvalidPortID) { 337 DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, " 338 "will use default port\n", addr); 339 return defaultPortID; 340 } 341 342 // we should use the range for the default port and it did not 343 // match, or the default port is not set 344 fatal("Unable to find destination for addr %#llx on %s\n", addr, 345 name()); 346} 347 348/** Function called by the port when the crossbar is receiving a range change.*/ 349void 350BaseXBar::recvRangeChange(PortID master_port_id) 351{ 352 DPRINTF(AddrRanges, "Received range change from slave port %s\n", 353 masterPorts[master_port_id]->getSlavePort().name()); 354 355 // remember that we got a range from this master port and thus the 356 // connected slave module 357 gotAddrRanges[master_port_id] = true; 358 359 // update the global flag 360 if (!gotAllAddrRanges) { 361 // take a logical AND of all the ports and see if we got 362 // ranges from everyone 363 gotAllAddrRanges = true; 364 std::vector<bool>::const_iterator r = gotAddrRanges.begin(); 365 while (gotAllAddrRanges && r != gotAddrRanges.end()) { 366 gotAllAddrRanges &= *r++; 367 } 368 if (gotAllAddrRanges) 369 DPRINTF(AddrRanges, "Got address ranges from all slaves\n"); 370 } 371 372 // note that we could get the range from the default port at any 373 // point in time, and we cannot assume that the default range is 374 // set before the other ones are, so we do additional checks once 375 // all ranges are provided 376 if (master_port_id == defaultPortID) { 377 // only update if we are indeed checking ranges for the 378 // default port since the port might not have a valid range 379 // otherwise 380 if (useDefaultRange) { 381 AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 382 383 if (ranges.size() != 1) 384 fatal("Crossbar %s may only have a single default range", 385 name()); 386 387 defaultRange = ranges.front(); 388 } 389 } else { 390 // the ports are allowed to update their address ranges 391 // dynamically, so remove any existing entries 392 if (gotAddrRanges[master_port_id]) { 393 for (auto p = portMap.begin(); p != portMap.end(); ) { 394 if (p->second == master_port_id) 395 // erasing invalidates the iterator, so advance it 396 // before the deletion takes place 397 portMap.erase(p++); 398 else 399 p++; 400 } 401 } 402 403 AddrRangeList ranges = masterPorts[master_port_id]->getAddrRanges(); 404 405 for (const auto& r: ranges) { 406 DPRINTF(AddrRanges, "Adding range %s for id %d\n", 407 r.to_string(), master_port_id); 408 if (portMap.insert(r, master_port_id) == portMap.end()) { 409 PortID conflict_id = portMap.find(r)->second; 410 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 411 name(), 412 masterPorts[master_port_id]->getSlavePort().name(), 413 masterPorts[conflict_id]->getSlavePort().name()); 414 } 415 } 416 } 417 418 // if we have received ranges from all our neighbouring slave 419 // modules, go ahead and tell our connected master modules in 420 // turn, this effectively assumes a tree structure of the system 421 if (gotAllAddrRanges) { 422 DPRINTF(AddrRanges, "Aggregating address ranges\n"); 423 xbarRanges.clear(); 424 425 // start out with the default range 426 if (useDefaultRange) { 427 if (!gotAddrRanges[defaultPortID]) 428 fatal("Crossbar %s uses default range, but none provided", 429 name()); 430 431 xbarRanges.push_back(defaultRange); 432 DPRINTF(AddrRanges, "-- Adding default %s\n", 433 defaultRange.to_string()); 434 } 435 436 // merge all interleaved ranges and add any range that is not 437 // a subset of the default range 438 std::vector<AddrRange> intlv_ranges; 439 for (const auto& r: portMap) { 440 // if the range is interleaved then save it for now 441 if (r.first.interleaved()) { 442 // if we already got interleaved ranges that are not 443 // part of the same range, then first do a merge 444 // before we add the new one 445 if (!intlv_ranges.empty() && 446 !intlv_ranges.back().mergesWith(r.first)) { 447 DPRINTF(AddrRanges, "-- Merging range from %d ranges\n", 448 intlv_ranges.size()); 449 AddrRange merged_range(intlv_ranges); 450 // next decide if we keep the merged range or not 451 if (!(useDefaultRange && 452 merged_range.isSubset(defaultRange))) { 453 xbarRanges.push_back(merged_range); 454 DPRINTF(AddrRanges, "-- Adding merged range %s\n", 455 merged_range.to_string()); 456 } 457 intlv_ranges.clear(); 458 } 459 intlv_ranges.push_back(r.first); 460 } else { 461 // keep the current range if not a subset of the default 462 if (!(useDefaultRange && 463 r.first.isSubset(defaultRange))) { 464 xbarRanges.push_back(r.first); 465 DPRINTF(AddrRanges, "-- Adding range %s\n", 466 r.first.to_string()); 467 } 468 } 469 } 470 471 // if there is still interleaved ranges waiting to be merged, 472 // go ahead and do it 473 if (!intlv_ranges.empty()) { 474 DPRINTF(AddrRanges, "-- Merging range from %d ranges\n", 475 intlv_ranges.size()); 476 AddrRange merged_range(intlv_ranges); 477 if (!(useDefaultRange && merged_range.isSubset(defaultRange))) { 478 xbarRanges.push_back(merged_range); 479 DPRINTF(AddrRanges, "-- Adding merged range %s\n", 480 merged_range.to_string()); 481 } 482 } 483 484 // also check that no range partially overlaps with the 485 // default range, this has to be done after all ranges are set 486 // as there are no guarantees for when the default range is 487 // update with respect to the other ones 488 if (useDefaultRange) { 489 for (const auto& r: xbarRanges) { 490 // see if the new range is partially 491 // overlapping the default range 492 if (r.intersects(defaultRange) && 493 !r.isSubset(defaultRange)) 494 fatal("Range %s intersects the " \ 495 "default range of %s but is not a " \ 496 "subset\n", r.to_string(), name()); 497 } 498 } 499 500 // tell all our neighbouring master ports that our address 501 // ranges have changed 502 for (const auto& s: slavePorts) 503 s->sendRangeChange(); 504 } 505 506 clearPortCache(); 507} 508 509AddrRangeList 510BaseXBar::getAddrRanges() const 511{ 512 // we should never be asked without first having sent a range 513 // change, and the latter is only done once we have all the ranges 514 // of the connected devices 515 assert(gotAllAddrRanges); 516 517 // at the moment, this never happens, as there are no cycles in 518 // the range queries and no devices on the master side of a crossbar 519 // (CPU, cache, bridge etc) actually care about the ranges of the 520 // ports they are connected to 521 522 DPRINTF(AddrRanges, "Received address range request\n"); 523 524 return xbarRanges; 525} 526 527void 528BaseXBar::regStats() 529{ 530 using namespace Stats; 531 532 transDist 533 .init(MemCmd::NUM_MEM_CMDS) 534 .name(name() + ".trans_dist") 535 .desc("Transaction distribution") 536 .flags(nozero); 537 538 // get the string representation of the commands 539 for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) { 540 MemCmd cmd(i); 541 const std::string &cstr = cmd.toString(); 542 transDist.subname(i, cstr); 543 } 544 545 pktCount 546 .init(slavePorts.size(), masterPorts.size()) 547 .name(name() + ".pkt_count") 548 .desc("Packet count per connected master and slave (bytes)") 549 .flags(total | nozero | nonan); 550 551 pktSize 552 .init(slavePorts.size(), masterPorts.size()) 553 .name(name() + ".pkt_size") 554 .desc("Cumulative packet size per connected master and slave (bytes)") 555 .flags(total | nozero | nonan); 556 557 // both the packet count and total size are two-dimensional 558 // vectors, indexed by slave port id and master port id, thus the 559 // neighbouring master and slave, they do not differentiate what 560 // came from the master and was forwarded to the slave (requests 561 // and snoop responses) and what came from the slave and was 562 // forwarded to the master (responses and snoop requests) 563 for (int i = 0; i < slavePorts.size(); i++) { 564 pktCount.subname(i, slavePorts[i]->getMasterPort().name()); 565 pktSize.subname(i, slavePorts[i]->getMasterPort().name()); 566 for (int j = 0; j < masterPorts.size(); j++) { 567 pktCount.ysubname(j, masterPorts[j]->getSlavePort().name()); 568 pktSize.ysubname(j, masterPorts[j]->getSlavePort().name()); 569 } 570 } 571} 572 573template <typename SrcType, typename DstType> 574unsigned int 575BaseXBar::Layer<SrcType,DstType>::drain(DrainManager *dm) 576{ 577 //We should check that we're not "doing" anything, and that noone is 578 //waiting. We might be idle but have someone waiting if the device we 579 //contacted for a retry didn't actually retry. 580 if (state != IDLE) { 581 DPRINTF(Drain, "Crossbar not drained\n"); 582 drainManager = dm; 583 return 1; 584 } 585 return 0; 586} 587 588template <typename SrcType, typename DstType> 589void 590BaseXBar::Layer<SrcType,DstType>::regStats() 591{ 592 using namespace Stats; 593 594 occupancy 595 .name(name() + ".occupancy") 596 .desc("Layer occupancy (ticks)") 597 .flags(nozero); 598 599 utilization 600 .name(name() + ".utilization") 601 .desc("Layer utilization (%)") 602 .precision(1) 603 .flags(nozero); 604 605 utilization = 100 * occupancy / simTicks; 606} 607 608/** 609 * Crossbar layer template instantiations. Could be removed with _impl.hh 610 * file, but since there are only two given options (MasterPort and 611 * SlavePort) it seems a bit excessive at this point. 612 */ 613template class BaseXBar::Layer<SlavePort,MasterPort>; 614template class BaseXBar::Layer<MasterPort,SlavePort>; 615