2 * Copyright (c) 2013 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Authors: Stephan Diestelhorst <stephan.diestelhorst@arm.com>
42 * Definition of a snoop filter.
45 #include "base/misc.hh"
46 #include "base/trace.hh"
47 #include "debug/SnoopFilter.hh"
48 #include "mem/snoop_filter.hh"
49 #include "sim/system.hh"
51 std::pair
<SnoopFilter::SnoopList
, Cycles
>
52 SnoopFilter::lookupRequest(const Packet
* cpkt
, const SlavePort
& slave_port
)
54 DPRINTF(SnoopFilter
, "%s: packet src %s addr 0x%x cmd %s\n",
55 __func__
, slave_port
.name(), cpkt
->getAddr(), cpkt
->cmdString());
57 Addr line_addr
= cpkt
->getAddr() & ~(linesize
- 1);
58 SnoopMask req_port
= portToMask(slave_port
);
59 auto sf_it
= cachedLocations
.find(line_addr
);
60 bool is_hit
= (sf_it
!= cachedLocations
.end());
61 // Create a new element through operator[] and modify in-place
62 SnoopItem
& sf_item
= is_hit
? sf_it
->second
: cachedLocations
[line_addr
];
63 SnoopMask interested
= sf_item
.holder
| sf_item
.requested
;
67 // Single bit set -> value is a power of two
68 if (isPow2(interested
))
74 DPRINTF(SnoopFilter
, "%s: SF value %x.%x\n",
75 __func__
, sf_item
.requested
, sf_item
.holder
);
77 if (!cpkt
->req
->isUncacheable() && cpkt
->needsResponse()) {
78 if (!cpkt
->memInhibitAsserted()) {
79 // Max one request per address per port
80 panic_if(sf_item
.requested
& req_port
, "double request :( "\
81 "SF value %x.%x\n", sf_item
.requested
, sf_item
.holder
);
83 // Mark in-flight requests to distinguish later on
84 sf_item
.requested
|= req_port
;
86 // NOTE: The memInhibit might have been asserted by a cache closer
87 // to the CPU, already -> the response will not be seen by this
88 // filter -> we do not need to keep the in-flight request, but make
89 // sure that we know that that cluster has a copy
90 panic_if(!(sf_item
.holder
& req_port
), "Need to hold the value!");
91 DPRINTF(SnoopFilter
, "%s: not marking request. SF value %x.%x\n",
92 __func__
, sf_item
.requested
, sf_item
.holder
);
94 DPRINTF(SnoopFilter
, "%s: new SF value %x.%x\n",
95 __func__
, sf_item
.requested
, sf_item
.holder
);
97 return snoopSelected(maskToPortList(interested
& ~req_port
), lookupLatency
);
101 SnoopFilter::updateRequest(const Packet
* cpkt
, const SlavePort
& slave_port
,
104 DPRINTF(SnoopFilter
, "%s: packet src %s addr 0x%x cmd %s\n",
105 __func__
, slave_port
.name(), cpkt
->getAddr(), cpkt
->cmdString());
107 if (cpkt
->req
->isUncacheable())
110 Addr line_addr
= cpkt
->getAddr() & ~(linesize
- 1);
111 SnoopMask req_port
= portToMask(slave_port
);
112 SnoopItem
& sf_item
= cachedLocations
[line_addr
];
114 DPRINTF(SnoopFilter
, "%s: old SF value %x.%x retry: %i\n",
115 __func__
, sf_item
.requested
, sf_item
.holder
, will_retry
);
118 // Unmark a request that will come again.
119 sf_item
.requested
&= ~req_port
;
123 // will_retry == false
124 if (!cpkt
->needsResponse()) {
125 // Packets that will not evoke a response but still need updates of the
126 // snoop filter; WRITEBACKs for now only
127 if (cpkt
->cmd
== MemCmd::Writeback
) {
128 // make sure that the sender actually had the line
129 panic_if(sf_item
.requested
& req_port
, "double request :( "\
130 "SF value %x.%x\n", sf_item
.requested
, sf_item
.holder
);
131 panic_if(!(sf_item
.holder
& req_port
), "requester %x is not a "\
132 "holder :( SF value %x.%x\n", req_port
,
133 sf_item
.requested
, sf_item
.holder
);
134 // Writebacks -> the sender does not have the line anymore
135 sf_item
.holder
&= ~req_port
;
137 // @todo Add CleanEvicts
138 assert(cpkt
->cmd
== MemCmd::CleanEvict
);
140 DPRINTF(SnoopFilter
, "%s: new SF value %x.%x\n",
141 __func__
, sf_item
.requested
, sf_item
.holder
);
145 std::pair
<SnoopFilter::SnoopList
, Cycles
>
146 SnoopFilter::lookupSnoop(const Packet
* cpkt
)
148 DPRINTF(SnoopFilter
, "%s: packet addr 0x%x cmd %s\n",
149 __func__
, cpkt
->getAddr(), cpkt
->cmdString());
151 assert(cpkt
->isRequest());
153 // Broadcast / filter upward snoops
154 const bool filter_upward
= true; // @todo: Make configurable
157 return snoopAll(lookupLatency
);
159 Addr line_addr
= cpkt
->getAddr() & ~(linesize
- 1);
160 auto sf_it
= cachedLocations
.find(line_addr
);
161 bool is_hit
= (sf_it
!= cachedLocations
.end());
162 // Create a new element through operator[] and modify in-place
163 SnoopItem
& sf_item
= is_hit
? sf_it
->second
: cachedLocations
[line_addr
];
165 DPRINTF(SnoopFilter
, "%s: old SF value %x.%x\n",
166 __func__
, sf_item
.requested
, sf_item
.holder
);
168 SnoopMask interested
= (sf_item
.holder
| sf_item
.requested
);
172 // Single bit set -> value is a power of two
173 if (isPow2(interested
))
178 // ReadEx and Writes require both invalidation and exlusivity, while reads
179 // require neither. Writebacks on the other hand require exclusivity but
180 // not the invalidation. Previously Writebacks did not generate upward
181 // snoops so this was never an aissue. Now that Writebacks generate snoops
182 // we need to special case for Writebacks.
183 assert(cpkt
->cmd
== MemCmd::Writeback
||
184 (cpkt
->isInvalidate() == cpkt
->needsExclusive()));
185 if (cpkt
->isInvalidate() && !sf_item
.requested
) {
186 // Early clear of the holder, if no other request is currently going on
187 // @todo: This should possibly be updated even though we do not filter
192 DPRINTF(SnoopFilter
, "%s: new SF value %x.%x interest: %x \n",
193 __func__
, sf_item
.requested
, sf_item
.holder
, interested
);
195 return snoopSelected(maskToPortList(interested
), lookupLatency
);
199 SnoopFilter::updateSnoopResponse(const Packet
* cpkt
,
200 const SlavePort
& rsp_port
,
201 const SlavePort
& req_port
)
203 DPRINTF(SnoopFilter
, "%s: packet rsp %s req %s addr 0x%x cmd %s\n",
204 __func__
, rsp_port
.name(), req_port
.name(), cpkt
->getAddr(),
207 assert(cpkt
->isResponse());
208 assert(cpkt
->memInhibitAsserted());
210 if (cpkt
->req
->isUncacheable())
213 Addr line_addr
= cpkt
->getAddr() & ~(linesize
- 1);
214 SnoopMask rsp_mask
= portToMask(rsp_port
);
215 SnoopMask req_mask
= portToMask(req_port
);
216 SnoopItem
& sf_item
= cachedLocations
[line_addr
];
218 DPRINTF(SnoopFilter
, "%s: old SF value %x.%x\n",
219 __func__
, sf_item
.requested
, sf_item
.holder
);
221 // The source should have the line
222 panic_if(!(sf_item
.holder
& rsp_mask
), "SF value %x.%x does not have "\
223 "the line\n", sf_item
.requested
, sf_item
.holder
);
225 // The destination should have had a request in
226 panic_if(!(sf_item
.requested
& req_mask
), "SF value %x.%x missing "\
227 "the original request\n", sf_item
.requested
, sf_item
.holder
);
229 // Update the residency of the cache line.
230 if (cpkt
->needsExclusive() || !cpkt
->sharedAsserted()) {
231 DPRINTF(SnoopFilter
, "%s: dropping %x because needs: %i shared: %i "\
232 "SF val: %x.%x\n", __func__
, rsp_mask
,
233 cpkt
->needsExclusive(), cpkt
->sharedAsserted(),
234 sf_item
.requested
, sf_item
.holder
);
236 sf_item
.holder
&= ~rsp_mask
;
237 // The snoop filter does not see any ACKs from non-responding sharers
238 // that have been invalidated :( So below assert would be nice, but..
239 //assert(sf_item.holder == 0);
242 assert(cpkt
->cmd
!= MemCmd::Writeback
);
243 sf_item
.holder
|= req_mask
;
244 sf_item
.requested
&= ~req_mask
;
245 DPRINTF(SnoopFilter
, "%s: new SF value %x.%x\n",
246 __func__
, sf_item
.requested
, sf_item
.holder
);
250 SnoopFilter::updateSnoopForward(const Packet
* cpkt
,
251 const SlavePort
& rsp_port
, const MasterPort
& req_port
)
253 DPRINTF(SnoopFilter
, "%s: packet rsp %s req %s addr 0x%x cmd %s\n",
254 __func__
, rsp_port
.name(), req_port
.name(), cpkt
->getAddr(),
257 Addr line_addr
= cpkt
->getAddr() & ~(linesize
- 1);
258 SnoopItem
& sf_item
= cachedLocations
[line_addr
];
259 SnoopMask rsp_mask M5_VAR_USED
= portToMask(rsp_port
);
261 assert(cpkt
->isResponse());
262 assert(cpkt
->memInhibitAsserted());
264 DPRINTF(SnoopFilter
, "%s: old SF value %x.%x\n",
265 __func__
, sf_item
.requested
, sf_item
.holder
);
267 // Remote (to this snoop filter) snoops update the filter already when they
268 // arrive from below, because we may not see any response.
269 if (cpkt
->needsExclusive()) {
270 // If the request to this snoop response hit an in-flight transaction,
271 // the holder was not reset -> no assertion & do that here, now!
272 //assert(sf_item.holder == 0);
275 DPRINTF(SnoopFilter
, "%s: new SF value %x.%x\n",
276 __func__
, sf_item
.requested
, sf_item
.holder
);
280 SnoopFilter::updateResponse(const Packet
* cpkt
, const SlavePort
& slave_port
)
282 DPRINTF(SnoopFilter
, "%s: packet src %s addr 0x%x cmd %s\n",
283 __func__
, slave_port
.name(), cpkt
->getAddr(), cpkt
->cmdString());
285 assert(cpkt
->isResponse());
287 if (cpkt
->req
->isUncacheable())
290 Addr line_addr
= cpkt
->getAddr() & ~(linesize
- 1);
291 SnoopMask slave_mask
= portToMask(slave_port
);
292 SnoopItem
& sf_item
= cachedLocations
[line_addr
];
294 DPRINTF(SnoopFilter
, "%s: old SF value %x.%x\n",
295 __func__
, sf_item
.requested
, sf_item
.holder
);
297 // Make sure we have seen the actual request, too
298 panic_if(!(sf_item
.requested
& slave_mask
), "SF value %x.%x missing "\
299 "request bit\n", sf_item
.requested
, sf_item
.holder
);
301 // Update the residency of the cache line.
302 if (cpkt
->needsExclusive() || !cpkt
->sharedAsserted())
304 sf_item
.holder
|= slave_mask
;
305 sf_item
.requested
&= ~slave_mask
;
306 DPRINTF(SnoopFilter
, "%s: new SF value %x.%x\n",
307 __func__
, sf_item
.requested
, sf_item
.holder
);
311 SnoopFilter::regStats()
314 .name(name() + ".tot_requests")
315 .desc("Total number of requests made to the snoop filter.");
318 .name(name() + ".hit_single_requests")
319 .desc("Number of requests hitting in the snoop filter with a single "\
320 "holder of the requested data.");
323 .name(name() + ".hit_multi_requests")
324 .desc("Number of requests hitting in the snoop filter with multiple "\
325 "(>1) holders of the requested data.");
328 .name(name() + ".tot_snoops")
329 .desc("Total number of snoops made to the snoop filter.");
332 .name(name() + ".hit_single_snoops")
333 .desc("Number of snoops hitting in the snoop filter with a single "\
334 "holder of the requested data.");
337 .name(name() + ".hit_multi_snoops")
338 .desc("Number of snoops hitting in the snoop filter with multiple "\
339 "(>1) holders of the requested data.");
343 SnoopFilterParams::create()
345 return new SnoopFilter(this);