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