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