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