coherent_xbar.cc revision 9095
12568SN/A/*
210325Sgeoffrey.blake@arm.com * Copyright (c) 2011-2012 ARM Limited
38668Sgeoffrey.blake@arm.com * All rights reserved
48668Sgeoffrey.blake@arm.com *
58668Sgeoffrey.blake@arm.com * The license below extends only to copyright in the software and shall
68668Sgeoffrey.blake@arm.com * not be construed as granting a license to any other intellectual
78668Sgeoffrey.blake@arm.com * property including but not limited to intellectual property relating
88668Sgeoffrey.blake@arm.com * to a hardware implementation of the functionality of the software
98668Sgeoffrey.blake@arm.com * licensed hereunder.  You may use the software subject to the license
108668Sgeoffrey.blake@arm.com * terms below provided that you ensure that this notice is replicated
118668Sgeoffrey.blake@arm.com * unmodified and in its entirety in all distributions of the software,
128668Sgeoffrey.blake@arm.com * modified or unmodified, in source code or in binary form.
138668Sgeoffrey.blake@arm.com *
142568SN/A * Copyright (c) 2006 The Regents of The University of Michigan
157636Ssteve.reinhardt@amd.com * All rights reserved.
162568SN/A *
172568SN/A * Redistribution and use in source and binary forms, with or without
182568SN/A * modification, are permitted provided that the following conditions are
192568SN/A * met: redistributions of source code must retain the above copyright
202568SN/A * notice, this list of conditions and the following disclaimer;
212568SN/A * redistributions in binary form must reproduce the above copyright
222568SN/A * notice, this list of conditions and the following disclaimer in the
232568SN/A * documentation and/or other materials provided with the distribution;
242568SN/A * neither the name of the copyright holders nor the names of its
252568SN/A * contributors may be used to endorse or promote products derived from
262568SN/A * this software without specific prior written permission.
272568SN/A *
282568SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292568SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302568SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342568SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352568SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382568SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392568SN/A *
402665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
412665Ssaidi@eecs.umich.edu *          Andreas Hansson
422665Ssaidi@eecs.umich.edu *          William Wang
432568SN/A */
442568SN/A
452568SN/A/**
462568SN/A * @file
472568SN/A * Definition of a bus object.
482568SN/A */
492568SN/A
503260Ssaidi@eecs.umich.edu#include "base/misc.hh"
518229Snate@binkert.org#include "base/trace.hh"
523260Ssaidi@eecs.umich.edu#include "debug/BusAddrRanges.hh"
538229Snate@binkert.org#include "debug/CoherentBus.hh"
545314Sstever@gmail.com#include "mem/coherent_bus.hh"
552590SN/A
563348Sbinkertn@umich.eduCoherentBus::CoherentBus(const CoherentBusParams *p)
572568SN/A    : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock),
582568SN/A      respLayer(*this, ".respLayer", p->clock),
595735Snate@binkert.org      snoopRespLayer(*this, ".snoopRespLayer", p->clock)
605735Snate@binkert.org{
614022Sstever@eecs.umich.edu    // create the ports based on the size of the master and slave
624022Sstever@eecs.umich.edu    // vector ports, and the presence of the default port, the ports
634022Sstever@eecs.umich.edu    // are enumerated starting from zero
644022Sstever@eecs.umich.edu    for (int i = 0; i < p->port_master_connection_count; ++i) {
654022Sstever@eecs.umich.edu        std::string portName = csprintf("%s.master[%d]", name(), i);
664022Sstever@eecs.umich.edu        MasterPort* bp = new CoherentBusMasterPort(portName, *this, i);
674022Sstever@eecs.umich.edu        masterPorts.push_back(bp);
682641Sstever@eecs.umich.edu    }
694022Sstever@eecs.umich.edu
704022Sstever@eecs.umich.edu    // see if we have a default slave device connected and if so add
712641Sstever@eecs.umich.edu    // our corresponding master port
724022Sstever@eecs.umich.edu    if (p->port_default_connection_count) {
734022Sstever@eecs.umich.edu        defaultPortID = masterPorts.size();
744022Sstever@eecs.umich.edu        std::string portName = name() + ".default";
754022Sstever@eecs.umich.edu        MasterPort* bp = new CoherentBusMasterPort(portName, *this,
764473Sstever@eecs.umich.edu                                                   defaultPortID);
774473Sstever@eecs.umich.edu        masterPorts.push_back(bp);
785319Sstever@gmail.com    }
795319Sstever@gmail.com
805319Sstever@gmail.com    // create the slave ports, once again starting at zero
814022Sstever@eecs.umich.edu    for (int i = 0; i < p->port_slave_connection_count; ++i) {
824626Sstever@eecs.umich.edu        std::string portName = csprintf("%s.slave[%d]", name(), i);
834022Sstever@eecs.umich.edu        SlavePort* bp = new CoherentBusSlavePort(portName, *this, i);
844022Sstever@eecs.umich.edu        slavePorts.push_back(bp);
854626Sstever@eecs.umich.edu    }
864022Sstever@eecs.umich.edu
874628Sstever@eecs.umich.edu    clearPortCache();
884628Sstever@eecs.umich.edu}
894022Sstever@eecs.umich.edu
904022Sstever@eecs.umich.eduvoid
914022Sstever@eecs.umich.eduCoherentBus::init()
924022Sstever@eecs.umich.edu{
934022Sstever@eecs.umich.edu    // iterate over our slave ports and determine which of our
944022Sstever@eecs.umich.edu    // neighbouring master ports are snooping and add them as snoopers
954022Sstever@eecs.umich.edu    for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end();
964022Sstever@eecs.umich.edu         ++p) {
974022Sstever@eecs.umich.edu        // check if the connected master port is snooping
984022Sstever@eecs.umich.edu        if ((*p)->isSnooping()) {
994022Sstever@eecs.umich.edu            DPRINTF(BusAddrRanges, "Adding snooping master %s\n",
1004022Sstever@eecs.umich.edu                    (*p)->getMasterPort().name());
10110345SCurtis.Dunham@arm.com            snoopPorts.push_back(*p);
1024626Sstever@eecs.umich.edu        }
1034626Sstever@eecs.umich.edu    }
1044022Sstever@eecs.umich.edu
10510345SCurtis.Dunham@arm.com    if (snoopPorts.empty())
1065319Sstever@gmail.com        warn("CoherentBus %s has no snooping ports attached!\n", name());
1074022Sstever@eecs.umich.edu}
1084022Sstever@eecs.umich.edu
1097465Ssteve.reinhardt@amd.combool
1104628Sstever@eecs.umich.eduCoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
1117465Ssteve.reinhardt@amd.com{
1127465Ssteve.reinhardt@amd.com    // determine the source port based on the id
1137465Ssteve.reinhardt@amd.com    SlavePort *src_port = slavePorts[slave_port_id];
1147465Ssteve.reinhardt@amd.com
1154628Sstever@eecs.umich.edu    // remember if the packet is an express snoop
1167465Ssteve.reinhardt@amd.com    bool is_express_snoop = pkt->isExpressSnoop();
1177465Ssteve.reinhardt@amd.com
11810325Sgeoffrey.blake@arm.com    // test if the bus should be considered occupied for the current
11910325Sgeoffrey.blake@arm.com    // port, and exclude express snoops from the check
12010325Sgeoffrey.blake@arm.com    if (!is_express_snoop && !reqLayer.tryTiming(src_port)) {
1217465Ssteve.reinhardt@amd.com        DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
12210325Sgeoffrey.blake@arm.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
12310325Sgeoffrey.blake@arm.com        return false;
12410325Sgeoffrey.blake@arm.com    }
1257465Ssteve.reinhardt@amd.com
1264022Sstever@eecs.umich.edu    DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n",
1274626Sstever@eecs.umich.edu            src_port->name(), pkt->cmdString(), is_express_snoop,
1284022Sstever@eecs.umich.edu            pkt->getAddr());
1294022Sstever@eecs.umich.edu
1305319Sstever@gmail.com    // set the source port for routing of the response
1314040Ssaidi@eecs.umich.edu    pkt->setSrc(slave_port_id);
1325507Sstever@gmail.com
1335507Sstever@gmail.com    Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt);
1346076Sgblack@eecs.umich.edu    Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime;
1355507Sstever@gmail.com
1364626Sstever@eecs.umich.edu    // uncacheable requests need never be snooped
1376076Sgblack@eecs.umich.edu    if (!pkt->req->isUncacheable()) {
1384626Sstever@eecs.umich.edu        // the packet is a memory-mapped request and should be
1394626Sstever@eecs.umich.edu        // broadcasted to our snoopers but the source
14010325Sgeoffrey.blake@arm.com        forwardTiming(pkt, slave_port_id);
1417669Ssteve.reinhardt@amd.com    }
1427669Ssteve.reinhardt@amd.com
1437669Ssteve.reinhardt@amd.com    // remember if we add an outstanding req so we can undo it if
1444626Sstever@eecs.umich.edu    // necessary, if the packet needs a response, we should add it
1456076Sgblack@eecs.umich.edu    // as outstanding and express snoops never fail so there is
1464626Sstever@eecs.umich.edu    // not need to worry about them
1474040Ssaidi@eecs.umich.edu    bool add_outstanding = !is_express_snoop && pkt->needsResponse();
1484626Sstever@eecs.umich.edu
1494040Ssaidi@eecs.umich.edu    // keep track that we have an outstanding request packet
1504040Ssaidi@eecs.umich.edu    // matching this request, this is used by the coherency
1514626Sstever@eecs.umich.edu    // mechanism in determining what to do with snoop responses
1524870Sstever@eecs.umich.edu    // (in recvTimingSnoop)
1535650Sgblack@eecs.umich.edu    if (add_outstanding) {
1545650Sgblack@eecs.umich.edu        // we should never have an exsiting request outstanding
1556063Sgblack@eecs.umich.edu        assert(outstandingReq.find(pkt->req) == outstandingReq.end());
1565650Sgblack@eecs.umich.edu        outstandingReq.insert(pkt->req);
1576063Sgblack@eecs.umich.edu    }
1584870Sstever@eecs.umich.edu
1594986Ssaidi@eecs.umich.edu    // since it is a normal request, determine the destination
1604870Sstever@eecs.umich.edu    // based on the address and attempt to send the packet
1615314Sstever@gmail.com    bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt);
1628436SBrad.Beckmann@amd.com
1638436SBrad.Beckmann@amd.com    // if this is an express snoop, we are done at this point
1648436SBrad.Beckmann@amd.com    if (is_express_snoop) {
1658436SBrad.Beckmann@amd.com        assert(success);
1665314Sstever@gmail.com    } else {
1678184Ssomayeh@cs.wisc.edu        // for normal requests, check if successful
1688184Ssomayeh@cs.wisc.edu        if (!success)  {
1698436SBrad.Beckmann@amd.com            // inhibited packets should never be forced to retry
1708716Snilay@cs.wisc.edu            assert(!pkt->memInhibitAsserted());
1718716Snilay@cs.wisc.edu
1728716Snilay@cs.wisc.edu            // if it was added as outstanding and the send failed, then
1734022Sstever@eecs.umich.edu            // erase it again
1742592SN/A            if (add_outstanding)
1753607Srdreslin@umich.edu                outstandingReq.erase(pkt->req);
17610028SGiacomo.Gabrielli@arm.com
17710570Sandreas.hansson@arm.com            DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
1782641Sstever@eecs.umich.edu                    src_port->name(), pkt->cmdString(), pkt->getAddr());
1794626Sstever@eecs.umich.edu
1804626Sstever@eecs.umich.edu            // update the bus state and schedule an idle event
1814626Sstever@eecs.umich.edu            reqLayer.failedTiming(src_port, headerFinishTime);
1824626Sstever@eecs.umich.edu        } else {
1833260Ssaidi@eecs.umich.edu            // update the bus state and schedule an idle event
18410028SGiacomo.Gabrielli@arm.com            reqLayer.succeededTiming(packetFinishTime);
18510028SGiacomo.Gabrielli@arm.com        }
1864626Sstever@eecs.umich.edu    }
1874626Sstever@eecs.umich.edu
1884626Sstever@eecs.umich.edu    return success;
1893260Ssaidi@eecs.umich.edu}
1905314Sstever@gmail.com
1915314Sstever@gmail.combool
19210570Sandreas.hansson@arm.comCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
19310376Sandreas.hansson@arm.com{
1945314Sstever@gmail.com    // determine the source port based on the id
1955314Sstever@gmail.com    MasterPort *src_port = masterPorts[master_port_id];
1965314Sstever@gmail.com
19710570Sandreas.hansson@arm.com    // test if the bus should be considered occupied for the current
19810570Sandreas.hansson@arm.com    // port
19910570Sandreas.hansson@arm.com    if (!respLayer.tryTiming(src_port)) {
2005314Sstever@gmail.com        DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
2015314Sstever@gmail.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
2025314Sstever@gmail.com        return false;
2034626Sstever@eecs.umich.edu    }
2044626Sstever@eecs.umich.edu
2054626Sstever@eecs.umich.edu    DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
2063260Ssaidi@eecs.umich.edu            src_port->name(), pkt->cmdString(), pkt->getAddr());
2074626Sstever@eecs.umich.edu
2084626Sstever@eecs.umich.edu    calcPacketTiming(pkt);
20910570Sandreas.hansson@arm.com    Tick packetFinishTime = pkt->finishTime;
21010570Sandreas.hansson@arm.com
21110570Sandreas.hansson@arm.com    // the packet is a normal response to a request that we should
2124626Sstever@eecs.umich.edu    // have seen passing through the bus
2133260Ssaidi@eecs.umich.edu    assert(outstandingReq.find(pkt->req) != outstandingReq.end());
2148668Sgeoffrey.blake@arm.com
2158668Sgeoffrey.blake@arm.com    // remove it as outstanding
2168668Sgeoffrey.blake@arm.com    outstandingReq.erase(pkt->req);
2178668Sgeoffrey.blake@arm.com
2188668Sgeoffrey.blake@arm.com    // send the packet to the destination through one of our slave
2198668Sgeoffrey.blake@arm.com    // ports, as determined by the destination field
2208668Sgeoffrey.blake@arm.com    bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
2218668Sgeoffrey.blake@arm.com
2228668Sgeoffrey.blake@arm.com    // currently it is illegal to block responses... can lead to
2238668Sgeoffrey.blake@arm.com    // deadlock
2248668Sgeoffrey.blake@arm.com    assert(success);
2258668Sgeoffrey.blake@arm.com
2268668Sgeoffrey.blake@arm.com    respLayer.succeededTiming(packetFinishTime);
2278668Sgeoffrey.blake@arm.com
2288668Sgeoffrey.blake@arm.com    return true;
2298668Sgeoffrey.blake@arm.com}
2308668Sgeoffrey.blake@arm.com
2318668Sgeoffrey.blake@arm.comvoid
2328668Sgeoffrey.blake@arm.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
2338668Sgeoffrey.blake@arm.com{
2348668Sgeoffrey.blake@arm.com    DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n",
2358668Sgeoffrey.blake@arm.com            masterPorts[master_port_id]->name(), pkt->cmdString(),
2368668Sgeoffrey.blake@arm.com            pkt->getAddr());
2378668Sgeoffrey.blake@arm.com
2388668Sgeoffrey.blake@arm.com    // we should only see express snoops from caches
2398668Sgeoffrey.blake@arm.com    assert(pkt->isExpressSnoop());
2408668Sgeoffrey.blake@arm.com
2418668Sgeoffrey.blake@arm.com    // set the source port for routing of the response
2428668Sgeoffrey.blake@arm.com    pkt->setSrc(master_port_id);
2438668Sgeoffrey.blake@arm.com
2448668Sgeoffrey.blake@arm.com    // forward to all snoopers
2458668Sgeoffrey.blake@arm.com    forwardTiming(pkt, InvalidPortID);
2468668Sgeoffrey.blake@arm.com
2478668Sgeoffrey.blake@arm.com    // a snoop request came from a connected slave device (one of
2488668Sgeoffrey.blake@arm.com    // our master ports), and if it is not coming from the slave
2498668Sgeoffrey.blake@arm.com    // device responsible for the address range something is
2508668Sgeoffrey.blake@arm.com    // wrong, hence there is nothing further to do as the packet
2518668Sgeoffrey.blake@arm.com    // would be going back to where it came from
2528668Sgeoffrey.blake@arm.com    assert(master_port_id == findPort(pkt->getAddr()));
2538668Sgeoffrey.blake@arm.com}
2548668Sgeoffrey.blake@arm.com
2558668Sgeoffrey.blake@arm.combool
2568668Sgeoffrey.blake@arm.comCoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
2578668Sgeoffrey.blake@arm.com{
2588668Sgeoffrey.blake@arm.com    // determine the source port based on the id
2598668Sgeoffrey.blake@arm.com    SlavePort* src_port = slavePorts[slave_port_id];
2608668Sgeoffrey.blake@arm.com
2618668Sgeoffrey.blake@arm.com    // test if the bus should be considered occupied for the current
2628668Sgeoffrey.blake@arm.com    // port
2638668Sgeoffrey.blake@arm.com    if (!snoopRespLayer.tryTiming(src_port)) {
2648668Sgeoffrey.blake@arm.com        DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
2658668Sgeoffrey.blake@arm.com                src_port->name(), pkt->cmdString(), pkt->getAddr());
2668668Sgeoffrey.blake@arm.com        return false;
2678668Sgeoffrey.blake@arm.com    }
2688668Sgeoffrey.blake@arm.com
2698668Sgeoffrey.blake@arm.com    DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
2708668Sgeoffrey.blake@arm.com            src_port->name(), pkt->cmdString(), pkt->getAddr());
2718668Sgeoffrey.blake@arm.com
2728668Sgeoffrey.blake@arm.com    // get the destination from the packet
2738668Sgeoffrey.blake@arm.com    PortID dest = pkt->getDest();
2748668Sgeoffrey.blake@arm.com
2758668Sgeoffrey.blake@arm.com    // responses are never express snoops
2768668Sgeoffrey.blake@arm.com    assert(!pkt->isExpressSnoop());
2778668Sgeoffrey.blake@arm.com
27810570Sandreas.hansson@arm.com    calcPacketTiming(pkt);
2798668Sgeoffrey.blake@arm.com    Tick packetFinishTime = pkt->finishTime;
2808668Sgeoffrey.blake@arm.com
2818668Sgeoffrey.blake@arm.com    // determine if the response is from a snoop request we
2828668Sgeoffrey.blake@arm.com    // created as the result of a normal request (in which case it
2838668Sgeoffrey.blake@arm.com    // should be in the outstandingReq), or if we merely forwarded
2848668Sgeoffrey.blake@arm.com    // someone else's snoop request
2858668Sgeoffrey.blake@arm.com    if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
2868668Sgeoffrey.blake@arm.com        // this is a snoop response to a snoop request we
2878668Sgeoffrey.blake@arm.com        // forwarded, e.g. coming from the L1 and going to the L2
2888668Sgeoffrey.blake@arm.com        // this should be forwarded as a snoop response
2898668Sgeoffrey.blake@arm.com        bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
2908668Sgeoffrey.blake@arm.com        assert(success);
2918668Sgeoffrey.blake@arm.com    } else {
2928668Sgeoffrey.blake@arm.com        // we got a snoop response on one of our slave ports,
2938668Sgeoffrey.blake@arm.com        // i.e. from a coherent master connected to the bus, and
2948668Sgeoffrey.blake@arm.com        // since we created the snoop request as part of
2958668Sgeoffrey.blake@arm.com        // recvTiming, this should now be a normal response again
2968692Ssaidi@eecs.umich.edu        outstandingReq.erase(pkt->req);
2978668Sgeoffrey.blake@arm.com
2988668Sgeoffrey.blake@arm.com        // this is a snoop response from a coherent master, with a
2998668Sgeoffrey.blake@arm.com        // destination field set on its way through the bus as
30010570Sandreas.hansson@arm.com        // request, hence it should never go back to where the
3018668Sgeoffrey.blake@arm.com        // snoop response came from, but instead to where the
3028668Sgeoffrey.blake@arm.com        // original request came from
3038668Sgeoffrey.blake@arm.com        assert(slave_port_id != dest);
3048668Sgeoffrey.blake@arm.com
3058668Sgeoffrey.blake@arm.com        // as a normal response, it should go back to a master
3063260Ssaidi@eecs.umich.edu        // through one of our slave ports
3074626Sstever@eecs.umich.edu        bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
3084626Sstever@eecs.umich.edu
30910570Sandreas.hansson@arm.com        // currently it is illegal to block responses... can lead
3105735Snate@binkert.org        // to deadlock
3115735Snate@binkert.org        assert(success);
3125735Snate@binkert.org    }
31310570Sandreas.hansson@arm.com
3145735Snate@binkert.org    snoopRespLayer.succeededTiming(packetFinishTime);
3153260Ssaidi@eecs.umich.edu
3165314Sstever@gmail.com    return true;
3174626Sstever@eecs.umich.edu}
3185314Sstever@gmail.com
3195314Sstever@gmail.com
3205314Sstever@gmail.comvoid
3215314Sstever@gmail.comCoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
3222641Sstever@eecs.umich.edu{
3233260Ssaidi@eecs.umich.edu    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
3245314Sstever@gmail.com        SlavePort *p = *s;
3259542Sandreas.hansson@arm.com        // we could have gotten this request from a snooping master
3269542Sandreas.hansson@arm.com        // (corresponding to our own slave port that is also in
3279542Sandreas.hansson@arm.com        // snoopPorts) and should not send it back to where it came
3289542Sandreas.hansson@arm.com        // from
3299542Sandreas.hansson@arm.com        if (exclude_slave_port_id == InvalidPortID ||
3309542Sandreas.hansson@arm.com            p->getId() != exclude_slave_port_id) {
3319542Sandreas.hansson@arm.com            // cache is not allowed to refuse snoop
3329542Sandreas.hansson@arm.com            p->sendTimingSnoopReq(pkt);
3339542Sandreas.hansson@arm.com        }
3349542Sandreas.hansson@arm.com    }
3359542Sandreas.hansson@arm.com}
3369542Sandreas.hansson@arm.com
3379542Sandreas.hansson@arm.comvoid
3389542Sandreas.hansson@arm.comCoherentBus::recvRetry()
3399542Sandreas.hansson@arm.com{
3409542Sandreas.hansson@arm.com    // responses and snoop responses never block on forwarding them,
3419542Sandreas.hansson@arm.com    // so the retry will always be coming from a port to which we
3429542Sandreas.hansson@arm.com    // tried to forward a request
3435735Snate@binkert.org    reqLayer.recvRetry();
3443260Ssaidi@eecs.umich.edu}
3455314Sstever@gmail.com
3465314Sstever@gmail.comTick
3473260Ssaidi@eecs.umich.eduCoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
3483260Ssaidi@eecs.umich.edu{
3499663Suri.wiener@arm.com    DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n",
3509663Suri.wiener@arm.com            slavePorts[slave_port_id]->name(), pkt->getAddr(),
3519663Suri.wiener@arm.com            pkt->cmdString());
3529663Suri.wiener@arm.com
3539663Suri.wiener@arm.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
3549663Suri.wiener@arm.com    Tick snoop_response_latency = 0;
3559663Suri.wiener@arm.com
3565735Snate@binkert.org    // uncacheable requests need never be snooped
3575735Snate@binkert.org    if (!pkt->req->isUncacheable()) {
3585314Sstever@gmail.com        // forward to all snoopers but the source
3595314Sstever@gmail.com        std::pair<MemCmd, Tick> snoop_result =
3605314Sstever@gmail.com            forwardAtomic(pkt, slave_port_id);
3615314Sstever@gmail.com        snoop_response_cmd = snoop_result.first;
3625314Sstever@gmail.com        snoop_response_latency = snoop_result.second;
3635314Sstever@gmail.com    }
3645314Sstever@gmail.com
3655314Sstever@gmail.com    // even if we had a snoop response, we must continue and also
3665314Sstever@gmail.com    // perform the actual request at the destination
3675314Sstever@gmail.com    PortID dest_id = findPort(pkt->getAddr());
3685314Sstever@gmail.com
3695314Sstever@gmail.com    // forward the request to the appropriate destination
3705735Snate@binkert.org    Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
3715314Sstever@gmail.com
3725314Sstever@gmail.com    // if we got a response from a snooper, restore it here
3735314Sstever@gmail.com    if (snoop_response_cmd != MemCmd::InvalidCmd) {
3745314Sstever@gmail.com        // no one else should have responded
3755314Sstever@gmail.com        assert(!pkt->isResponse());
3765735Snate@binkert.org        pkt->cmd = snoop_response_cmd;
3775314Sstever@gmail.com        response_latency = snoop_response_latency;
3785314Sstever@gmail.com    }
3795735Snate@binkert.org
3805314Sstever@gmail.com    pkt->finishTime = curTick() + response_latency;
3815314Sstever@gmail.com    return response_latency;
3825314Sstever@gmail.com}
3835314Sstever@gmail.com
3845314Sstever@gmail.comTick
3855314Sstever@gmail.comCoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
3865314Sstever@gmail.com{
3875314Sstever@gmail.com    DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n",
3885314Sstever@gmail.com            masterPorts[master_port_id]->name(), pkt->getAddr(),
3895314Sstever@gmail.com            pkt->cmdString());
3905314Sstever@gmail.com
3915314Sstever@gmail.com    // forward to all snoopers
3925314Sstever@gmail.com    std::pair<MemCmd, Tick> snoop_result =
3935314Sstever@gmail.com        forwardAtomic(pkt, InvalidPortID);
3945314Sstever@gmail.com    MemCmd snoop_response_cmd = snoop_result.first;
3955314Sstever@gmail.com    Tick snoop_response_latency = snoop_result.second;
3965314Sstever@gmail.com
3975314Sstever@gmail.com    if (snoop_response_cmd != MemCmd::InvalidCmd)
3985314Sstever@gmail.com        pkt->cmd = snoop_response_cmd;
3995314Sstever@gmail.com
4005314Sstever@gmail.com    pkt->finishTime = curTick() + snoop_response_latency;
4015314Sstever@gmail.com    return snoop_response_latency;
4025314Sstever@gmail.com}
4035314Sstever@gmail.com
4045314Sstever@gmail.comstd::pair<MemCmd, Tick>
4055314Sstever@gmail.comCoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
4065314Sstever@gmail.com{
4075314Sstever@gmail.com    // the packet may be changed on snoops, record the original
4085314Sstever@gmail.com    // command to enable us to restore it between snoops so that
4095314Sstever@gmail.com    // additional snoops can take place properly
4105314Sstever@gmail.com    MemCmd orig_cmd = pkt->cmd;
4115314Sstever@gmail.com    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
4125314Sstever@gmail.com    Tick snoop_response_latency = 0;
4135314Sstever@gmail.com
4145314Sstever@gmail.com    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
415        SlavePort *p = *s;
416        // we could have gotten this request from a snooping master
417        // (corresponding to our own slave port that is also in
418        // snoopPorts) and should not send it back to where it came
419        // from
420        if (exclude_slave_port_id == InvalidPortID ||
421            p->getId() != exclude_slave_port_id) {
422            Tick latency = p->sendAtomicSnoop(pkt);
423            // in contrast to a functional access, we have to keep on
424            // going as all snoopers must be updated even if we get a
425            // response
426            if (pkt->isResponse()) {
427                // response from snoop agent
428                assert(pkt->cmd != orig_cmd);
429                assert(pkt->memInhibitAsserted());
430                // should only happen once
431                assert(snoop_response_cmd == MemCmd::InvalidCmd);
432                // save response state
433                snoop_response_cmd = pkt->cmd;
434                snoop_response_latency = latency;
435                // restore original packet state for remaining snoopers
436                pkt->cmd = orig_cmd;
437            }
438        }
439    }
440
441    // the packet is restored as part of the loop and any potential
442    // snoop response is part of the returned pair
443    return std::make_pair(snoop_response_cmd, snoop_response_latency);
444}
445
446void
447CoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
448{
449    if (!pkt->isPrint()) {
450        // don't do DPRINTFs on PrintReq as it clutters up the output
451        DPRINTF(CoherentBus,
452                "recvFunctional: packet src %s addr 0x%x cmd %s\n",
453                slavePorts[slave_port_id]->name(), pkt->getAddr(),
454                pkt->cmdString());
455    }
456
457    // uncacheable requests need never be snooped
458    if (!pkt->req->isUncacheable()) {
459        // forward to all snoopers but the source
460        forwardFunctional(pkt, slave_port_id);
461    }
462
463    // there is no need to continue if the snooping has found what we
464    // were looking for and the packet is already a response
465    if (!pkt->isResponse()) {
466        PortID dest_id = findPort(pkt->getAddr());
467
468        masterPorts[dest_id]->sendFunctional(pkt);
469    }
470}
471
472void
473CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id)
474{
475    if (!pkt->isPrint()) {
476        // don't do DPRINTFs on PrintReq as it clutters up the output
477        DPRINTF(CoherentBus,
478                "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n",
479                masterPorts[master_port_id]->name(), pkt->getAddr(),
480                pkt->cmdString());
481    }
482
483    // forward to all snoopers
484    forwardFunctional(pkt, InvalidPortID);
485}
486
487void
488CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
489{
490    for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
491        SlavePort *p = *s;
492        // we could have gotten this request from a snooping master
493        // (corresponding to our own slave port that is also in
494        // snoopPorts) and should not send it back to where it came
495        // from
496        if (exclude_slave_port_id == InvalidPortID ||
497            p->getId() != exclude_slave_port_id)
498            p->sendFunctionalSnoop(pkt);
499
500        // if we get a response we are done
501        if (pkt->isResponse()) {
502            break;
503        }
504    }
505}
506
507unsigned int
508CoherentBus::drain(Event *de)
509{
510    // sum up the individual layers
511    return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de);
512}
513
514CoherentBus *
515CoherentBusParams::create()
516{
517    return new CoherentBus(this);
518}
519