coherent_xbar.cc revision 9278
12381SN/A/* 210713Sandreas.hansson@arm.com * Copyright (c) 2011-2012 ARM Limited 38711Sandreas.hansson@arm.com * All rights reserved 48711Sandreas.hansson@arm.com * 58711Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 68711Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 78711Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 88711Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 98711Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 108711Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 118711Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 128711Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 138711Sandreas.hansson@arm.com * 142381SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152381SN/A * All rights reserved. 162381SN/A * 172381SN/A * Redistribution and use in source and binary forms, with or without 182381SN/A * modification, are permitted provided that the following conditions are 192381SN/A * met: redistributions of source code must retain the above copyright 202381SN/A * notice, this list of conditions and the following disclaimer; 212381SN/A * redistributions in binary form must reproduce the above copyright 222381SN/A * notice, this list of conditions and the following disclaimer in the 232381SN/A * documentation and/or other materials provided with the distribution; 242381SN/A * neither the name of the copyright holders nor the names of its 252381SN/A * contributors may be used to endorse or promote products derived from 262381SN/A * this software without specific prior written permission. 272381SN/A * 282381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665Ssaidi@eecs.umich.edu * 402665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 418853Sandreas.hansson@arm.com * Andreas Hansson 428922Swilliam.wang@arm.com * William Wang 432381SN/A */ 442381SN/A 452381SN/A/** 462381SN/A * @file 478922Swilliam.wang@arm.com * Definition of a bus object. 482381SN/A */ 492381SN/A 502381SN/A#include "base/misc.hh" 512381SN/A#include "base/trace.hh" 522381SN/A#include "debug/BusAddrRanges.hh" 539235Sandreas.hansson@arm.com#include "debug/CoherentBus.hh" 542381SN/A#include "mem/coherent_bus.hh" 552381SN/A 563401Sktlim@umich.eduCoherentBus::CoherentBus(const CoherentBusParams *p) 573401Sktlim@umich.edu : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock), 582381SN/A respLayer(*this, ".respLayer", p->clock), 598922Swilliam.wang@arm.com snoopRespLayer(*this, ".snoopRespLayer", p->clock) 608922Swilliam.wang@arm.com{ 619087Sandreas.hansson@arm.com // create the ports based on the size of the master and slave 622381SN/A // vector ports, and the presence of the default port, the ports 638708Sandreas.hansson@arm.com // are enumerated starting from zero 642381SN/A for (int i = 0; i < p->port_master_connection_count; ++i) { 658922Swilliam.wang@arm.com std::string portName = csprintf("%s.master[%d]", name(), i); 668922Swilliam.wang@arm.com MasterPort* bp = new CoherentBusMasterPort(portName, *this, i); 678922Swilliam.wang@arm.com masterPorts.push_back(bp); 688922Swilliam.wang@arm.com } 698922Swilliam.wang@arm.com 708922Swilliam.wang@arm.com // see if we have a default slave device connected and if so add 715476Snate@binkert.org // our corresponding master port 722640Sstever@eecs.umich.edu if (p->port_default_connection_count) { 738965Sandreas.hansson@arm.com defaultPortID = masterPorts.size(); 748965Sandreas.hansson@arm.com std::string portName = name() + ".default"; 759031Sandreas.hansson@arm.com MasterPort* bp = new CoherentBusMasterPort(portName, *this, 768965Sandreas.hansson@arm.com defaultPortID); 779031Sandreas.hansson@arm.com masterPorts.push_back(bp); 788965Sandreas.hansson@arm.com } 798922Swilliam.wang@arm.com 808922Swilliam.wang@arm.com // create the slave ports, once again starting at zero 818922Swilliam.wang@arm.com for (int i = 0; i < p->port_slave_connection_count; ++i) { 828922Swilliam.wang@arm.com std::string portName = csprintf("%s.slave[%d]", name(), i); 838922Swilliam.wang@arm.com SlavePort* bp = new CoherentBusSlavePort(portName, *this, i); 848922Swilliam.wang@arm.com slavePorts.push_back(bp); 858922Swilliam.wang@arm.com } 868922Swilliam.wang@arm.com 878965Sandreas.hansson@arm.com clearPortCache(); 888922Swilliam.wang@arm.com} 899031Sandreas.hansson@arm.com 908922Swilliam.wang@arm.comvoid 918922Swilliam.wang@arm.comCoherentBus::init() 928922Swilliam.wang@arm.com{ 938922Swilliam.wang@arm.com // the base class is responsible for determining the block size 948922Swilliam.wang@arm.com BaseBus::init(); 953401Sktlim@umich.edu 962381SN/A // iterate over our slave ports and determine which of our 972640Sstever@eecs.umich.edu // neighbouring master ports are snooping and add them as snoopers 982640Sstever@eecs.umich.edu for (SlavePortConstIter p = slavePorts.begin(); p != slavePorts.end(); 998922Swilliam.wang@arm.com ++p) { 1004190Ssaidi@eecs.umich.edu // check if the connected master port is snooping 1018965Sandreas.hansson@arm.com if ((*p)->isSnooping()) { 1029031Sandreas.hansson@arm.com DPRINTF(BusAddrRanges, "Adding snooping master %s\n", 1038965Sandreas.hansson@arm.com (*p)->getMasterPort().name()); 1048922Swilliam.wang@arm.com snoopPorts.push_back(*p); 1058922Swilliam.wang@arm.com } 1068922Swilliam.wang@arm.com } 1079294Sandreas.hansson@arm.com 1089294Sandreas.hansson@arm.com if (snoopPorts.empty()) 1099294Sandreas.hansson@arm.com warn("CoherentBus %s has no snooping ports attached!\n", name()); 1109294Sandreas.hansson@arm.com} 1119294Sandreas.hansson@arm.com 1129294Sandreas.hansson@arm.combool 1139294Sandreas.hansson@arm.comCoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id) 1149294Sandreas.hansson@arm.com{ 1159294Sandreas.hansson@arm.com // determine the source port based on the id 1169294Sandreas.hansson@arm.com SlavePort *src_port = slavePorts[slave_port_id]; 1179294Sandreas.hansson@arm.com 1189294Sandreas.hansson@arm.com // remember if the packet is an express snoop 1199294Sandreas.hansson@arm.com bool is_express_snoop = pkt->isExpressSnoop(); 1209294Sandreas.hansson@arm.com 1219294Sandreas.hansson@arm.com // test if the bus should be considered occupied for the current 1229294Sandreas.hansson@arm.com // port, and exclude express snoops from the check 1239294Sandreas.hansson@arm.com if (!is_express_snoop && !reqLayer.tryTiming(src_port)) { 1249294Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n", 1259294Sandreas.hansson@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 1269294Sandreas.hansson@arm.com return false; 1279294Sandreas.hansson@arm.com } 1289294Sandreas.hansson@arm.com 1299294Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvTimingReq: src %s %s expr %d 0x%x\n", 1309294Sandreas.hansson@arm.com src_port->name(), pkt->cmdString(), is_express_snoop, 1319294Sandreas.hansson@arm.com pkt->getAddr()); 1329294Sandreas.hansson@arm.com 1339294Sandreas.hansson@arm.com // set the source port for routing of the response 1349294Sandreas.hansson@arm.com pkt->setSrc(slave_port_id); 1359294Sandreas.hansson@arm.com 1369294Sandreas.hansson@arm.com Tick headerFinishTime = is_express_snoop ? 0 : calcPacketTiming(pkt); 1379294Sandreas.hansson@arm.com Tick packetFinishTime = is_express_snoop ? 0 : pkt->finishTime; 1389294Sandreas.hansson@arm.com 1399294Sandreas.hansson@arm.com // uncacheable requests need never be snooped 1409294Sandreas.hansson@arm.com if (!pkt->req->isUncacheable()) { 1419294Sandreas.hansson@arm.com // the packet is a memory-mapped request and should be 1429294Sandreas.hansson@arm.com // broadcasted to our snoopers but the source 1439294Sandreas.hansson@arm.com forwardTiming(pkt, slave_port_id); 1449294Sandreas.hansson@arm.com } 1459294Sandreas.hansson@arm.com 1469294Sandreas.hansson@arm.com // remember if we add an outstanding req so we can undo it if 1479294Sandreas.hansson@arm.com // necessary, if the packet needs a response, we should add it 1489294Sandreas.hansson@arm.com // as outstanding and express snoops never fail so there is 1499294Sandreas.hansson@arm.com // not need to worry about them 1509294Sandreas.hansson@arm.com bool add_outstanding = !is_express_snoop && pkt->needsResponse(); 1519294Sandreas.hansson@arm.com 1529294Sandreas.hansson@arm.com // keep track that we have an outstanding request packet 1539294Sandreas.hansson@arm.com // matching this request, this is used by the coherency 1549294Sandreas.hansson@arm.com // mechanism in determining what to do with snoop responses 1559294Sandreas.hansson@arm.com // (in recvTimingSnoop) 1569294Sandreas.hansson@arm.com if (add_outstanding) { 1579294Sandreas.hansson@arm.com // we should never have an exsiting request outstanding 1588922Swilliam.wang@arm.com assert(outstandingReq.find(pkt->req) == outstandingReq.end()); 1598922Swilliam.wang@arm.com outstandingReq.insert(pkt->req); 1608922Swilliam.wang@arm.com } 1619294Sandreas.hansson@arm.com 1629294Sandreas.hansson@arm.com // since it is a normal request, determine the destination 1639294Sandreas.hansson@arm.com // based on the address and attempt to send the packet 1649294Sandreas.hansson@arm.com bool success = masterPorts[findPort(pkt->getAddr())]->sendTimingReq(pkt); 1659294Sandreas.hansson@arm.com 1668922Swilliam.wang@arm.com // if this is an express snoop, we are done at this point 1679294Sandreas.hansson@arm.com if (is_express_snoop) { 1688922Swilliam.wang@arm.com assert(success); 1698922Swilliam.wang@arm.com } else { 1708975Sandreas.hansson@arm.com // for normal requests, check if successful 1718975Sandreas.hansson@arm.com if (!success) { 1728922Swilliam.wang@arm.com // inhibited packets should never be forced to retry 1738922Swilliam.wang@arm.com assert(!pkt->memInhibitAsserted()); 1748922Swilliam.wang@arm.com 1758922Swilliam.wang@arm.com // if it was added as outstanding and the send failed, then 1768922Swilliam.wang@arm.com // erase it again 1778922Swilliam.wang@arm.com if (add_outstanding) 1788965Sandreas.hansson@arm.com outstandingReq.erase(pkt->req); 1799031Sandreas.hansson@arm.com 1808922Swilliam.wang@arm.com DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n", 1818922Swilliam.wang@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 1829178Sandreas.hansson@arm.com 1839178Sandreas.hansson@arm.com // update the bus state and schedule an idle event 1849178Sandreas.hansson@arm.com reqLayer.failedTiming(src_port, headerFinishTime); 1859178Sandreas.hansson@arm.com } else { 1869294Sandreas.hansson@arm.com // update the bus state and schedule an idle event 1879178Sandreas.hansson@arm.com reqLayer.succeededTiming(packetFinishTime); 1889178Sandreas.hansson@arm.com } 1899178Sandreas.hansson@arm.com } 1909178Sandreas.hansson@arm.com 1919178Sandreas.hansson@arm.com return success; 1929178Sandreas.hansson@arm.com} 1938922Swilliam.wang@arm.com 1948948Sandreas.hansson@arm.combool 1958948Sandreas.hansson@arm.comCoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id) 1968948Sandreas.hansson@arm.com{ 1978948Sandreas.hansson@arm.com // determine the source port based on the id 1988948Sandreas.hansson@arm.com MasterPort *src_port = masterPorts[master_port_id]; 1998948Sandreas.hansson@arm.com 2008948Sandreas.hansson@arm.com // test if the bus should be considered occupied for the current 2018948Sandreas.hansson@arm.com // port 2028948Sandreas.hansson@arm.com if (!respLayer.tryTiming(src_port)) { 2038948Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n", 2048948Sandreas.hansson@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 2058948Sandreas.hansson@arm.com return false; 2068948Sandreas.hansson@arm.com } 2078948Sandreas.hansson@arm.com 2088948Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n", 2098948Sandreas.hansson@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 2108948Sandreas.hansson@arm.com 2118948Sandreas.hansson@arm.com calcPacketTiming(pkt); 2128948Sandreas.hansson@arm.com Tick packetFinishTime = pkt->finishTime; 2138948Sandreas.hansson@arm.com 2148975Sandreas.hansson@arm.com // the packet is a normal response to a request that we should 2158975Sandreas.hansson@arm.com // have seen passing through the bus 2168975Sandreas.hansson@arm.com assert(outstandingReq.find(pkt->req) != outstandingReq.end()); 21710713Sandreas.hansson@arm.com 2188975Sandreas.hansson@arm.com // remove it as outstanding 2198975Sandreas.hansson@arm.com outstandingReq.erase(pkt->req); 2208975Sandreas.hansson@arm.com 2218975Sandreas.hansson@arm.com // send the packet to the destination through one of our slave 2228975Sandreas.hansson@arm.com // ports, as determined by the destination field 2238975Sandreas.hansson@arm.com bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt); 2248975Sandreas.hansson@arm.com 2258948Sandreas.hansson@arm.com // currently it is illegal to block responses... can lead to 2268948Sandreas.hansson@arm.com // deadlock 2278975Sandreas.hansson@arm.com assert(success); 2288975Sandreas.hansson@arm.com 2298975Sandreas.hansson@arm.com respLayer.succeededTiming(packetFinishTime); 23010713Sandreas.hansson@arm.com 23110713Sandreas.hansson@arm.com return true; 2328975Sandreas.hansson@arm.com} 2338975Sandreas.hansson@arm.com 2348948Sandreas.hansson@arm.comvoid 2358975Sandreas.hansson@arm.comCoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id) 2368922Swilliam.wang@arm.com{ 2378922Swilliam.wang@arm.com DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x\n", 2389087Sandreas.hansson@arm.com masterPorts[master_port_id]->name(), pkt->cmdString(), 23910713Sandreas.hansson@arm.com pkt->getAddr()); 24010713Sandreas.hansson@arm.com 24110713Sandreas.hansson@arm.com // we should only see express snoops from caches 2429087Sandreas.hansson@arm.com assert(pkt->isExpressSnoop()); 24310713Sandreas.hansson@arm.com 2449087Sandreas.hansson@arm.com // set the source port for routing of the response 2459087Sandreas.hansson@arm.com pkt->setSrc(master_port_id); 2468922Swilliam.wang@arm.com 2478711Sandreas.hansson@arm.com // forward to all snoopers 2488922Swilliam.wang@arm.com forwardTiming(pkt, InvalidPortID); 2498922Swilliam.wang@arm.com 2508922Swilliam.wang@arm.com // a snoop request came from a connected slave device (one of 2518711Sandreas.hansson@arm.com // our master ports), and if it is not coming from the slave 2528711Sandreas.hansson@arm.com // device responsible for the address range something is 2538711Sandreas.hansson@arm.com // wrong, hence there is nothing further to do as the packet 2548922Swilliam.wang@arm.com // would be going back to where it came from 2552381SN/A assert(master_port_id == findPort(pkt->getAddr())); 2568711Sandreas.hansson@arm.com} 2579089Sandreas.hansson@arm.com 2589089Sandreas.hansson@arm.combool 2599089Sandreas.hansson@arm.comCoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) 2609089Sandreas.hansson@arm.com{ 2615314Sstever@gmail.com // determine the source port based on the id 2625314Sstever@gmail.com SlavePort* src_port = slavePorts[slave_port_id]; 2635314Sstever@gmail.com 2645314Sstever@gmail.com // test if the bus should be considered occupied for the current 2658975Sandreas.hansson@arm.com // port 2668975Sandreas.hansson@arm.com if (!snoopRespLayer.tryTiming(src_port)) { 2678975Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", 2688975Sandreas.hansson@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 2698975Sandreas.hansson@arm.com return false; 2708975Sandreas.hansson@arm.com } 2718975Sandreas.hansson@arm.com 2728975Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n", 2738975Sandreas.hansson@arm.com src_port->name(), pkt->cmdString(), pkt->getAddr()); 2748975Sandreas.hansson@arm.com 2758975Sandreas.hansson@arm.com // get the destination from the packet 2768975Sandreas.hansson@arm.com PortID dest = pkt->getDest(); 2778975Sandreas.hansson@arm.com 2788975Sandreas.hansson@arm.com // responses are never express snoops 2798975Sandreas.hansson@arm.com assert(!pkt->isExpressSnoop()); 2808975Sandreas.hansson@arm.com 2818975Sandreas.hansson@arm.com calcPacketTiming(pkt); 2828975Sandreas.hansson@arm.com Tick packetFinishTime = pkt->finishTime; 2838975Sandreas.hansson@arm.com 2848975Sandreas.hansson@arm.com // determine if the response is from a snoop request we 2858975Sandreas.hansson@arm.com // created as the result of a normal request (in which case it 2868975Sandreas.hansson@arm.com // should be in the outstandingReq), or if we merely forwarded 2878975Sandreas.hansson@arm.com // someone else's snoop request 2888975Sandreas.hansson@arm.com if (outstandingReq.find(pkt->req) == outstandingReq.end()) { 2898975Sandreas.hansson@arm.com // this is a snoop response to a snoop request we 2908975Sandreas.hansson@arm.com // forwarded, e.g. coming from the L1 and going to the L2 2918975Sandreas.hansson@arm.com // this should be forwarded as a snoop response 2928975Sandreas.hansson@arm.com bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt); 2938975Sandreas.hansson@arm.com assert(success); 2948975Sandreas.hansson@arm.com } else { 2958975Sandreas.hansson@arm.com // we got a snoop response on one of our slave ports, 2968975Sandreas.hansson@arm.com // i.e. from a coherent master connected to the bus, and 2978975Sandreas.hansson@arm.com // since we created the snoop request as part of 2988975Sandreas.hansson@arm.com // recvTiming, this should now be a normal response again 29910713Sandreas.hansson@arm.com outstandingReq.erase(pkt->req); 30010713Sandreas.hansson@arm.com 30110713Sandreas.hansson@arm.com // this is a snoop response from a coherent master, with a 3029087Sandreas.hansson@arm.com // destination field set on its way through the bus as 30310713Sandreas.hansson@arm.com // request, hence it should never go back to where the 30410713Sandreas.hansson@arm.com // snoop response came from, but instead to where the 30510713Sandreas.hansson@arm.com // original request came from 30610713Sandreas.hansson@arm.com assert(slave_port_id != dest); 30710713Sandreas.hansson@arm.com 30810713Sandreas.hansson@arm.com // as a normal response, it should go back to a master 30910713Sandreas.hansson@arm.com // through one of our slave ports 31010713Sandreas.hansson@arm.com bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt); 31110713Sandreas.hansson@arm.com 31210713Sandreas.hansson@arm.com // currently it is illegal to block responses... can lead 31310713Sandreas.hansson@arm.com // to deadlock 3149087Sandreas.hansson@arm.com assert(success); 3159087Sandreas.hansson@arm.com } 3168975Sandreas.hansson@arm.com 3179325Sandreas.hansson@arm.com snoopRespLayer.succeededTiming(packetFinishTime); 3188975Sandreas.hansson@arm.com 3199325Sandreas.hansson@arm.com return true; 3208975Sandreas.hansson@arm.com} 3218975Sandreas.hansson@arm.com 3228975Sandreas.hansson@arm.com 3232381SN/Avoid 3242381SN/ACoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) 3258922Swilliam.wang@arm.com{ 3268922Swilliam.wang@arm.com for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 3278922Swilliam.wang@arm.com SlavePort *p = *s; 3288922Swilliam.wang@arm.com // we could have gotten this request from a snooping master 3298922Swilliam.wang@arm.com // (corresponding to our own slave port that is also in 3308922Swilliam.wang@arm.com // snoopPorts) and should not send it back to where it came 3319294Sandreas.hansson@arm.com // from 3328922Swilliam.wang@arm.com if (exclude_slave_port_id == InvalidPortID || 3338922Swilliam.wang@arm.com p->getId() != exclude_slave_port_id) { 3348975Sandreas.hansson@arm.com // cache is not allowed to refuse snoop 3358975Sandreas.hansson@arm.com p->sendTimingSnoopReq(pkt); 3368922Swilliam.wang@arm.com } 3378922Swilliam.wang@arm.com } 3388922Swilliam.wang@arm.com} 3398922Swilliam.wang@arm.com 3408922Swilliam.wang@arm.comvoid 3418922Swilliam.wang@arm.comCoherentBus::recvRetry() 3428965Sandreas.hansson@arm.com{ 3439031Sandreas.hansson@arm.com // responses and snoop responses never block on forwarding them, 3448922Swilliam.wang@arm.com // so the retry will always be coming from a port to which we 3458922Swilliam.wang@arm.com // tried to forward a request 3468922Swilliam.wang@arm.com reqLayer.recvRetry(); 3478948Sandreas.hansson@arm.com} 3488948Sandreas.hansson@arm.com 3498948Sandreas.hansson@arm.comTick 3508948Sandreas.hansson@arm.comCoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id) 3518948Sandreas.hansson@arm.com{ 3528948Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvAtomic: packet src %s addr 0x%x cmd %s\n", 3538948Sandreas.hansson@arm.com slavePorts[slave_port_id]->name(), pkt->getAddr(), 3548948Sandreas.hansson@arm.com pkt->cmdString()); 3558948Sandreas.hansson@arm.com 3568948Sandreas.hansson@arm.com MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 3578948Sandreas.hansson@arm.com Tick snoop_response_latency = 0; 3588948Sandreas.hansson@arm.com 3598948Sandreas.hansson@arm.com // uncacheable requests need never be snooped 3608948Sandreas.hansson@arm.com if (!pkt->req->isUncacheable()) { 3618948Sandreas.hansson@arm.com // forward to all snoopers but the source 3628948Sandreas.hansson@arm.com std::pair<MemCmd, Tick> snoop_result = 3638948Sandreas.hansson@arm.com forwardAtomic(pkt, slave_port_id); 3648948Sandreas.hansson@arm.com snoop_response_cmd = snoop_result.first; 3658948Sandreas.hansson@arm.com snoop_response_latency = snoop_result.second; 3668948Sandreas.hansson@arm.com } 3678975Sandreas.hansson@arm.com 3688975Sandreas.hansson@arm.com // even if we had a snoop response, we must continue and also 3698975Sandreas.hansson@arm.com // perform the actual request at the destination 37010713Sandreas.hansson@arm.com PortID dest_id = findPort(pkt->getAddr()); 3718975Sandreas.hansson@arm.com 3728975Sandreas.hansson@arm.com // forward the request to the appropriate destination 3738975Sandreas.hansson@arm.com Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt); 3748975Sandreas.hansson@arm.com 3758975Sandreas.hansson@arm.com // if we got a response from a snooper, restore it here 3768975Sandreas.hansson@arm.com if (snoop_response_cmd != MemCmd::InvalidCmd) { 3778975Sandreas.hansson@arm.com // no one else should have responded 3788948Sandreas.hansson@arm.com assert(!pkt->isResponse()); 3798948Sandreas.hansson@arm.com pkt->cmd = snoop_response_cmd; 3808975Sandreas.hansson@arm.com response_latency = snoop_response_latency; 3818975Sandreas.hansson@arm.com } 3828975Sandreas.hansson@arm.com 3838975Sandreas.hansson@arm.com pkt->finishTime = curTick() + response_latency; 3848975Sandreas.hansson@arm.com return response_latency; 3858948Sandreas.hansson@arm.com} 3868975Sandreas.hansson@arm.com 3878948Sandreas.hansson@arm.comTick 3888948Sandreas.hansson@arm.comCoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id) 3899087Sandreas.hansson@arm.com{ 39010713Sandreas.hansson@arm.com DPRINTF(CoherentBus, "recvAtomicSnoop: packet src %s addr 0x%x cmd %s\n", 3919087Sandreas.hansson@arm.com masterPorts[master_port_id]->name(), pkt->getAddr(), 39210713Sandreas.hansson@arm.com pkt->cmdString()); 39310713Sandreas.hansson@arm.com 39410713Sandreas.hansson@arm.com // forward to all snoopers 39510713Sandreas.hansson@arm.com std::pair<MemCmd, Tick> snoop_result = 39610713Sandreas.hansson@arm.com forwardAtomic(pkt, InvalidPortID); 39710713Sandreas.hansson@arm.com MemCmd snoop_response_cmd = snoop_result.first; 39810713Sandreas.hansson@arm.com Tick snoop_response_latency = snoop_result.second; 3999087Sandreas.hansson@arm.com 4009087Sandreas.hansson@arm.com if (snoop_response_cmd != MemCmd::InvalidCmd) 4019088Sandreas.hansson@arm.com pkt->cmd = snoop_response_cmd; 4029088Sandreas.hansson@arm.com 4039088Sandreas.hansson@arm.com pkt->finishTime = curTick() + snoop_response_latency; 4049088Sandreas.hansson@arm.com return snoop_response_latency; 4059088Sandreas.hansson@arm.com} 4069088Sandreas.hansson@arm.com 4079088Sandreas.hansson@arm.comstd::pair<MemCmd, Tick> 4088922Swilliam.wang@arm.comCoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id) 4098922Swilliam.wang@arm.com{ 41010413SCurtis.Dunham@arm.com // the packet may be changed on snoops, record the original 41110413SCurtis.Dunham@arm.com // command to enable us to restore it between snoops so that 41210413SCurtis.Dunham@arm.com // additional snoops can take place properly 41310413SCurtis.Dunham@arm.com MemCmd orig_cmd = pkt->cmd; 41410413SCurtis.Dunham@arm.com MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 4158922Swilliam.wang@arm.com Tick snoop_response_latency = 0; 4168922Swilliam.wang@arm.com 4178922Swilliam.wang@arm.com for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 4188922Swilliam.wang@arm.com SlavePort *p = *s; 4198922Swilliam.wang@arm.com // we could have gotten this request from a snooping master 4208922Swilliam.wang@arm.com // (corresponding to our own slave port that is also in 4218922Swilliam.wang@arm.com // snoopPorts) and should not send it back to where it came 4228922Swilliam.wang@arm.com // from 4239090Sandreas.hansson@arm.com if (exclude_slave_port_id == InvalidPortID || 4248975Sandreas.hansson@arm.com p->getId() != exclude_slave_port_id) { 4258975Sandreas.hansson@arm.com Tick latency = p->sendAtomicSnoop(pkt); 4268975Sandreas.hansson@arm.com // in contrast to a functional access, we have to keep on 4278975Sandreas.hansson@arm.com // going as all snoopers must be updated even if we get a 4289178Sandreas.hansson@arm.com // response 4299178Sandreas.hansson@arm.com if (pkt->isResponse()) { 4309178Sandreas.hansson@arm.com // response from snoop agent 4319178Sandreas.hansson@arm.com assert(pkt->cmd != orig_cmd); 4329178Sandreas.hansson@arm.com assert(pkt->memInhibitAsserted()); 4339178Sandreas.hansson@arm.com // should only happen once 4349178Sandreas.hansson@arm.com assert(snoop_response_cmd == MemCmd::InvalidCmd); 4359178Sandreas.hansson@arm.com // save response state 4369178Sandreas.hansson@arm.com snoop_response_cmd = pkt->cmd; 4379178Sandreas.hansson@arm.com snoop_response_latency = latency; 4389178Sandreas.hansson@arm.com // restore original packet state for remaining snoopers 4399178Sandreas.hansson@arm.com pkt->cmd = orig_cmd; 4408975Sandreas.hansson@arm.com } 4418975Sandreas.hansson@arm.com } 4428975Sandreas.hansson@arm.com } 4438975Sandreas.hansson@arm.com 4448975Sandreas.hansson@arm.com // the packet is restored as part of the loop and any potential 4458975Sandreas.hansson@arm.com // snoop response is part of the returned pair 4468975Sandreas.hansson@arm.com return std::make_pair(snoop_response_cmd, snoop_response_latency); 4478975Sandreas.hansson@arm.com} 4488975Sandreas.hansson@arm.com 4498975Sandreas.hansson@arm.comvoid 4508975Sandreas.hansson@arm.comCoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id) 4518975Sandreas.hansson@arm.com{ 4528975Sandreas.hansson@arm.com if (!pkt->isPrint()) { 4538975Sandreas.hansson@arm.com // don't do DPRINTFs on PrintReq as it clutters up the output 4548975Sandreas.hansson@arm.com DPRINTF(CoherentBus, 4558975Sandreas.hansson@arm.com "recvFunctional: packet src %s addr 0x%x cmd %s\n", 4568975Sandreas.hansson@arm.com slavePorts[slave_port_id]->name(), pkt->getAddr(), 4578975Sandreas.hansson@arm.com pkt->cmdString()); 4588975Sandreas.hansson@arm.com } 4598975Sandreas.hansson@arm.com 4608975Sandreas.hansson@arm.com // uncacheable requests need never be snooped 4618975Sandreas.hansson@arm.com if (!pkt->req->isUncacheable()) { 4629087Sandreas.hansson@arm.com // forward to all snoopers but the source 4639087Sandreas.hansson@arm.com forwardFunctional(pkt, slave_port_id); 4649087Sandreas.hansson@arm.com } 4659087Sandreas.hansson@arm.com 4669087Sandreas.hansson@arm.com // there is no need to continue if the snooping has found what we 46710713Sandreas.hansson@arm.com // were looking for and the packet is already a response 4689087Sandreas.hansson@arm.com if (!pkt->isResponse()) { 4698922Swilliam.wang@arm.com PortID dest_id = findPort(pkt->getAddr()); 4708922Swilliam.wang@arm.com 4712381SN/A masterPorts[dest_id]->sendFunctional(pkt); 472 } 473} 474 475void 476CoherentBus::recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id) 477{ 478 if (!pkt->isPrint()) { 479 // don't do DPRINTFs on PrintReq as it clutters up the output 480 DPRINTF(CoherentBus, 481 "recvFunctionalSnoop: packet src %s addr 0x%x cmd %s\n", 482 masterPorts[master_port_id]->name(), pkt->getAddr(), 483 pkt->cmdString()); 484 } 485 486 // forward to all snoopers 487 forwardFunctional(pkt, InvalidPortID); 488} 489 490void 491CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id) 492{ 493 for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) { 494 SlavePort *p = *s; 495 // we could have gotten this request from a snooping master 496 // (corresponding to our own slave port that is also in 497 // snoopPorts) and should not send it back to where it came 498 // from 499 if (exclude_slave_port_id == InvalidPortID || 500 p->getId() != exclude_slave_port_id) 501 p->sendFunctionalSnoop(pkt); 502 503 // if we get a response we are done 504 if (pkt->isResponse()) { 505 break; 506 } 507 } 508} 509 510unsigned int 511CoherentBus::drain(Event *de) 512{ 513 // sum up the individual layers 514 return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de); 515} 516 517CoherentBus * 518CoherentBusParams::create() 519{ 520 return new CoherentBus(this); 521} 522