xbar.cc revision 5490
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
43Port *
44Bus::getPort(const std::string &if_name, int idx)
45{
46    if (if_name == "default") {
47        if (defaultPort == NULL) {
48            defaultPort = new BusPort(csprintf("%s-default",name()), this,
49                                      defaultId);
50            cachedBlockSizeValid = false;
51            return defaultPort;
52        } else
53            fatal("Default port already set\n");
54    }
55    int id;
56    if (if_name == "functional") {
57        if (!funcPort) {
58            id = maxId++;
59            funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);
60            funcPortId = id;
61            interfaces[id] = funcPort;
62        }
63        return funcPort;
64    }
65
66    // if_name ignored?  forced to be empty?
67    id = maxId++;
68    assert(maxId < std::numeric_limits<typeof(maxId)>::max());
69    BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
70    interfaces[id] = bp;
71    cachedBlockSizeValid = false;
72    return bp;
73}
74
75bool
76Bus::deletePort(Port *p)
77{
78
79    BusPort *bp =  dynamic_cast<BusPort*>(p);
80    if (bp == NULL)
81        panic("Couldn't convert Port* to BusPort*\n");
82    // If this is our one functional port
83    if (funcPort == bp)
84        return false;
85    interfaces.erase(bp->getId());
86    clearBusCache();
87    delete bp;
88    return true;
89}
90
91/** Get the ranges of anyone other buses that we are connected to. */
92void
93Bus::init()
94{
95    m5::hash_map<short,BusPort*>::iterator intIter;
96
97    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
98        intIter->second->sendStatusChange(Port::RangeChange);
99}
100
101Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
102{}
103
104void Bus::BusFreeEvent::process()
105{
106    bus->recvRetry(-1);
107}
108
109const char * Bus::BusFreeEvent::description() const
110{
111    return "bus became available";
112}
113
114Tick Bus::calcPacketTiming(PacketPtr pkt)
115{
116    // Bring tickNextIdle up to the present tick.
117    // There is some potential ambiguity where a cycle starts, which
118    // might make a difference when devices are acting right around a
119    // cycle boundary. Using a < allows things which happen exactly on
120    // a cycle boundary to take up only the following cycle. Anything
121    // that happens later will have to "wait" for the end of that
122    // cycle, and then start using the bus after that.
123    if (tickNextIdle < curTick) {
124        tickNextIdle = curTick;
125        if (tickNextIdle % clock != 0)
126            tickNextIdle = curTick - (curTick % clock) + clock;
127    }
128
129    Tick headerTime = tickNextIdle + headerCycles * clock;
130
131    // The packet will be sent. Figure out how long it occupies the bus, and
132    // how much of that time is for the first "word", aka bus width.
133    int numCycles = 0;
134    if (pkt->hasData()) {
135        // If a packet has data, it needs ceil(size/width) cycles to send it
136        int dataSize = pkt->getSize();
137        numCycles += dataSize/width;
138        if (dataSize % width)
139            numCycles++;
140    }
141
142    // The first word will be delivered after the current tick, the delivery
143    // of the address if any, and one bus cycle to deliver the data
144    pkt->firstWordTime = headerTime + clock;
145
146    pkt->finishTime = headerTime + numCycles * clock;
147
148    return headerTime;
149}
150
151void Bus::occupyBus(Tick until)
152{
153    if (until == 0) {
154        // shortcut for express snoop packets
155        return;
156    }
157
158    tickNextIdle = until;
159
160    if (!busIdle.scheduled()) {
161        busIdle.schedule(tickNextIdle);
162    } else {
163        busIdle.reschedule(tickNextIdle);
164    }
165    DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
166            curTick, tickNextIdle);
167}
168
169/** Function called by the port when the bus is receiving a Timing
170 * transaction.*/
171bool
172Bus::recvTiming(PacketPtr pkt)
173{
174    short src = pkt->getSrc();
175
176    BusPort *src_port;
177    if (src == defaultId)
178        src_port = defaultPort;
179    else {
180        src_port = checkBusCache(src);
181        if (src_port == NULL) {
182            src_port = interfaces[src];
183            updateBusCache(src, src_port);
184        }
185    }
186
187    // If the bus is busy, or other devices are in line ahead of the current
188    // one, put this device on the retry list.
189    if (!pkt->isExpressSnoop() &&
190        (tickNextIdle > curTick ||
191         (retryList.size() && (!inRetry || src_port != retryList.front()))))
192    {
193        addToRetryList(src_port);
194        DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
195                src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
196        return false;
197    }
198
199    DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
200            src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
201
202    Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
203    Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
204
205    short dest = pkt->getDest();
206    int dest_port_id;
207    Port *dest_port;
208
209    if (dest == Packet::Broadcast) {
210        dest_port_id = findPort(pkt->getAddr());
211        dest_port = (dest_port_id == defaultId) ?
212            defaultPort : interfaces[dest_port_id];
213        SnoopIter s_end = snoopPorts.end();
214        for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
215            BusPort *p = *s_iter;
216            if (p != dest_port && p != src_port) {
217                // cache is not allowed to refuse snoop
218                bool success M5_VAR_USED = p->sendTiming(pkt);
219                assert(success);
220            }
221        }
222    } else {
223        assert(dest >= 0 && dest < maxId);
224        assert(dest != src); // catch infinite loops
225        dest_port_id = dest;
226        if (dest_port_id == defaultId)
227            dest_port = defaultPort;
228        else {
229            dest_port = checkBusCache(dest);
230            if (dest_port == NULL) {
231                dest_port = interfaces[dest_port_id];
232            // updateBusCache(dest_port_id, dest_port);
233            }
234        }
235        dest_port = (dest_port_id == defaultId) ?
236            defaultPort : interfaces[dest_port_id];
237    }
238
239    if (dest_port_id == src) {
240        // Must be forwarded snoop up from below...
241        assert(dest == Packet::Broadcast);
242        assert(src != defaultId); // catch infinite loops
243    } else {
244        // send to actual target
245        if (!dest_port->sendTiming(pkt))  {
246            // Packet not successfully sent. Leave or put it on the retry list.
247            // illegal to block responses... can lead to deadlock
248            assert(!pkt->isResponse());
249            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
250                    src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
251            addToRetryList(src_port);
252            occupyBus(headerFinishTime);
253            return false;
254        }
255        // send OK, fall through... pkt may have been deleted by
256        // target at this point, so it should *not* be referenced
257        // again.  We'll set it to NULL here just to be safe.
258        pkt = NULL;
259    }
260
261    occupyBus(packetFinishTime);
262
263    // Packet was successfully sent.
264    // Also take care of retries
265    if (inRetry) {
266        DPRINTF(Bus, "Remove retry from list %d\n", src);
267        retryList.front()->onRetryList(false);
268        retryList.pop_front();
269        inRetry = false;
270    }
271    return true;
272}
273
274void
275Bus::recvRetry(int id)
276{
277    // If there's anything waiting, and the bus isn't busy...
278    if (retryList.size() && curTick >= tickNextIdle) {
279        //retryingPort = retryList.front();
280        inRetry = true;
281        DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
282        retryList.front()->sendRetry();
283        // If inRetry is still true, sendTiming wasn't called
284        if (inRetry)
285        {
286            retryList.front()->onRetryList(false);
287            retryList.pop_front();
288            inRetry = false;
289
290            //Bring tickNextIdle up to the present
291            while (tickNextIdle < curTick)
292                tickNextIdle += clock;
293
294            //Burn a cycle for the missed grant.
295            tickNextIdle += clock;
296
297            busIdle.reschedule(tickNextIdle, true);
298        }
299    }
300    //If we weren't able to drain before, we might be able to now.
301    if (drainEvent && retryList.size() == 0 && curTick >= tickNextIdle) {
302        drainEvent->process();
303        // Clear the drain event once we're done with it.
304        drainEvent = NULL;
305    }
306}
307
308int
309Bus::findPort(Addr addr)
310{
311    /* An interval tree would be a better way to do this. --ali. */
312    int dest_id = -1;
313
314    dest_id = checkPortCache(addr);
315    if (dest_id == -1) {
316        PortIter i = portMap.find(RangeSize(addr,1));
317        if (i != portMap.end()) {
318            dest_id = i->second;
319            updatePortCache(dest_id, i->first.start, i->first.end);
320        }
321    }
322
323    // Check if this matches the default range
324    if (dest_id == -1) {
325        AddrRangeIter a_end = defaultRange.end();
326        for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
327            if (*i == addr) {
328                DPRINTF(Bus, "  found addr %#llx on default\n", addr);
329                return defaultId;
330            }
331        }
332
333        if (responderSet) {
334            panic("Unable to find destination for addr (user set default "
335                  "responder): %#llx", addr);
336        } else {
337            DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use "
338                    "default port", addr);
339
340            return defaultId;
341        }
342    }
343
344    return dest_id;
345}
346
347
348/** Function called by the port when the bus is receiving a Atomic
349 * transaction.*/
350Tick
351Bus::recvAtomic(PacketPtr pkt)
352{
353    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
354            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
355    assert(pkt->getDest() == Packet::Broadcast);
356    assert(pkt->isRequest());
357
358    // Variables for recording original command and snoop response (if
359    // any)... if a snooper respondes, we will need to restore
360    // original command so that additional snoops can take place
361    // properly
362    MemCmd orig_cmd = pkt->cmd;
363    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
364    Tick snoop_response_latency = 0;
365    int orig_src = pkt->getSrc();
366
367    int target_port_id = findPort(pkt->getAddr());
368    BusPort *target_port;
369    if (target_port_id == defaultId)
370        target_port = defaultPort;
371    else {
372      target_port = checkBusCache(target_port_id);
373      if (target_port == NULL) {
374          target_port = interfaces[target_port_id];
375          updateBusCache(target_port_id, target_port);
376      }
377    }
378
379    SnoopIter s_end = snoopPorts.end();
380    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
381        BusPort *p = *s_iter;
382        // same port should not have both target addresses and snooping
383        assert(p != target_port);
384        if (p->getId() != pkt->getSrc()) {
385            Tick latency = p->sendAtomic(pkt);
386            if (pkt->isResponse()) {
387                // response from snoop agent
388                assert(pkt->cmd != orig_cmd);
389                assert(pkt->memInhibitAsserted());
390                // should only happen once
391                assert(snoop_response_cmd == MemCmd::InvalidCmd);
392                // save response state
393                snoop_response_cmd = pkt->cmd;
394                snoop_response_latency = latency;
395                // restore original packet state for remaining snoopers
396                pkt->cmd = orig_cmd;
397                pkt->setSrc(orig_src);
398                pkt->setDest(Packet::Broadcast);
399            }
400        }
401    }
402
403    Tick response_latency = 0;
404
405    // we can get requests sent up from the memory side of the bus for
406    // snooping... don't send them back down!
407    if (target_port_id != pkt->getSrc()) {
408        response_latency = target_port->sendAtomic(pkt);
409    }
410
411    // if we got a response from a snooper, restore it here
412    if (snoop_response_cmd != MemCmd::InvalidCmd) {
413        // no one else should have responded
414        assert(!pkt->isResponse());
415        assert(pkt->cmd == orig_cmd);
416        pkt->cmd = snoop_response_cmd;
417        response_latency = snoop_response_latency;
418    }
419
420    // why do we have this packet field and the return value both???
421    pkt->finishTime = curTick + response_latency;
422    return response_latency;
423}
424
425/** Function called by the port when the bus is receiving a Functional
426 * transaction.*/
427void
428Bus::recvFunctional(PacketPtr pkt)
429{
430    if (!pkt->isPrint()) {
431        // don't do DPRINTFs on PrintReq as it clutters up the output
432        DPRINTF(Bus,
433                "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
434                pkt->getSrc(), pkt->getDest(), pkt->getAddr(),
435                pkt->cmdString());
436    }
437    assert(pkt->getDest() == Packet::Broadcast);
438
439    int port_id = findPort(pkt->getAddr());
440    Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
441    // The packet may be changed by another bus on snoops, restore the
442    // id after each
443    int src_id = pkt->getSrc();
444
445    assert(pkt->isRequest()); // hasn't already been satisfied
446
447    SnoopIter s_end = snoopPorts.end();
448    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
449        BusPort *p = *s_iter;
450        if (p != port && p->getId() != src_id) {
451            p->sendFunctional(pkt);
452        }
453        if (pkt->isResponse()) {
454            break;
455        }
456        pkt->setSrc(src_id);
457    }
458
459    // If the snooping hasn't found what we were looking for, keep going.
460    if (!pkt->isResponse() && port_id != pkt->getSrc()) {
461        port->sendFunctional(pkt);
462    }
463}
464
465/** Function called by the port when the bus is receiving a status change.*/
466void
467Bus::recvStatusChange(Port::Status status, int id)
468{
469    AddrRangeList ranges;
470    bool snoops;
471    AddrRangeIter iter;
472
473    if (inRecvStatusChange.count(id))
474        return;
475    inRecvStatusChange.insert(id);
476
477    assert(status == Port::RangeChange &&
478           "The other statuses need to be implemented.");
479
480    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
481
482    clearPortCache();
483    if (id == defaultId) {
484        defaultRange.clear();
485        // Only try to update these ranges if the user set a default responder.
486        if (responderSet) {
487            defaultPort->getPeerAddressRanges(ranges, snoops);
488            assert(snoops == false);
489            for(iter = ranges.begin(); iter != ranges.end(); iter++) {
490                defaultRange.push_back(*iter);
491                DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
492                        iter->start, iter->end);
493            }
494        }
495    } else {
496
497        assert((id < maxId && id >= 0) || id == defaultId);
498        BusPort *port = interfaces[id];
499
500        // Clean out any previously existent ids
501        for (PortIter portIter = portMap.begin();
502             portIter != portMap.end(); ) {
503            if (portIter->second == id)
504                portMap.erase(portIter++);
505            else
506                portIter++;
507        }
508
509        for (SnoopIter s_iter = snoopPorts.begin();
510             s_iter != snoopPorts.end(); ) {
511            if ((*s_iter)->getId() == id)
512                s_iter = snoopPorts.erase(s_iter);
513            else
514                s_iter++;
515        }
516
517        port->getPeerAddressRanges(ranges, snoops);
518
519        if (snoops) {
520            DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id);
521            snoopPorts.push_back(port);
522        }
523
524        for (iter = ranges.begin(); iter != ranges.end(); iter++) {
525            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
526                    iter->start, iter->end, id);
527            if (portMap.insert(*iter, id) == portMap.end()) {
528                int conflict_id = portMap.find(*iter)->second;
529                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
530                      name(), interfaces[id]->getPeer()->name(),
531                      interfaces[conflict_id]->getPeer()->name());
532            }
533        }
534    }
535    DPRINTF(MMU, "port list has %d entries\n", portMap.size());
536
537    // tell all our peers that our address range has changed.
538    // Don't tell the device that caused this change, it already knows
539    m5::hash_map<short,BusPort*>::iterator intIter;
540
541    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
542        if (intIter->first != id && intIter->first != funcPortId)
543            intIter->second->sendStatusChange(Port::RangeChange);
544
545    if (id != defaultId && defaultPort)
546        defaultPort->sendStatusChange(Port::RangeChange);
547    inRecvStatusChange.erase(id);
548}
549
550void
551Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
552{
553    resp.clear();
554    snoop = false;
555
556    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
557
558    for (AddrRangeIter dflt_iter = defaultRange.begin();
559         dflt_iter != defaultRange.end(); dflt_iter++) {
560        resp.push_back(*dflt_iter);
561        DPRINTF(BusAddrRanges, "  -- Dflt: %#llx : %#llx\n",dflt_iter->start,
562                dflt_iter->end);
563    }
564    for (PortIter portIter = portMap.begin();
565         portIter != portMap.end(); portIter++) {
566        bool subset = false;
567        for (AddrRangeIter dflt_iter = defaultRange.begin();
568             dflt_iter != defaultRange.end(); dflt_iter++) {
569            if ((portIter->first.start < dflt_iter->start &&
570                portIter->first.end >= dflt_iter->start) ||
571               (portIter->first.start < dflt_iter->end &&
572                portIter->first.end >= dflt_iter->end))
573                fatal("Devices can not set ranges that itersect the default set\
574                        but are not a subset of the default set.\n");
575            if (portIter->first.start >= dflt_iter->start &&
576                portIter->first.end <= dflt_iter->end) {
577                subset = true;
578                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
579                    portIter->first.start, portIter->first.end);
580            }
581        }
582        if (portIter->second != id && !subset) {
583            resp.push_back(portIter->first);
584            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
585                    portIter->first.start, portIter->first.end);
586        }
587    }
588
589    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
590         s_iter++) {
591        if ((*s_iter)->getId() != id) {
592            snoop = true;
593            break;
594        }
595    }
596}
597
598int
599Bus::findBlockSize(int id)
600{
601    if (cachedBlockSizeValid)
602        return cachedBlockSize;
603
604    int max_bs = -1;
605
606    PortIter p_end = portMap.end();
607    for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
608        int tmp_bs = interfaces[p_iter->second]->peerBlockSize();
609        if (tmp_bs > max_bs)
610            max_bs = tmp_bs;
611    }
612    SnoopIter s_end = snoopPorts.end();
613    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
614        int tmp_bs = (*s_iter)->peerBlockSize();
615        if (tmp_bs > max_bs)
616            max_bs = tmp_bs;
617    }
618    if (max_bs <= 0)
619        max_bs = defaultBlockSize;
620
621    if (max_bs != 64)
622        warn_once("Blocksize found to not be 64... hmm... probably not.\n");
623    cachedBlockSize = max_bs;
624    cachedBlockSizeValid = true;
625    return max_bs;
626}
627
628
629unsigned int
630Bus::drain(Event * de)
631{
632    //We should check that we're not "doing" anything, and that noone is
633    //waiting. We might be idle but have someone waiting if the device we
634    //contacted for a retry didn't actually retry.
635    if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) {
636        drainEvent = de;
637        return 1;
638    }
639    return 0;
640}
641
642void
643Bus::startup()
644{
645    if (tickNextIdle < curTick)
646        tickNextIdle = (curTick / clock) * clock + clock;
647}
648
649Bus *
650BusParams::create()
651{
652    return new Bus(this);
653}
654