snoop_filter.cc (14122:11979370f6f8) snoop_filter.cc (14123:3525a51d01ef)
1/*
2 * Copyright (c) 2013-2017,2019 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Stephan Diestelhorst
38 */
39
40/**
41 * @file
42 * Implementation of a snoop filter.
43 */
44
45#include "mem/snoop_filter.hh"
46
47#include "base/logging.hh"
48#include "base/trace.hh"
49#include "debug/SnoopFilter.hh"
50#include "sim/system.hh"
51
52const int SnoopFilter::SNOOP_MASK_SIZE;
53
54void
55SnoopFilter::eraseIfNullEntry(SnoopFilterCache::iterator& sf_it)
56{
57 SnoopItem& sf_item = sf_it->second;
58 if ((sf_item.requested | sf_item.holder).none()) {
59 cachedLocations.erase(sf_it);
60 DPRINTF(SnoopFilter, "%s: Removed SF entry.\n",
61 __func__);
62 }
63}
64
65std::pair<SnoopFilter::SnoopList, Cycles>
66SnoopFilter::lookupRequest(const Packet* cpkt, const SlavePort& slave_port)
67{
68 DPRINTF(SnoopFilter, "%s: src %s packet %s\n", __func__,
69 slave_port.name(), cpkt->print());
70
71 // check if the packet came from a cache
72 bool allocate = !cpkt->req->isUncacheable() && slave_port.isSnooping() &&
73 cpkt->fromCache();
74 Addr line_addr = cpkt->getBlockAddr(linesize);
75 if (cpkt->isSecure()) {
76 line_addr |= LineSecure;
77 }
78 SnoopMask req_port = portToMask(slave_port);
79 reqLookupResult.it = cachedLocations.find(line_addr);
80 bool is_hit = (reqLookupResult.it != cachedLocations.end());
81
82 // If the snoop filter has no entry, and we should not allocate,
83 // do not create a new snoop filter entry, simply return a NULL
84 // portlist.
85 if (!is_hit && !allocate)
86 return snoopDown(lookupLatency);
87
88 // If no hit in snoop filter create a new element and update iterator
89 if (!is_hit) {
90 reqLookupResult.it =
91 cachedLocations.emplace(line_addr, SnoopItem()).first;
92 }
93 SnoopItem& sf_item = reqLookupResult.it->second;
94 SnoopMask interested = sf_item.holder | sf_item.requested;
95
96 // Store unmodified value of snoop filter item in temp storage in
97 // case we need to revert because of a send retry in
98 // updateRequest.
99 reqLookupResult.retryItem = sf_item;
100
101 totRequests++;
102 if (is_hit) {
103 if (interested.count() == 1)
104 hitSingleRequests++;
105 else
106 hitMultiRequests++;
107 }
108
109 DPRINTF(SnoopFilter, "%s: SF value %x.%x\n",
110 __func__, sf_item.requested, sf_item.holder);
111
112 // If we are not allocating, we are done
113 if (!allocate)
114 return snoopSelected(maskToPortList(interested & ~req_port),
115 lookupLatency);
116
117 if (cpkt->needsResponse()) {
118 if (!cpkt->cacheResponding()) {
119 // Max one request per address per port
120 panic_if((sf_item.requested & req_port).any(),
121 "double request :( SF value %x.%x\n",
122 sf_item.requested, sf_item.holder);
123
124 // Mark in-flight requests to distinguish later on
125 sf_item.requested |= req_port;
126 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
127 __func__, sf_item.requested, sf_item.holder);
128 } else {
129 // NOTE: The memInhibit might have been asserted by a cache closer
130 // to the CPU, already -> the response will not be seen by this
131 // filter -> we do not need to keep the in-flight request, but make
132 // sure that we know that that cluster has a copy
133 panic_if((sf_item.holder & req_port).none(),
134 "Need to hold the value!");
135 DPRINTF(SnoopFilter,
136 "%s: not marking request. SF value %x.%x\n",
137 __func__, sf_item.requested, sf_item.holder);
138 }
139 } else { // if (!cpkt->needsResponse())
140 assert(cpkt->isEviction());
141 // make sure that the sender actually had the line
142 panic_if((sf_item.holder & req_port).none(), "requester %x is not a " \
143 "holder :( SF value %x.%x\n", req_port,
144 sf_item.requested, sf_item.holder);
145 // CleanEvicts and Writebacks -> the sender and all caches above
146 // it may not have the line anymore.
147 if (!cpkt->isBlockCached()) {
148 sf_item.holder &= ~req_port;
149 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
150 __func__, sf_item.requested, sf_item.holder);
151 }
152 }
153
154 return snoopSelected(maskToPortList(interested & ~req_port), lookupLatency);
155}
156
157void
158SnoopFilter::finishRequest(bool will_retry, Addr addr, bool is_secure)
159{
160 if (reqLookupResult.it != cachedLocations.end()) {
161 // since we rely on the caller, do a basic check to ensure
162 // that finishRequest is being called following lookupRequest
163 Addr line_addr = (addr & ~(Addr(linesize - 1)));
164 if (is_secure) {
165 line_addr |= LineSecure;
166 }
167 assert(reqLookupResult.it->first == line_addr);
168 if (will_retry) {
169 SnoopItem retry_item = reqLookupResult.retryItem;
170 // Undo any changes made in lookupRequest to the snoop filter
171 // entry if the request will come again. retryItem holds
172 // the previous value of the snoopfilter entry.
173 reqLookupResult.it->second = retry_item;
174
175 DPRINTF(SnoopFilter, "%s: restored SF value %x.%x\n",
176 __func__, retry_item.requested, retry_item.holder);
177 }
178
179 eraseIfNullEntry(reqLookupResult.it);
180 }
181}
182
183std::pair<SnoopFilter::SnoopList, Cycles>
184SnoopFilter::lookupSnoop(const Packet* cpkt)
185{
186 DPRINTF(SnoopFilter, "%s: packet %s\n", __func__, cpkt->print());
187
188 assert(cpkt->isRequest());
189
190 Addr line_addr = cpkt->getBlockAddr(linesize);
191 if (cpkt->isSecure()) {
192 line_addr |= LineSecure;
193 }
194 auto sf_it = cachedLocations.find(line_addr);
195 bool is_hit = (sf_it != cachedLocations.end());
196
197 panic_if(!is_hit && (cachedLocations.size() >= maxEntryCount),
198 "snoop filter exceeded capacity of %d cache blocks\n",
199 maxEntryCount);
200
201 // If the snoop filter has no entry, simply return a NULL
202 // portlist, there is no point creating an entry only to remove it
203 // later
204 if (!is_hit)
205 return snoopDown(lookupLatency);
206
207 SnoopItem& sf_item = sf_it->second;
208
1/*
2 * Copyright (c) 2013-2017,2019 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Stephan Diestelhorst
38 */
39
40/**
41 * @file
42 * Implementation of a snoop filter.
43 */
44
45#include "mem/snoop_filter.hh"
46
47#include "base/logging.hh"
48#include "base/trace.hh"
49#include "debug/SnoopFilter.hh"
50#include "sim/system.hh"
51
52const int SnoopFilter::SNOOP_MASK_SIZE;
53
54void
55SnoopFilter::eraseIfNullEntry(SnoopFilterCache::iterator& sf_it)
56{
57 SnoopItem& sf_item = sf_it->second;
58 if ((sf_item.requested | sf_item.holder).none()) {
59 cachedLocations.erase(sf_it);
60 DPRINTF(SnoopFilter, "%s: Removed SF entry.\n",
61 __func__);
62 }
63}
64
65std::pair<SnoopFilter::SnoopList, Cycles>
66SnoopFilter::lookupRequest(const Packet* cpkt, const SlavePort& slave_port)
67{
68 DPRINTF(SnoopFilter, "%s: src %s packet %s\n", __func__,
69 slave_port.name(), cpkt->print());
70
71 // check if the packet came from a cache
72 bool allocate = !cpkt->req->isUncacheable() && slave_port.isSnooping() &&
73 cpkt->fromCache();
74 Addr line_addr = cpkt->getBlockAddr(linesize);
75 if (cpkt->isSecure()) {
76 line_addr |= LineSecure;
77 }
78 SnoopMask req_port = portToMask(slave_port);
79 reqLookupResult.it = cachedLocations.find(line_addr);
80 bool is_hit = (reqLookupResult.it != cachedLocations.end());
81
82 // If the snoop filter has no entry, and we should not allocate,
83 // do not create a new snoop filter entry, simply return a NULL
84 // portlist.
85 if (!is_hit && !allocate)
86 return snoopDown(lookupLatency);
87
88 // If no hit in snoop filter create a new element and update iterator
89 if (!is_hit) {
90 reqLookupResult.it =
91 cachedLocations.emplace(line_addr, SnoopItem()).first;
92 }
93 SnoopItem& sf_item = reqLookupResult.it->second;
94 SnoopMask interested = sf_item.holder | sf_item.requested;
95
96 // Store unmodified value of snoop filter item in temp storage in
97 // case we need to revert because of a send retry in
98 // updateRequest.
99 reqLookupResult.retryItem = sf_item;
100
101 totRequests++;
102 if (is_hit) {
103 if (interested.count() == 1)
104 hitSingleRequests++;
105 else
106 hitMultiRequests++;
107 }
108
109 DPRINTF(SnoopFilter, "%s: SF value %x.%x\n",
110 __func__, sf_item.requested, sf_item.holder);
111
112 // If we are not allocating, we are done
113 if (!allocate)
114 return snoopSelected(maskToPortList(interested & ~req_port),
115 lookupLatency);
116
117 if (cpkt->needsResponse()) {
118 if (!cpkt->cacheResponding()) {
119 // Max one request per address per port
120 panic_if((sf_item.requested & req_port).any(),
121 "double request :( SF value %x.%x\n",
122 sf_item.requested, sf_item.holder);
123
124 // Mark in-flight requests to distinguish later on
125 sf_item.requested |= req_port;
126 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
127 __func__, sf_item.requested, sf_item.holder);
128 } else {
129 // NOTE: The memInhibit might have been asserted by a cache closer
130 // to the CPU, already -> the response will not be seen by this
131 // filter -> we do not need to keep the in-flight request, but make
132 // sure that we know that that cluster has a copy
133 panic_if((sf_item.holder & req_port).none(),
134 "Need to hold the value!");
135 DPRINTF(SnoopFilter,
136 "%s: not marking request. SF value %x.%x\n",
137 __func__, sf_item.requested, sf_item.holder);
138 }
139 } else { // if (!cpkt->needsResponse())
140 assert(cpkt->isEviction());
141 // make sure that the sender actually had the line
142 panic_if((sf_item.holder & req_port).none(), "requester %x is not a " \
143 "holder :( SF value %x.%x\n", req_port,
144 sf_item.requested, sf_item.holder);
145 // CleanEvicts and Writebacks -> the sender and all caches above
146 // it may not have the line anymore.
147 if (!cpkt->isBlockCached()) {
148 sf_item.holder &= ~req_port;
149 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
150 __func__, sf_item.requested, sf_item.holder);
151 }
152 }
153
154 return snoopSelected(maskToPortList(interested & ~req_port), lookupLatency);
155}
156
157void
158SnoopFilter::finishRequest(bool will_retry, Addr addr, bool is_secure)
159{
160 if (reqLookupResult.it != cachedLocations.end()) {
161 // since we rely on the caller, do a basic check to ensure
162 // that finishRequest is being called following lookupRequest
163 Addr line_addr = (addr & ~(Addr(linesize - 1)));
164 if (is_secure) {
165 line_addr |= LineSecure;
166 }
167 assert(reqLookupResult.it->first == line_addr);
168 if (will_retry) {
169 SnoopItem retry_item = reqLookupResult.retryItem;
170 // Undo any changes made in lookupRequest to the snoop filter
171 // entry if the request will come again. retryItem holds
172 // the previous value of the snoopfilter entry.
173 reqLookupResult.it->second = retry_item;
174
175 DPRINTF(SnoopFilter, "%s: restored SF value %x.%x\n",
176 __func__, retry_item.requested, retry_item.holder);
177 }
178
179 eraseIfNullEntry(reqLookupResult.it);
180 }
181}
182
183std::pair<SnoopFilter::SnoopList, Cycles>
184SnoopFilter::lookupSnoop(const Packet* cpkt)
185{
186 DPRINTF(SnoopFilter, "%s: packet %s\n", __func__, cpkt->print());
187
188 assert(cpkt->isRequest());
189
190 Addr line_addr = cpkt->getBlockAddr(linesize);
191 if (cpkt->isSecure()) {
192 line_addr |= LineSecure;
193 }
194 auto sf_it = cachedLocations.find(line_addr);
195 bool is_hit = (sf_it != cachedLocations.end());
196
197 panic_if(!is_hit && (cachedLocations.size() >= maxEntryCount),
198 "snoop filter exceeded capacity of %d cache blocks\n",
199 maxEntryCount);
200
201 // If the snoop filter has no entry, simply return a NULL
202 // portlist, there is no point creating an entry only to remove it
203 // later
204 if (!is_hit)
205 return snoopDown(lookupLatency);
206
207 SnoopItem& sf_item = sf_it->second;
208
209 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
210 __func__, sf_item.requested, sf_item.holder);
211
212 SnoopMask interested = (sf_item.holder | sf_item.requested);
213
214 totSnoops++;
215
216 if (interested.count() == 1)
217 hitSingleSnoops++;
218 else
219 hitMultiSnoops++;
220
221 // ReadEx and Writes require both invalidation and exlusivity, while reads
222 // require neither. Writebacks on the other hand require exclusivity but
223 // not the invalidation. Previously Writebacks did not generate upward
224 // snoops so this was never an issue. Now that Writebacks generate snoops
225 // we need a special case for Writebacks. Additionally cache maintenance
226 // operations can generate snoops as they clean and/or invalidate all
227 // caches down to the specified point of reference.
228 assert(cpkt->isWriteback() || cpkt->req->isUncacheable() ||
229 (cpkt->isInvalidate() == cpkt->needsWritable()) ||
230 cpkt->req->isCacheMaintenance());
231 if (cpkt->isInvalidate() && sf_item.requested.none()) {
232 // Early clear of the holder, if no other request is currently going on
233 // @todo: This should possibly be updated even though we do not filter
234 // upward snoops
209 SnoopMask interested = (sf_item.holder | sf_item.requested);
210
211 totSnoops++;
212
213 if (interested.count() == 1)
214 hitSingleSnoops++;
215 else
216 hitMultiSnoops++;
217
218 // ReadEx and Writes require both invalidation and exlusivity, while reads
219 // require neither. Writebacks on the other hand require exclusivity but
220 // not the invalidation. Previously Writebacks did not generate upward
221 // snoops so this was never an issue. Now that Writebacks generate snoops
222 // we need a special case for Writebacks. Additionally cache maintenance
223 // operations can generate snoops as they clean and/or invalidate all
224 // caches down to the specified point of reference.
225 assert(cpkt->isWriteback() || cpkt->req->isUncacheable() ||
226 (cpkt->isInvalidate() == cpkt->needsWritable()) ||
227 cpkt->req->isCacheMaintenance());
228 if (cpkt->isInvalidate() && sf_item.requested.none()) {
229 // Early clear of the holder, if no other request is currently going on
230 // @todo: This should possibly be updated even though we do not filter
231 // upward snoops
232 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
233 __func__, sf_item.requested, sf_item.holder);
235 sf_item.holder = 0;
234 sf_item.holder = 0;
235 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
236 __func__, sf_item.requested, sf_item.holder);
237 eraseIfNullEntry(sf_it);
236 }
237
238 }
239
238 eraseIfNullEntry(sf_it);
239 DPRINTF(SnoopFilter, "%s: new SF value %x.%x interest: %x \n",
240 __func__, sf_item.requested, sf_item.holder, interested);
241
242 return snoopSelected(maskToPortList(interested), lookupLatency);
243}
244
245void
246SnoopFilter::updateSnoopResponse(const Packet* cpkt,
247 const SlavePort& rsp_port,
248 const SlavePort& req_port)
249{
250 DPRINTF(SnoopFilter, "%s: rsp %s req %s packet %s\n",
251 __func__, rsp_port.name(), req_port.name(), cpkt->print());
252
253 assert(cpkt->isResponse());
254 assert(cpkt->cacheResponding());
255
256 // if this snoop response is due to an uncacheable request, or is
257 // being turned into a normal response, there is nothing more to
258 // do
259 if (cpkt->req->isUncacheable() || !req_port.isSnooping()) {
260 return;
261 }
262
263 Addr line_addr = cpkt->getBlockAddr(linesize);
264 if (cpkt->isSecure()) {
265 line_addr |= LineSecure;
266 }
267 SnoopMask rsp_mask = portToMask(rsp_port);
268 SnoopMask req_mask = portToMask(req_port);
269 SnoopItem& sf_item = cachedLocations[line_addr];
270
271 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
272 __func__, sf_item.requested, sf_item.holder);
273
274 // The source should have the line
275 panic_if((sf_item.holder & rsp_mask).none(),
276 "SF value %x.%x does not have the line\n",
277 sf_item.requested, sf_item.holder);
278
279 // The destination should have had a request in
280 panic_if((sf_item.requested & req_mask).none(), "SF value %x.%x missing "\
281 "the original request\n", sf_item.requested, sf_item.holder);
282
283 // If the snoop response has no sharers the line is passed in
284 // Modified state, and we know that there are no other copies, or
285 // they will all be invalidated imminently
286 if (!cpkt->hasSharers()) {
287 DPRINTF(SnoopFilter,
288 "%s: dropping %x because non-shared snoop "
289 "response SF val: %x.%x\n", __func__, rsp_mask,
290 sf_item.requested, sf_item.holder);
291 sf_item.holder = 0;
292 }
293 assert(!cpkt->isWriteback());
294 // @todo Deal with invalidating responses
295 sf_item.holder |= req_mask;
296 sf_item.requested &= ~req_mask;
297 assert((sf_item.requested | sf_item.holder).any());
298 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
299 __func__, sf_item.requested, sf_item.holder);
300}
301
302void
303SnoopFilter::updateSnoopForward(const Packet* cpkt,
304 const SlavePort& rsp_port, const MasterPort& req_port)
305{
306 DPRINTF(SnoopFilter, "%s: rsp %s req %s packet %s\n",
307 __func__, rsp_port.name(), req_port.name(), cpkt->print());
308
309 assert(cpkt->isResponse());
310 assert(cpkt->cacheResponding());
311
312 Addr line_addr = cpkt->getBlockAddr(linesize);
313 if (cpkt->isSecure()) {
314 line_addr |= LineSecure;
315 }
316 auto sf_it = cachedLocations.find(line_addr);
317 bool is_hit = sf_it != cachedLocations.end();
318
319 // Nothing to do if it is not a hit
320 if (!is_hit)
321 return;
322
240 return snoopSelected(maskToPortList(interested), lookupLatency);
241}
242
243void
244SnoopFilter::updateSnoopResponse(const Packet* cpkt,
245 const SlavePort& rsp_port,
246 const SlavePort& req_port)
247{
248 DPRINTF(SnoopFilter, "%s: rsp %s req %s packet %s\n",
249 __func__, rsp_port.name(), req_port.name(), cpkt->print());
250
251 assert(cpkt->isResponse());
252 assert(cpkt->cacheResponding());
253
254 // if this snoop response is due to an uncacheable request, or is
255 // being turned into a normal response, there is nothing more to
256 // do
257 if (cpkt->req->isUncacheable() || !req_port.isSnooping()) {
258 return;
259 }
260
261 Addr line_addr = cpkt->getBlockAddr(linesize);
262 if (cpkt->isSecure()) {
263 line_addr |= LineSecure;
264 }
265 SnoopMask rsp_mask = portToMask(rsp_port);
266 SnoopMask req_mask = portToMask(req_port);
267 SnoopItem& sf_item = cachedLocations[line_addr];
268
269 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
270 __func__, sf_item.requested, sf_item.holder);
271
272 // The source should have the line
273 panic_if((sf_item.holder & rsp_mask).none(),
274 "SF value %x.%x does not have the line\n",
275 sf_item.requested, sf_item.holder);
276
277 // The destination should have had a request in
278 panic_if((sf_item.requested & req_mask).none(), "SF value %x.%x missing "\
279 "the original request\n", sf_item.requested, sf_item.holder);
280
281 // If the snoop response has no sharers the line is passed in
282 // Modified state, and we know that there are no other copies, or
283 // they will all be invalidated imminently
284 if (!cpkt->hasSharers()) {
285 DPRINTF(SnoopFilter,
286 "%s: dropping %x because non-shared snoop "
287 "response SF val: %x.%x\n", __func__, rsp_mask,
288 sf_item.requested, sf_item.holder);
289 sf_item.holder = 0;
290 }
291 assert(!cpkt->isWriteback());
292 // @todo Deal with invalidating responses
293 sf_item.holder |= req_mask;
294 sf_item.requested &= ~req_mask;
295 assert((sf_item.requested | sf_item.holder).any());
296 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
297 __func__, sf_item.requested, sf_item.holder);
298}
299
300void
301SnoopFilter::updateSnoopForward(const Packet* cpkt,
302 const SlavePort& rsp_port, const MasterPort& req_port)
303{
304 DPRINTF(SnoopFilter, "%s: rsp %s req %s packet %s\n",
305 __func__, rsp_port.name(), req_port.name(), cpkt->print());
306
307 assert(cpkt->isResponse());
308 assert(cpkt->cacheResponding());
309
310 Addr line_addr = cpkt->getBlockAddr(linesize);
311 if (cpkt->isSecure()) {
312 line_addr |= LineSecure;
313 }
314 auto sf_it = cachedLocations.find(line_addr);
315 bool is_hit = sf_it != cachedLocations.end();
316
317 // Nothing to do if it is not a hit
318 if (!is_hit)
319 return;
320
323 SnoopItem& sf_item = sf_it->second;
324
325 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
326 __func__, sf_item.requested, sf_item.holder);
327
328 // If the snoop response has no sharers the line is passed in
329 // Modified state, and we know that there are no other copies, or
330 // they will all be invalidated imminently
331 if (!cpkt->hasSharers()) {
321 // If the snoop response has no sharers the line is passed in
322 // Modified state, and we know that there are no other copies, or
323 // they will all be invalidated imminently
324 if (!cpkt->hasSharers()) {
325 SnoopItem& sf_item = sf_it->second;
326
327 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
328 __func__, sf_item.requested, sf_item.holder);
332 sf_item.holder = 0;
329 sf_item.holder = 0;
333 }
334 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
335 __func__, sf_item.requested, sf_item.holder);
336 eraseIfNullEntry(sf_it);
330 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
331 __func__, sf_item.requested, sf_item.holder);
337
332
333 eraseIfNullEntry(sf_it);
334 }
338}
339
340void
341SnoopFilter::updateResponse(const Packet* cpkt, const SlavePort& slave_port)
342{
343 DPRINTF(SnoopFilter, "%s: src %s packet %s\n",
344 __func__, slave_port.name(), cpkt->print());
345
346 assert(cpkt->isResponse());
347
348 // we only allocate if the packet actually came from a cache, but
349 // start by checking if the port is snooping
350 if (cpkt->req->isUncacheable() || !slave_port.isSnooping())
351 return;
352
353 // next check if we actually allocated an entry
354 Addr line_addr = cpkt->getBlockAddr(linesize);
355 if (cpkt->isSecure()) {
356 line_addr |= LineSecure;
357 }
358 auto sf_it = cachedLocations.find(line_addr);
359 if (sf_it == cachedLocations.end())
360 return;
361
362 SnoopMask slave_mask = portToMask(slave_port);
363 SnoopItem& sf_item = sf_it->second;
364
365 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
366 __func__, sf_item.requested, sf_item.holder);
367
368 // Make sure we have seen the actual request, too
369 panic_if((sf_item.requested & slave_mask).none(),
370 "SF value %x.%x missing request bit\n",
371 sf_item.requested, sf_item.holder);
372
373 sf_item.requested &= ~slave_mask;
374 // Update the residency of the cache line.
375
376 if (cpkt->req->isCacheMaintenance()) {
377 // A cache clean response does not carry any data so it
378 // shouldn't change the holders, unless it is invalidating.
379 if (cpkt->isInvalidate()) {
380 sf_item.holder &= ~slave_mask;
381 }
382 eraseIfNullEntry(sf_it);
383 } else {
384 // Any other response implies that a cache above will have the
385 // block.
386 sf_item.holder |= slave_mask;
387 assert((sf_item.holder | sf_item.requested).any());
388 }
389 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
390 __func__, sf_item.requested, sf_item.holder);
391}
392
393void
394SnoopFilter::regStats()
395{
396 SimObject::regStats();
397
398 totRequests
399 .name(name() + ".tot_requests")
400 .desc("Total number of requests made to the snoop filter.");
401
402 hitSingleRequests
403 .name(name() + ".hit_single_requests")
404 .desc("Number of requests hitting in the snoop filter with a single "\
405 "holder of the requested data.");
406
407 hitMultiRequests
408 .name(name() + ".hit_multi_requests")
409 .desc("Number of requests hitting in the snoop filter with multiple "\
410 "(>1) holders of the requested data.");
411
412 totSnoops
413 .name(name() + ".tot_snoops")
414 .desc("Total number of snoops made to the snoop filter.");
415
416 hitSingleSnoops
417 .name(name() + ".hit_single_snoops")
418 .desc("Number of snoops hitting in the snoop filter with a single "\
419 "holder of the requested data.");
420
421 hitMultiSnoops
422 .name(name() + ".hit_multi_snoops")
423 .desc("Number of snoops hitting in the snoop filter with multiple "\
424 "(>1) holders of the requested data.");
425}
426
427SnoopFilter *
428SnoopFilterParams::create()
429{
430 return new SnoopFilter(this);
431}
335}
336
337void
338SnoopFilter::updateResponse(const Packet* cpkt, const SlavePort& slave_port)
339{
340 DPRINTF(SnoopFilter, "%s: src %s packet %s\n",
341 __func__, slave_port.name(), cpkt->print());
342
343 assert(cpkt->isResponse());
344
345 // we only allocate if the packet actually came from a cache, but
346 // start by checking if the port is snooping
347 if (cpkt->req->isUncacheable() || !slave_port.isSnooping())
348 return;
349
350 // next check if we actually allocated an entry
351 Addr line_addr = cpkt->getBlockAddr(linesize);
352 if (cpkt->isSecure()) {
353 line_addr |= LineSecure;
354 }
355 auto sf_it = cachedLocations.find(line_addr);
356 if (sf_it == cachedLocations.end())
357 return;
358
359 SnoopMask slave_mask = portToMask(slave_port);
360 SnoopItem& sf_item = sf_it->second;
361
362 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
363 __func__, sf_item.requested, sf_item.holder);
364
365 // Make sure we have seen the actual request, too
366 panic_if((sf_item.requested & slave_mask).none(),
367 "SF value %x.%x missing request bit\n",
368 sf_item.requested, sf_item.holder);
369
370 sf_item.requested &= ~slave_mask;
371 // Update the residency of the cache line.
372
373 if (cpkt->req->isCacheMaintenance()) {
374 // A cache clean response does not carry any data so it
375 // shouldn't change the holders, unless it is invalidating.
376 if (cpkt->isInvalidate()) {
377 sf_item.holder &= ~slave_mask;
378 }
379 eraseIfNullEntry(sf_it);
380 } else {
381 // Any other response implies that a cache above will have the
382 // block.
383 sf_item.holder |= slave_mask;
384 assert((sf_item.holder | sf_item.requested).any());
385 }
386 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
387 __func__, sf_item.requested, sf_item.holder);
388}
389
390void
391SnoopFilter::regStats()
392{
393 SimObject::regStats();
394
395 totRequests
396 .name(name() + ".tot_requests")
397 .desc("Total number of requests made to the snoop filter.");
398
399 hitSingleRequests
400 .name(name() + ".hit_single_requests")
401 .desc("Number of requests hitting in the snoop filter with a single "\
402 "holder of the requested data.");
403
404 hitMultiRequests
405 .name(name() + ".hit_multi_requests")
406 .desc("Number of requests hitting in the snoop filter with multiple "\
407 "(>1) holders of the requested data.");
408
409 totSnoops
410 .name(name() + ".tot_snoops")
411 .desc("Total number of snoops made to the snoop filter.");
412
413 hitSingleSnoops
414 .name(name() + ".hit_single_snoops")
415 .desc("Number of snoops hitting in the snoop filter with a single "\
416 "holder of the requested data.");
417
418 hitMultiSnoops
419 .name(name() + ".hit_multi_snoops")
420 .desc("Number of snoops hitting in the snoop filter with multiple "\
421 "(>1) holders of the requested data.");
422}
423
424SnoopFilter *
425SnoopFilterParams::create()
426{
427 return new SnoopFilter(this);
428}