snoop_filter.hh revision 11129
110399Sstephan.diestelhorst@arm.com/* 211129Sali.jafri@arm.com * Copyright (c) 2013-2015 ARM Limited 310399Sstephan.diestelhorst@arm.com * All rights reserved 410399Sstephan.diestelhorst@arm.com * 510399Sstephan.diestelhorst@arm.com * The license below extends only to copyright in the software and shall 610399Sstephan.diestelhorst@arm.com * not be construed as granting a license to any other intellectual 710399Sstephan.diestelhorst@arm.com * property including but not limited to intellectual property relating 810399Sstephan.diestelhorst@arm.com * to a hardware implementation of the functionality of the software 910399Sstephan.diestelhorst@arm.com * licensed hereunder. You may use the software subject to the license 1010399Sstephan.diestelhorst@arm.com * terms below provided that you ensure that this notice is replicated 1110399Sstephan.diestelhorst@arm.com * unmodified and in its entirety in all distributions of the software, 1210399Sstephan.diestelhorst@arm.com * modified or unmodified, in source code or in binary form. 1310399Sstephan.diestelhorst@arm.com * 1410399Sstephan.diestelhorst@arm.com * Redistribution and use in source and binary forms, with or without 1510399Sstephan.diestelhorst@arm.com * modification, are permitted provided that the following conditions are 1610399Sstephan.diestelhorst@arm.com * met: redistributions of source code must retain the above copyright 1710399Sstephan.diestelhorst@arm.com * notice, this list of conditions and the following disclaimer; 1810399Sstephan.diestelhorst@arm.com * redistributions in binary form must reproduce the above copyright 1910399Sstephan.diestelhorst@arm.com * notice, this list of conditions and the following disclaimer in the 2010399Sstephan.diestelhorst@arm.com * documentation and/or other materials provided with the distribution; 2110399Sstephan.diestelhorst@arm.com * neither the name of the copyright holders nor the names of its 2210399Sstephan.diestelhorst@arm.com * contributors may be used to endorse or promote products derived from 2310399Sstephan.diestelhorst@arm.com * this software without specific prior written permission. 2410399Sstephan.diestelhorst@arm.com * 2510399Sstephan.diestelhorst@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610399Sstephan.diestelhorst@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710399Sstephan.diestelhorst@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810399Sstephan.diestelhorst@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910399Sstephan.diestelhorst@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010399Sstephan.diestelhorst@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110399Sstephan.diestelhorst@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210399Sstephan.diestelhorst@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310399Sstephan.diestelhorst@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410399Sstephan.diestelhorst@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510399Sstephan.diestelhorst@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610399Sstephan.diestelhorst@arm.com * 3710399Sstephan.diestelhorst@arm.com * Authors: Stephan Diestelhorst <stephan.diestelhorst@arm.com> 3810399Sstephan.diestelhorst@arm.com */ 3910399Sstephan.diestelhorst@arm.com 4010399Sstephan.diestelhorst@arm.com/** 4110399Sstephan.diestelhorst@arm.com * @file 4210399Sstephan.diestelhorst@arm.com * Definition of a snoop filter. 4310399Sstephan.diestelhorst@arm.com */ 4410399Sstephan.diestelhorst@arm.com 4510399Sstephan.diestelhorst@arm.com#ifndef __MEM_SNOOP_FILTER_HH__ 4610399Sstephan.diestelhorst@arm.com#define __MEM_SNOOP_FILTER_HH__ 4710399Sstephan.diestelhorst@arm.com 4810399Sstephan.diestelhorst@arm.com#include <utility> 4910399Sstephan.diestelhorst@arm.com 5010399Sstephan.diestelhorst@arm.com#include "base/hashmap.hh" 5110399Sstephan.diestelhorst@arm.com#include "mem/packet.hh" 5210399Sstephan.diestelhorst@arm.com#include "mem/port.hh" 5310888Sandreas.hansson@arm.com#include "mem/qport.hh" 5410399Sstephan.diestelhorst@arm.com#include "params/SnoopFilter.hh" 5510399Sstephan.diestelhorst@arm.com#include "sim/sim_object.hh" 5610399Sstephan.diestelhorst@arm.com#include "sim/system.hh" 5710399Sstephan.diestelhorst@arm.com 5810399Sstephan.diestelhorst@arm.com/** 5910399Sstephan.diestelhorst@arm.com * This snoop filter keeps track of which connected port has a 6010399Sstephan.diestelhorst@arm.com * particular line of data. It can be queried (through lookup*) on 6110399Sstephan.diestelhorst@arm.com * memory requests from above (reads / writes / ...); and also from 6210399Sstephan.diestelhorst@arm.com * below (snoops). The snoop filter precisely knows about the location 6310399Sstephan.diestelhorst@arm.com * of lines "above" it through a map from cache line address to 6410399Sstephan.diestelhorst@arm.com * sharers/ports. The snoop filter ties into the flows of requests 6510399Sstephan.diestelhorst@arm.com * (when they succeed at the lower interface), regular responses from 6610399Sstephan.diestelhorst@arm.com * below and also responses from sideway's caches (in update*). This 6710399Sstephan.diestelhorst@arm.com * allows the snoop filter to model cache-line residency by snooping 6810399Sstephan.diestelhorst@arm.com * the messages. 6910399Sstephan.diestelhorst@arm.com * 7010399Sstephan.diestelhorst@arm.com * The tracking happens in two fields to be able to distinguish 7110399Sstephan.diestelhorst@arm.com * between in-flight requests (in requested) and already pulled in 7210399Sstephan.diestelhorst@arm.com * lines (in holder). This distinction is used for producing tighter 7310399Sstephan.diestelhorst@arm.com * assertions and tracking request completion. For safety, (requested 7410399Sstephan.diestelhorst@arm.com * | holder) should be notified and the requesting MSHRs will take 7510399Sstephan.diestelhorst@arm.com * care of ordering. 7610399Sstephan.diestelhorst@arm.com * 7710399Sstephan.diestelhorst@arm.com * Overall, some trickery is required because: 7810399Sstephan.diestelhorst@arm.com * (1) snoops are not followed by an ACK, but only evoke a response if 7910399Sstephan.diestelhorst@arm.com * they need to (hit dirty) 8010399Sstephan.diestelhorst@arm.com * (2) side-channel information is funnelled through direct modifications of 8110399Sstephan.diestelhorst@arm.com * pkt, instead of proper messages through the bus 8210399Sstephan.diestelhorst@arm.com * (3) there are no clean evict messages telling the snoop filter that a local, 8310399Sstephan.diestelhorst@arm.com * upper cache dropped a line, making the snoop filter pessimistic for now 8410399Sstephan.diestelhorst@arm.com * (4) ordering: there is no single point of order in the system. Instead, 8510399Sstephan.diestelhorst@arm.com * requesting MSHRs track order between local requests and remote snoops 8610399Sstephan.diestelhorst@arm.com */ 8710399Sstephan.diestelhorst@arm.comclass SnoopFilter : public SimObject { 8810399Sstephan.diestelhorst@arm.com public: 8910888Sandreas.hansson@arm.com typedef std::vector<QueuedSlavePort*> SnoopList; 9010399Sstephan.diestelhorst@arm.com 9110399Sstephan.diestelhorst@arm.com SnoopFilter (const SnoopFilterParams *p) : SimObject(p), 9210399Sstephan.diestelhorst@arm.com linesize(p->system->cacheLineSize()), lookupLatency(p->lookup_latency) 9310399Sstephan.diestelhorst@arm.com { 9410399Sstephan.diestelhorst@arm.com } 9510399Sstephan.diestelhorst@arm.com 9610399Sstephan.diestelhorst@arm.com /** 9710399Sstephan.diestelhorst@arm.com * Init a new snoop filter and tell it about all the slave ports of the 9810399Sstephan.diestelhorst@arm.com * enclosing bus. 9910399Sstephan.diestelhorst@arm.com * 10010399Sstephan.diestelhorst@arm.com * @param bus_slave_ports Vector of slave ports that the bus is attached to. 10110399Sstephan.diestelhorst@arm.com */ 10210888Sandreas.hansson@arm.com void setSlavePorts(const SnoopList& bus_slave_ports) { 10310399Sstephan.diestelhorst@arm.com slavePorts = bus_slave_ports; 10410399Sstephan.diestelhorst@arm.com } 10510399Sstephan.diestelhorst@arm.com 10610399Sstephan.diestelhorst@arm.com /** 10710399Sstephan.diestelhorst@arm.com * Lookup a request (from a slave port) in the snoop filter and return a 10810399Sstephan.diestelhorst@arm.com * list of other slave ports that need forwarding of the resulting snoops. 10910399Sstephan.diestelhorst@arm.com * Additionally, update the tracking structures with new request 11010399Sstephan.diestelhorst@arm.com * information. 11110399Sstephan.diestelhorst@arm.com * 11210399Sstephan.diestelhorst@arm.com * @param cpkt Pointer to the request packet. Not changed. 11310399Sstephan.diestelhorst@arm.com * @param slave_port Slave port where the request came from. 11410399Sstephan.diestelhorst@arm.com * @return Pair of a vector of snoop target ports and lookup latency. 11510399Sstephan.diestelhorst@arm.com */ 11610399Sstephan.diestelhorst@arm.com std::pair<SnoopList, Cycles> lookupRequest(const Packet* cpkt, 11710399Sstephan.diestelhorst@arm.com const SlavePort& slave_port); 11810399Sstephan.diestelhorst@arm.com 11910399Sstephan.diestelhorst@arm.com /** 12010399Sstephan.diestelhorst@arm.com * For a successful request, update all data structures in the snoop filter 12110399Sstephan.diestelhorst@arm.com * reflecting the changes caused by that request 12210399Sstephan.diestelhorst@arm.com * 12310399Sstephan.diestelhorst@arm.com * @param cpkt Pointer to the request packet. Not changed. 12410399Sstephan.diestelhorst@arm.com * @param slave_port Slave port where the request came from. 12510399Sstephan.diestelhorst@arm.com * @param will_retry This request will retry on this bus / snoop filter 12610399Sstephan.diestelhorst@arm.com */ 12710399Sstephan.diestelhorst@arm.com void updateRequest(const Packet* cpkt, const SlavePort& slave_port, 12810399Sstephan.diestelhorst@arm.com bool will_retry); 12910399Sstephan.diestelhorst@arm.com 13010399Sstephan.diestelhorst@arm.com /** 13110399Sstephan.diestelhorst@arm.com * Handle an incoming snoop from below (the master port). These can upgrade the 13210399Sstephan.diestelhorst@arm.com * tracking logic and may also benefit from additional steering thanks to the 13310399Sstephan.diestelhorst@arm.com * snoop filter. 13410399Sstephan.diestelhorst@arm.com * @param cpkt Pointer to const Packet containing the snoop. 13510399Sstephan.diestelhorst@arm.com * @return Pair with a vector of SlavePorts that need snooping and a lookup 13610399Sstephan.diestelhorst@arm.com * latency. 13710399Sstephan.diestelhorst@arm.com */ 13810399Sstephan.diestelhorst@arm.com std::pair<SnoopList, Cycles> lookupSnoop(const Packet* cpkt); 13910399Sstephan.diestelhorst@arm.com 14010399Sstephan.diestelhorst@arm.com /** 14110399Sstephan.diestelhorst@arm.com * Let the snoop filter see any snoop responses that turn into request responses 14210399Sstephan.diestelhorst@arm.com * and indicate cache to cache transfers. These will update the corresponding 14310399Sstephan.diestelhorst@arm.com * state in the filter. 14410399Sstephan.diestelhorst@arm.com * 14510399Sstephan.diestelhorst@arm.com * @param cpkt Pointer to const Packet holding the snoop response. 14610399Sstephan.diestelhorst@arm.com * @param rsp_port SlavePort that sends the response. 14710399Sstephan.diestelhorst@arm.com * @param req_port SlavePort that made the original request and is the 14810399Sstephan.diestelhorst@arm.com * destination of the snoop response. 14910399Sstephan.diestelhorst@arm.com */ 15010399Sstephan.diestelhorst@arm.com void updateSnoopResponse(const Packet *cpkt, const SlavePort& rsp_port, 15110399Sstephan.diestelhorst@arm.com const SlavePort& req_port); 15210399Sstephan.diestelhorst@arm.com 15310399Sstephan.diestelhorst@arm.com /** 15410399Sstephan.diestelhorst@arm.com * Pass snoop responses that travel downward through the snoop filter and let 15510399Sstephan.diestelhorst@arm.com * them update the snoop filter state. No additional routing happens. 15610399Sstephan.diestelhorst@arm.com * 15710399Sstephan.diestelhorst@arm.com * @param cpkt Pointer to const Packet holding the snoop response. 15810399Sstephan.diestelhorst@arm.com * @param rsp_port SlavePort that sends the response. 15910399Sstephan.diestelhorst@arm.com * @param req_port MasterPort through which the response leaves this cluster. 16010399Sstephan.diestelhorst@arm.com */ 16110399Sstephan.diestelhorst@arm.com void updateSnoopForward(const Packet *cpkt, const SlavePort& rsp_port, 16210399Sstephan.diestelhorst@arm.com const MasterPort& req_port); 16310399Sstephan.diestelhorst@arm.com 16410399Sstephan.diestelhorst@arm.com /** 16510399Sstephan.diestelhorst@arm.com * Update the snoop filter with a response from below (outer / other cache, 16610399Sstephan.diestelhorst@arm.com * or memory) and update the tracking information in the snoop filter. 16710399Sstephan.diestelhorst@arm.com * 16810399Sstephan.diestelhorst@arm.com * @param cpkt Pointer to const Packet holding the snoop response. 16910399Sstephan.diestelhorst@arm.com * @param slave_port SlavePort that made the original request and is the target 17010399Sstephan.diestelhorst@arm.com * of this response. 17110399Sstephan.diestelhorst@arm.com */ 17210399Sstephan.diestelhorst@arm.com void updateResponse(const Packet *cpkt, const SlavePort& slave_port); 17310399Sstephan.diestelhorst@arm.com 17410399Sstephan.diestelhorst@arm.com /** 17510399Sstephan.diestelhorst@arm.com * Simple factory methods for standard return values for lookupRequest 17610399Sstephan.diestelhorst@arm.com */ 17710399Sstephan.diestelhorst@arm.com std::pair<SnoopList, Cycles> snoopAll(Cycles latency) const 17810399Sstephan.diestelhorst@arm.com { 17910399Sstephan.diestelhorst@arm.com return std::make_pair(slavePorts, latency); 18010399Sstephan.diestelhorst@arm.com } 18110399Sstephan.diestelhorst@arm.com std::pair<SnoopList, Cycles> snoopSelected(const SnoopList& slave_ports, 18210399Sstephan.diestelhorst@arm.com Cycles latency) const 18310399Sstephan.diestelhorst@arm.com { 18410399Sstephan.diestelhorst@arm.com return std::make_pair(slave_ports, latency); 18510399Sstephan.diestelhorst@arm.com } 18610399Sstephan.diestelhorst@arm.com std::pair<SnoopList, Cycles> snoopDown(Cycles latency) const 18710399Sstephan.diestelhorst@arm.com { 18810399Sstephan.diestelhorst@arm.com SnoopList empty; 18910399Sstephan.diestelhorst@arm.com return std::make_pair(empty , latency); 19010399Sstephan.diestelhorst@arm.com } 19110399Sstephan.diestelhorst@arm.com 19210403Sstephan.diestelhorst@arm.com virtual void regStats(); 19310403Sstephan.diestelhorst@arm.com 19410399Sstephan.diestelhorst@arm.com protected: 19510399Sstephan.diestelhorst@arm.com typedef uint64_t SnoopMask; 19610399Sstephan.diestelhorst@arm.com /** 19710399Sstephan.diestelhorst@arm.com * Per cache line item tracking a bitmask of SlavePorts who have an 19810399Sstephan.diestelhorst@arm.com * outstanding request to this line (requested) or already share a cache line 19910399Sstephan.diestelhorst@arm.com * with this address (holder). 20010399Sstephan.diestelhorst@arm.com */ 20110399Sstephan.diestelhorst@arm.com struct SnoopItem { 20210399Sstephan.diestelhorst@arm.com SnoopMask requested; 20310399Sstephan.diestelhorst@arm.com SnoopMask holder; 20410399Sstephan.diestelhorst@arm.com }; 20510399Sstephan.diestelhorst@arm.com /** 20611129Sali.jafri@arm.com * HashMap of SnoopItems indexed by line address 20711129Sali.jafri@arm.com */ 20811129Sali.jafri@arm.com typedef m5::hash_map<Addr, SnoopItem> SnoopFilterCache; 20911129Sali.jafri@arm.com 21011129Sali.jafri@arm.com /** 21110399Sstephan.diestelhorst@arm.com * Convert a single port to a corresponding, one-hot bitmask 21210399Sstephan.diestelhorst@arm.com * @param port SlavePort that should be converted. 21310399Sstephan.diestelhorst@arm.com * @return One-hot bitmask corresponding to the port. 21410399Sstephan.diestelhorst@arm.com */ 21510399Sstephan.diestelhorst@arm.com SnoopMask portToMask(const SlavePort& port) const; 21610399Sstephan.diestelhorst@arm.com /** 21710399Sstephan.diestelhorst@arm.com * Convert multiple ports to a corresponding bitmask 21810399Sstephan.diestelhorst@arm.com * @param ports SnoopList that should be converted. 21910399Sstephan.diestelhorst@arm.com * @return Bitmask corresponding to the ports in the list. 22010399Sstephan.diestelhorst@arm.com */ 22110399Sstephan.diestelhorst@arm.com SnoopMask portListToMask(const SnoopList& ports) const; 22210399Sstephan.diestelhorst@arm.com /** 22310399Sstephan.diestelhorst@arm.com * Converts a bitmask of ports into the corresponing list of ports 22410399Sstephan.diestelhorst@arm.com * @param ports SnoopMask of the requested ports 22510399Sstephan.diestelhorst@arm.com * @return SnoopList containing all the requested SlavePorts 22610399Sstephan.diestelhorst@arm.com */ 22710399Sstephan.diestelhorst@arm.com SnoopList maskToPortList(SnoopMask ports) const; 22810399Sstephan.diestelhorst@arm.com 22910399Sstephan.diestelhorst@arm.com private: 23011129Sali.jafri@arm.com 23111129Sali.jafri@arm.com /** 23211129Sali.jafri@arm.com * Removes snoop filter items which have no requesters and no holders. 23311129Sali.jafri@arm.com */ 23411129Sali.jafri@arm.com void eraseIfNullEntry(SnoopFilterCache::iterator& sf_it); 23510399Sstephan.diestelhorst@arm.com /** Simple hash set of cached addresses. */ 23611129Sali.jafri@arm.com SnoopFilterCache cachedLocations; 23711129Sali.jafri@arm.com /** 23811129Sali.jafri@arm.com * Variable to temporarily store value of snoopfilter entry 23911129Sali.jafri@arm.com * incase updateRequest needs to undo changes made in lookupRequest 24011129Sali.jafri@arm.com * (because of crossbar retry) 24111129Sali.jafri@arm.com */ 24211129Sali.jafri@arm.com SnoopItem retryItem; 24310399Sstephan.diestelhorst@arm.com /** List of all attached slave ports. */ 24410399Sstephan.diestelhorst@arm.com SnoopList slavePorts; 24510399Sstephan.diestelhorst@arm.com /** Cache line size. */ 24610399Sstephan.diestelhorst@arm.com const unsigned linesize; 24710399Sstephan.diestelhorst@arm.com /** Latency for doing a lookup in the filter */ 24810399Sstephan.diestelhorst@arm.com const Cycles lookupLatency; 24910403Sstephan.diestelhorst@arm.com 25010403Sstephan.diestelhorst@arm.com /** Statistics */ 25110403Sstephan.diestelhorst@arm.com Stats::Scalar totRequests; 25210403Sstephan.diestelhorst@arm.com Stats::Scalar hitSingleRequests; 25310403Sstephan.diestelhorst@arm.com Stats::Scalar hitMultiRequests; 25410403Sstephan.diestelhorst@arm.com 25510403Sstephan.diestelhorst@arm.com Stats::Scalar totSnoops; 25610403Sstephan.diestelhorst@arm.com Stats::Scalar hitSingleSnoops; 25710403Sstephan.diestelhorst@arm.com Stats::Scalar hitMultiSnoops; 25810399Sstephan.diestelhorst@arm.com}; 25910399Sstephan.diestelhorst@arm.com 26010399Sstephan.diestelhorst@arm.cominline SnoopFilter::SnoopMask 26110399Sstephan.diestelhorst@arm.comSnoopFilter::portToMask(const SlavePort& port) const 26210399Sstephan.diestelhorst@arm.com{ 26310399Sstephan.diestelhorst@arm.com unsigned id = (unsigned)port.getId(); 26410399Sstephan.diestelhorst@arm.com assert(id != (unsigned)InvalidPortID); 26510399Sstephan.diestelhorst@arm.com assert((int)id < 8 * sizeof(SnoopMask)); 26610399Sstephan.diestelhorst@arm.com 26710399Sstephan.diestelhorst@arm.com return ((SnoopMask)1) << id; 26810399Sstephan.diestelhorst@arm.com} 26910399Sstephan.diestelhorst@arm.com 27010399Sstephan.diestelhorst@arm.cominline SnoopFilter::SnoopMask 27110399Sstephan.diestelhorst@arm.comSnoopFilter::portListToMask(const SnoopList& ports) const 27210399Sstephan.diestelhorst@arm.com{ 27310399Sstephan.diestelhorst@arm.com SnoopMask m = 0; 27410399Sstephan.diestelhorst@arm.com for (auto port = ports.begin(); port != ports.end(); ++port) 27510399Sstephan.diestelhorst@arm.com m |= portToMask(**port); 27610399Sstephan.diestelhorst@arm.com return m; 27710399Sstephan.diestelhorst@arm.com} 27810399Sstephan.diestelhorst@arm.com 27910399Sstephan.diestelhorst@arm.cominline SnoopFilter::SnoopList 28010399Sstephan.diestelhorst@arm.comSnoopFilter::maskToPortList(SnoopMask port_mask) const 28110399Sstephan.diestelhorst@arm.com{ 28210399Sstephan.diestelhorst@arm.com SnoopList res; 28310399Sstephan.diestelhorst@arm.com for (auto port = slavePorts.begin(); port != slavePorts.end(); ++port) 28410399Sstephan.diestelhorst@arm.com if (port_mask & portToMask(**port)) 28510399Sstephan.diestelhorst@arm.com res.push_back(*port); 28610399Sstephan.diestelhorst@arm.com return res; 28710399Sstephan.diestelhorst@arm.com} 28810399Sstephan.diestelhorst@arm.com#endif // __MEM_SNOOP_FILTER_HH__ 289