/*
- * Copyright (c) 2013-2015 ARM Limited
+ * Copyright (c) 2013-2016 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Authors: Stephan Diestelhorst <stephan.diestelhorst@arm.com>
+ * Authors: Stephan Diestelhorst
*/
/**
#ifndef __MEM_SNOOP_FILTER_HH__
#define __MEM_SNOOP_FILTER_HH__
+#include <unordered_map>
#include <utility>
-#include "base/hashmap.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
#include "mem/qport.hh"
public:
typedef std::vector<QueuedSlavePort*> SnoopList;
- SnoopFilter (const SnoopFilterParams *p) : SimObject(p),
- linesize(p->system->cacheLineSize()), lookupLatency(p->lookup_latency)
+ SnoopFilter (const SnoopFilterParams *p) :
+ SimObject(p), reqLookupResult(cachedLocations.end()), retryItem{0, 0},
+ linesize(p->system->cacheLineSize()), lookupLatency(p->lookup_latency),
+ maxEntryCount(p->max_capacity / p->system->cacheLineSize())
{
}
/**
- * Init a new snoop filter and tell it about all the slave ports of the
- * enclosing bus.
+ * Init a new snoop filter and tell it about all the slave ports
+ * of the enclosing bus.
*
- * @param bus_slave_ports Vector of slave ports that the bus is attached to.
+ * @param slave_ports Slave ports that the bus is attached to.
*/
- void setSlavePorts(const SnoopList& bus_slave_ports) {
- slavePorts = bus_slave_ports;
+ void setSlavePorts(const SnoopList& slave_ports) {
+ localSlavePortIds.resize(slave_ports.size(), InvalidPortID);
+
+ PortID id = 0;
+ for (const auto& p : slave_ports) {
+ // no need to track this port if it is not snooping
+ if (p->isSnooping()) {
+ slavePorts.push_back(p);
+ localSlavePortIds[p->getId()] = id++;
+ }
+ }
+
+ // make sure we can deal with this many ports
+ fatal_if(id > 8 * sizeof(SnoopMask),
+ "Snoop filter only supports %d snooping ports, got %d\n",
+ 8 * sizeof(SnoopMask), id);
}
/**
- * Lookup a request (from a slave port) in the snoop filter and return a
- * list of other slave ports that need forwarding of the resulting snoops.
- * Additionally, update the tracking structures with new request
- * information.
+ * Lookup a request (from a slave port) in the snoop filter and
+ * return a list of other slave ports that need forwarding of the
+ * resulting snoops. Additionally, update the tracking structures
+ * with new request information. Note that the caller must also
+ * call finishRequest once it is known if the request needs to
+ * retry or not.
*
- * @param cpkt Pointer to the request packet. Not changed.
+ * @param cpkt Pointer to the request packet. Not changed.
* @param slave_port Slave port where the request came from.
* @return Pair of a vector of snoop target ports and lookup latency.
*/
const SlavePort& slave_port);
/**
- * For a successful request, update all data structures in the snoop filter
- * reflecting the changes caused by that request
+ * For an un-successful request, revert the change to the snoop
+ * filter. Also take care of erasing any null entries. This method
+ * relies on the result from lookupRequest being stored in
+ * reqLookupResult.
*
- * @param cpkt Pointer to the request packet. Not changed.
- * @param slave_port Slave port where the request came from.
* @param will_retry This request will retry on this bus / snoop filter
+ * @param addr Packet address, merely for sanity checking
*/
- void updateRequest(const Packet* cpkt, const SlavePort& slave_port,
- bool will_retry);
+ void finishRequest(bool will_retry, Addr addr, bool is_secure);
/**
- * Handle an incoming snoop from below (the master port). These can upgrade the
- * tracking logic and may also benefit from additional steering thanks to the
- * snoop filter.
+ * Handle an incoming snoop from below (the master port). These
+ * can upgrade the tracking logic and may also benefit from
+ * additional steering thanks to the snoop filter.
+ *
* @param cpkt Pointer to const Packet containing the snoop.
* @return Pair with a vector of SlavePorts that need snooping and a lookup
* latency.
std::pair<SnoopList, Cycles> lookupSnoop(const Packet* cpkt);
/**
- * Let the snoop filter see any snoop responses that turn into request responses
- * and indicate cache to cache transfers. These will update the corresponding
- * state in the filter.
+ * Let the snoop filter see any snoop responses that turn into
+ * request responses and indicate cache to cache transfers. These
+ * will update the corresponding state in the filter.
*
* @param cpkt Pointer to const Packet holding the snoop response.
* @param rsp_port SlavePort that sends the response.
const SlavePort& req_port);
/**
- * Pass snoop responses that travel downward through the snoop filter and let
- * them update the snoop filter state. No additional routing happens.
+ * Pass snoop responses that travel downward through the snoop
+ * filter and let them update the snoop filter state. No
+ * additional routing happens.
*
* @param cpkt Pointer to const Packet holding the snoop response.
* @param rsp_port SlavePort that sends the response.
- * @param req_port MasterPort through which the response leaves this cluster.
+ * @param req_port MasterPort through which the response is forwarded.
*/
void updateSnoopForward(const Packet *cpkt, const SlavePort& rsp_port,
const MasterPort& req_port);
/**
- * Update the snoop filter with a response from below (outer / other cache,
- * or memory) and update the tracking information in the snoop filter.
+ * Update the snoop filter with a response from below (outer /
+ * other cache, or memory) and update the tracking information in
+ * the snoop filter.
*
* @param cpkt Pointer to const Packet holding the snoop response.
- * @param slave_port SlavePort that made the original request and is the target
- * of this response.
+ * @param slave_port SlavePort that made the original request and
+ * is the target of this response.
*/
void updateResponse(const Packet *cpkt, const SlavePort& slave_port);
+ virtual void regStats();
+
+ protected:
+
+ /**
+ * The underlying type for the bitmask we use for tracking. This
+ * limits the number of snooping ports supported per crossbar. For
+ * the moment it is an uint64_t to offer maximum
+ * scalability. However, it is possible to use e.g. a uint16_t or
+ * uint32_to slim down the footprint of the hash map (and
+ * ultimately improve the simulation performance).
+ */
+ typedef uint64_t SnoopMask;
+
+ /**
+ * Per cache line item tracking a bitmask of SlavePorts who have an
+ * outstanding request to this line (requested) or already share a
+ * cache line with this address (holder).
+ */
+ struct SnoopItem {
+ SnoopMask requested;
+ SnoopMask holder;
+ };
+ /**
+ * HashMap of SnoopItems indexed by line address
+ */
+ typedef std::unordered_map<Addr, SnoopItem> SnoopFilterCache;
+
/**
- * Simple factory methods for standard return values for lookupRequest
+ * Simple factory methods for standard return values.
*/
std::pair<SnoopList, Cycles> snoopAll(Cycles latency) const
{
return std::make_pair(empty , latency);
}
- virtual void regStats();
-
- protected:
- typedef uint64_t SnoopMask;
- /**
- * Per cache line item tracking a bitmask of SlavePorts who have an
- * outstanding request to this line (requested) or already share a cache line
- * with this address (holder).
- */
- struct SnoopItem {
- SnoopMask requested;
- SnoopMask holder;
- };
- /**
- * HashMap of SnoopItems indexed by line address
- */
- typedef m5::hash_map<Addr, SnoopItem> SnoopFilterCache;
-
/**
* Convert a single port to a corresponding, one-hot bitmask
* @param port SlavePort that should be converted.
* @return One-hot bitmask corresponding to the port.
*/
SnoopMask portToMask(const SlavePort& port) const;
- /**
- * Convert multiple ports to a corresponding bitmask
- * @param ports SnoopList that should be converted.
- * @return Bitmask corresponding to the ports in the list.
- */
- SnoopMask portListToMask(const SnoopList& ports) const;
/**
* Converts a bitmask of ports into the corresponing list of ports
* @param ports SnoopMask of the requested ports
* Removes snoop filter items which have no requesters and no holders.
*/
void eraseIfNullEntry(SnoopFilterCache::iterator& sf_it);
+
/** Simple hash set of cached addresses. */
SnoopFilterCache cachedLocations;
+ /**
+ * Iterator used to store the result from lookupRequest until we
+ * call finishRequest.
+ */
+ SnoopFilterCache::iterator reqLookupResult;
/**
* Variable to temporarily store value of snoopfilter entry
- * incase updateRequest needs to undo changes made in lookupRequest
+ * incase finishRequest needs to undo changes made in lookupRequest
* (because of crossbar retry)
*/
SnoopItem retryItem;
- /** List of all attached slave ports. */
+ /** List of all attached snooping slave ports. */
SnoopList slavePorts;
+ /** Track the mapping from port ids to the local mask ids. */
+ std::vector<PortID> localSlavePortIds;
/** Cache line size. */
const unsigned linesize;
/** Latency for doing a lookup in the filter */
const Cycles lookupLatency;
+ /** Max capacity in terms of cache blocks tracked, for sanity checking */
+ const unsigned maxEntryCount;
+
+ /**
+ * Use the lower bits of the address to keep track of the line status
+ */
+ enum LineStatus {
+ /** block holds data from the secure memory space */
+ LineSecure = 0x01,
+ };
/** Statistics */
Stats::Scalar totRequests;
inline SnoopFilter::SnoopMask
SnoopFilter::portToMask(const SlavePort& port) const
{
- unsigned id = (unsigned)port.getId();
- assert(id != (unsigned)InvalidPortID);
- assert((int)id < 8 * sizeof(SnoopMask));
-
- return ((SnoopMask)1) << id;
-}
-
-inline SnoopFilter::SnoopMask
-SnoopFilter::portListToMask(const SnoopList& ports) const
-{
- SnoopMask m = 0;
- for (auto port = ports.begin(); port != ports.end(); ++port)
- m |= portToMask(**port);
- return m;
+ assert(port.getId() != InvalidPortID);
+ // if this is not a snooping port, return a zero mask
+ return !port.isSnooping() ? 0 :
+ ((SnoopMask)1) << localSlavePortIds[port.getId()];
}
inline SnoopFilter::SnoopList
SnoopFilter::maskToPortList(SnoopMask port_mask) const
{
SnoopList res;
- for (auto port = slavePorts.begin(); port != slavePorts.end(); ++port)
- if (port_mask & portToMask(**port))
- res.push_back(*port);
+ for (const auto& p : slavePorts)
+ if (port_mask & portToMask(*p))
+ res.push_back(p);
return res;
}
+
#endif // __MEM_SNOOP_FILTER_HH__