snoop_filter.cc revision 10399
16145SN/A/* 28257SN/A * Copyright (c) 2013 ARM Limited 36145SN/A * All rights reserved 46145SN/A * 56145SN/A * The license below extends only to copyright in the software and shall 66145SN/A * not be construed as granting a license to any other intellectual 76145SN/A * property including but not limited to intellectual property relating 86145SN/A * to a hardware implementation of the functionality of the software 96145SN/A * licensed hereunder. You may use the software subject to the license 106145SN/A * terms below provided that you ensure that this notice is replicated 116145SN/A * unmodified and in its entirety in all distributions of the software, 126145SN/A * modified or unmodified, in source code or in binary form. 136145SN/A * 146145SN/A * Redistribution and use in source and binary forms, with or without 156145SN/A * modification, are permitted provided that the following conditions are 166145SN/A * met: redistributions of source code must retain the above copyright 176145SN/A * notice, this list of conditions and the following disclaimer; 186145SN/A * redistributions in binary form must reproduce the above copyright 196145SN/A * notice, this list of conditions and the following disclaimer in the 206145SN/A * documentation and/or other materials provided with the distribution; 216145SN/A * neither the name of the copyright holders nor the names of its 226145SN/A * contributors may be used to endorse or promote products derived from 236145SN/A * this software without specific prior written permission. 246145SN/A * 256145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 266145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 276145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 286145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 298258SBrad.Beckmann@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 308258SBrad.Beckmann@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 316145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327055SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337055SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347454SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357055SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368258SBrad.Beckmann@amd.com * 378258SBrad.Beckmann@amd.com * Authors: Stephan Diestelhorst <stephan.diestelhorst@arm.com> 388258SBrad.Beckmann@amd.com */ 396145SN/A 408258SBrad.Beckmann@amd.com/** 417054SN/A * @file 427054SN/A * Definition of a snoop filter. 438258SBrad.Beckmann@amd.com */ 448258SBrad.Beckmann@amd.com 458257SN/A#include "base/misc.hh" 466145SN/A#include "base/trace.hh" 478258SBrad.Beckmann@amd.com#include "debug/SnoopFilter.hh" 488257SN/A#include "mem/snoop_filter.hh" 496493SN/A#include "sim/system.hh" 508257SN/A 516145SN/Astd::pair<SnoopFilter::SnoopList, Cycles> 526145SN/ASnoopFilter::lookupRequest(const Packet* cpkt, const SlavePort& slave_port) 537055SN/A{ 548258SBrad.Beckmann@amd.com DPRINTF(SnoopFilter, "%s: packet src %s addr 0x%x cmd %s\n", 556145SN/A __func__, slave_port.name(), cpkt->getAddr(), cpkt->cmdString()); 567054SN/A 577055SN/A Addr line_addr = cpkt->getAddr() & ~(linesize - 1); 587054SN/A SnoopMask req_port = portToMask(slave_port); 596145SN/A SnoopItem& sf_item = cachedLocations[line_addr]; 606145SN/A 618258SBrad.Beckmann@amd.com DPRINTF(SnoopFilter, "%s: SF value %x.%x\n", 628257SN/A __func__, sf_item.requested, sf_item.holder); 638257SN/A 648258SBrad.Beckmann@amd.com if (cpkt->needsResponse()) { 658258SBrad.Beckmann@amd.com if (!cpkt->memInhibitAsserted()) { 668257SN/A // Max one request per address per port 678257SN/A panic_if(sf_item.requested & req_port, "double request :( "\ 688257SN/A "SF value %x.%x\n", sf_item.requested, sf_item.holder); 698258SBrad.Beckmann@amd.com 708257SN/A // Mark in-flight requests to distinguish later on 718258SBrad.Beckmann@amd.com sf_item.requested |= req_port; 728257SN/A } else { 738257SN/A // NOTE: The memInhibit might have been asserted by a cache closer 748258SBrad.Beckmann@amd.com // to the CPU, already -> the response will not be seen by this 758258SBrad.Beckmann@amd.com // filter -> we do not need to keep the in-flight request, but make 768257SN/A // sure that we know that that cluster has a copy 778258SBrad.Beckmann@amd.com panic_if(!(sf_item.holder & req_port), "Need to hold the value!"); 788258SBrad.Beckmann@amd.com DPRINTF(SnoopFilter, "%s: not marking request. SF value %x.%x\n", 798258SBrad.Beckmann@amd.com __func__, sf_item.requested, sf_item.holder); 808258SBrad.Beckmann@amd.com } 818257SN/A DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n", 828258SBrad.Beckmann@amd.com __func__, sf_item.requested, sf_item.holder); 83 } 84 SnoopMask interested = (sf_item.holder | sf_item.requested) & ~req_port; 85 return snoopSelected(maskToPortList(interested), lookupLatency); 86} 87 88void 89SnoopFilter::updateRequest(const Packet* cpkt, const SlavePort& slave_port, 90 bool will_retry) 91{ 92 DPRINTF(SnoopFilter, "%s: packet src %s addr 0x%x cmd %s\n", 93 __func__, slave_port.name(), cpkt->getAddr(), cpkt->cmdString()); 94 95 Addr line_addr = cpkt->getAddr() & ~(linesize - 1); 96 SnoopMask req_port = portToMask(slave_port); 97 SnoopItem& sf_item = cachedLocations[line_addr]; 98 99 DPRINTF(SnoopFilter, "%s: old SF value %x.%x retry: %i\n", 100 __func__, sf_item.requested, sf_item.holder, will_retry); 101 102 if (will_retry) { 103 // Unmark a request that will come again. 104 sf_item.requested &= ~req_port; 105 return; 106 } 107 108 // will_retry == false 109 if (!cpkt->needsResponse()) { 110 // Packets that will not evoke a response but still need updates of the 111 // snoop filter; WRITEBACKs for now only 112 if (cpkt->cmd == MemCmd::Writeback) { 113 // make sure that the sender actually had the line 114 panic_if(sf_item.requested & req_port, "double request :( "\ 115 "SF value %x.%x\n", sf_item.requested, sf_item.holder); 116 panic_if(!(sf_item.holder & req_port), "requester %x is not a "\ 117 "holder :( SF value %x.%x\n", req_port, 118 sf_item.requested, sf_item.holder); 119 // Writebacks -> the sender does not have the line anymore 120 sf_item.holder &= ~req_port; 121 } else { 122 assert(0 == "Handle non-writeback, here"); 123 } 124 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n", 125 __func__, sf_item.requested, sf_item.holder); 126 } 127} 128 129std::pair<SnoopFilter::SnoopList, Cycles> 130SnoopFilter::lookupSnoop(const Packet* cpkt) 131{ 132 DPRINTF(SnoopFilter, "%s: packet addr 0x%x cmd %s\n", 133 __func__, cpkt->getAddr(), cpkt->cmdString()); 134 135 assert(cpkt->isRequest()); 136 137 // Broadcast / filter upward snoops 138 const bool filter_upward = true; // @todo: Make configurable 139 140 if (!filter_upward) 141 return snoopAll(lookupLatency); 142 143 Addr line_addr = cpkt->getAddr() & ~(linesize - 1); 144 SnoopItem& sf_item = cachedLocations[line_addr]; 145 146 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n", 147 __func__, sf_item.requested, sf_item.holder); 148 149 SnoopMask interested = (sf_item.holder | sf_item.requested); 150 assert(cpkt->isInvalidate() == cpkt->needsExclusive()); 151 if (cpkt->isInvalidate() && !sf_item.requested) { 152 // Early clear of the holder, if no other request is currently going on 153 // @todo: This should possibly be updated even though we do not filter 154 // upward snoops 155 sf_item.holder = 0; 156 } 157 158 DPRINTF(SnoopFilter, "%s: new SF value %x.%x interest: %x \n", 159 __func__, sf_item.requested, sf_item.holder, interested); 160 161 return snoopSelected(maskToPortList(interested), lookupLatency); 162} 163 164void 165SnoopFilter::updateSnoopResponse(const Packet* cpkt, 166 const SlavePort& rsp_port, 167 const SlavePort& req_port) 168{ 169 DPRINTF(SnoopFilter, "%s: packet rsp %s req %s addr 0x%x cmd %s\n", 170 __func__, rsp_port.name(), req_port.name(), cpkt->getAddr(), 171 cpkt->cmdString()); 172 173 Addr line_addr = cpkt->getAddr() & ~(linesize - 1); 174 SnoopMask rsp_mask = portToMask(rsp_port); 175 SnoopMask req_mask = portToMask(req_port); 176 SnoopItem& sf_item = cachedLocations[line_addr]; 177 178 assert(cpkt->isResponse()); 179 assert(cpkt->memInhibitAsserted()); 180 181 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n", 182 __func__, sf_item.requested, sf_item.holder); 183 184 // The source should have the line 185 panic_if(!(sf_item.holder & rsp_mask), "SF value %x.%x does not have "\ 186 "the line\n", sf_item.requested, sf_item.holder); 187 188 // The destination should have had a request in 189 panic_if(!(sf_item.requested & req_mask), "SF value %x.%x missing "\ 190 "the original request\n", sf_item.requested, sf_item.holder); 191 192 // Update the residency of the cache line. 193 if (cpkt->needsExclusive() || !cpkt->sharedAsserted()) { 194 DPRINTF(SnoopFilter, "%s: dropping %x because needs: %i shared: %i "\ 195 "SF val: %x.%x\n", __func__, rsp_mask, 196 cpkt->needsExclusive(), cpkt->sharedAsserted(), 197 sf_item.requested, sf_item.holder); 198 199 sf_item.holder &= ~rsp_mask; 200 // The snoop filter does not see any ACKs from non-responding sharers 201 // that have been invalidated :( So below assert would be nice, but.. 202 //assert(sf_item.holder == 0); 203 sf_item.holder = 0; 204 } 205 assert(cpkt->cmd != MemCmd::Writeback); 206 sf_item.holder |= req_mask; 207 sf_item.requested &= ~req_mask; 208 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n", 209 __func__, sf_item.requested, sf_item.holder); 210} 211 212void 213SnoopFilter::updateSnoopForward(const Packet* cpkt, 214 const SlavePort& rsp_port, const MasterPort& req_port) 215{ 216 DPRINTF(SnoopFilter, "%s: packet rsp %s req %s addr 0x%x cmd %s\n", 217 __func__, rsp_port.name(), req_port.name(), cpkt->getAddr(), 218 cpkt->cmdString()); 219 220 Addr line_addr = cpkt->getAddr() & ~(linesize - 1); 221 SnoopItem& sf_item = cachedLocations[line_addr]; 222 SnoopMask rsp_mask M5_VAR_USED = portToMask(rsp_port); 223 224 assert(cpkt->isResponse()); 225 assert(cpkt->memInhibitAsserted()); 226 227 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n", 228 __func__, sf_item.requested, sf_item.holder); 229 230 // Remote (to this snoop filter) snoops update the filter already when they 231 // arrive from below, because we may not see any response. 232 if (cpkt->needsExclusive()) { 233 // If the request to this snoop response hit an in-flight transaction, 234 // the holder was not reset -> no assertion & do that here, now! 235 //assert(sf_item.holder == 0); 236 sf_item.holder = 0; 237 } 238 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n", 239 __func__, sf_item.requested, sf_item.holder); 240} 241 242void 243SnoopFilter::updateResponse(const Packet* cpkt, const SlavePort& slave_port) 244{ 245 DPRINTF(SnoopFilter, "%s: packet src %s addr 0x%x cmd %s\n", 246 __func__, slave_port.name(), cpkt->getAddr(), cpkt->cmdString()); 247 248 Addr line_addr = cpkt->getAddr() & ~(linesize - 1); 249 SnoopMask slave_mask = portToMask(slave_port); 250 SnoopItem& sf_item = cachedLocations[line_addr]; 251 252 assert(cpkt->isResponse()); 253 254 DPRINTF(SnoopFilter, "%s: old SF value %x.%x\n", 255 __func__, sf_item.requested, sf_item.holder); 256 257 // Make sure we have seen the actual request, too 258 panic_if(!(sf_item.requested & slave_mask), "SF value %x.%x missing "\ 259 "request bit\n", sf_item.requested, sf_item.holder); 260 261 // Update the residency of the cache line. 262 if (cpkt->needsExclusive() || !cpkt->sharedAsserted()) 263 sf_item.holder = 0; 264 sf_item.holder |= slave_mask; 265 sf_item.requested &= ~slave_mask; 266 DPRINTF(SnoopFilter, "%s: new SF value %x.%x\n", 267 __func__, sf_item.requested, sf_item.holder); 268} 269 270SnoopFilter * 271SnoopFilterParams::create() 272{ 273 return new SnoopFilter(this); 274} 275