coherent_xbar.cc revision 9278
15703SN/A/* 25703SN/A * Copyright (c) 2011-2012 ARM Limited 35703SN/A * All rights reserved 49988Snilay@cs.wisc.edu * 58825Snilay@cs.wisc.edu * The license below extends only to copyright in the software and shall 69988Snilay@cs.wisc.edu * not be construed as granting a license to any other intellectual 77935SN/A * property including but not limited to intellectual property relating 87935SN/A * to a hardware implementation of the functionality of the software 97935SN/A * licensed hereunder. You may use the software subject to the license 105703SN/A * terms below provided that you ensure that this notice is replicated 115703SN/A * unmodified and in its entirety in all distributions of the software, 125703SN/A * modified or unmodified, in source code or in binary form. 1310315Snilay@cs.wisc.edu * 145703SN/A * Copyright (c) 2006 The Regents of The University of Michigan 155703SN/A * All rights reserved. 169885Sstever@gmail.com * 179885Sstever@gmail.com * Redistribution and use in source and binary forms, with or without 1811570SCurtis.Dunham@arm.com * modification, are permitted provided that the following conditions are 1911570SCurtis.Dunham@arm.com * met: redistributions of source code must retain the above copyright 209988Snilay@cs.wisc.edu * notice, this list of conditions and the following disclaimer; 2111570SCurtis.Dunham@arm.com * redistributions in binary form must reproduce the above copyright 225703SN/A * notice, this list of conditions and the following disclaimer in the 2311570SCurtis.Dunham@arm.com * documentation and/or other materials provided with the distribution; 2410315Snilay@cs.wisc.edu * neither the name of the copyright holders nor the names of its 257670SN/A * contributors may be used to endorse or promote products derived from 2610242Ssteve.reinhardt@amd.com * this software without specific prior written permission. 275703SN/A * 2811680SCurtis.Dunham@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 298464SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3010798Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3111245Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 328721SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3311570SCurtis.Dunham@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3411570SCurtis.Dunham@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3511570SCurtis.Dunham@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3611570SCurtis.Dunham@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3711570SCurtis.Dunham@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3811570SCurtis.Dunham@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 395703SN/A * 405703SN/A * Authors: Ali Saidi 415703SN/A * Andreas Hansson 4211570SCurtis.Dunham@arm.com * William Wang 4311570SCurtis.Dunham@arm.com */ 447935SN/A 457935SN/A/** 467935SN/A * @file 477935SN/A * Definition of a bus object. 487935SN/A */ 497935SN/A 507935SN/A#include "base/misc.hh" 518983Snate@binkert.org#include "base/trace.hh" 525703SN/A#include "debug/BusAddrRanges.hh" 535703SN/A#include "debug/CoherentBus.hh" 545703SN/A#include "mem/coherent_bus.hh" 559885Sstever@gmail.com 5611570SCurtis.Dunham@arm.comCoherentBus::CoherentBus(const CoherentBusParams *p) 575703SN/A : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock), 589988Snilay@cs.wisc.edu respLayer(*this, ".respLayer", p->clock), 5911570SCurtis.Dunham@arm.com snoopRespLayer(*this, ".snoopRespLayer", p->clock) 6011570SCurtis.Dunham@arm.com{ 6111570SCurtis.Dunham@arm.com // create the ports based on the size of the master and slave 6211570SCurtis.Dunham@arm.com // vector ports, and the presence of the default port, the ports 6311680SCurtis.Dunham@arm.com // are enumerated starting from zero 648721SN/A for (int i = 0; i < p->port_master_connection_count; ++i) { 658721SN/A std::string portName = csprintf("%s.master[%d]", name(), i); 668983Snate@binkert.org MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); 678983Snate@binkert.org masterPorts.push_back(bp); 685703SN/A } 699885Sstever@gmail.com 709885Sstever@gmail.com // see if we have a default slave device connected and if so add 719885Sstever@gmail.com // our corresponding master port 7210315Snilay@cs.wisc.edu if (p->port_default_connection_count) { 739988Snilay@cs.wisc.edu defaultPortID = masterPorts.size(); 7410315Snilay@cs.wisc.edu std::string portName = name() + ".default"; 759885Sstever@gmail.com MasterPort* bp = new CoherentBusMasterPort(portName, *this, 769885Sstever@gmail.com defaultPortID); 775703SN/A masterPorts.push_back(bp); 785703SN/A } 799481Snilay@cs.wisc.edu 805703SN/A // create the slave ports, once again starting at zero 815703SN/A for (int i = 0; i < p->port_slave_connection_count; ++i) { 828241SN/A std::string portName = csprintf("%s.slave[%d]", name(), i); 838241SN/A SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); 845703SN/A slavePorts.push_back(bp); 855703SN/A } 865703SN/A 875703SN/A clearPortCache(); 889481Snilay@cs.wisc.edu} 895703SN/A 905876SN/Avoid 919885Sstever@gmail.comCoherentBus::init() 925703SN/A{ 935703SN/A // the base class is responsible for determining the block size 945703SN/A BaseBus::init(); 955703SN/A 965703SN/A // iterate over our slave ports and determine which of our 975703SN/A // neighbouring master ports are snooping and add them as snoopers 985703SN/A for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 995703SN/A ++p) { 1005703SN/A // check if the connected master port is snooping 10111570SCurtis.Dunham@arm.com if ((*p)->isSnooping()) { 1025703SN/A DPRINTF(BusAddrRanges, "Adding snooping master %s\n", 1035703SN/A (*p)->getMasterPort().name()); 1045703SN/A snoopPorts.push_back(*p); 1055703SN/A } 1065703SN/A } 1079988Snilay@cs.wisc.edu 1089988Snilay@cs.wisc.edu if (snoopPorts.empty()) 10910451Snilay@cs.wisc.edu warn("CoherentBus %s has no snooping ports attached!\n", name()); 1105703SN/A} 1115703SN/A 1125703SN/Abool 1135703SN/ACoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) 1145703SN/A{ 1155703SN/A // determine the source port based on the id 1165703SN/A SlavePort *src_port = slavePorts[slave_port_id]; 1175703SN/A 1185703SN/A // remember if the packet is an express snoop 1195703SN/A bool is_express_snoop = pkt->isExpressSnoop(); 1205703SN/A 1215703SN/A // test if the bus should be considered occupied for the current 1229348SAli.Saidi@ARM.com // port, and exclude express snoops from the check 1235703SN/A if (!is_express_snoop && !reqLayer.tryTiming(src_port)) { 1245703SN/A DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", 1255703SN/A src_port->name(), pkt->cmdString(), pkt->getAddr()); 1265703SN/A return false; 1275703SN/A } 1285703SN/A 1295703SN/A DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n", 1308825Snilay@cs.wisc.edu src_port->name(), pkt->cmdString(), is_express_snoop, 1315703SN/A pkt->getAddr()); 1329924Ssteve.reinhardt@amd.com 1335703SN/A // set the source port for routing of the response 1345703SN/A pkt->setSrc(slave_port_id); 1355703SN/A 1365703SN/A Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt); 1375703SN/A Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime; 13811570SCurtis.Dunham@arm.com 13911570SCurtis.Dunham@arm.com // uncacheable requests need never be snooped 14011570SCurtis.Dunham@arm.com if (!pkt->req->isUncacheable()) { 14111570SCurtis.Dunham@arm.com // the packet is a memory-mapped request and should be 1425703SN/A // broadcasted to our snoopers but the source 1435703SN/A forwardTiming(pkt, slave_port_id); 1445703SN/A } 1455703SN/A 1465703SN/A // remember if we add an outstanding req so we can undo it if 1475703SN/A // necessary, if the packet needs a response, we should add it 1485703SN/A // as outstanding and express snoops never fail so there is 1499661SAli.Saidi@ARM.com // not need to worry about them 1505703SN/A bool add_outstanding = !is_express_snoop && pkt->needsResponse(); 1515703SN/A 1525703SN/A // keep track that we have an outstanding request packet 1535703SN/A // matching this request, this is used by the coherency 1545703SN/A // mechanism in determining what to do with snoop responses 1555703SN/A // (in recvTimingSnoop) 1565703SN/A if (add_outstanding) { 1575703SN/A // we should never have an exsiting request outstanding 1585703SN/A assert(outstandingReq.find(pkt->req) == outstandingReq.end()); 15910242Ssteve.reinhardt@amd.com outstandingReq.insert(pkt->req); 1605703SN/A } 1618521SN/A 1629449SAli.Saidi@ARM.com // since it is a normal request, determine the destination 1635703SN/A // based on the address and attempt to send the packet 1645703SN/A bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); 1655703SN/A 1665703SN/A // if this is an express snoop, we are done at this point 1678825Snilay@cs.wisc.edu if (is_express_snoop) { 1685703SN/A assert(success); 1695703SN/A } else { 1705703SN/A // for normal requests, check if successful 1719481Snilay@cs.wisc.edu if (!success) { 17210798Ssteve.reinhardt@amd.com // inhibited packets should never be forced to retry 1739481Snilay@cs.wisc.edu assert(!pkt->memInhibitAsserted()); 1749481Snilay@cs.wisc.edu 1759481Snilay@cs.wisc.edu // if it was added as outstanding and the send failed, then 1769481Snilay@cs.wisc.edu // erase it again 1779481Snilay@cs.wisc.edu if (add_outstanding) 1789988Snilay@cs.wisc.edu outstandingReq.erase(pkt->req); 1799481Snilay@cs.wisc.edu 1809481Snilay@cs.wisc.edu DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", 18111570SCurtis.Dunham@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 18211570SCurtis.Dunham@arm.com 18311570SCurtis.Dunham@arm.com // update the bus state and schedule an idle event 18411570SCurtis.Dunham@arm.com reqLayer.failedTiming(src_port, headerFinishTime); 18511570SCurtis.Dunham@arm.com } else { 18611570SCurtis.Dunham@arm.com // update the bus state and schedule an idle event 1879481Snilay@cs.wisc.edu reqLayer.succeededTiming(packetFinishTime); 1889481Snilay@cs.wisc.edu } 1899481Snilay@cs.wisc.edu } 1909481Snilay@cs.wisc.edu 1919481Snilay@cs.wisc.edu return success; 19211570SCurtis.Dunham@arm.com} 1939481Snilay@cs.wisc.edu 1945703SN/Abool 19511103Snilay@cs.wisc.eduCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) 1969885Sstever@gmail.com{ 19711680SCurtis.Dunham@arm.com // determine the source port based on the id 1985703SN/A MasterPort *src_port = masterPorts[master_port_id]; 1999885Sstever@gmail.com 20011245Sandreas.sandberg@arm.com // test if the bus should be considered occupied for the current 20111570SCurtis.Dunham@arm.com // port 20210798Ssteve.reinhardt@amd.com if (!respLayer.tryTiming(src_port)) { 2039988Snilay@cs.wisc.edu DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", 2049348SAli.Saidi@ARM.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 20510900Snilay@cs.wisc.edu return false; 2065703SN/A } 2075703SN/A 20811570SCurtis.Dunham@arm.com DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", 20911570SCurtis.Dunham@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 21011570SCurtis.Dunham@arm.com 21111570SCurtis.Dunham@arm.com calcPacketTiming(pkt); 2125876SN/A Tick packetFinishTime = pkt->finishTime; 2138835SAli.Saidi@ARM.com 2149348SAli.Saidi@ARM.com // the packet is a normal response to a request that we should 21510036SAli.Saidi@ARM.com // have seen passing through the bus 2165703SN/A assert(outstandingReq.find(pkt->req) != outstandingReq.end()); 2178835SAli.Saidi@ARM.com 2189885Sstever@gmail.com // remove it as outstanding 2195703SN/A outstandingReq.erase(pkt->req); 2205703SN/A 22111245Sandreas.sandberg@arm.com // send the packet to the destination through one of our slave 2225703SN/A // ports, as determined by the destination field 2238983Snate@binkert.org bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); 2245703SN/A 2259885Sstever@gmail.com // currently it is illegal to block responses... can lead to 2269885Sstever@gmail.com // deadlock 2279885Sstever@gmail.com assert(success); 2289885Sstever@gmail.com 2299885Sstever@gmail.com respLayer.succeededTiming(packetFinishTime); 23011570SCurtis.Dunham@arm.com 2319988Snilay@cs.wisc.edu return true; 2329885Sstever@gmail.com} 23311570SCurtis.Dunham@arm.com 23411570SCurtis.Dunham@arm.comvoid 23511570SCurtis.Dunham@arm.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) 23611570SCurtis.Dunham@arm.com{ 23710036SAli.Saidi@ARM.com DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", 2389885Sstever@gmail.com masterPorts[master_port_id]->name(), pkt->cmdString(), 2399885Sstever@gmail.com pkt->getAddr()); 2405703SN/A 2416024SN/A // we should only see express snoops from caches 2429988Snilay@cs.wisc.edu assert(pkt->isExpressSnoop()); 2435703SN/A 2445703SN/A // set the source port for routing of the response 2455703SN/A pkt->setSrc(master_port_id); 2465703SN/A 2477761SN/A // forward to all snoopers 2487761SN/A forwardTiming(pkt, InvalidPortID); 2499988Snilay@cs.wisc.edu 2505703SN/A // a snoop request came from a connected slave device (one of 2515703SN/A // our master ports), and if it is not coming from the slave 2525703SN/A // device responsible for the address range something is 2535703SN/A // wrong, hence there is nothing further to do as the packet 2545703SN/A // would be going back to where it came from 2559988Snilay@cs.wisc.edu assert(master_port_id == findPort(pkt->getAddr())); 2565703SN/A} 2575703SN/A 2585703SN/Abool 2595703SN/ACoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) 2609988Snilay@cs.wisc.edu{ 2615703SN/A // determine the source port based on the id 2625703SN/A SlavePort* src_port = slavePorts[slave_port_id]; 26310900Snilay@cs.wisc.edu 2645703SN/A // test if the bus should be considered occupied for the current 2655703SN/A // port 2665703SN/A if (!snoopRespLayer.tryTiming(src_port)) { 2675703SN/A DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 2685703SN/A src_port->name(), pkt->cmdString(), pkt->getAddr()); 2699988Snilay@cs.wisc.edu return false; 2705703SN/A } 2715703SN/A 2725703SN/A DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n", 2735703SN/A src_port->name(), pkt->cmdString(), pkt->getAddr()); 2749988Snilay@cs.wisc.edu 2755703SN/A // get the destination from the packet 2765703SN/A PortID dest = pkt->getDest(); 27710900Snilay@cs.wisc.edu 2785703SN/A // responses are never express snoops 2795703SN/A assert(!pkt->isExpressSnoop()); 2805703SN/A 2819988Snilay@cs.wisc.edu calcPacketTiming(pkt); 2825703SN/A Tick packetFinishTime = pkt->finishTime; 2835703SN/A 28410900Snilay@cs.wisc.edu // determine if the response is from a snoop request we 2855703SN/A // created as the result of a normal request (in which case it 2865703SN/A // should be in the outstandingReq), or if we merely forwarded 2875703SN/A // someone else's snoop request 2885703SN/A if (outstandingReq.find(pkt->req) == outstandingReq.end()) { 2895703SN/A // this is a snoop response to a snoop request we 2909988Snilay@cs.wisc.edu // forwarded, e.g. coming from the L1 and going to the L2 2915703SN/A // this should be forwarded as a snoop response 2925703SN/A bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt); 2935703SN/A assert(success); 2945703SN/A } else { 2959988Snilay@cs.wisc.edu // we got a snoop response on one of our slave ports, 2965703SN/A // i.e. from a coherent master connected to the bus, and 2975703SN/A // since we created the snoop request as part of 29810900Snilay@cs.wisc.edu // recvTiming, this should now be a normal response again 2995703SN/A outstandingReq.erase(pkt->req); 3005703SN/A 3015703SN/A // this is a snoop response from a coherent master, with a 3029988Snilay@cs.wisc.edu // destination field set on its way through the bus as 3035703SN/A // request, hence it should never go back to where the 3045703SN/A // snoop response came from, but instead to where the 30510900Snilay@cs.wisc.edu // original request came from 3065703SN/A assert(slave_port_id != dest); 3075703SN/A 3085703SN/A // as a normal response, it should go back to a master 3099988Snilay@cs.wisc.edu // through one of our slave ports 3105703SN/A bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt); 3115703SN/A 31210900Snilay@cs.wisc.edu // currently it is illegal to block responses... can lead 3135703SN/A // to deadlock 3145703SN/A assert(success); 3155703SN/A } 3165703SN/A 3175703SN/A snoopRespLayer.succeededTiming(packetFinishTime); 3189988Snilay@cs.wisc.edu 3195703SN/A return true; 3205703SN/A} 3215703SN/A 3225703SN/A 3239988Snilay@cs.wisc.eduvoid 3245703SN/ACoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) 3255703SN/A{ 32610900Snilay@cs.wisc.edu for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 3275703SN/A SlavePort *p = *s; 3285703SN/A // we could have gotten this request from a snooping master 3295703SN/A // (corresponding to our own slave port that is also in 3309988Snilay@cs.wisc.edu // snoopPorts) and should not send it back to where it came 3315703SN/A // from 3325703SN/A if (exclude_slave_port_id == InvalidPortID || 33310900Snilay@cs.wisc.edu p->getId() != exclude_slave_port_id) { 3345703SN/A // cache is not allowed to refuse snoop 3355703SN/A p->sendTimingSnoopReq(pkt); 3365703SN/A } 3379988Snilay@cs.wisc.edu } 3385703SN/A} 3395703SN/A 34010900Snilay@cs.wisc.eduvoid 3415703SN/ACoherentBus::recvRetry() 3425703SN/A{ 3435703SN/A // responses and snoop responses never block on forwarding them, 3445703SN/A // so the retry will always be coming from a port to which we 3455703SN/A // tried to forward a request 3469988Snilay@cs.wisc.edu reqLayer.recvRetry(); 3475703SN/A} 3485703SN/A 3495703SN/ATick 3505703SN/ACoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) 3519988Snilay@cs.wisc.edu{ 3525703SN/A DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 3535703SN/A slavePorts[slave_port_id]->name(), pkt->getAddr(), 35410900Snilay@cs.wisc.edu pkt->cmdString()); 3555703SN/A 3565703SN/A MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 3575703SN/A Tick snoop_response_latency = 0; 3587761SN/A 3597761SN/A // uncacheable requests need never be snooped 3609988Snilay@cs.wisc.edu if (!pkt->req->isUncacheable()) { 3617761SN/A // forward to all snoopers but the source 3625703SN/A std::pair<MemCmd, Tick> snoop_result = 3637761SN/A forwardAtomic(pkt, slave_port_id); 3645703SN/A snoop_response_cmd = snoop_result.first; 3659988Snilay@cs.wisc.edu snoop_response_latency = snoop_result.second; 3667761SN/A } 3677761SN/A 36810900Snilay@cs.wisc.edu // even if we had a snoop response, we must continue and also 3697761SN/A // perform the actual request at the destination 3707761SN/A PortID dest_id = findPort(pkt->getAddr()); 3717761SN/A 3729988Snilay@cs.wisc.edu // forward the request to the appropriate destination 3737761SN/A Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 3747761SN/A 37510900Snilay@cs.wisc.edu // if we got a response from a snooper, restore it here 3767761SN/A if (snoop_response_cmd != MemCmd::InvalidCmd) { 3777761SN/A // no one else should have responded 3787761SN/A assert(!pkt->isResponse()); 3799988Snilay@cs.wisc.edu pkt->cmd = snoop_response_cmd; 3807761SN/A response_latency = snoop_response_latency; 3817761SN/A } 38210900Snilay@cs.wisc.edu 3837761SN/A pkt->finishTime = curTick() + response_latency; 3847761SN/A return response_latency; 3857761SN/A} 3869988Snilay@cs.wisc.edu 3877761SN/ATick 3887761SN/ACoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) 38910900Snilay@cs.wisc.edu{ 3907761SN/A DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", 3917761SN/A masterPorts[master_port_id]->name(), pkt->getAddr(), 3927761SN/A pkt->cmdString()); 3939988Snilay@cs.wisc.edu 3947761SN/A // forward to all snoopers 3957761SN/A std::pair<MemCmd, Tick> snoop_result = 39610900Snilay@cs.wisc.edu forwardAtomic(pkt, InvalidPortID); 3977761SN/A MemCmd snoop_response_cmd = snoop_result.first; 3987761SN/A Tick snoop_response_latency = snoop_result.second; 3997761SN/A 4009988Snilay@cs.wisc.edu if (snoop_response_cmd != MemCmd::InvalidCmd) 4017761SN/A pkt->cmd = snoop_response_cmd; 4027761SN/A 40310900Snilay@cs.wisc.edu pkt->finishTime = curTick() + snoop_response_latency; 4047761SN/A return snoop_response_latency; 4057761SN/A} 4067761SN/A 4079988Snilay@cs.wisc.edustd::pair<MemCmd, Tick> 4087761SN/ACoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) 4097761SN/A{ 41010900Snilay@cs.wisc.edu // the packet may be changed on snoops, record the original 4117761SN/A // command to enable us to restore it between snoops so that 4127761SN/A // additional snoops can take place properly 4137761SN/A MemCmd orig_cmd = pkt->cmd; 4149988Snilay@cs.wisc.edu MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 4157761SN/A Tick snoop_response_latency = 0; 4167761SN/A 41710900Snilay@cs.wisc.edu for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 4187761SN/A SlavePort *p = *s; 4197761SN/A // we could have gotten this request from a snooping master 4207761SN/A // (corresponding to our own slave port that is also in 4219988Snilay@cs.wisc.edu // snoopPorts) and should not send it back to where it came 4227761SN/A // from 4237761SN/A if (exclude_slave_port_id == InvalidPortID || 42410900Snilay@cs.wisc.edu p->getId() != exclude_slave_port_id) { 4257761SN/A Tick latency = p->sendAtomicSnoop(pkt); 4267761SN/A // in contrast to a functional access, we have to keep on 4277761SN/A // going as all snoopers must be updated even if we get a 4289988Snilay@cs.wisc.edu // response 4297761SN/A if (pkt->isResponse()) { 4307761SN/A // response from snoop agent 43110900Snilay@cs.wisc.edu assert(pkt->cmd != orig_cmd); 4327761SN/A assert(pkt->memInhibitAsserted()); 4337761SN/A // should only happen once 4347761SN/A assert(snoop_response_cmd == MemCmd::InvalidCmd); 4359988Snilay@cs.wisc.edu // save response state 4367761SN/A snoop_response_cmd = pkt->cmd; 4377761SN/A snoop_response_latency = latency; 43810900Snilay@cs.wisc.edu // restore original packet state for remaining snoopers 4397761SN/A pkt->cmd = orig_cmd; 4407761SN/A } 4417761SN/A } 4429988Snilay@cs.wisc.edu } 4437761SN/A 4447761SN/A // the packet is restored as part of the loop and any potential 44510900Snilay@cs.wisc.edu // snoop response is part of the returned pair 4467761SN/A return std::make_pair(snoop_response_cmd, snoop_response_latency); 4477761SN/A} 4487761SN/A 4499988Snilay@cs.wisc.eduvoid 4507761SN/ACoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) 4517761SN/A{ 45210900Snilay@cs.wisc.edu if (!pkt->isPrint()) { 4537761SN/A // don't do DPRINTFs on PrintReq as it clutters up the output 4547761SN/A DPRINTF(CoherentBus, 4557761SN/A "recvFunctional: packet src %s addr 0x%x cmd %s\n", 4569988Snilay@cs.wisc.edu slavePorts[slave_port_id]->name(), pkt->getAddr(), 4577761SN/A pkt->cmdString()); 4587761SN/A } 45910900Snilay@cs.wisc.edu 4607761SN/A // uncacheable requests need never be snooped 4617761SN/A if (!pkt->req->isUncacheable()) { 4627761SN/A // forward to all snoopers but the source 4639988Snilay@cs.wisc.edu forwardFunctional(pkt, slave_port_id); 4647761SN/A } 4657761SN/A 46610900Snilay@cs.wisc.edu // there is no need to continue if the snooping has found what we 4677761SN/A // were looking for and the packet is already a response 4687761SN/A if (!pkt->isResponse()) { 4697761SN/A PortID dest_id = findPort(pkt->getAddr()); 4709988Snilay@cs.wisc.edu 4717761SN/A masterPorts[dest_id]->sendFunctional(pkt); 4727761SN/A } 47310900Snilay@cs.wisc.edu} 4747761SN/A 4757761SN/Avoid 4767761SN/ACoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) 4779988Snilay@cs.wisc.edu{ 4787761SN/A if (!pkt->isPrint()) { 4797761SN/A // don't do DPRINTFs on PrintReq as it clutters up the output 48010900Snilay@cs.wisc.edu DPRINTF(CoherentBus, 4817761SN/A "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", 4827761SN/A masterPorts[master_port_id]->name(), pkt->getAddr(), 4837761SN/A pkt->cmdString()); 4849988Snilay@cs.wisc.edu } 4857761SN/A 4867761SN/A // forward to all snoopers 48710900Snilay@cs.wisc.edu forwardFunctional(pkt, InvalidPortID); 4887761SN/A} 4897761SN/A 4907761SN/Avoid 4919988Snilay@cs.wisc.eduCoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) 4927761SN/A{ 4937761SN/A for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 49410900Snilay@cs.wisc.edu SlavePort *p = *s; 4957761SN/A // we could have gotten this request from a snooping master 4967761SN/A // (corresponding to our own slave port that is also in 4977761SN/A // snoopPorts) and should not send it back to where it came 4989988Snilay@cs.wisc.edu // from 4997761SN/A if (exclude_slave_port_id == InvalidPortID || 5005703SN/A p->getId() != exclude_slave_port_id) 50110900Snilay@cs.wisc.edu p->sendFunctionalSnoop(pkt); 5025703SN/A 5035703SN/A // if we get a response we are done 5045703SN/A if (pkt->isResponse()) { 5057761SN/A break; 5067761SN/A } 5079988Snilay@cs.wisc.edu } 5087761SN/A} 5095703SN/A 5107761SN/Aunsigned int 5115703SN/ACoherentBus::drain(Event *de) 5129988Snilay@cs.wisc.edu{ 5135703SN/A // sum up the individual layers 5145703SN/A return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de); 51510900Snilay@cs.wisc.edu} 5165703SN/A 5175703SN/ACoherentBus * 5185703SN/ACoherentBusParams::create() 5197761SN/A{ 5207761SN/A return new CoherentBus(this); 5219988Snilay@cs.wisc.edu} 5227761SN/A