snoop_filter.hh revision 11129:48c02e8b0bbb
16876Ssteve.reinhardt@amd.com/*
210089Sandreas.hansson@arm.com * Copyright (c) 2013-2015 ARM Limited
38922Swilliam.wang@arm.com * All rights reserved
48922Swilliam.wang@arm.com *
58922Swilliam.wang@arm.com * The license below extends only to copyright in the software and shall
68922Swilliam.wang@arm.com * not be construed as granting a license to any other intellectual
78922Swilliam.wang@arm.com * property including but not limited to intellectual property relating
88922Swilliam.wang@arm.com * to a hardware implementation of the functionality of the software
98922Swilliam.wang@arm.com * licensed hereunder.  You may use the software subject to the license
108922Swilliam.wang@arm.com * terms below provided that you ensure that this notice is replicated
118922Swilliam.wang@arm.com * unmodified and in its entirety in all distributions of the software,
128922Swilliam.wang@arm.com * modified or unmodified, in source code or in binary form.
138922Swilliam.wang@arm.com *
146876Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without
158717Snilay@cs.wisc.edu * modification, are permitted provided that the following conditions are
166876Ssteve.reinhardt@amd.com * met: redistributions of source code must retain the above copyright
176876Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer;
186876Ssteve.reinhardt@amd.com * redistributions in binary form must reproduce the above copyright
196876Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer in the
206876Ssteve.reinhardt@amd.com * documentation and/or other materials provided with the distribution;
216876Ssteve.reinhardt@amd.com * neither the name of the copyright holders nor the names of its
226876Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from
236876Ssteve.reinhardt@amd.com * this software without specific prior written permission.
246876Ssteve.reinhardt@amd.com *
256876Ssteve.reinhardt@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266876Ssteve.reinhardt@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
276876Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286876Ssteve.reinhardt@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
296876Ssteve.reinhardt@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
306876Ssteve.reinhardt@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
316876Ssteve.reinhardt@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
326876Ssteve.reinhardt@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
336876Ssteve.reinhardt@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
346876Ssteve.reinhardt@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
356876Ssteve.reinhardt@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366876Ssteve.reinhardt@amd.com *
376876Ssteve.reinhardt@amd.com * Authors: Stephan Diestelhorst <stephan.diestelhorst@arm.com>
386876Ssteve.reinhardt@amd.com */
396876Ssteve.reinhardt@amd.com
406876Ssteve.reinhardt@amd.com/**
416876Ssteve.reinhardt@amd.com * @file
427039Snate@binkert.org * Definition of a snoop filter.
437039Snate@binkert.org */
446285Snate@binkert.org
457039Snate@binkert.org#ifndef __MEM_SNOOP_FILTER_HH__
466285Snate@binkert.org#define __MEM_SNOOP_FILTER_HH__
476285Snate@binkert.org
486922SBrad.Beckmann@amd.com#include <utility>
4910301Snilay@cs.wisc.edu
507909Shestness@cs.utexas.edu#include "base/hashmap.hh"
518229Snate@binkert.org#include "mem/packet.hh"
527039Snate@binkert.org#include "mem/port.hh"
536876Ssteve.reinhardt@amd.com#include "mem/qport.hh"
546876Ssteve.reinhardt@amd.com#include "params/SnoopFilter.hh"
556876Ssteve.reinhardt@amd.com#include "sim/sim_object.hh"
566876Ssteve.reinhardt@amd.com#include "sim/system.hh"
577039Snate@binkert.org
587039Snate@binkert.org/**
597039Snate@binkert.org * This snoop filter keeps track of which connected port has a
6010090Snilay@cs.wisc.edu * particular line of data. It can be queried (through lookup*) on
6110090Snilay@cs.wisc.edu * memory requests from above (reads / writes / ...); and also from
6210090Snilay@cs.wisc.edu * below (snoops). The snoop filter precisely knows about the location
6310090Snilay@cs.wisc.edu * of lines "above" it through a map from cache line address to
6410090Snilay@cs.wisc.edu * sharers/ports. The snoop filter ties into the flows of requests
6510090Snilay@cs.wisc.edu * (when they succeed at the lower interface), regular responses from
6610090Snilay@cs.wisc.edu * below and also responses from sideway's caches (in update*). This
6710090Snilay@cs.wisc.edu * allows the snoop filter to model cache-line residency by snooping
6810090Snilay@cs.wisc.edu * the messages.
6910090Snilay@cs.wisc.edu *
7010090Snilay@cs.wisc.edu * The tracking happens in two fields to be able to distinguish
7110090Snilay@cs.wisc.edu * between in-flight requests (in requested) and already pulled in
7210090Snilay@cs.wisc.edu * lines (in holder). This distinction is used for producing tighter
7310090Snilay@cs.wisc.edu * assertions and tracking request completion. For safety, (requested
746882SBrad.Beckmann@amd.com * | holder) should be notified and the requesting MSHRs will take
757039Snate@binkert.org * care of ordering.
768975Sandreas.hansson@arm.com *
778436SBrad.Beckmann@amd.com * Overall, some trickery is required because:
7810525Snilay@cs.wisc.edu * (1) snoops are not followed by an ACK, but only evoke a response if
796882SBrad.Beckmann@amd.com *     they need to (hit dirty)
806882SBrad.Beckmann@amd.com * (2) side-channel information is funnelled through direct modifications of
8110090Snilay@cs.wisc.edu *     pkt, instead of proper messages through the bus
8210525Snilay@cs.wisc.edu * (3) there are no clean evict messages telling the snoop filter that a local,
836882SBrad.Beckmann@amd.com *     upper cache dropped a line, making the snoop filter pessimistic for now
848717Snilay@cs.wisc.edu * (4) ordering: there is no single point of order in the system.  Instead,
856882SBrad.Beckmann@amd.com *     requesting MSHRs track order between local requests and remote snoops
866882SBrad.Beckmann@amd.com */
8710089Sandreas.hansson@arm.comclass SnoopFilter : public SimObject {
8810090Snilay@cs.wisc.edu  public:
8910090Snilay@cs.wisc.edu    typedef std::vector<QueuedSlavePort*> SnoopList;
9010090Snilay@cs.wisc.edu
9110090Snilay@cs.wisc.edu    SnoopFilter (const SnoopFilterParams *p) : SimObject(p),
9210089Sandreas.hansson@arm.com        linesize(p->system->cacheLineSize()), lookupLatency(p->lookup_latency)
9310090Snilay@cs.wisc.edu    {
9410090Snilay@cs.wisc.edu    }
9510090Snilay@cs.wisc.edu
966882SBrad.Beckmann@amd.com    /**
976882SBrad.Beckmann@amd.com     * Init a new snoop filter and tell it about all the slave ports of the
9810089Sandreas.hansson@arm.com     * enclosing bus.
996882SBrad.Beckmann@amd.com     *
1006882SBrad.Beckmann@amd.com     * @param bus_slave_ports Vector of slave ports that the bus is attached to.
10110090Snilay@cs.wisc.edu     */
1026882SBrad.Beckmann@amd.com    void setSlavePorts(const SnoopList& bus_slave_ports) {
1037039Snate@binkert.org        slavePorts = bus_slave_ports;
1048975Sandreas.hansson@arm.com    }
1058914Sandreas.hansson@arm.com
1066882SBrad.Beckmann@amd.com    /**
10710090Snilay@cs.wisc.edu     * Lookup a request (from a slave port) in the snoop filter and return a
1086882SBrad.Beckmann@amd.com     * list of other slave ports that need forwarding of the resulting snoops.
1096882SBrad.Beckmann@amd.com     * Additionally, update the tracking structures with new request
11010090Snilay@cs.wisc.edu     * information.
11110090Snilay@cs.wisc.edu     *
1126882SBrad.Beckmann@amd.com     * @param cpkt          Pointer to the request packet.  Not changed.
1136882SBrad.Beckmann@amd.com     * @param slave_port    Slave port where the request came from.
11410090Snilay@cs.wisc.edu     * @return Pair of a vector of snoop target ports and lookup latency.
11510090Snilay@cs.wisc.edu     */
11610090Snilay@cs.wisc.edu    std::pair<SnoopList, Cycles> lookupRequest(const Packet* cpkt,
11710090Snilay@cs.wisc.edu                                               const SlavePort& slave_port);
11810090Snilay@cs.wisc.edu
11910090Snilay@cs.wisc.edu    /**
12010090Snilay@cs.wisc.edu     * For a successful request, update all data structures in the snoop filter
12110090Snilay@cs.wisc.edu     * reflecting the changes caused by that request
12210090Snilay@cs.wisc.edu     *
12310090Snilay@cs.wisc.edu     * @param cpkt          Pointer to the request packet.  Not changed.
12410090Snilay@cs.wisc.edu     * @param slave_port    Slave port where the request came from.
12510090Snilay@cs.wisc.edu     * @param will_retry    This request will retry on this bus / snoop filter
12610090Snilay@cs.wisc.edu     */
12710090Snilay@cs.wisc.edu    void updateRequest(const Packet* cpkt, const SlavePort& slave_port,
12810090Snilay@cs.wisc.edu                       bool will_retry);
12910090Snilay@cs.wisc.edu
13010090Snilay@cs.wisc.edu    /**
13110090Snilay@cs.wisc.edu     * Handle an incoming snoop from below (the master port).  These can upgrade the
13210090Snilay@cs.wisc.edu     * tracking logic and may also benefit from additional steering thanks to the
13310090Snilay@cs.wisc.edu     * snoop filter.
13410090Snilay@cs.wisc.edu     * @param cpkt Pointer to const Packet containing the snoop.
13510090Snilay@cs.wisc.edu     * @return Pair with a vector of SlavePorts that need snooping and a lookup
13610090Snilay@cs.wisc.edu     *         latency.
13710090Snilay@cs.wisc.edu     */
13810090Snilay@cs.wisc.edu    std::pair<SnoopList, Cycles> lookupSnoop(const Packet* cpkt);
13910090Snilay@cs.wisc.edu
14010090Snilay@cs.wisc.edu    /**
1416876Ssteve.reinhardt@amd.com     * Let the snoop filter see any snoop responses that turn into request responses
1426876Ssteve.reinhardt@amd.com     * and indicate cache to cache transfers.  These will update the corresponding
1436882SBrad.Beckmann@amd.com     * state in the filter.
1446882SBrad.Beckmann@amd.com     *
1456882SBrad.Beckmann@amd.com     * @param cpkt     Pointer to const Packet holding the snoop response.
1466285Snate@binkert.org     * @param rsp_port SlavePort that sends the response.
1479294Sandreas.hansson@arm.com     * @param req_port SlavePort that made the original request and is the
1489294Sandreas.hansson@arm.com     *                 destination of the snoop response.
1499294Sandreas.hansson@arm.com     */
1509294Sandreas.hansson@arm.com    void updateSnoopResponse(const Packet *cpkt, const SlavePort& rsp_port,
1516876Ssteve.reinhardt@amd.com                             const SlavePort& req_port);
1528615Snilay@cs.wisc.edu
1538688Snilay@cs.wisc.edu    /**
1548688Snilay@cs.wisc.edu     * Pass snoop responses that travel downward through the snoop filter and let
1558688Snilay@cs.wisc.edu     * them update the snoop filter state.  No additional routing happens.
1566882SBrad.Beckmann@amd.com     *
1576882SBrad.Beckmann@amd.com     * @param cpkt     Pointer to const Packet holding the snoop response.
1586882SBrad.Beckmann@amd.com     * @param rsp_port SlavePort that sends the response.
1596882SBrad.Beckmann@amd.com     * @param req_port MasterPort through which the response leaves this cluster.
1606882SBrad.Beckmann@amd.com     */
1616882SBrad.Beckmann@amd.com    void updateSnoopForward(const Packet *cpkt, const SlavePort& rsp_port,
16210012Snilay@cs.wisc.edu                            const MasterPort& req_port);
1639342SAndreas.Sandberg@arm.com
1646285Snate@binkert.org    /**
1657039Snate@binkert.org     * Update the snoop filter with a response from below (outer / other cache,
1667039Snate@binkert.org     * or memory) and update the tracking information in the snoop filter.
1678688Snilay@cs.wisc.edu     *
1688717Snilay@cs.wisc.edu     * @param cpkt       Pointer to const Packet holding the snoop response.
1696285Snate@binkert.org     * @param slave_port SlavePort that made the original request and is the target
17010089Sandreas.hansson@arm.com     *                   of this response.
17110089Sandreas.hansson@arm.com     */
17210089Sandreas.hansson@arm.com    void updateResponse(const Packet *cpkt, const SlavePort& slave_port);
17310089Sandreas.hansson@arm.com
17410089Sandreas.hansson@arm.com    /**
17510089Sandreas.hansson@arm.com     * Simple factory methods for standard return values for lookupRequest
17610089Sandreas.hansson@arm.com     */
17710089Sandreas.hansson@arm.com    std::pair<SnoopList, Cycles> snoopAll(Cycles latency) const
17810089Sandreas.hansson@arm.com    {
17910089Sandreas.hansson@arm.com        return std::make_pair(slavePorts, latency);
18010012Snilay@cs.wisc.edu    }
1817039Snate@binkert.org    std::pair<SnoopList, Cycles> snoopSelected(const SnoopList& slave_ports,
1827039Snate@binkert.org                                               Cycles latency) const
1837910SBrad.Beckmann@amd.com    {
18410467Sandreas.hansson@arm.com        return std::make_pair(slave_ports, latency);
1856876Ssteve.reinhardt@amd.com    }
1867039Snate@binkert.org    std::pair<SnoopList, Cycles> snoopDown(Cycles latency) const
18710090Snilay@cs.wisc.edu    {
1887910SBrad.Beckmann@amd.com        SnoopList empty;
18910089Sandreas.hansson@arm.com        return std::make_pair(empty , latency);
19010089Sandreas.hansson@arm.com    }
19110089Sandreas.hansson@arm.com
1927910SBrad.Beckmann@amd.com    virtual void regStats();
1937910SBrad.Beckmann@amd.com
1949342SAndreas.Sandberg@arm.com  protected:
1958688Snilay@cs.wisc.edu    typedef uint64_t SnoopMask;
19610090Snilay@cs.wisc.edu   /**
19710090Snilay@cs.wisc.edu    * Per cache line item tracking a bitmask of SlavePorts who have an
19810090Snilay@cs.wisc.edu    * outstanding request to this line (requested) or already share a cache line
19910090Snilay@cs.wisc.edu    * with this address (holder).
20010090Snilay@cs.wisc.edu    */
20110090Snilay@cs.wisc.edu    struct SnoopItem {
2028922Swilliam.wang@arm.com        SnoopMask requested;
20310090Snilay@cs.wisc.edu        SnoopMask holder;
20410090Snilay@cs.wisc.edu    };
20510090Snilay@cs.wisc.edu    /**
2068686Snilay@cs.wisc.edu     * HashMap of SnoopItems indexed by line address
2079342SAndreas.Sandberg@arm.com     */
2087910SBrad.Beckmann@amd.com    typedef m5::hash_map<Addr, SnoopItem> SnoopFilterCache;
2097910SBrad.Beckmann@amd.com
2107910SBrad.Beckmann@amd.com    /**
2117910SBrad.Beckmann@amd.com     * Convert a single port to a corresponding, one-hot bitmask
2127910SBrad.Beckmann@amd.com     * @param port SlavePort that should be converted.
21310090Snilay@cs.wisc.edu     * @return One-hot bitmask corresponding to the port.
2146285Snate@binkert.org     */
2156285Snate@binkert.org    SnoopMask portToMask(const SlavePort& port) const;
2167039Snate@binkert.org    /**
217     * Convert multiple ports to a corresponding bitmask
218     * @param ports SnoopList that should be converted.
219     * @return Bitmask corresponding to the ports in the list.
220     */
221    SnoopMask portListToMask(const SnoopList& ports) const;
222    /**
223     * Converts a bitmask of ports into the corresponing list of ports
224     * @param ports SnoopMask of the requested ports
225     * @return SnoopList containing all the requested SlavePorts
226     */
227    SnoopList maskToPortList(SnoopMask ports) const;
228
229  private:
230
231    /**
232     * Removes snoop filter items which have no requesters and no holders.
233     */
234    void eraseIfNullEntry(SnoopFilterCache::iterator& sf_it);
235    /** Simple hash set of cached addresses. */
236    SnoopFilterCache cachedLocations;
237    /**
238     * Variable to temporarily store value of snoopfilter entry
239     * incase updateRequest needs to undo changes made in lookupRequest
240     * (because of crossbar retry)
241     */
242    SnoopItem retryItem;
243    /** List of all attached slave ports. */
244    SnoopList slavePorts;
245    /** Cache line size. */
246    const unsigned linesize;
247    /** Latency for doing a lookup in the filter */
248    const Cycles lookupLatency;
249
250    /** Statistics */
251    Stats::Scalar totRequests;
252    Stats::Scalar hitSingleRequests;
253    Stats::Scalar hitMultiRequests;
254
255    Stats::Scalar totSnoops;
256    Stats::Scalar hitSingleSnoops;
257    Stats::Scalar hitMultiSnoops;
258};
259
260inline SnoopFilter::SnoopMask
261SnoopFilter::portToMask(const SlavePort& port) const
262{
263    unsigned id = (unsigned)port.getId();
264    assert(id != (unsigned)InvalidPortID);
265    assert((int)id < 8 * sizeof(SnoopMask));
266
267    return ((SnoopMask)1) << id;
268}
269
270inline SnoopFilter::SnoopMask
271SnoopFilter::portListToMask(const SnoopList& ports) const
272{
273    SnoopMask m = 0;
274    for (auto port = ports.begin(); port != ports.end(); ++port)
275        m |= portToMask(**port);
276    return m;
277}
278
279inline SnoopFilter::SnoopList
280SnoopFilter::maskToPortList(SnoopMask port_mask) const
281{
282    SnoopList res;
283    for (auto port = slavePorts.begin(); port != slavePorts.end(); ++port)
284        if (port_mask & portToMask(**port))
285            res.push_back(*port);
286    return res;
287}
288#endif // __MEM_SNOOP_FILTER_HH__
289