* (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
*/
/**
* @file
- * Definition of a snoop filter.
+ * Implementation of a snoop filter.
*/
#include "base/misc.hh"
bool allocate = !cpkt->req->isUncacheable() && slave_port.isSnooping();
Addr line_addr = cpkt->getBlockAddr(linesize);
SnoopMask req_port = portToMask(slave_port);
- auto sf_it = cachedLocations.find(line_addr);
- bool is_hit = (sf_it != cachedLocations.end());
+ reqLookupResult = cachedLocations.find(line_addr);
+ bool is_hit = (reqLookupResult != cachedLocations.end());
// If the snoop filter has no entry, and we should not allocate,
// do not create a new snoop filter entry, simply return a NULL
if (!is_hit && !allocate)
return snoopDown(lookupLatency);
- // Create a new element through operator[] and modify in-place
- SnoopItem& sf_item = is_hit ? sf_it->second : cachedLocations[line_addr];
+ // If no hit in snoop filter create a new element and update iterator
+ if (!is_hit)
+ reqLookupResult = cachedLocations.emplace(line_addr, SnoopItem()).first;
+ SnoopItem& sf_item = reqLookupResult->second;
SnoopMask interested = sf_item.holder | sf_item.requested;
// Store unmodified value of snoop filter item in temp storage in
lookupLatency);
if (cpkt->needsResponse()) {
- if (!cpkt->memInhibitAsserted()) {
+ if (!cpkt->cacheResponding()) {
// Max one request per address per port
panic_if(sf_item.requested & req_port, "double request :( " \
"SF value %x.%x\n", sf_item.requested, sf_item.holder);
__func__, sf_item.requested, sf_item.holder);
}
} else { // if (!cpkt->needsResponse())
- assert(cpkt->evictingBlock());
+ assert(cpkt->isEviction());
// make sure that the sender actually had the line
panic_if(!(sf_item.holder & req_port), "requester %x is not a " \
"holder :( SF value %x.%x\n", req_port,
}
void
-SnoopFilter::updateRequest(const Packet* cpkt, const SlavePort& slave_port,
- bool will_retry)
+SnoopFilter::finishRequest(bool will_retry, const Packet* cpkt)
{
- DPRINTF(SnoopFilter, "%s: packet src %s addr 0x%x cmd %s\n",
- __func__, slave_port.name(), cpkt->getAddr(), cpkt->cmdString());
-
- // Ultimately we should check if the packet came from an
- // allocating source, not just if the port is snooping
- bool allocate = !cpkt->req->isUncacheable() && slave_port.isSnooping();
- if (!allocate)
- return;
+ if (reqLookupResult != cachedLocations.end()) {
+ // since we rely on the caller, do a basic check to ensure
+ // that finishRequest is being called following lookupRequest
+ assert(reqLookupResult->first == cpkt->getBlockAddr(linesize));
+ if (will_retry) {
+ // Undo any changes made in lookupRequest to the snoop filter
+ // entry if the request will come again. retryItem holds
+ // the previous value of the snoopfilter entry.
+ reqLookupResult->second = retryItem;
+
+ DPRINTF(SnoopFilter, "%s: restored SF value %x.%x\n",
+ __func__, retryItem.requested, retryItem.holder);
+ }
- Addr line_addr = cpkt->getBlockAddr(linesize);
- auto sf_it = cachedLocations.find(line_addr);
- assert(sf_it != cachedLocations.end());
- if (will_retry) {
- // Undo any changes made in lookupRequest to the snoop filter
- // entry if the request will come again. retryItem holds
- // the previous value of the snoopfilter entry.
- sf_it->second = retryItem;
-
- DPRINTF(SnoopFilter, "%s: restored SF value %x.%x\n",
- __func__, retryItem.requested, retryItem.holder);
+ eraseIfNullEntry(reqLookupResult);
}
-
- eraseIfNullEntry(sf_it);
}
std::pair<SnoopFilter::SnoopList, Cycles>
assert(cpkt->isRequest());
- // Broadcast / filter upward snoops
- const bool filter_upward = true; // @todo: Make configurable
-
- if (!filter_upward)
- return snoopAll(lookupLatency);
-
Addr line_addr = cpkt->getBlockAddr(linesize);
auto sf_it = cachedLocations.find(line_addr);
bool is_hit = (sf_it != cachedLocations.end());
- // If the snoop filter has no entry and its an uncacheable
- // request, do not create a new snoop filter entry, simply return
- // a NULL portlist.
- if (!is_hit && cpkt->req->isUncacheable())
- return snoopDown(lookupLatency);
+ panic_if(!is_hit && (cachedLocations.size() >= maxEntryCount),
+ "snoop filter exceeded capacity of %d cache blocks\n",
+ maxEntryCount);
- // If no hit in snoop filter create a new element and update iterator
+ // If the snoop filter has no entry, simply return a NULL
+ // portlist, there is no point creating an entry only to remove it
+ // later
if (!is_hit)
- sf_it = cachedLocations.emplace(line_addr, SnoopItem()).first;
+ return snoopDown(lookupLatency);
+
SnoopItem& sf_item = sf_it->second;
DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
SnoopMask interested = (sf_item.holder | sf_item.requested);
totSnoops++;
- if (is_hit) {
- // Single bit set -> value is a power of two
- if (isPow2(interested))
- hitSingleSnoops++;
- else
- hitMultiSnoops++;
- }
+ // Single bit set -> value is a power of two
+ if (isPow2(interested))
+ hitSingleSnoops++;
+ else
+ hitMultiSnoops++;
+
// ReadEx and Writes require both invalidation and exlusivity, while reads
// require neither. Writebacks on the other hand require exclusivity but
// not the invalidation. Previously Writebacks did not generate upward
// snoops so this was never an aissue. Now that Writebacks generate snoops
// we need to special case for Writebacks.
- assert(cpkt->cmd == MemCmd::Writeback || cpkt->req->isUncacheable() ||
- (cpkt->isInvalidate() == cpkt->needsExclusive()));
+ assert(cpkt->isWriteback() || cpkt->req->isUncacheable() ||
+ (cpkt->isInvalidate() == cpkt->needsWritable()));
if (cpkt->isInvalidate() && !sf_item.requested) {
// Early clear of the holder, if no other request is currently going on
// @todo: This should possibly be updated even though we do not filter
cpkt->cmdString());
assert(cpkt->isResponse());
- assert(cpkt->memInhibitAsserted());
+ assert(cpkt->cacheResponding());
// Ultimately we should check if the packet came from an
// allocating source, not just if the port is snooping
panic_if(!(sf_item.requested & req_mask), "SF value %x.%x missing "\
"the original request\n", sf_item.requested, sf_item.holder);
- // Update the residency of the cache line.
- if (cpkt->needsExclusive() || !cpkt->sharedAsserted()) {
- DPRINTF(SnoopFilter, "%s: dropping %x because needs: %i shared: %i "\
- "SF val: %x.%x\n", __func__, rsp_mask,
- cpkt->needsExclusive(), cpkt->sharedAsserted(),
+ // If the snoop response has no sharers the line is passed in
+ // Modified state, and we know that there are no other copies, or
+ // they will all be invalidated imminently
+ if (!cpkt->hasSharers()) {
+ DPRINTF(SnoopFilter,
+ "%s: dropping %x because non-shared snoop "
+ "response SF val: %x.%x\n", __func__, rsp_mask,
sf_item.requested, sf_item.holder);
-
- sf_item.holder &= ~rsp_mask;
- // The snoop filter does not see any ACKs from non-responding sharers
- // that have been invalidated :( So below assert would be nice, but..
- //assert(sf_item.holder == 0);
sf_item.holder = 0;
}
- assert(cpkt->cmd != MemCmd::Writeback);
+ assert(!cpkt->isWriteback());
sf_item.holder |= req_mask;
sf_item.requested &= ~req_mask;
assert(sf_item.requested | sf_item.holder);
__func__, rsp_port.name(), req_port.name(), cpkt->getAddr(),
cpkt->cmdString());
+ assert(cpkt->isResponse());
+ assert(cpkt->cacheResponding());
+
Addr line_addr = cpkt->getBlockAddr(linesize);
auto sf_it = cachedLocations.find(line_addr);
- if (sf_it == cachedLocations.end())
- sf_it = cachedLocations.emplace(line_addr, SnoopItem()).first;
- SnoopItem& sf_item = sf_it->second;
- SnoopMask rsp_mask M5_VAR_USED = portToMask(rsp_port);
+ bool is_hit = sf_it != cachedLocations.end();
- assert(cpkt->isResponse());
- assert(cpkt->memInhibitAsserted());
+ // Nothing to do if it is not a hit
+ if (!is_hit)
+ return;
+
+ SnoopItem& sf_item = sf_it->second;
DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n",
__func__, sf_item.requested, sf_item.holder);
- // Remote (to this snoop filter) snoops update the filter already when they
- // arrive from below, because we may not see any response.
- if (cpkt->needsExclusive()) {
- // If the request to this snoop response hit an in-flight transaction,
- // the holder was not reset -> no assertion & do that here, now!
- //assert(sf_item.holder == 0);
+ // If the snoop response has no sharers the line is passed in
+ // Modified state, and we know that there are no other copies, or
+ // they will all be invalidated imminently
+ if (!cpkt->hasSharers()) {
sf_item.holder = 0;
}
DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n",
__func__, sf_item.requested, sf_item.holder);
eraseIfNullEntry(sf_it);
+
}
void
panic_if(!(sf_item.requested & slave_mask), "SF value %x.%x missing "\
"request bit\n", sf_item.requested, sf_item.holder);
- // Update the residency of the cache line. Here we assume that the
- // line has been zapped in all caches that are not the responder.
- if (cpkt->needsExclusive() || !cpkt->sharedAsserted())
+ // Update the residency of the cache line. If the response has no
+ // sharers we know that the line has been invalidated in all
+ // branches that are not where we are responding to.
+ if (!cpkt->hasSharers())
sf_item.holder = 0;
sf_item.holder |= slave_mask;
sf_item.requested &= ~slave_mask;