xbar.cc revision 7523
1/*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 */
30
31/**
32 * @file
33 * Definition of a bus object.
34 */
35
36#include <algorithm>
37#include <limits>
38
39#include "base/misc.hh"
40#include "base/trace.hh"
41#include "mem/bus.hh"
42
43Bus::Bus(const BusParams *p)
44    : MemObject(p), busId(p->bus_id), clock(p->clock),
45      headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
46      drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
47      defaultPort(NULL), funcPort(NULL), funcPortId(-4),
48      useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
49      cachedBlockSize(0), cachedBlockSizeValid(false)
50{
51    //width, clock period, and header cycles must be positive
52    if (width <= 0)
53        fatal("Bus width must be positive\n");
54    if (clock <= 0)
55        fatal("Bus clock period must be positive\n");
56    if (headerCycles <= 0)
57        fatal("Number of header cycles must be positive\n");
58    clearBusCache();
59    clearPortCache();
60}
61
62Port *
63Bus::getPort(const std::string &if_name, int idx)
64{
65    if (if_name == "default") {
66        if (defaultPort == NULL) {
67            defaultPort = new BusPort(csprintf("%s-default",name()), this,
68                                      defaultId);
69            cachedBlockSizeValid = false;
70            return defaultPort;
71        } else
72            fatal("Default port already set\n");
73    }
74    int id;
75    if (if_name == "functional") {
76        if (!funcPort) {
77            id = maxId++;
78            funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);
79            funcPortId = id;
80            interfaces[id] = funcPort;
81        }
82        return funcPort;
83    }
84
85    // if_name ignored?  forced to be empty?
86    id = maxId++;
87    assert(maxId < std::numeric_limits<typeof(maxId)>::max());
88    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
89    interfaces[id] = bp;
90    cachedBlockSizeValid = false;
91    return bp;
92}
93
94void
95Bus::deletePortRefs(Port *p)
96{
97
98    BusPort *bp =  dynamic_cast<BusPort*>(p);
99    if (bp == NULL)
100        panic("Couldn't convert Port* to BusPort*\n");
101    // If this is our one functional port
102    if (funcPort == bp)
103        return;
104    interfaces.erase(bp->getId());
105    clearBusCache();
106    delete bp;
107}
108
109/** Get the ranges of anyone other buses that we are connected to. */
110void
111Bus::init()
112{
113    m5::hash_map<short,BusPort*>::iterator intIter;
114
115    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
116        intIter->second->sendStatusChange(Port::RangeChange);
117}
118
119Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
120    : bus(_bus)
121{}
122
123void
124Bus::BusFreeEvent::process()
125{
126    bus->recvRetry(-1);
127}
128
129const char *
130Bus::BusFreeEvent::description() const
131{
132    return "bus became available";
133}
134
135Tick
136Bus::calcPacketTiming(PacketPtr pkt)
137{
138    // Bring tickNextIdle up to the present tick.
139    // There is some potential ambiguity where a cycle starts, which
140    // might make a difference when devices are acting right around a
141    // cycle boundary. Using a < allows things which happen exactly on
142    // a cycle boundary to take up only the following cycle. Anything
143    // that happens later will have to "wait" for the end of that
144    // cycle, and then start using the bus after that.
145    if (tickNextIdle < curTick) {
146        tickNextIdle = curTick;
147        if (tickNextIdle % clock != 0)
148            tickNextIdle = curTick - (curTick % clock) + clock;
149    }
150
151    Tick headerTime = tickNextIdle + 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(busIdle, 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    short src = pkt->getSrc();
193
194    BusPort *src_port;
195    if (src == defaultId)
196        src_port = defaultPort;
197    else {
198        src_port = checkBusCache(src);
199        if (src_port == NULL) {
200            src_port = interfaces[src];
201            updateBusCache(src, src_port);
202        }
203    }
204
205    // If the bus is busy, or other devices are in line ahead of the current
206    // one, put this device on the retry list.
207    if (!pkt->isExpressSnoop() &&
208        (tickNextIdle > curTick ||
209         (retryList.size() && (!inRetry || src_port != retryList.front()))))
210    {
211        addToRetryList(src_port);
212        DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
213                src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
214        return false;
215    }
216
217    DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
218            src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
219
220    Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
221    Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
222
223    short dest = pkt->getDest();
224    int dest_port_id;
225    Port *dest_port;
226
227    if (dest == Packet::Broadcast) {
228        dest_port_id = findPort(pkt->getAddr());
229        dest_port = (dest_port_id == defaultId) ?
230            defaultPort : interfaces[dest_port_id];
231        SnoopIter s_end = snoopPorts.end();
232        for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
233            BusPort *p = *s_iter;
234            if (p != dest_port && p != src_port) {
235                // cache is not allowed to refuse snoop
236                bool success M5_VAR_USED = p->sendTiming(pkt);
237                assert(success);
238            }
239        }
240    } else {
241        assert(dest < maxId);
242        assert(dest != src); // catch infinite loops
243        dest_port_id = dest;
244        if (dest_port_id == defaultId)
245            dest_port = defaultPort;
246        else {
247            dest_port = checkBusCache(dest);
248            if (dest_port == NULL) {
249                dest_port = interfaces[dest_port_id];
250            // updateBusCache(dest_port_id, dest_port);
251            }
252        }
253        dest_port = (dest_port_id == defaultId) ?
254            defaultPort : interfaces[dest_port_id];
255    }
256
257    if (dest_port_id == src) {
258        // Must be forwarded snoop up from below...
259        assert(dest == Packet::Broadcast);
260    } else {
261        // send to actual target
262        if (!dest_port->sendTiming(pkt))  {
263            // Packet not successfully sent. Leave or put it on the retry list.
264            // illegal to block responses... can lead to deadlock
265            assert(!pkt->isResponse());
266            // It's also illegal to force a transaction to retry after
267            // someone else has committed to respond.
268            assert(!pkt->memInhibitAsserted());
269            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
270                    src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
271            addToRetryList(src_port);
272            occupyBus(headerFinishTime);
273            return false;
274        }
275        // send OK, fall through... pkt may have been deleted by
276        // target at this point, so it should *not* be referenced
277        // again.  We'll set it to NULL here just to be safe.
278        pkt = NULL;
279    }
280
281    occupyBus(packetFinishTime);
282
283    // Packet was successfully sent.
284    // Also take care of retries
285    if (inRetry) {
286        DPRINTF(Bus, "Remove retry from list %d\n", src);
287        retryList.front()->onRetryList(false);
288        retryList.pop_front();
289        inRetry = false;
290    }
291    return true;
292}
293
294void
295Bus::recvRetry(int id)
296{
297    // If there's anything waiting, and the bus isn't busy...
298    if (retryList.size() && curTick >= tickNextIdle) {
299        //retryingPort = retryList.front();
300        inRetry = true;
301        DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
302        retryList.front()->sendRetry();
303        // If inRetry is still true, sendTiming wasn't called
304        if (inRetry)
305        {
306            retryList.front()->onRetryList(false);
307            retryList.pop_front();
308            inRetry = false;
309
310            //Bring tickNextIdle up to the present
311            while (tickNextIdle < curTick)
312                tickNextIdle += clock;
313
314            //Burn a cycle for the missed grant.
315            tickNextIdle += clock;
316
317            reschedule(busIdle, tickNextIdle, true);
318        }
319    }
320    //If we weren't able to drain before, we might be able to now.
321    if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) {
322        drainEvent->process();
323        // Clear the drain event once we're done with it.
324        drainEvent = NULL;
325    }
326}
327
328int
329Bus::findPort(Addr addr)
330{
331    /* An interval tree would be a better way to do this. --ali. */
332    int dest_id;
333
334    dest_id = checkPortCache(addr);
335    if (dest_id != -1)
336        return dest_id;
337
338    // Check normal port ranges
339    PortIter i = portMap.find(RangeSize(addr,1));
340    if (i != portMap.end()) {
341        dest_id = i->second;
342        updatePortCache(dest_id, i->first.start, i->first.end);
343        return dest_id;
344    }
345
346    // Check if this matches the default range
347    if (useDefaultRange) {
348        AddrRangeIter a_end = defaultRange.end();
349        for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
350            if (*i == addr) {
351                DPRINTF(Bus, "  found addr %#llx on default\n", addr);
352                return defaultId;
353            }
354        }
355
356        panic("Unable to find destination for addr %#llx\n", addr);
357    }
358
359    DPRINTF(Bus, "Unable to find destination for addr %#llx, "
360            "will use default port\n", addr);
361    return defaultId;
362}
363
364
365/** Function called by the port when the bus is receiving a Atomic
366 * transaction.*/
367Tick
368Bus::recvAtomic(PacketPtr pkt)
369{
370    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
371            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
372    assert(pkt->getDest() == Packet::Broadcast);
373    assert(pkt->isRequest());
374
375    // Variables for recording original command and snoop response (if
376    // any)... if a snooper respondes, we will need to restore
377    // original command so that additional snoops can take place
378    // properly
379    MemCmd orig_cmd = pkt->cmd;
380    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
381    Tick snoop_response_latency = 0;
382    int orig_src = pkt->getSrc();
383
384    int target_port_id = findPort(pkt->getAddr());
385    BusPort *target_port;
386    if (target_port_id == defaultId)
387        target_port = defaultPort;
388    else {
389      target_port = checkBusCache(target_port_id);
390      if (target_port == NULL) {
391          target_port = interfaces[target_port_id];
392          updateBusCache(target_port_id, target_port);
393      }
394    }
395
396    SnoopIter s_end = snoopPorts.end();
397    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
398        BusPort *p = *s_iter;
399        // same port should not have both target addresses and snooping
400        assert(p != target_port);
401        if (p->getId() != pkt->getSrc()) {
402            Tick latency = p->sendAtomic(pkt);
403            if (pkt->isResponse()) {
404                // response from snoop agent
405                assert(pkt->cmd != orig_cmd);
406                assert(pkt->memInhibitAsserted());
407                // should only happen once
408                assert(snoop_response_cmd == MemCmd::InvalidCmd);
409                // save response state
410                snoop_response_cmd = pkt->cmd;
411                snoop_response_latency = latency;
412                // restore original packet state for remaining snoopers
413                pkt->cmd = orig_cmd;
414                pkt->setSrc(orig_src);
415                pkt->setDest(Packet::Broadcast);
416            }
417        }
418    }
419
420    Tick response_latency = 0;
421
422    // we can get requests sent up from the memory side of the bus for
423    // snooping... don't send them back down!
424    if (target_port_id != pkt->getSrc()) {
425        response_latency = target_port->sendAtomic(pkt);
426    }
427
428    // if we got a response from a snooper, restore it here
429    if (snoop_response_cmd != MemCmd::InvalidCmd) {
430        // no one else should have responded
431        assert(!pkt->isResponse());
432        assert(pkt->cmd == orig_cmd);
433        pkt->cmd = snoop_response_cmd;
434        response_latency = snoop_response_latency;
435    }
436
437    // why do we have this packet field and the return value both???
438    pkt->finishTime = curTick + response_latency;
439    return response_latency;
440}
441
442/** Function called by the port when the bus is receiving a Functional
443 * transaction.*/
444void
445Bus::recvFunctional(PacketPtr pkt)
446{
447    if (!pkt->isPrint()) {
448        // don't do DPRINTFs on PrintReq as it clutters up the output
449        DPRINTF(Bus,
450                "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
451                pkt->getSrc(), pkt->getDest(), pkt->getAddr(),
452                pkt->cmdString());
453    }
454    assert(pkt->getDest() == Packet::Broadcast);
455
456    int port_id = findPort(pkt->getAddr());
457    Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
458    // The packet may be changed by another bus on snoops, restore the
459    // id after each
460    int src_id = pkt->getSrc();
461
462    assert(pkt->isRequest()); // hasn't already been satisfied
463
464    SnoopIter s_end = snoopPorts.end();
465    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
466        BusPort *p = *s_iter;
467        if (p != port && p->getId() != src_id) {
468            p->sendFunctional(pkt);
469        }
470        if (pkt->isResponse()) {
471            break;
472        }
473        pkt->setSrc(src_id);
474    }
475
476    // If the snooping hasn't found what we were looking for, keep going.
477    if (!pkt->isResponse() && port_id != pkt->getSrc()) {
478        port->sendFunctional(pkt);
479    }
480}
481
482/** Function called by the port when the bus is receiving a status change.*/
483void
484Bus::recvStatusChange(Port::Status status, int id)
485{
486    AddrRangeList ranges;
487    bool snoops;
488    AddrRangeIter iter;
489
490    if (inRecvStatusChange.count(id))
491        return;
492    inRecvStatusChange.insert(id);
493
494    assert(status == Port::RangeChange &&
495           "The other statuses need to be implemented.");
496
497    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
498
499    clearPortCache();
500    if (id == defaultId) {
501        defaultRange.clear();
502        // Only try to update these ranges if the user set a default responder.
503        if (useDefaultRange) {
504            defaultPort->getPeerAddressRanges(ranges, snoops);
505            assert(snoops == false);
506            for(iter = ranges.begin(); iter != ranges.end(); iter++) {
507                defaultRange.push_back(*iter);
508                DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
509                        iter->start, iter->end);
510            }
511        }
512    } else {
513
514        assert((id < maxId && id >= 0) || id == defaultId);
515        BusPort *port = interfaces[id];
516
517        // Clean out any previously existent ids
518        for (PortIter portIter = portMap.begin();
519             portIter != portMap.end(); ) {
520            if (portIter->second == id)
521                portMap.erase(portIter++);
522            else
523                portIter++;
524        }
525
526        for (SnoopIter s_iter = snoopPorts.begin();
527             s_iter != snoopPorts.end(); ) {
528            if ((*s_iter)->getId() == id)
529                s_iter = snoopPorts.erase(s_iter);
530            else
531                s_iter++;
532        }
533
534        port->getPeerAddressRanges(ranges, snoops);
535
536        if (snoops) {
537            DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id);
538            snoopPorts.push_back(port);
539        }
540
541        for (iter = ranges.begin(); iter != ranges.end(); iter++) {
542            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
543                    iter->start, iter->end, id);
544            if (portMap.insert(*iter, id) == portMap.end()) {
545                int conflict_id = portMap.find(*iter)->second;
546                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
547                      name(), interfaces[id]->getPeer()->name(),
548                      interfaces[conflict_id]->getPeer()->name());
549            }
550        }
551    }
552    DPRINTF(MMU, "port list has %d entries\n", portMap.size());
553
554    // tell all our peers that our address range has changed.
555    // Don't tell the device that caused this change, it already knows
556    m5::hash_map<short,BusPort*>::iterator intIter;
557
558    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
559        if (intIter->first != id && intIter->first != funcPortId)
560            intIter->second->sendStatusChange(Port::RangeChange);
561
562    if (id != defaultId && defaultPort)
563        defaultPort->sendStatusChange(Port::RangeChange);
564    inRecvStatusChange.erase(id);
565}
566
567void
568Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
569{
570    resp.clear();
571    snoop = false;
572
573    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
574
575    for (AddrRangeIter dflt_iter = defaultRange.begin();
576         dflt_iter != defaultRange.end(); dflt_iter++) {
577        resp.push_back(*dflt_iter);
578        DPRINTF(BusAddrRanges, "  -- Dflt: %#llx : %#llx\n",dflt_iter->start,
579                dflt_iter->end);
580    }
581    for (PortIter portIter = portMap.begin();
582         portIter != portMap.end(); portIter++) {
583        bool subset = false;
584        for (AddrRangeIter dflt_iter = defaultRange.begin();
585             dflt_iter != defaultRange.end(); dflt_iter++) {
586            if ((portIter->first.start < dflt_iter->start &&
587                portIter->first.end >= dflt_iter->start) ||
588               (portIter->first.start < dflt_iter->end &&
589                portIter->first.end >= dflt_iter->end))
590                fatal("Devices can not set ranges that itersect the default set\
591                        but are not a subset of the default set.\n");
592            if (portIter->first.start >= dflt_iter->start &&
593                portIter->first.end <= dflt_iter->end) {
594                subset = true;
595                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
596                    portIter->first.start, portIter->first.end);
597            }
598        }
599        if (portIter->second != id && !subset) {
600            resp.push_back(portIter->first);
601            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
602                    portIter->first.start, portIter->first.end);
603        }
604    }
605
606    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
607         s_iter++) {
608        if ((*s_iter)->getId() != id) {
609            snoop = true;
610            break;
611        }
612    }
613}
614
615unsigned
616Bus::findBlockSize(int id)
617{
618    if (cachedBlockSizeValid)
619        return cachedBlockSize;
620
621    unsigned max_bs = 0;
622
623    PortIter p_end = portMap.end();
624    for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
625        unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
626        if (tmp_bs > max_bs)
627            max_bs = tmp_bs;
628    }
629    SnoopIter s_end = snoopPorts.end();
630    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
631        unsigned tmp_bs = (*s_iter)->peerBlockSize();
632        if (tmp_bs > max_bs)
633            max_bs = tmp_bs;
634    }
635    if (max_bs == 0)
636        max_bs = defaultBlockSize;
637
638    if (max_bs != 64)
639        warn_once("Blocksize found to not be 64... hmm... probably not.\n");
640    cachedBlockSize = max_bs;
641    cachedBlockSizeValid = true;
642    return max_bs;
643}
644
645
646unsigned int
647Bus::drain(Event * de)
648{
649    //We should check that we're not "doing" anything, and that noone is
650    //waiting. We might be idle but have someone waiting if the device we
651    //contacted for a retry didn't actually retry.
652    if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) {
653        drainEvent = de;
654        return 1;
655    }
656    return 0;
657}
658
659void
660Bus::startup()
661{
662    if (tickNextIdle < curTick)
663        tickNextIdle = (curTick / clock) * clock + clock;
664}
665
666Bus *
667BusParams::create()
668{
669    return new Bus(this);
670}
671