coherent_xbar.cc revision 9092
112855Sgabeblack@google.com/* 213490Sgabeblack@google.com * Copyright (c) 2011-2012 ARM Limited 312855Sgabeblack@google.com * All rights reserved 413490Sgabeblack@google.com * 512855Sgabeblack@google.com * The license below extends only to copyright in the software and shall 613490Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712855Sgabeblack@google.com * property including but not limited to intellectual property relating 813490Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912855Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1013490Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112855Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1213490Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312855Sgabeblack@google.com * 1413490Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan 1512855Sgabeblack@google.com * All rights reserved. 1613490Sgabeblack@google.com * 1712855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1813490Sgabeblack@google.com * modification, are permitted provided that the following conditions are 1912855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2013490Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2112855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2213490Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2312855Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2413490Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2512855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2613490Sgabeblack@google.com * this software without specific prior written permission. 2712855Sgabeblack@google.com * 2813490Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3013490Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3213490Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3413490Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3613490Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3813490Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3912855Sgabeblack@google.com * 4013490Sgabeblack@google.com * Authors: Ali Saidi 4112855Sgabeblack@google.com * Andreas Hansson 4213490Sgabeblack@google.com * William Wang 4312855Sgabeblack@google.com */ 4413490Sgabeblack@google.com 4512855Sgabeblack@google.com/** 4613490Sgabeblack@google.com * @file 4712855Sgabeblack@google.com * Definition of a bus object. 4813490Sgabeblack@google.com */ 4912855Sgabeblack@google.com 5013490Sgabeblack@google.com#include "base/misc.hh" 5112855Sgabeblack@google.com#include "base/trace.hh" 5213490Sgabeblack@google.com#include "debug/BusAddrRanges.hh" 5312855Sgabeblack@google.com#include "debug/CoherentBus.hh" 5413490Sgabeblack@google.com#include "mem/coherent_bus.hh" 5512855Sgabeblack@google.com 5613490Sgabeblack@google.comCoherentBus::CoherentBus(const CoherentBusParams *p) 5712855Sgabeblack@google.com : BaseBus(p), layer(*this, ".layer", p->clock) 5813490Sgabeblack@google.com{ 5912855Sgabeblack@google.com // create the ports based on the size of the master and slave 6013490Sgabeblack@google.com // vector ports, and the presence of the default port, the ports 6112855Sgabeblack@google.com // are enumerated starting from zero 6213490Sgabeblack@google.com for (int i = 0; i < p->port_master_connection_count; ++i) { 6312855Sgabeblack@google.com std::string portName = csprintf("%s-p%d", name(), i); 6413490Sgabeblack@google.com MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); 6512855Sgabeblack@google.com masterPorts.push_back(bp); 6613490Sgabeblack@google.com } 6712855Sgabeblack@google.com 6813490Sgabeblack@google.com // see if we have a default slave device connected and if so add 6912855Sgabeblack@google.com // our corresponding master port 7013490Sgabeblack@google.com if (p->port_default_connection_count) { 7112855Sgabeblack@google.com defaultPortID = masterPorts.size(); 7213490Sgabeblack@google.com std::string portName = csprintf("%s-default", name()); 7312855Sgabeblack@google.com MasterPort* bp = new CoherentBusMasterPort(portName, *this, 7413490Sgabeblack@google.com defaultPortID); 7512855Sgabeblack@google.com masterPorts.push_back(bp); 7613490Sgabeblack@google.com } 7712855Sgabeblack@google.com 7813490Sgabeblack@google.com // create the slave ports, once again starting at zero 7912855Sgabeblack@google.com for (int i = 0; i < p->port_slave_connection_count; ++i) { 8013490Sgabeblack@google.com std::string portName = csprintf("%s-p%d", name(), i); 8112855Sgabeblack@google.com SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); 8213490Sgabeblack@google.com slavePorts.push_back(bp); 8312855Sgabeblack@google.com } 8413490Sgabeblack@google.com 8512855Sgabeblack@google.com clearPortCache(); 8613490Sgabeblack@google.com} 8712855Sgabeblack@google.com 8813490Sgabeblack@google.comvoid 8912855Sgabeblack@google.comCoherentBus::init() 9013490Sgabeblack@google.com{ 9112855Sgabeblack@google.com // iterate over our slave ports and determine which of our 9213490Sgabeblack@google.com // neighbouring master ports are snooping and add them as snoopers 9312855Sgabeblack@google.com for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 9413490Sgabeblack@google.com ++p) { 9512855Sgabeblack@google.com // check if the connected master port is snooping 9613490Sgabeblack@google.com if ((*p)->isSnooping()) { 9712855Sgabeblack@google.com DPRINTF(BusAddrRanges, "Adding snooping master %s\n", 9813490Sgabeblack@google.com (*p)->getMasterPort().name()); 9912855Sgabeblack@google.com snoopPorts.push_back(*p); 10013490Sgabeblack@google.com } 10112855Sgabeblack@google.com } 10213490Sgabeblack@google.com 10312855Sgabeblack@google.com if (snoopPorts.empty()) 10413490Sgabeblack@google.com warn("CoherentBus %s has no snooping ports attached!\n", name()); 10512855Sgabeblack@google.com} 10613490Sgabeblack@google.com 10712855Sgabeblack@google.combool 10813490Sgabeblack@google.comCoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) 10912855Sgabeblack@google.com{ 11013490Sgabeblack@google.com // determine the source port based on the id 11112855Sgabeblack@google.com SlavePort *src_port = slavePorts[slave_port_id]; 11213490Sgabeblack@google.com 11312855Sgabeblack@google.com // remember if the packet is an express snoop 11413490Sgabeblack@google.com bool is_express_snoop = pkt->isExpressSnoop(); 11512855Sgabeblack@google.com 11613490Sgabeblack@google.com // test if the bus should be considered occupied for the current 11712855Sgabeblack@google.com // port, and exclude express snoops from the check 11813490Sgabeblack@google.com if (!is_express_snoop && !layer.tryTiming(src_port)) { 11912855Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", 12013490Sgabeblack@google.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 12112855Sgabeblack@google.com return false; 12213490Sgabeblack@google.com } 12312855Sgabeblack@google.com 12413490Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n", 12512855Sgabeblack@google.com src_port->name(), pkt->cmdString(), is_express_snoop, 12613490Sgabeblack@google.com pkt->getAddr()); 12712855Sgabeblack@google.com 12813490Sgabeblack@google.com // set the source port for routing of the response 12912855Sgabeblack@google.com pkt->setSrc(slave_port_id); 13013490Sgabeblack@google.com 13112855Sgabeblack@google.com Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt); 13213490Sgabeblack@google.com Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime; 13312855Sgabeblack@google.com 13413490Sgabeblack@google.com // uncacheable requests need never be snooped 13512855Sgabeblack@google.com if (!pkt->req->isUncacheable()) { 13613490Sgabeblack@google.com // the packet is a memory-mapped request and should be 13712855Sgabeblack@google.com // broadcasted to our snoopers but the source 13813490Sgabeblack@google.com forwardTiming(pkt, slave_port_id); 13912855Sgabeblack@google.com } 14013490Sgabeblack@google.com 14112855Sgabeblack@google.com // remember if we add an outstanding req so we can undo it if 14213490Sgabeblack@google.com // necessary, if the packet needs a response, we should add it 14312855Sgabeblack@google.com // as outstanding and express snoops never fail so there is 14413490Sgabeblack@google.com // not need to worry about them 14512855Sgabeblack@google.com bool add_outstanding = !is_express_snoop && pkt->needsResponse(); 14613490Sgabeblack@google.com 14712855Sgabeblack@google.com // keep track that we have an outstanding request packet 14813490Sgabeblack@google.com // matching this request, this is used by the coherency 14912855Sgabeblack@google.com // mechanism in determining what to do with snoop responses 15013490Sgabeblack@google.com // (in recvTimingSnoop) 15112855Sgabeblack@google.com if (add_outstanding) { 15213490Sgabeblack@google.com // we should never have an exsiting request outstanding 15312855Sgabeblack@google.com assert(outstandingReq.find(pkt->req) == outstandingReq.end()); 15413490Sgabeblack@google.com outstandingReq.insert(pkt->req); 15512855Sgabeblack@google.com } 15613490Sgabeblack@google.com 15712855Sgabeblack@google.com // since it is a normal request, determine the destination 15813490Sgabeblack@google.com // based on the address and attempt to send the packet 15912855Sgabeblack@google.com bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); 16013490Sgabeblack@google.com 16112855Sgabeblack@google.com // if this is an express snoop, we are done at this point 16213490Sgabeblack@google.com if (is_express_snoop) { 16312855Sgabeblack@google.com assert(success); 16413490Sgabeblack@google.com } else { 16512855Sgabeblack@google.com // for normal requests, check if successful 16613490Sgabeblack@google.com if (!success) { 16712855Sgabeblack@google.com // inhibited packets should never be forced to retry 16813490Sgabeblack@google.com assert(!pkt->memInhibitAsserted()); 16912855Sgabeblack@google.com 17013490Sgabeblack@google.com // if it was added as outstanding and the send failed, then 17112855Sgabeblack@google.com // erase it again 17213490Sgabeblack@google.com if (add_outstanding) 17312855Sgabeblack@google.com outstandingReq.erase(pkt->req); 17413490Sgabeblack@google.com 17512855Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", 17613490Sgabeblack@google.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 17712855Sgabeblack@google.com 17813490Sgabeblack@google.com // update the bus state and schedule an idle event 17912855Sgabeblack@google.com layer.failedTiming(src_port, headerFinishTime); 18013490Sgabeblack@google.com } else { 18112855Sgabeblack@google.com // update the bus state and schedule an idle event 18213490Sgabeblack@google.com layer.succeededTiming(packetFinishTime); 18312855Sgabeblack@google.com } 18413490Sgabeblack@google.com } 18512855Sgabeblack@google.com 18613490Sgabeblack@google.com return success; 18712855Sgabeblack@google.com} 18813490Sgabeblack@google.com 18912855Sgabeblack@google.combool 19013490Sgabeblack@google.comCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) 19112855Sgabeblack@google.com{ 19213490Sgabeblack@google.com // determine the source port based on the id 19312855Sgabeblack@google.com MasterPort *src_port = masterPorts[master_port_id]; 19413490Sgabeblack@google.com 19512855Sgabeblack@google.com // test if the bus should be considered occupied for the current 19613490Sgabeblack@google.com // port 19712855Sgabeblack@google.com if (!layer.tryTiming(src_port)) { 19813490Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", 19912855Sgabeblack@google.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 20013490Sgabeblack@google.com return false; 20112855Sgabeblack@google.com } 20213490Sgabeblack@google.com 20312855Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", 20413490Sgabeblack@google.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 20512855Sgabeblack@google.com 20613490Sgabeblack@google.com calcPacketTiming(pkt); 20712855Sgabeblack@google.com Tick packetFinishTime = pkt->finishTime; 20813490Sgabeblack@google.com 20912855Sgabeblack@google.com // the packet is a normal response to a request that we should 21013490Sgabeblack@google.com // have seen passing through the bus 21112855Sgabeblack@google.com assert(outstandingReq.find(pkt->req) != outstandingReq.end()); 21213490Sgabeblack@google.com 21312855Sgabeblack@google.com // remove it as outstanding 21413490Sgabeblack@google.com outstandingReq.erase(pkt->req); 21512855Sgabeblack@google.com 21613490Sgabeblack@google.com // send the packet to the destination through one of our slave 21712855Sgabeblack@google.com // ports, as determined by the destination field 21813490Sgabeblack@google.com bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); 21912855Sgabeblack@google.com 22013490Sgabeblack@google.com // currently it is illegal to block responses... can lead to 22112855Sgabeblack@google.com // deadlock 22213490Sgabeblack@google.com assert(success); 22312855Sgabeblack@google.com 22413490Sgabeblack@google.com layer.succeededTiming(packetFinishTime); 22512855Sgabeblack@google.com 22613490Sgabeblack@google.com return true; 22712855Sgabeblack@google.com} 22813490Sgabeblack@google.com 22912855Sgabeblack@google.comvoid 23013490Sgabeblack@google.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) 23112855Sgabeblack@google.com{ 23213490Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", 23312855Sgabeblack@google.com masterPorts[master_port_id]->name(), pkt->cmdString(), 23413490Sgabeblack@google.com pkt->getAddr()); 23512855Sgabeblack@google.com 23613490Sgabeblack@google.com // we should only see express snoops from caches 23712855Sgabeblack@google.com assert(pkt->isExpressSnoop()); 23813490Sgabeblack@google.com 23912855Sgabeblack@google.com // set the source port for routing of the response 24013490Sgabeblack@google.com pkt->setSrc(master_port_id); 24112855Sgabeblack@google.com 24213490Sgabeblack@google.com // forward to all snoopers 24312855Sgabeblack@google.com forwardTiming(pkt, InvalidPortID); 24413490Sgabeblack@google.com 24512855Sgabeblack@google.com // a snoop request came from a connected slave device (one of 24613490Sgabeblack@google.com // our master ports), and if it is not coming from the slave 24712855Sgabeblack@google.com // device responsible for the address range something is 24813490Sgabeblack@google.com // wrong, hence there is nothing further to do as the packet 24912855Sgabeblack@google.com // would be going back to where it came from 25013490Sgabeblack@google.com assert(master_port_id == findPort(pkt->getAddr())); 25112855Sgabeblack@google.com} 25213490Sgabeblack@google.com 25312855Sgabeblack@google.combool 25413490Sgabeblack@google.comCoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) 25512855Sgabeblack@google.com{ 25613490Sgabeblack@google.com // determine the source port based on the id 25712855Sgabeblack@google.com SlavePort* src_port = slavePorts[slave_port_id]; 25813490Sgabeblack@google.com 25912855Sgabeblack@google.com // test if the bus should be considered occupied for the current 26013490Sgabeblack@google.com // port 26112855Sgabeblack@google.com if (!layer.tryTiming(src_port)) { 26213490Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 26312855Sgabeblack@google.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 26413490Sgabeblack@google.com return false; 26512855Sgabeblack@google.com } 26613490Sgabeblack@google.com 26712855Sgabeblack@google.com DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n", 26813490Sgabeblack@google.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 26912855Sgabeblack@google.com 27013490Sgabeblack@google.com // get the destination from the packet 27112855Sgabeblack@google.com PortID dest = pkt->getDest(); 27213490Sgabeblack@google.com 27312855Sgabeblack@google.com // responses are never express snoops 27413490Sgabeblack@google.com assert(!pkt->isExpressSnoop()); 27512855Sgabeblack@google.com 27613490Sgabeblack@google.com calcPacketTiming(pkt); 27712855Sgabeblack@google.com Tick packetFinishTime = pkt->finishTime; 27813490Sgabeblack@google.com 27912855Sgabeblack@google.com // determine if the response is from a snoop request we 28013490Sgabeblack@google.com // created as the result of a normal request (in which case it 28112855Sgabeblack@google.com // should be in the outstandingReq), or if we merely forwarded 28213490Sgabeblack@google.com // someone else's snoop request 28312855Sgabeblack@google.com if (outstandingReq.find(pkt->req) == outstandingReq.end()) { 28413490Sgabeblack@google.com // this is a snoop response to a snoop request we 28512855Sgabeblack@google.com // forwarded, e.g. coming from the L1 and going to the L2 28613490Sgabeblack@google.com // this should be forwarded as a snoop response 28712855Sgabeblack@google.com bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt); 28813490Sgabeblack@google.com assert(success); 28912855Sgabeblack@google.com } else { 29013490Sgabeblack@google.com // we got a snoop response on one of our slave ports, 29112855Sgabeblack@google.com // i.e. from a coherent master connected to the bus, and 29213490Sgabeblack@google.com // since we created the snoop request as part of 29312855Sgabeblack@google.com // recvTiming, this should now be a normal response again 29413490Sgabeblack@google.com outstandingReq.erase(pkt->req); 29512855Sgabeblack@google.com 29613490Sgabeblack@google.com // this is a snoop response from a coherent master, with a 29712855Sgabeblack@google.com // destination field set on its way through the bus as 29813490Sgabeblack@google.com // request, hence it should never go back to where the 29912855Sgabeblack@google.com // snoop response came from, but instead to where the 30013490Sgabeblack@google.com // original request came from 30112855Sgabeblack@google.com assert(slave_port_id != dest); 30213490Sgabeblack@google.com 30312855Sgabeblack@google.com // as a normal response, it should go back to a master 30413490Sgabeblack@google.com // through one of our slave ports 30512855Sgabeblack@google.com bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt); 30613490Sgabeblack@google.com 30712855Sgabeblack@google.com // currently it is illegal to block responses... can lead 30813490Sgabeblack@google.com // to deadlock 30912855Sgabeblack@google.com assert(success); 31013490Sgabeblack@google.com } 31112855Sgabeblack@google.com 31213490Sgabeblack@google.com layer.succeededTiming(packetFinishTime); 31312855Sgabeblack@google.com 31413490Sgabeblack@google.com return true; 31512855Sgabeblack@google.com} 31613490Sgabeblack@google.com 31712855Sgabeblack@google.com 31813490Sgabeblack@google.comvoid 31912855Sgabeblack@google.comCoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) 32013490Sgabeblack@google.com{ 32112855Sgabeblack@google.com for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 32213490Sgabeblack@google.com SlavePort *p = *s; 32312855Sgabeblack@google.com // we could have gotten this request from a snooping master 32413490Sgabeblack@google.com // (corresponding to our own slave port that is also in 32512855Sgabeblack@google.com // snoopPorts) and should not send it back to where it came 32613490Sgabeblack@google.com // from 32712855Sgabeblack@google.com if (exclude_slave_port_id == InvalidPortID || 32813490Sgabeblack@google.com p->getId() != exclude_slave_port_id) { 32912855Sgabeblack@google.com // cache is not allowed to refuse snoop 33013490Sgabeblack@google.com p->sendTimingSnoopReq(pkt); 33112855Sgabeblack@google.com } 33213490Sgabeblack@google.com } 33312855Sgabeblack@google.com} 33413490Sgabeblack@google.com 33512855Sgabeblack@google.comvoid 33613490Sgabeblack@google.comCoherentBus::recvRetry() 33712855Sgabeblack@google.com{ 33813490Sgabeblack@google.com // only one layer that can deal with it 33912855Sgabeblack@google.com layer.recvRetry(); 34013490Sgabeblack@google.com} 34112855Sgabeblack@google.com 34213490Sgabeblack@google.comTick 34312855Sgabeblack@google.comCoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) 34413490Sgabeblack@google.com{ 34512855Sgabeblack@google.com DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 34613490Sgabeblack@google.com slavePorts[slave_port_id]->name(), pkt->getAddr(), 34712855Sgabeblack@google.com pkt->cmdString()); 34813490Sgabeblack@google.com 34912855Sgabeblack@google.com MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 35013490Sgabeblack@google.com Tick snoop_response_latency = 0; 35112855Sgabeblack@google.com 35213490Sgabeblack@google.com // uncacheable requests need never be snooped 35312855Sgabeblack@google.com if (!pkt->req->isUncacheable()) { 35413490Sgabeblack@google.com // forward to all snoopers but the source 35512855Sgabeblack@google.com std::pair<MemCmd, Tick> snoop_result = 35613490Sgabeblack@google.com forwardAtomic(pkt, slave_port_id); 35712855Sgabeblack@google.com snoop_response_cmd = snoop_result.first; 35813490Sgabeblack@google.com snoop_response_latency = snoop_result.second; 35912855Sgabeblack@google.com } 36013490Sgabeblack@google.com 36112855Sgabeblack@google.com // even if we had a snoop response, we must continue and also 36213490Sgabeblack@google.com // perform the actual request at the destination 36312855Sgabeblack@google.com PortID dest_id = findPort(pkt->getAddr()); 36413490Sgabeblack@google.com 36512855Sgabeblack@google.com // forward the request to the appropriate destination 36613490Sgabeblack@google.com Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 36712855Sgabeblack@google.com 36813490Sgabeblack@google.com // if we got a response from a snooper, restore it here 36912855Sgabeblack@google.com if (snoop_response_cmd != MemCmd::InvalidCmd) { 37013490Sgabeblack@google.com // no one else should have responded 37112855Sgabeblack@google.com assert(!pkt->isResponse()); 37213490Sgabeblack@google.com pkt->cmd = snoop_response_cmd; 37312855Sgabeblack@google.com response_latency = snoop_response_latency; 37413490Sgabeblack@google.com } 37512855Sgabeblack@google.com 37613490Sgabeblack@google.com pkt->finishTime = curTick() + response_latency; 37712855Sgabeblack@google.com return response_latency; 37813490Sgabeblack@google.com} 37912855Sgabeblack@google.com 38013490Sgabeblack@google.comTick 38112855Sgabeblack@google.comCoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) 38213490Sgabeblack@google.com{ 38312855Sgabeblack@google.com DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", 38413490Sgabeblack@google.com masterPorts[master_port_id]->name(), pkt->getAddr(), 38512855Sgabeblack@google.com pkt->cmdString()); 38613490Sgabeblack@google.com 38712855Sgabeblack@google.com // forward to all snoopers 38813490Sgabeblack@google.com std::pair<MemCmd, Tick> snoop_result = 38912855Sgabeblack@google.com forwardAtomic(pkt, InvalidPortID); 39013490Sgabeblack@google.com MemCmd snoop_response_cmd = snoop_result.first; 39112855Sgabeblack@google.com Tick snoop_response_latency = snoop_result.second; 39213490Sgabeblack@google.com 39312855Sgabeblack@google.com if (snoop_response_cmd != MemCmd::InvalidCmd) 39413490Sgabeblack@google.com pkt->cmd = snoop_response_cmd; 39512855Sgabeblack@google.com 39613490Sgabeblack@google.com pkt->finishTime = curTick() + snoop_response_latency; 39712855Sgabeblack@google.com return snoop_response_latency; 39813490Sgabeblack@google.com} 39912855Sgabeblack@google.com 40013490Sgabeblack@google.comstd::pair<MemCmd, Tick> 40112855Sgabeblack@google.comCoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) 40213490Sgabeblack@google.com{ 40312855Sgabeblack@google.com // the packet may be changed on snoops, record the original 40413490Sgabeblack@google.com // command to enable us to restore it between snoops so that 40512855Sgabeblack@google.com // additional snoops can take place properly 40613490Sgabeblack@google.com MemCmd orig_cmd = pkt->cmd; 40712855Sgabeblack@google.com MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 40813490Sgabeblack@google.com Tick snoop_response_latency = 0; 40912855Sgabeblack@google.com 41013490Sgabeblack@google.com for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 41112855Sgabeblack@google.com SlavePort *p = *s; 41213490Sgabeblack@google.com // we could have gotten this request from a snooping master 41312855Sgabeblack@google.com // (corresponding to our own slave port that is also in 41413490Sgabeblack@google.com // snoopPorts) and should not send it back to where it came 41512855Sgabeblack@google.com // from 41613490Sgabeblack@google.com if (exclude_slave_port_id == InvalidPortID || 41712855Sgabeblack@google.com p->getId() != exclude_slave_port_id) { 41813490Sgabeblack@google.com Tick latency = p->sendAtomicSnoop(pkt); 41912855Sgabeblack@google.com // in contrast to a functional access, we have to keep on 42013490Sgabeblack@google.com // going as all snoopers must be updated even if we get a 42112855Sgabeblack@google.com // response 42213490Sgabeblack@google.com if (pkt->isResponse()) { 42312855Sgabeblack@google.com // response from snoop agent 42413490Sgabeblack@google.com assert(pkt->cmd != orig_cmd); 42512855Sgabeblack@google.com assert(pkt->memInhibitAsserted()); 42613490Sgabeblack@google.com // should only happen once 42712855Sgabeblack@google.com assert(snoop_response_cmd == MemCmd::InvalidCmd); 42813490Sgabeblack@google.com // save response state 42912855Sgabeblack@google.com snoop_response_cmd = pkt->cmd; 43013490Sgabeblack@google.com snoop_response_latency = latency; 43112855Sgabeblack@google.com // restore original packet state for remaining snoopers 43213490Sgabeblack@google.com pkt->cmd = orig_cmd; 43312855Sgabeblack@google.com } 43413490Sgabeblack@google.com } 43512855Sgabeblack@google.com } 43613490Sgabeblack@google.com 43712855Sgabeblack@google.com // the packet is restored as part of the loop and any potential 43813490Sgabeblack@google.com // snoop response is part of the returned pair 43912855Sgabeblack@google.com return std::make_pair(snoop_response_cmd, snoop_response_latency); 44013490Sgabeblack@google.com} 44112855Sgabeblack@google.com 44213490Sgabeblack@google.comvoid 44312855Sgabeblack@google.comCoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) 44413490Sgabeblack@google.com{ 44512855Sgabeblack@google.com if (!pkt->isPrint()) { 44613490Sgabeblack@google.com // don't do DPRINTFs on PrintReq as it clutters up the output 44712855Sgabeblack@google.com DPRINTF(CoherentBus, 44813490Sgabeblack@google.com "recvFunctional: packet src %s addr 0x%x cmd %s\n", 44912855Sgabeblack@google.com slavePorts[slave_port_id]->name(), pkt->getAddr(), 45013490Sgabeblack@google.com pkt->cmdString()); 45112855Sgabeblack@google.com } 45213490Sgabeblack@google.com 45312855Sgabeblack@google.com // uncacheable requests need never be snooped 45413490Sgabeblack@google.com if (!pkt->req->isUncacheable()) { 45512855Sgabeblack@google.com // forward to all snoopers but the source 45613490Sgabeblack@google.com forwardFunctional(pkt, slave_port_id); 45712855Sgabeblack@google.com } 45813490Sgabeblack@google.com 45912855Sgabeblack@google.com // there is no need to continue if the snooping has found what we 46013490Sgabeblack@google.com // were looking for and the packet is already a response 46112855Sgabeblack@google.com if (!pkt->isResponse()) { 46213490Sgabeblack@google.com PortID dest_id = findPort(pkt->getAddr()); 46312855Sgabeblack@google.com 46413490Sgabeblack@google.com masterPorts[dest_id]->sendFunctional(pkt); 46512855Sgabeblack@google.com } 46613490Sgabeblack@google.com} 46712855Sgabeblack@google.com 46813490Sgabeblack@google.comvoid 46912855Sgabeblack@google.comCoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) 47013490Sgabeblack@google.com{ 47112855Sgabeblack@google.com if (!pkt->isPrint()) { 47213490Sgabeblack@google.com // don't do DPRINTFs on PrintReq as it clutters up the output 47312855Sgabeblack@google.com DPRINTF(CoherentBus, 47413490Sgabeblack@google.com "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", 47512855Sgabeblack@google.com masterPorts[master_port_id]->name(), pkt->getAddr(), 47613490Sgabeblack@google.com pkt->cmdString()); 47712855Sgabeblack@google.com } 47813490Sgabeblack@google.com 47912855Sgabeblack@google.com // forward to all snoopers 48013490Sgabeblack@google.com forwardFunctional(pkt, InvalidPortID); 48112855Sgabeblack@google.com} 48213490Sgabeblack@google.com 48312855Sgabeblack@google.comvoid 48413490Sgabeblack@google.comCoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) 48512855Sgabeblack@google.com{ 48613490Sgabeblack@google.com for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 48712855Sgabeblack@google.com SlavePort *p = *s; 48813490Sgabeblack@google.com // we could have gotten this request from a snooping master 48912855Sgabeblack@google.com // (corresponding to our own slave port that is also in 49013490Sgabeblack@google.com // snoopPorts) and should not send it back to where it came 49112855Sgabeblack@google.com // from 49213490Sgabeblack@google.com if (exclude_slave_port_id == InvalidPortID || 49312855Sgabeblack@google.com p->getId() != exclude_slave_port_id) 49413490Sgabeblack@google.com p->sendFunctionalSnoop(pkt); 49512855Sgabeblack@google.com 49613490Sgabeblack@google.com // if we get a response we are done 49712855Sgabeblack@google.com if (pkt->isResponse()) { 49813490Sgabeblack@google.com break; 49912855Sgabeblack@google.com } 50013490Sgabeblack@google.com } 50112855Sgabeblack@google.com} 50213490Sgabeblack@google.com 50312855Sgabeblack@google.comunsigned int 50413490Sgabeblack@google.comCoherentBus::drain(Event *de) 50512855Sgabeblack@google.com{ 50613490Sgabeblack@google.com // only one layer to worry about at the moment 50712855Sgabeblack@google.com return layer.drain(de); 50813490Sgabeblack@google.com} 50912855Sgabeblack@google.com 51013490Sgabeblack@google.comCoherentBus * 51112855Sgabeblack@google.comCoherentBusParams::create() 51213490Sgabeblack@google.com{ 51312855Sgabeblack@google.com return new CoherentBus(this); 51413490Sgabeblack@google.com} 51512855Sgabeblack@google.com