xbar.cc revision 8849
12391SN/A/*
212218Snikos.nikoleris@arm.com * Copyright (c) 2011-2012 ARM Limited
37733SN/A * All rights reserved
47733SN/A *
57733SN/A * The license below extends only to copyright in the software and shall
67733SN/A * not be construed as granting a license to any other intellectual
77733SN/A * property including but not limited to intellectual property relating
87733SN/A * to a hardware implementation of the functionality of the software
97733SN/A * licensed hereunder.  You may use the software subject to the license
107733SN/A * terms below provided that you ensure that this notice is replicated
117733SN/A * unmodified and in its entirety in all distributions of the software,
127733SN/A * modified or unmodified, in source code or in binary form.
137733SN/A *
142391SN/A * Copyright (c) 2006 The Regents of The University of Michigan
152391SN/A * All rights reserved.
162391SN/A *
172391SN/A * Redistribution and use in source and binary forms, with or without
182391SN/A * modification, are permitted provided that the following conditions are
192391SN/A * met: redistributions of source code must retain the above copyright
202391SN/A * notice, this list of conditions and the following disclaimer;
212391SN/A * redistributions in binary form must reproduce the above copyright
222391SN/A * notice, this list of conditions and the following disclaimer in the
232391SN/A * documentation and/or other materials provided with the distribution;
242391SN/A * neither the name of the copyright holders nor the names of its
252391SN/A * contributors may be used to endorse or promote products derived from
262391SN/A * this software without specific prior written permission.
272391SN/A *
282391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Ali Saidi
412914SN/A *          Andreas Hansson
428931Sandreas.hansson@arm.com */
432391SN/A
442391SN/A/**
4511793Sbrandon.potter@amd.com * @file
4611793Sbrandon.potter@amd.com * Definition of a bus object.
4710466Sandreas.hansson@arm.com */
4810466Sandreas.hansson@arm.com
4912218Snikos.nikoleris@arm.com#include "base/misc.hh"
5010102Sali.saidi@arm.com#include "base/trace.hh"
5110102Sali.saidi@arm.com#include "debug/Bus.hh"
528232SN/A#include "debug/BusAddrRanges.hh"
538232SN/A#include "debug/MMU.hh"
543879SN/A#include "mem/bus.hh"
559053Sdam.sunwoo@arm.com
562394SN/ABus::Bus(const BusParams *p)
572391SN/A    : MemObject(p), busId(p->bus_id), clock(p->clock),
582391SN/A      headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
598931Sandreas.hansson@arm.com      drainEvent(NULL), busIdle(this), inRetry(false),
608931Sandreas.hansson@arm.com      defaultPortId(INVALID_PORT_ID), useDefaultRange(p->use_default_range),
619053Sdam.sunwoo@arm.com      defaultBlockSize(p->block_size),
6211614Sdavid.j.hashe@gmail.com      cachedBlockSize(0), cachedBlockSizeValid(false)
632391SN/A{
6410466Sandreas.hansson@arm.com    //width, clock period, and header cycles must be positive
6510466Sandreas.hansson@arm.com    if (width <= 0)
6610466Sandreas.hansson@arm.com        fatal("Bus width must be positive\n");
6710466Sandreas.hansson@arm.com    if (clock <= 0)
6810466Sandreas.hansson@arm.com        fatal("Bus clock period must be positive\n");
6910466Sandreas.hansson@arm.com    if (headerCycles <= 0)
7010466Sandreas.hansson@arm.com        fatal("Number of header cycles must be positive\n");
7110466Sandreas.hansson@arm.com    clearPortCache();
722391SN/A}
732391SN/A
742391SN/APort *
759293Sandreas.hansson@arm.comBus::getPort(const std::string &if_name, int idx)
769293Sandreas.hansson@arm.com{
772391SN/A    std::string portName;
789293Sandreas.hansson@arm.com    int id = interfaces.size();
792391SN/A    if (if_name == "default") {
802391SN/A        if (defaultPortId == INVALID_PORT_ID) {
818719SN/A            defaultPortId = id;
828931Sandreas.hansson@arm.com            portName = csprintf("%s-default", name());
838719SN/A        } else
8411522Sstephan.diestelhorst@arm.com            fatal("Default port already set on %s\n", name());
8511522Sstephan.diestelhorst@arm.com    } else {
868719SN/A        portName = csprintf("%s-p%d", name(), id);
878719SN/A    }
889053Sdam.sunwoo@arm.com    BusPort *bp = new BusPort(portName, this, id);
899053Sdam.sunwoo@arm.com    interfaces.push_back(bp);
908719SN/A    cachedBlockSizeValid = false;
919053Sdam.sunwoo@arm.com    return bp;
928719SN/A}
938719SN/A
949053Sdam.sunwoo@arm.comvoid
958719SN/ABus::init()
969053Sdam.sunwoo@arm.com{
979053Sdam.sunwoo@arm.com    std::vector<BusPort*>::iterator intIter;
989053Sdam.sunwoo@arm.com
998719SN/A    // iterate over our interfaces and determine which of our neighbours
1009053Sdam.sunwoo@arm.com    // are snooping and add them as snoopers
1018719SN/A    for (intIter = interfaces.begin(); intIter != interfaces.end();
1028719SN/A         intIter++) {
1039053Sdam.sunwoo@arm.com        if ((*intIter)->getPeer()->isSnooping()) {
1048719SN/A            DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
1059053Sdam.sunwoo@arm.com                    (*intIter)->getPeer()->name());
1069053Sdam.sunwoo@arm.com            snoopPorts.push_back(*intIter);
1079053Sdam.sunwoo@arm.com        }
1088719SN/A    }
1099053Sdam.sunwoo@arm.com}
1108719SN/A
1118719SN/ABus::BusFreeEvent::BusFreeEvent(Bus *_bus)
1129053Sdam.sunwoo@arm.com    : bus(_bus)
1138719SN/A{}
1149053Sdam.sunwoo@arm.com
1159053Sdam.sunwoo@arm.comvoid
1169053Sdam.sunwoo@arm.comBus::BusFreeEvent::process()
1178719SN/A{
1189053Sdam.sunwoo@arm.com    bus->recvRetry(-1);
1198719SN/A}
1208719SN/A
1219053Sdam.sunwoo@arm.comconst char *
1228719SN/ABus::BusFreeEvent::description() const
1239053Sdam.sunwoo@arm.com{
1249053Sdam.sunwoo@arm.com    return "bus became available";
1259053Sdam.sunwoo@arm.com}
1268719SN/A
1279053Sdam.sunwoo@arm.comTick
1288719SN/ABus::calcPacketTiming(PacketPtr pkt)
1298719SN/A{
1309053Sdam.sunwoo@arm.com    // Bring tickNextIdle up to the present tick.
1318719SN/A    // There is some potential ambiguity where a cycle starts, which
1329053Sdam.sunwoo@arm.com    // might make a difference when devices are acting right around a
1339053Sdam.sunwoo@arm.com    // cycle boundary. Using a < allows things which happen exactly on
1349053Sdam.sunwoo@arm.com    // a cycle boundary to take up only the following cycle. Anything
1358719SN/A    // that happens later will have to "wait" for the end of that
1369053Sdam.sunwoo@arm.com    // cycle, and then start using the bus after that.
1378719SN/A    if (tickNextIdle < curTick()) {
1388719SN/A        tickNextIdle = curTick();
1399053Sdam.sunwoo@arm.com        if (tickNextIdle % clock != 0)
1408719SN/A            tickNextIdle = curTick() - (curTick() % clock) + clock;
1419053Sdam.sunwoo@arm.com    }
1429053Sdam.sunwoo@arm.com
1439053Sdam.sunwoo@arm.com    Tick headerTime = tickNextIdle + headerCycles * clock;
1448719SN/A
1458719SN/A    // The packet will be sent. Figure out how long it occupies the bus, and
1468719SN/A    // how much of that time is for the first "word", aka bus width.
1478719SN/A    int numCycles = 0;
1488719SN/A    if (pkt->hasData()) {
1499053Sdam.sunwoo@arm.com        // If a packet has data, it needs ceil(size/width) cycles to send it
1508719SN/A        int dataSize = pkt->getSize();
1519053Sdam.sunwoo@arm.com        numCycles += dataSize/width;
1529053Sdam.sunwoo@arm.com        if (dataSize % width)
1539053Sdam.sunwoo@arm.com            numCycles++;
1549053Sdam.sunwoo@arm.com    }
1558719SN/A
1568719SN/A    // The first word will be delivered after the current tick, the delivery
1578719SN/A    // of the address if any, and one bus cycle to deliver the data
1588719SN/A    pkt->firstWordTime = headerTime + clock;
1598719SN/A
1609053Sdam.sunwoo@arm.com    pkt->finishTime = headerTime + numCycles * clock;
1618719SN/A
1629053Sdam.sunwoo@arm.com    return headerTime;
1639053Sdam.sunwoo@arm.com}
1649053Sdam.sunwoo@arm.com
1658719SN/Avoid Bus::occupyBus(Tick until)
1668719SN/A{
1678719SN/A    if (until == 0) {
1688719SN/A        // shortcut for express snoop packets
1698719SN/A        return;
1709053Sdam.sunwoo@arm.com    }
1718719SN/A
1729053Sdam.sunwoo@arm.com    tickNextIdle = until;
1739053Sdam.sunwoo@arm.com    reschedule(busIdle, tickNextIdle, true);
1749053Sdam.sunwoo@arm.com
1758719SN/A    DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
1768719SN/A            curTick(), tickNextIdle);
1778719SN/A}
1788719SN/A
1798719SN/A/** Function called by the port when the bus is receiving a Timing
1809053Sdam.sunwoo@arm.com * transaction.*/
1818719SN/Abool
1829053Sdam.sunwoo@arm.comBus::recvTiming(PacketPtr pkt)
1839053Sdam.sunwoo@arm.com{
1849053Sdam.sunwoo@arm.com    short src = pkt->getSrc();
1858719SN/A
1868719SN/A    BusPort *src_port = interfaces[src];
1878719SN/A
1888719SN/A    // If the bus is busy, or other devices are in line ahead of the current
1898719SN/A    // one, put this device on the retry list.
1908719SN/A    if (!pkt->isExpressSnoop() &&
1919235Sandreas.hansson@arm.com        (tickNextIdle > curTick() ||
1929098Sandreas.hansson@arm.com         (retryList.size() && (!inRetry || src_port != retryList.front()))))
1932408SN/A    {
1948931Sandreas.hansson@arm.com        addToRetryList(src_port);
1952408SN/A        DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
1962408SN/A                src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
1973170SN/A        return false;
1986076SN/A    }
1993170SN/A
2008931Sandreas.hansson@arm.com    DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
2013170SN/A            src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
20212749Sgiacomo.travaglini@arm.com
2033170SN/A    Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
2043170SN/A    Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
2053170SN/A
2063170SN/A    short dest = pkt->getDest();
2073170SN/A    int dest_port_id;
2083170SN/A    Port *dest_port;
2093170SN/A
2103170SN/A    if (dest == Packet::Broadcast) {
2113170SN/A        dest_port_id = findPort(pkt->getAddr());
2125714SN/A        dest_port = interfaces[dest_port_id];
2135714SN/A        SnoopIter s_end = snoopPorts.end();
2143170SN/A        for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
2153170SN/A            BusPort *p = *s_iter;
2163170SN/A            if (p != dest_port && p != src_port) {
2173170SN/A                // cache is not allowed to refuse snoop
2183170SN/A                bool success M5_VAR_USED = p->sendTiming(pkt);
2193170SN/A                assert(success);
2205714SN/A            }
2215714SN/A        }
2223170SN/A    } else {
2233170SN/A        assert(dest < interfaces.size());
2243170SN/A        assert(dest != src); // catch infinite loops
2253170SN/A        dest_port_id = dest;
2263170SN/A        dest_port = interfaces[dest_port_id];
2273170SN/A    }
2283170SN/A
2293170SN/A    if (dest_port_id == src) {
2303170SN/A        // Must be forwarded snoop up from below...
2318931Sandreas.hansson@arm.com        assert(dest == Packet::Broadcast);
2323170SN/A    } else {
23312749Sgiacomo.travaglini@arm.com        // send to actual target
2343170SN/A        if (!dest_port->sendTiming(pkt))  {
2356102SN/A            // Packet not successfully sent. Leave or put it on the retry list.
2363170SN/A            // illegal to block responses... can lead to deadlock
2373170SN/A            assert(!pkt->isResponse());
2383170SN/A            // It's also illegal to force a transaction to retry after
2393170SN/A            // someone else has committed to respond.
2409080Smatt.evans@arm.com            assert(!pkt->memInhibitAsserted());
2413170SN/A            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
2429080Smatt.evans@arm.com                    src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
2439080Smatt.evans@arm.com            addToRetryList(src_port);
2449080Smatt.evans@arm.com            occupyBus(headerFinishTime);
2459080Smatt.evans@arm.com            return false;
2469080Smatt.evans@arm.com        }
2473170SN/A        // send OK, fall through... pkt may have been deleted by
2483170SN/A        // target at this point, so it should *not* be referenced
2499080Smatt.evans@arm.com        // again.  We'll set it to NULL here just to be safe.
2509080Smatt.evans@arm.com        pkt = NULL;
2519080Smatt.evans@arm.com    }
2529080Smatt.evans@arm.com
2539080Smatt.evans@arm.com    occupyBus(packetFinishTime);
2545714SN/A
2555714SN/A    // Packet was successfully sent.
2569080Smatt.evans@arm.com    // Also take care of retries
2579080Smatt.evans@arm.com    if (inRetry) {
2583170SN/A        DPRINTF(Bus, "Remove retry from list %d\n", src);
2599080Smatt.evans@arm.com        retryList.pop_front();
2609080Smatt.evans@arm.com        inRetry = false;
2619080Smatt.evans@arm.com    }
2629080Smatt.evans@arm.com    return true;
2633170SN/A}
2649080Smatt.evans@arm.com
2659080Smatt.evans@arm.comvoid
2669080Smatt.evans@arm.comBus::recvRetry(int id)
2679080Smatt.evans@arm.com{
2689080Smatt.evans@arm.com    // If there's anything waiting, and the bus isn't busy...
2699080Smatt.evans@arm.com    if (retryList.size() && curTick() >= tickNextIdle) {
2709080Smatt.evans@arm.com        //retryingPort = retryList.front();
2719080Smatt.evans@arm.com        inRetry = true;
2729080Smatt.evans@arm.com        DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
2739080Smatt.evans@arm.com        retryList.front()->sendRetry();
2749080Smatt.evans@arm.com        // If inRetry is still true, sendTiming wasn't called
2759080Smatt.evans@arm.com        if (inRetry)
27612218Snikos.nikoleris@arm.com        {
27712218Snikos.nikoleris@arm.com            retryList.pop_front();
27812218Snikos.nikoleris@arm.com            inRetry = false;
27912218Snikos.nikoleris@arm.com
28012218Snikos.nikoleris@arm.com            //Bring tickNextIdle up to the present
28112218Snikos.nikoleris@arm.com            while (tickNextIdle < curTick())
2829080Smatt.evans@arm.com                tickNextIdle += clock;
2839080Smatt.evans@arm.com
2849080Smatt.evans@arm.com            //Burn a cycle for the missed grant.
2859080Smatt.evans@arm.com            tickNextIdle += clock;
2863170SN/A
2873170SN/A            reschedule(busIdle, tickNextIdle, true);
2883170SN/A        }
2899080Smatt.evans@arm.com    }
2903170SN/A    //If we weren't able to drain before, we might be able to now.
2913170SN/A    if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) {
29213346Sgabeblack@google.com        drainEvent->process();
29313346Sgabeblack@google.com        // Clear the drain event once we're done with it.
29413346Sgabeblack@google.com        drainEvent = NULL;
29513346Sgabeblack@google.com    }
29613346Sgabeblack@google.com}
29713346Sgabeblack@google.com
29813346Sgabeblack@google.comint
29913346Sgabeblack@google.comBus::findPort(Addr addr)
30013346Sgabeblack@google.com{
30113346Sgabeblack@google.com    /* An interval tree would be a better way to do this. --ali. */
30213346Sgabeblack@google.com    int dest_id;
30313346Sgabeblack@google.com
30413346Sgabeblack@google.com    dest_id = checkPortCache(addr);
30513346Sgabeblack@google.com    if (dest_id != INVALID_PORT_ID)
30613346Sgabeblack@google.com        return dest_id;
30713346Sgabeblack@google.com
30813346Sgabeblack@google.com    // Check normal port ranges
30913346Sgabeblack@google.com    PortIter i = portMap.find(RangeSize(addr,1));
3104626SN/A    if (i != portMap.end()) {
3114626SN/A        dest_id = i->second;
31213346Sgabeblack@google.com        updatePortCache(dest_id, i->first.start, i->first.end);
3134626SN/A        return dest_id;
31413346Sgabeblack@google.com    }
3154626SN/A
3164626SN/A    // Check if this matches the default range
3178931Sandreas.hansson@arm.com    if (useDefaultRange) {
3188931Sandreas.hansson@arm.com        AddrRangeIter a_end = defaultRange.end();
3192413SN/A        for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
32011284Sandreas.hansson@arm.com            if (*i == addr) {
32111284Sandreas.hansson@arm.com                DPRINTF(Bus, "  found addr %#llx on default\n", addr);
3224626SN/A                return defaultPortId;
3238931Sandreas.hansson@arm.com            }
3243175SN/A        }
3254626SN/A    } else if (defaultPortId != INVALID_PORT_ID) {
32611199Sandreas.hansson@arm.com        DPRINTF(Bus, "Unable to find destination for addr %#llx, "
32710883Sali.jafri@arm.com                "will use default port\n", addr);
32810883Sali.jafri@arm.com        return defaultPortId;
32910883Sali.jafri@arm.com    }
33010883Sali.jafri@arm.com
33110883Sali.jafri@arm.com    // we should use the range for the default port and it did not
33210883Sali.jafri@arm.com    // match, or the default port is not set
33310883Sali.jafri@arm.com    fatal("Unable to find destination for addr %#llx on bus %s\n", addr,
33410883Sali.jafri@arm.com          name());
3359405Sandreas.hansson@arm.com}
3364626SN/A
3374626SN/A
33811306Santhony.gutierrez@amd.com/** Function called by the port when the bus is receiving a Atomic
33911306Santhony.gutierrez@amd.com * transaction.*/
34011306Santhony.gutierrez@amd.comTick
34111306Santhony.gutierrez@amd.comBus::recvAtomic(PacketPtr pkt)
34211306Santhony.gutierrez@amd.com{
34311306Santhony.gutierrez@amd.com    DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
34411306Santhony.gutierrez@amd.com            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
34511306Santhony.gutierrez@amd.com    assert(pkt->getDest() == Packet::Broadcast);
34611306Santhony.gutierrez@amd.com    assert(pkt->isRequest());
3474040SN/A
34811306Santhony.gutierrez@amd.com    // Variables for recording original command and snoop response (if
34911306Santhony.gutierrez@amd.com    // any)... if a snooper respondes, we will need to restore
3504040SN/A    // original command so that additional snoops can take place
35111306Santhony.gutierrez@amd.com    // properly
35211306Santhony.gutierrez@amd.com    MemCmd orig_cmd = pkt->cmd;
35311306Santhony.gutierrez@amd.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
35411306Santhony.gutierrez@amd.com    Tick snoop_response_latency = 0;
35511306Santhony.gutierrez@amd.com    int orig_src = pkt->getSrc();
35611306Santhony.gutierrez@amd.com
3574040SN/A    int target_port_id = findPort(pkt->getAddr());
35811306Santhony.gutierrez@amd.com    BusPort *target_port = interfaces[target_port_id];
35911306Santhony.gutierrez@amd.com
36011306Santhony.gutierrez@amd.com    SnoopIter s_end = snoopPorts.end();
36111306Santhony.gutierrez@amd.com    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
36211306Santhony.gutierrez@amd.com        BusPort *p = *s_iter;
36311306Santhony.gutierrez@amd.com        // same port should not have both target addresses and snooping
36411306Santhony.gutierrez@amd.com        assert(p != target_port);
36511306Santhony.gutierrez@amd.com        if (p->getId() != pkt->getSrc()) {
36611306Santhony.gutierrez@amd.com            Tick latency = p->sendAtomic(pkt);
36711306Santhony.gutierrez@amd.com            if (pkt->isResponse()) {
36811306Santhony.gutierrez@amd.com                // response from snoop agent
36911306Santhony.gutierrez@amd.com                assert(pkt->cmd != orig_cmd);
37011306Santhony.gutierrez@amd.com                assert(pkt->memInhibitAsserted());
37111306Santhony.gutierrez@amd.com                // should only happen once
37211306Santhony.gutierrez@amd.com                assert(snoop_response_cmd == MemCmd::InvalidCmd);
37311306Santhony.gutierrez@amd.com                // save response state
37411306Santhony.gutierrez@amd.com                snoop_response_cmd = pkt->cmd;
37511306Santhony.gutierrez@amd.com                snoop_response_latency = latency;
37611306Santhony.gutierrez@amd.com                // restore original packet state for remaining snoopers
3774040SN/A                pkt->cmd = orig_cmd;
3784626SN/A                pkt->setSrc(orig_src);
3794626SN/A                pkt->setDest(Packet::Broadcast);
3806102SN/A            }
38112218Snikos.nikoleris@arm.com        }
38212218Snikos.nikoleris@arm.com    }
38312218Snikos.nikoleris@arm.com
3844626SN/A    Tick response_latency = 0;
3854040SN/A
3865477SN/A    // we can get requests sent up from the memory side of the bus for
3875477SN/A    // snooping... don't send them back down!
3886429SN/A    if (target_port_id != pkt->getSrc()) {
3899053Sdam.sunwoo@arm.com        response_latency = target_port->sendAtomic(pkt);
3909053Sdam.sunwoo@arm.com    }
3918719SN/A
3929053Sdam.sunwoo@arm.com    // if we got a response from a snooper, restore it here
39312354Snikos.nikoleris@arm.com    if (snoop_response_cmd != MemCmd::InvalidCmd) {
39412354Snikos.nikoleris@arm.com        // no one else should have responded
39512354Snikos.nikoleris@arm.com        assert(!pkt->isResponse());
39612354Snikos.nikoleris@arm.com        assert(pkt->cmd == orig_cmd);
39712354Snikos.nikoleris@arm.com        pkt->cmd = snoop_response_cmd;
39810583SCurtis.Dunham@arm.com        response_latency = snoop_response_latency;
3994626SN/A    }
4004626SN/A
4019663Suri.wiener@arm.com    // why do we have this packet field and the return value both???
40210563Sandreas.hansson@arm.com    pkt->finishTime = curTick() + response_latency;
40311653SBrad.Beckmann@amd.com    return response_latency;
4049663Suri.wiener@arm.com}
4059663Suri.wiener@arm.com
4066429SN/A/** Function called by the port when the bus is receiving a Functional
4074626SN/A * transaction.*/
4089053Sdam.sunwoo@arm.comvoid
4099053Sdam.sunwoo@arm.comBus::recvFunctional(PacketPtr pkt)
4104626SN/A{
4114040SN/A    assert(pkt->getDest() == Packet::Broadcast);
41212354Snikos.nikoleris@arm.com
4132413SN/A    int port_id = findPort(pkt->getAddr());
4142420SN/A    Port *port = interfaces[port_id];
4154626SN/A    // The packet may be changed by another bus on snoops, restore the
4168931Sandreas.hansson@arm.com    // id after each
4174626SN/A    int src_id = pkt->getSrc();
4182413SN/A
4192413SN/A    if (!pkt->isPrint()) {
4208931Sandreas.hansson@arm.com        // don't do DPRINTFs on PrintReq as it clutters up the output
4218931Sandreas.hansson@arm.com        DPRINTF(Bus,
4228931Sandreas.hansson@arm.com                "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
4239405Sandreas.hansson@arm.com                src_id, port_id, pkt->getAddr(),
4249405Sandreas.hansson@arm.com                pkt->cmdString());
4254626SN/A    }
4269405Sandreas.hansson@arm.com
4274626SN/A    assert(pkt->isRequest()); // hasn't already been satisfied
4285314SN/A
4295477SN/A    SnoopIter s_end = snoopPorts.end();
4305477SN/A    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
4314626SN/A        BusPort *p = *s_iter;
4328931Sandreas.hansson@arm.com        if (p != port && p->getId() != src_id) {
4335314SN/A            p->sendFunctional(pkt);
4345477SN/A        }
43510563Sandreas.hansson@arm.com        if (pkt->isResponse()) {
4364626SN/A            break;
4378931Sandreas.hansson@arm.com        }
4385314SN/A        pkt->setSrc(src_id);
4395315SN/A    }
4405315SN/A
4418992SAli.Saidi@ARM.com    // If the snooping hasn't found what we were looking for and it is not
4425315SN/A    // a forwarded snoop from below, keep going.
4435315SN/A    if (!pkt->isResponse() && port_id != pkt->getSrc()) {
4445314SN/A        port->sendFunctional(pkt);
4455315SN/A    }
4465314SN/A}
4474626SN/A
4488931Sandreas.hansson@arm.com/** Function called by the port when the bus is receiving a range change.*/
4494626SN/Avoid
4504626SN/ABus::recvRangeChange(int id)
4514490SN/A{
452    AddrRangeList ranges;
453    AddrRangeIter iter;
454
455    if (inRecvRangeChange.count(id))
456        return;
457    inRecvRangeChange.insert(id);
458
459    DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
460
461    clearPortCache();
462    if (id == defaultPortId) {
463        defaultRange.clear();
464        // Only try to update these ranges if the user set a default responder.
465        if (useDefaultRange) {
466            AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges();
467            for(iter = ranges.begin(); iter != ranges.end(); iter++) {
468                defaultRange.push_back(*iter);
469                DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
470                        iter->start, iter->end);
471            }
472        }
473    } else {
474
475        assert(id < interfaces.size() && id >= 0);
476        BusPort *port = interfaces[id];
477
478        // Clean out any previously existent ids
479        for (PortIter portIter = portMap.begin();
480             portIter != portMap.end(); ) {
481            if (portIter->second == id)
482                portMap.erase(portIter++);
483            else
484                portIter++;
485        }
486
487        ranges = port->getPeer()->getAddrRanges();
488
489        for (iter = ranges.begin(); iter != ranges.end(); iter++) {
490            DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
491                    iter->start, iter->end, id);
492            if (portMap.insert(*iter, id) == portMap.end()) {
493                int conflict_id = portMap.find(*iter)->second;
494                fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
495                      name(), interfaces[id]->getPeer()->name(),
496                      interfaces[conflict_id]->getPeer()->name());
497            }
498        }
499    }
500    DPRINTF(MMU, "port list has %d entries\n", portMap.size());
501
502    // tell all our peers that our address range has changed.
503    // Don't tell the device that caused this change, it already knows
504    std::vector<BusPort*>::const_iterator intIter;
505
506    for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
507        if ((*intIter)->getId() != id)
508            (*intIter)->sendRangeChange();
509
510    inRecvRangeChange.erase(id);
511}
512
513AddrRangeList
514Bus::getAddrRanges(int id)
515{
516    AddrRangeList ranges;
517
518    DPRINTF(BusAddrRanges, "received address range request, returning:\n");
519
520    for (AddrRangeIter dflt_iter = defaultRange.begin();
521         dflt_iter != defaultRange.end(); dflt_iter++) {
522        ranges.push_back(*dflt_iter);
523        DPRINTF(BusAddrRanges, "  -- Dflt: %#llx : %#llx\n",dflt_iter->start,
524                dflt_iter->end);
525    }
526    for (PortIter portIter = portMap.begin();
527         portIter != portMap.end(); portIter++) {
528        bool subset = false;
529        for (AddrRangeIter dflt_iter = defaultRange.begin();
530             dflt_iter != defaultRange.end(); dflt_iter++) {
531            if ((portIter->first.start < dflt_iter->start &&
532                portIter->first.end >= dflt_iter->start) ||
533               (portIter->first.start < dflt_iter->end &&
534                portIter->first.end >= dflt_iter->end))
535                fatal("Devices can not set ranges that itersect the default set\
536                        but are not a subset of the default set.\n");
537            if (portIter->first.start >= dflt_iter->start &&
538                portIter->first.end <= dflt_iter->end) {
539                subset = true;
540                DPRINTF(BusAddrRanges, "  -- %#llx : %#llx is a SUBSET\n",
541                    portIter->first.start, portIter->first.end);
542            }
543        }
544        if (portIter->second != id && !subset) {
545            ranges.push_back(portIter->first);
546            DPRINTF(BusAddrRanges, "  -- %#llx : %#llx\n",
547                    portIter->first.start, portIter->first.end);
548        }
549    }
550
551    return ranges;
552}
553
554bool
555Bus::isSnooping(int id)
556{
557    // in essence, answer the question if there are other snooping
558    // ports rather than the port that is asking
559    bool snoop = false;
560    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
561         s_iter++) {
562        if ((*s_iter)->getId() != id) {
563            snoop = true;
564            break;
565        }
566    }
567    return snoop;
568}
569
570unsigned
571Bus::findBlockSize(int id)
572{
573    if (cachedBlockSizeValid)
574        return cachedBlockSize;
575
576    unsigned max_bs = 0;
577
578    PortIter p_end = portMap.end();
579    for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
580        unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize();
581        if (tmp_bs > max_bs)
582            max_bs = tmp_bs;
583    }
584    SnoopIter s_end = snoopPorts.end();
585    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
586        unsigned tmp_bs = (*s_iter)->peerBlockSize();
587        if (tmp_bs > max_bs)
588            max_bs = tmp_bs;
589    }
590    if (max_bs == 0)
591        max_bs = defaultBlockSize;
592
593    if (max_bs != 64)
594        warn_once("Blocksize found to not be 64... hmm... probably not.\n");
595    cachedBlockSize = max_bs;
596    cachedBlockSizeValid = true;
597    return max_bs;
598}
599
600
601unsigned int
602Bus::drain(Event * de)
603{
604    //We should check that we're not "doing" anything, and that noone is
605    //waiting. We might be idle but have someone waiting if the device we
606    //contacted for a retry didn't actually retry.
607    if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) {
608        drainEvent = de;
609        return 1;
610    }
611    return 0;
612}
613
614void
615Bus::startup()
616{
617    if (tickNextIdle < curTick())
618        tickNextIdle = (curTick() / clock) * clock + clock;
619}
620
621Bus *
622BusParams::create()
623{
624    return new Bus(this);
625}
626