xbar.cc revision 8849
12391SN/A/* 212218Snikos.nikoleris@arm.com * Copyright (c) 2011-2012 ARM Limited 37733SN/A * All rights reserved 47733SN/A * 57733SN/A * The license below extends only to copyright in the software and shall 67733SN/A * not be construed as granting a license to any other intellectual 77733SN/A * property including but not limited to intellectual property relating 87733SN/A * to a hardware implementation of the functionality of the software 97733SN/A * licensed hereunder. You may use the software subject to the license 107733SN/A * terms below provided that you ensure that this notice is replicated 117733SN/A * unmodified and in its entirety in all distributions of the software, 127733SN/A * modified or unmodified, in source code or in binary form. 137733SN/A * 142391SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152391SN/A * All rights reserved. 162391SN/A * 172391SN/A * Redistribution and use in source and binary forms, with or without 182391SN/A * modification, are permitted provided that the following conditions are 192391SN/A * met: redistributions of source code must retain the above copyright 202391SN/A * notice, this list of conditions and the following disclaimer; 212391SN/A * redistributions in binary form must reproduce the above copyright 222391SN/A * notice, this list of conditions and the following disclaimer in the 232391SN/A * documentation and/or other materials provided with the distribution; 242391SN/A * neither the name of the copyright holders nor the names of its 252391SN/A * contributors may be used to endorse or promote products derived from 262391SN/A * this software without specific prior written permission. 272391SN/A * 282391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665SN/A * 402665SN/A * Authors: Ali Saidi 412914SN/A * Andreas Hansson 428931Sandreas.hansson@arm.com */ 432391SN/A 442391SN/A/** 4511793Sbrandon.potter@amd.com * @file 4611793Sbrandon.potter@amd.com * Definition of a bus object. 4710466Sandreas.hansson@arm.com */ 4810466Sandreas.hansson@arm.com 4912218Snikos.nikoleris@arm.com#include "base/misc.hh" 5010102Sali.saidi@arm.com#include "base/trace.hh" 5110102Sali.saidi@arm.com#include "debug/Bus.hh" 528232SN/A#include "debug/BusAddrRanges.hh" 538232SN/A#include "debug/MMU.hh" 543879SN/A#include "mem/bus.hh" 559053Sdam.sunwoo@arm.com 562394SN/ABus::Bus(const BusParams *p) 572391SN/A : MemObject(p), busId(p->bus_id), clock(p->clock), 582391SN/A headerCycles(p->header_cycles), width(p->width), tickNextIdle(0), 598931Sandreas.hansson@arm.com drainEvent(NULL), busIdle(this), inRetry(false), 608931Sandreas.hansson@arm.com defaultPortId(INVALID_PORT_ID), useDefaultRange(p->use_default_range), 619053Sdam.sunwoo@arm.com defaultBlockSize(p->block_size), 6211614Sdavid.j.hashe@gmail.com cachedBlockSize(0), cachedBlockSizeValid(false) 632391SN/A{ 6410466Sandreas.hansson@arm.com //width, clock period, and header cycles must be positive 6510466Sandreas.hansson@arm.com if (width <= 0) 6610466Sandreas.hansson@arm.com fatal("Bus width must be positive\n"); 6710466Sandreas.hansson@arm.com if (clock <= 0) 6810466Sandreas.hansson@arm.com fatal("Bus clock period must be positive\n"); 6910466Sandreas.hansson@arm.com if (headerCycles <= 0) 7010466Sandreas.hansson@arm.com fatal("Number of header cycles must be positive\n"); 7110466Sandreas.hansson@arm.com clearPortCache(); 722391SN/A} 732391SN/A 742391SN/APort * 759293Sandreas.hansson@arm.comBus::getPort(const std::string &if_name, int idx) 769293Sandreas.hansson@arm.com{ 772391SN/A std::string portName; 789293Sandreas.hansson@arm.com int id = interfaces.size(); 792391SN/A if (if_name == "default") { 802391SN/A if (defaultPortId == INVALID_PORT_ID) { 818719SN/A defaultPortId = id; 828931Sandreas.hansson@arm.com portName = csprintf("%s-default", name()); 838719SN/A } else 8411522Sstephan.diestelhorst@arm.com fatal("Default port already set on %s\n", name()); 8511522Sstephan.diestelhorst@arm.com } else { 868719SN/A portName = csprintf("%s-p%d", name(), id); 878719SN/A } 889053Sdam.sunwoo@arm.com BusPort *bp = new BusPort(portName, this, id); 899053Sdam.sunwoo@arm.com interfaces.push_back(bp); 908719SN/A cachedBlockSizeValid = false; 919053Sdam.sunwoo@arm.com return bp; 928719SN/A} 938719SN/A 949053Sdam.sunwoo@arm.comvoid 958719SN/ABus::init() 969053Sdam.sunwoo@arm.com{ 979053Sdam.sunwoo@arm.com std::vector<BusPort*>::iterator intIter; 989053Sdam.sunwoo@arm.com 998719SN/A // iterate over our interfaces and determine which of our neighbours 1009053Sdam.sunwoo@arm.com // are snooping and add them as snoopers 1018719SN/A for (intIter = interfaces.begin(); intIter != interfaces.end(); 1028719SN/A intIter++) { 1039053Sdam.sunwoo@arm.com if ((*intIter)->getPeer()->isSnooping()) { 1048719SN/A DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n", 1059053Sdam.sunwoo@arm.com (*intIter)->getPeer()->name()); 1069053Sdam.sunwoo@arm.com snoopPorts.push_back(*intIter); 1079053Sdam.sunwoo@arm.com } 1088719SN/A } 1099053Sdam.sunwoo@arm.com} 1108719SN/A 1118719SN/ABus::BusFreeEvent::BusFreeEvent(Bus *_bus) 1129053Sdam.sunwoo@arm.com : bus(_bus) 1138719SN/A{} 1149053Sdam.sunwoo@arm.com 1159053Sdam.sunwoo@arm.comvoid 1169053Sdam.sunwoo@arm.comBus::BusFreeEvent::process() 1178719SN/A{ 1189053Sdam.sunwoo@arm.com bus->recvRetry(-1); 1198719SN/A} 1208719SN/A 1219053Sdam.sunwoo@arm.comconst char * 1228719SN/ABus::BusFreeEvent::description() const 1239053Sdam.sunwoo@arm.com{ 1249053Sdam.sunwoo@arm.com return "bus became available"; 1259053Sdam.sunwoo@arm.com} 1268719SN/A 1279053Sdam.sunwoo@arm.comTick 1288719SN/ABus::calcPacketTiming(PacketPtr pkt) 1298719SN/A{ 1309053Sdam.sunwoo@arm.com // Bring tickNextIdle up to the present tick. 1318719SN/A // There is some potential ambiguity where a cycle starts, which 1329053Sdam.sunwoo@arm.com // might make a difference when devices are acting right around a 1339053Sdam.sunwoo@arm.com // cycle boundary. Using a < allows things which happen exactly on 1349053Sdam.sunwoo@arm.com // a cycle boundary to take up only the following cycle. Anything 1358719SN/A // that happens later will have to "wait" for the end of that 1369053Sdam.sunwoo@arm.com // cycle, and then start using the bus after that. 1378719SN/A if (tickNextIdle < curTick()) { 1388719SN/A tickNextIdle = curTick(); 1399053Sdam.sunwoo@arm.com if (tickNextIdle % clock != 0) 1408719SN/A tickNextIdle = curTick() - (curTick() % clock) + clock; 1419053Sdam.sunwoo@arm.com } 1429053Sdam.sunwoo@arm.com 1439053Sdam.sunwoo@arm.com Tick headerTime = tickNextIdle + headerCycles * clock; 1448719SN/A 1458719SN/A // The packet will be sent. Figure out how long it occupies the bus, and 1468719SN/A // how much of that time is for the first "word", aka bus width. 1478719SN/A int numCycles = 0; 1488719SN/A if (pkt->hasData()) { 1499053Sdam.sunwoo@arm.com // If a packet has data, it needs ceil(size/width) cycles to send it 1508719SN/A int dataSize = pkt->getSize(); 1519053Sdam.sunwoo@arm.com numCycles += dataSize/width; 1529053Sdam.sunwoo@arm.com if (dataSize % width) 1539053Sdam.sunwoo@arm.com numCycles++; 1549053Sdam.sunwoo@arm.com } 1558719SN/A 1568719SN/A // The first word will be delivered after the current tick, the delivery 1578719SN/A // of the address if any, and one bus cycle to deliver the data 1588719SN/A pkt->firstWordTime = headerTime + clock; 1598719SN/A 1609053Sdam.sunwoo@arm.com pkt->finishTime = headerTime + numCycles * clock; 1618719SN/A 1629053Sdam.sunwoo@arm.com return headerTime; 1639053Sdam.sunwoo@arm.com} 1649053Sdam.sunwoo@arm.com 1658719SN/Avoid Bus::occupyBus(Tick until) 1668719SN/A{ 1678719SN/A if (until == 0) { 1688719SN/A // shortcut for express snoop packets 1698719SN/A return; 1709053Sdam.sunwoo@arm.com } 1718719SN/A 1729053Sdam.sunwoo@arm.com tickNextIdle = until; 1739053Sdam.sunwoo@arm.com reschedule(busIdle, tickNextIdle, true); 1749053Sdam.sunwoo@arm.com 1758719SN/A DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n", 1768719SN/A curTick(), tickNextIdle); 1778719SN/A} 1788719SN/A 1798719SN/A/** Function called by the port when the bus is receiving a Timing 1809053Sdam.sunwoo@arm.com * transaction.*/ 1818719SN/Abool 1829053Sdam.sunwoo@arm.comBus::recvTiming(PacketPtr pkt) 1839053Sdam.sunwoo@arm.com{ 1849053Sdam.sunwoo@arm.com short src = pkt->getSrc(); 1858719SN/A 1868719SN/A BusPort *src_port = interfaces[src]; 1878719SN/A 1888719SN/A // If the bus is busy, or other devices are in line ahead of the current 1898719SN/A // one, put this device on the retry list. 1908719SN/A if (!pkt->isExpressSnoop() && 1919235Sandreas.hansson@arm.com (tickNextIdle > curTick() || 1929098Sandreas.hansson@arm.com (retryList.size() && (!inRetry || src_port != retryList.front())))) 1932408SN/A { 1948931Sandreas.hansson@arm.com addToRetryList(src_port); 1952408SN/A DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n", 1962408SN/A src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 1973170SN/A return false; 1986076SN/A } 1993170SN/A 2008931Sandreas.hansson@arm.com DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n", 2013170SN/A src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 20212749Sgiacomo.travaglini@arm.com 2033170SN/A Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt); 2043170SN/A Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime; 2053170SN/A 2063170SN/A short dest = pkt->getDest(); 2073170SN/A int dest_port_id; 2083170SN/A Port *dest_port; 2093170SN/A 2103170SN/A if (dest == Packet::Broadcast) { 2113170SN/A dest_port_id = findPort(pkt->getAddr()); 2125714SN/A dest_port = interfaces[dest_port_id]; 2135714SN/A SnoopIter s_end = snoopPorts.end(); 2143170SN/A for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 2153170SN/A BusPort *p = *s_iter; 2163170SN/A if (p != dest_port && p != src_port) { 2173170SN/A // cache is not allowed to refuse snoop 2183170SN/A bool success M5_VAR_USED = p->sendTiming(pkt); 2193170SN/A assert(success); 2205714SN/A } 2215714SN/A } 2223170SN/A } else { 2233170SN/A assert(dest < interfaces.size()); 2243170SN/A assert(dest != src); // catch infinite loops 2253170SN/A dest_port_id = dest; 2263170SN/A dest_port = interfaces[dest_port_id]; 2273170SN/A } 2283170SN/A 2293170SN/A if (dest_port_id == src) { 2303170SN/A // Must be forwarded snoop up from below... 2318931Sandreas.hansson@arm.com assert(dest == Packet::Broadcast); 2323170SN/A } else { 23312749Sgiacomo.travaglini@arm.com // send to actual target 2343170SN/A if (!dest_port->sendTiming(pkt)) { 2356102SN/A // Packet not successfully sent. Leave or put it on the retry list. 2363170SN/A // illegal to block responses... can lead to deadlock 2373170SN/A assert(!pkt->isResponse()); 2383170SN/A // It's also illegal to force a transaction to retry after 2393170SN/A // someone else has committed to respond. 2409080Smatt.evans@arm.com assert(!pkt->memInhibitAsserted()); 2413170SN/A DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n", 2429080Smatt.evans@arm.com src, pkt->getDest(), pkt->cmdString(), pkt->getAddr()); 2439080Smatt.evans@arm.com addToRetryList(src_port); 2449080Smatt.evans@arm.com occupyBus(headerFinishTime); 2459080Smatt.evans@arm.com return false; 2469080Smatt.evans@arm.com } 2473170SN/A // send OK, fall through... pkt may have been deleted by 2483170SN/A // target at this point, so it should *not* be referenced 2499080Smatt.evans@arm.com // again. We'll set it to NULL here just to be safe. 2509080Smatt.evans@arm.com pkt = NULL; 2519080Smatt.evans@arm.com } 2529080Smatt.evans@arm.com 2539080Smatt.evans@arm.com occupyBus(packetFinishTime); 2545714SN/A 2555714SN/A // Packet was successfully sent. 2569080Smatt.evans@arm.com // Also take care of retries 2579080Smatt.evans@arm.com if (inRetry) { 2583170SN/A DPRINTF(Bus, "Remove retry from list %d\n", src); 2599080Smatt.evans@arm.com retryList.pop_front(); 2609080Smatt.evans@arm.com inRetry = false; 2619080Smatt.evans@arm.com } 2629080Smatt.evans@arm.com return true; 2633170SN/A} 2649080Smatt.evans@arm.com 2659080Smatt.evans@arm.comvoid 2669080Smatt.evans@arm.comBus::recvRetry(int id) 2679080Smatt.evans@arm.com{ 2689080Smatt.evans@arm.com // If there's anything waiting, and the bus isn't busy... 2699080Smatt.evans@arm.com if (retryList.size() && curTick() >= tickNextIdle) { 2709080Smatt.evans@arm.com //retryingPort = retryList.front(); 2719080Smatt.evans@arm.com inRetry = true; 2729080Smatt.evans@arm.com DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name()); 2739080Smatt.evans@arm.com retryList.front()->sendRetry(); 2749080Smatt.evans@arm.com // If inRetry is still true, sendTiming wasn't called 2759080Smatt.evans@arm.com if (inRetry) 27612218Snikos.nikoleris@arm.com { 27712218Snikos.nikoleris@arm.com retryList.pop_front(); 27812218Snikos.nikoleris@arm.com inRetry = false; 27912218Snikos.nikoleris@arm.com 28012218Snikos.nikoleris@arm.com //Bring tickNextIdle up to the present 28112218Snikos.nikoleris@arm.com while (tickNextIdle < curTick()) 2829080Smatt.evans@arm.com tickNextIdle += clock; 2839080Smatt.evans@arm.com 2849080Smatt.evans@arm.com //Burn a cycle for the missed grant. 2859080Smatt.evans@arm.com tickNextIdle += clock; 2863170SN/A 2873170SN/A reschedule(busIdle, tickNextIdle, true); 2883170SN/A } 2899080Smatt.evans@arm.com } 2903170SN/A //If we weren't able to drain before, we might be able to now. 2913170SN/A if (drainEvent && retryList.size() == 0 && curTick() >= tickNextIdle) { 29213346Sgabeblack@google.com drainEvent->process(); 29313346Sgabeblack@google.com // Clear the drain event once we're done with it. 29413346Sgabeblack@google.com drainEvent = NULL; 29513346Sgabeblack@google.com } 29613346Sgabeblack@google.com} 29713346Sgabeblack@google.com 29813346Sgabeblack@google.comint 29913346Sgabeblack@google.comBus::findPort(Addr addr) 30013346Sgabeblack@google.com{ 30113346Sgabeblack@google.com /* An interval tree would be a better way to do this. --ali. */ 30213346Sgabeblack@google.com int dest_id; 30313346Sgabeblack@google.com 30413346Sgabeblack@google.com dest_id = checkPortCache(addr); 30513346Sgabeblack@google.com if (dest_id != INVALID_PORT_ID) 30613346Sgabeblack@google.com return dest_id; 30713346Sgabeblack@google.com 30813346Sgabeblack@google.com // Check normal port ranges 30913346Sgabeblack@google.com PortIter i = portMap.find(RangeSize(addr,1)); 3104626SN/A if (i != portMap.end()) { 3114626SN/A dest_id = i->second; 31213346Sgabeblack@google.com updatePortCache(dest_id, i->first.start, i->first.end); 3134626SN/A return dest_id; 31413346Sgabeblack@google.com } 3154626SN/A 3164626SN/A // Check if this matches the default range 3178931Sandreas.hansson@arm.com if (useDefaultRange) { 3188931Sandreas.hansson@arm.com AddrRangeIter a_end = defaultRange.end(); 3192413SN/A for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { 32011284Sandreas.hansson@arm.com if (*i == addr) { 32111284Sandreas.hansson@arm.com DPRINTF(Bus, " found addr %#llx on default\n", addr); 3224626SN/A return defaultPortId; 3238931Sandreas.hansson@arm.com } 3243175SN/A } 3254626SN/A } else if (defaultPortId != INVALID_PORT_ID) { 32611199Sandreas.hansson@arm.com DPRINTF(Bus, "Unable to find destination for addr %#llx, " 32710883Sali.jafri@arm.com "will use default port\n", addr); 32810883Sali.jafri@arm.com return defaultPortId; 32910883Sali.jafri@arm.com } 33010883Sali.jafri@arm.com 33110883Sali.jafri@arm.com // we should use the range for the default port and it did not 33210883Sali.jafri@arm.com // match, or the default port is not set 33310883Sali.jafri@arm.com fatal("Unable to find destination for addr %#llx on bus %s\n", addr, 33410883Sali.jafri@arm.com name()); 3359405Sandreas.hansson@arm.com} 3364626SN/A 3374626SN/A 33811306Santhony.gutierrez@amd.com/** Function called by the port when the bus is receiving a Atomic 33911306Santhony.gutierrez@amd.com * transaction.*/ 34011306Santhony.gutierrez@amd.comTick 34111306Santhony.gutierrez@amd.comBus::recvAtomic(PacketPtr pkt) 34211306Santhony.gutierrez@amd.com{ 34311306Santhony.gutierrez@amd.com DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", 34411306Santhony.gutierrez@amd.com pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); 34511306Santhony.gutierrez@amd.com assert(pkt->getDest() == Packet::Broadcast); 34611306Santhony.gutierrez@amd.com assert(pkt->isRequest()); 3474040SN/A 34811306Santhony.gutierrez@amd.com // Variables for recording original command and snoop response (if 34911306Santhony.gutierrez@amd.com // any)... if a snooper respondes, we will need to restore 3504040SN/A // original command so that additional snoops can take place 35111306Santhony.gutierrez@amd.com // properly 35211306Santhony.gutierrez@amd.com MemCmd orig_cmd = pkt->cmd; 35311306Santhony.gutierrez@amd.com MemCmd snoop_response_cmd = MemCmd::InvalidCmd; 35411306Santhony.gutierrez@amd.com Tick snoop_response_latency = 0; 35511306Santhony.gutierrez@amd.com int orig_src = pkt->getSrc(); 35611306Santhony.gutierrez@amd.com 3574040SN/A int target_port_id = findPort(pkt->getAddr()); 35811306Santhony.gutierrez@amd.com BusPort *target_port = interfaces[target_port_id]; 35911306Santhony.gutierrez@amd.com 36011306Santhony.gutierrez@amd.com SnoopIter s_end = snoopPorts.end(); 36111306Santhony.gutierrez@amd.com for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 36211306Santhony.gutierrez@amd.com BusPort *p = *s_iter; 36311306Santhony.gutierrez@amd.com // same port should not have both target addresses and snooping 36411306Santhony.gutierrez@amd.com assert(p != target_port); 36511306Santhony.gutierrez@amd.com if (p->getId() != pkt->getSrc()) { 36611306Santhony.gutierrez@amd.com Tick latency = p->sendAtomic(pkt); 36711306Santhony.gutierrez@amd.com if (pkt->isResponse()) { 36811306Santhony.gutierrez@amd.com // response from snoop agent 36911306Santhony.gutierrez@amd.com assert(pkt->cmd != orig_cmd); 37011306Santhony.gutierrez@amd.com assert(pkt->memInhibitAsserted()); 37111306Santhony.gutierrez@amd.com // should only happen once 37211306Santhony.gutierrez@amd.com assert(snoop_response_cmd == MemCmd::InvalidCmd); 37311306Santhony.gutierrez@amd.com // save response state 37411306Santhony.gutierrez@amd.com snoop_response_cmd = pkt->cmd; 37511306Santhony.gutierrez@amd.com snoop_response_latency = latency; 37611306Santhony.gutierrez@amd.com // restore original packet state for remaining snoopers 3774040SN/A pkt->cmd = orig_cmd; 3784626SN/A pkt->setSrc(orig_src); 3794626SN/A pkt->setDest(Packet::Broadcast); 3806102SN/A } 38112218Snikos.nikoleris@arm.com } 38212218Snikos.nikoleris@arm.com } 38312218Snikos.nikoleris@arm.com 3844626SN/A Tick response_latency = 0; 3854040SN/A 3865477SN/A // we can get requests sent up from the memory side of the bus for 3875477SN/A // snooping... don't send them back down! 3886429SN/A if (target_port_id != pkt->getSrc()) { 3899053Sdam.sunwoo@arm.com response_latency = target_port->sendAtomic(pkt); 3909053Sdam.sunwoo@arm.com } 3918719SN/A 3929053Sdam.sunwoo@arm.com // if we got a response from a snooper, restore it here 39312354Snikos.nikoleris@arm.com if (snoop_response_cmd != MemCmd::InvalidCmd) { 39412354Snikos.nikoleris@arm.com // no one else should have responded 39512354Snikos.nikoleris@arm.com assert(!pkt->isResponse()); 39612354Snikos.nikoleris@arm.com assert(pkt->cmd == orig_cmd); 39712354Snikos.nikoleris@arm.com pkt->cmd = snoop_response_cmd; 39810583SCurtis.Dunham@arm.com response_latency = snoop_response_latency; 3994626SN/A } 4004626SN/A 4019663Suri.wiener@arm.com // why do we have this packet field and the return value both??? 40210563Sandreas.hansson@arm.com pkt->finishTime = curTick() + response_latency; 40311653SBrad.Beckmann@amd.com return response_latency; 4049663Suri.wiener@arm.com} 4059663Suri.wiener@arm.com 4066429SN/A/** Function called by the port when the bus is receiving a Functional 4074626SN/A * transaction.*/ 4089053Sdam.sunwoo@arm.comvoid 4099053Sdam.sunwoo@arm.comBus::recvFunctional(PacketPtr pkt) 4104626SN/A{ 4114040SN/A assert(pkt->getDest() == Packet::Broadcast); 41212354Snikos.nikoleris@arm.com 4132413SN/A int port_id = findPort(pkt->getAddr()); 4142420SN/A Port *port = interfaces[port_id]; 4154626SN/A // The packet may be changed by another bus on snoops, restore the 4168931Sandreas.hansson@arm.com // id after each 4174626SN/A int src_id = pkt->getSrc(); 4182413SN/A 4192413SN/A if (!pkt->isPrint()) { 4208931Sandreas.hansson@arm.com // don't do DPRINTFs on PrintReq as it clutters up the output 4218931Sandreas.hansson@arm.com DPRINTF(Bus, 4228931Sandreas.hansson@arm.com "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", 4239405Sandreas.hansson@arm.com src_id, port_id, pkt->getAddr(), 4249405Sandreas.hansson@arm.com pkt->cmdString()); 4254626SN/A } 4269405Sandreas.hansson@arm.com 4274626SN/A assert(pkt->isRequest()); // hasn't already been satisfied 4285314SN/A 4295477SN/A SnoopIter s_end = snoopPorts.end(); 4305477SN/A for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 4314626SN/A BusPort *p = *s_iter; 4328931Sandreas.hansson@arm.com if (p != port && p->getId() != src_id) { 4335314SN/A p->sendFunctional(pkt); 4345477SN/A } 43510563Sandreas.hansson@arm.com if (pkt->isResponse()) { 4364626SN/A break; 4378931Sandreas.hansson@arm.com } 4385314SN/A pkt->setSrc(src_id); 4395315SN/A } 4405315SN/A 4418992SAli.Saidi@ARM.com // If the snooping hasn't found what we were looking for and it is not 4425315SN/A // a forwarded snoop from below, keep going. 4435315SN/A if (!pkt->isResponse() && port_id != pkt->getSrc()) { 4445314SN/A port->sendFunctional(pkt); 4455315SN/A } 4465314SN/A} 4474626SN/A 4488931Sandreas.hansson@arm.com/** Function called by the port when the bus is receiving a range change.*/ 4494626SN/Avoid 4504626SN/ABus::recvRangeChange(int id) 4514490SN/A{ 452 AddrRangeList ranges; 453 AddrRangeIter iter; 454 455 if (inRecvRangeChange.count(id)) 456 return; 457 inRecvRangeChange.insert(id); 458 459 DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); 460 461 clearPortCache(); 462 if (id == defaultPortId) { 463 defaultRange.clear(); 464 // Only try to update these ranges if the user set a default responder. 465 if (useDefaultRange) { 466 AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges(); 467 for(iter = ranges.begin(); iter != ranges.end(); iter++) { 468 defaultRange.push_back(*iter); 469 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n", 470 iter->start, iter->end); 471 } 472 } 473 } else { 474 475 assert(id < interfaces.size() && id >= 0); 476 BusPort *port = interfaces[id]; 477 478 // Clean out any previously existent ids 479 for (PortIter portIter = portMap.begin(); 480 portIter != portMap.end(); ) { 481 if (portIter->second == id) 482 portMap.erase(portIter++); 483 else 484 portIter++; 485 } 486 487 ranges = port->getPeer()->getAddrRanges(); 488 489 for (iter = ranges.begin(); iter != ranges.end(); iter++) { 490 DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n", 491 iter->start, iter->end, id); 492 if (portMap.insert(*iter, id) == portMap.end()) { 493 int conflict_id = portMap.find(*iter)->second; 494 fatal("%s has two ports with same range:\n\t%s\n\t%s\n", 495 name(), interfaces[id]->getPeer()->name(), 496 interfaces[conflict_id]->getPeer()->name()); 497 } 498 } 499 } 500 DPRINTF(MMU, "port list has %d entries\n", portMap.size()); 501 502 // tell all our peers that our address range has changed. 503 // Don't tell the device that caused this change, it already knows 504 std::vector<BusPort*>::const_iterator intIter; 505 506 for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) 507 if ((*intIter)->getId() != id) 508 (*intIter)->sendRangeChange(); 509 510 inRecvRangeChange.erase(id); 511} 512 513AddrRangeList 514Bus::getAddrRanges(int id) 515{ 516 AddrRangeList ranges; 517 518 DPRINTF(BusAddrRanges, "received address range request, returning:\n"); 519 520 for (AddrRangeIter dflt_iter = defaultRange.begin(); 521 dflt_iter != defaultRange.end(); dflt_iter++) { 522 ranges.push_back(*dflt_iter); 523 DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start, 524 dflt_iter->end); 525 } 526 for (PortIter portIter = portMap.begin(); 527 portIter != portMap.end(); portIter++) { 528 bool subset = false; 529 for (AddrRangeIter dflt_iter = defaultRange.begin(); 530 dflt_iter != defaultRange.end(); dflt_iter++) { 531 if ((portIter->first.start < dflt_iter->start && 532 portIter->first.end >= dflt_iter->start) || 533 (portIter->first.start < dflt_iter->end && 534 portIter->first.end >= dflt_iter->end)) 535 fatal("Devices can not set ranges that itersect the default set\ 536 but are not a subset of the default set.\n"); 537 if (portIter->first.start >= dflt_iter->start && 538 portIter->first.end <= dflt_iter->end) { 539 subset = true; 540 DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n", 541 portIter->first.start, portIter->first.end); 542 } 543 } 544 if (portIter->second != id && !subset) { 545 ranges.push_back(portIter->first); 546 DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n", 547 portIter->first.start, portIter->first.end); 548 } 549 } 550 551 return ranges; 552} 553 554bool 555Bus::isSnooping(int id) 556{ 557 // in essence, answer the question if there are other snooping 558 // ports rather than the port that is asking 559 bool snoop = false; 560 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end(); 561 s_iter++) { 562 if ((*s_iter)->getId() != id) { 563 snoop = true; 564 break; 565 } 566 } 567 return snoop; 568} 569 570unsigned 571Bus::findBlockSize(int id) 572{ 573 if (cachedBlockSizeValid) 574 return cachedBlockSize; 575 576 unsigned max_bs = 0; 577 578 PortIter p_end = portMap.end(); 579 for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { 580 unsigned tmp_bs = interfaces[p_iter->second]->peerBlockSize(); 581 if (tmp_bs > max_bs) 582 max_bs = tmp_bs; 583 } 584 SnoopIter s_end = snoopPorts.end(); 585 for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { 586 unsigned tmp_bs = (*s_iter)->peerBlockSize(); 587 if (tmp_bs > max_bs) 588 max_bs = tmp_bs; 589 } 590 if (max_bs == 0) 591 max_bs = defaultBlockSize; 592 593 if (max_bs != 64) 594 warn_once("Blocksize found to not be 64... hmm... probably not.\n"); 595 cachedBlockSize = max_bs; 596 cachedBlockSizeValid = true; 597 return max_bs; 598} 599 600 601unsigned int 602Bus::drain(Event * de) 603{ 604 //We should check that we're not "doing" anything, and that noone is 605 //waiting. We might be idle but have someone waiting if the device we 606 //contacted for a retry didn't actually retry. 607 if (retryList.size() || (curTick() < tickNextIdle && busIdle.scheduled())) { 608 drainEvent = de; 609 return 1; 610 } 611 return 0; 612} 613 614void 615Bus::startup() 616{ 617 if (tickNextIdle < curTick()) 618 tickNextIdle = (curTick() / clock) * clock + clock; 619} 620 621Bus * 622BusParams::create() 623{ 624 return new Bus(this); 625} 626