coherent_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