mshr.cc revision 7667
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * Copyright (c) 2010 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Erik Hallnor
30 *          Dave Greene
31 */
32
33/**
34 * @file
35 * Miss Status and Handling Register (MSHR) definitions.
36 */
37
38#include <algorithm>
39#include <cassert>
40#include <string>
41#include <vector>
42
43#include "base/misc.hh"
44#include "base/types.hh"
45#include "mem/cache/cache.hh"
46#include "mem/cache/mshr.hh"
47#include "sim/core.hh"
48
49using namespace std;
50
51MSHR::MSHR()
52{
53    inService = false;
54    ntargets = 0;
55    threadNum = InvalidThreadID;
56    targets = new TargetList();
57    deferredTargets = new TargetList();
58}
59
60
61MSHR::TargetList::TargetList()
62    : needsExclusive(false), hasUpgrade(false)
63{}
64
65
66inline void
67MSHR::TargetList::add(PacketPtr pkt, Tick readyTime,
68                      Counter order, Target::Source source, bool markPending)
69{
70    if (source != Target::FromSnoop) {
71        if (pkt->needsExclusive()) {
72            needsExclusive = true;
73        }
74
75        if (pkt->isUpgrade()) {
76            hasUpgrade = true;
77        }
78    }
79
80    if (markPending) {
81        MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
82        if (mshr != NULL) {
83            assert(!mshr->downstreamPending);
84            mshr->downstreamPending = true;
85        }
86    }
87
88    push_back(Target(pkt, readyTime, order, source, markPending));
89}
90
91
92static void
93replaceUpgrade(PacketPtr pkt)
94{
95    if (pkt->cmd == MemCmd::UpgradeReq) {
96        pkt->cmd = MemCmd::ReadExReq;
97        DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n");
98    } else if (pkt->cmd == MemCmd::SCUpgradeReq) {
99        pkt->cmd = MemCmd::SCUpgradeFailReq;
100        DPRINTF(Cache, "Replacing SCUpgradeReq with SCUpgradeFailReq\n");
101    }
102}
103
104
105void
106MSHR::TargetList::replaceUpgrades()
107{
108    if (!hasUpgrade)
109        return;
110
111    Iterator end_i = end();
112    for (Iterator i = begin(); i != end_i; ++i) {
113        replaceUpgrade(i->pkt);
114    }
115
116    hasUpgrade = false;
117}
118
119
120void
121MSHR::TargetList::clearDownstreamPending()
122{
123    Iterator end_i = end();
124    for (Iterator i = begin(); i != end_i; ++i) {
125        if (i->markedPending) {
126            MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState);
127            if (mshr != NULL) {
128                mshr->clearDownstreamPending();
129            }
130        }
131    }
132}
133
134
135bool
136MSHR::TargetList::checkFunctional(PacketPtr pkt)
137{
138    Iterator end_i = end();
139    for (Iterator i = begin(); i != end_i; ++i) {
140        if (pkt->checkFunctional(i->pkt)) {
141            return true;
142        }
143    }
144
145    return false;
146}
147
148
149void
150MSHR::TargetList::
151print(std::ostream &os, int verbosity, const std::string &prefix) const
152{
153    ConstIterator end_i = end();
154    for (ConstIterator i = begin(); i != end_i; ++i) {
155        const char *s;
156        switch (i->source) {
157          case Target::FromCPU: s = "FromCPU";
158          case Target::FromSnoop: s = "FromSnoop";
159          case Target::FromPrefetcher: s = "FromPrefetcher";
160          default: s = "";
161        }
162        ccprintf(os, "%s%s: ", prefix, s);
163        i->pkt->print(os, verbosity, "");
164    }
165}
166
167
168void
169MSHR::allocate(Addr _addr, int _size, PacketPtr target,
170               Tick whenReady, Counter _order)
171{
172    addr = _addr;
173    size = _size;
174    readyTime = whenReady;
175    order = _order;
176    assert(target);
177    isForward = false;
178    _isUncacheable = target->req->isUncacheable();
179    inService = false;
180    downstreamPending = false;
181    threadNum = 0;
182    ntargets = 1;
183    assert(targets->isReset());
184    // Don't know of a case where we would allocate a new MSHR for a
185    // snoop (mem-side request), so set source according to request here
186    Target::Source source = (target->cmd == MemCmd::HardPFReq) ?
187        Target::FromPrefetcher : Target::FromCPU;
188    targets->add(target, whenReady, _order, source, true);
189    assert(deferredTargets->isReset());
190    data = NULL;
191}
192
193
194void
195MSHR::clearDownstreamPending()
196{
197    assert(downstreamPending);
198    downstreamPending = false;
199    // recursively clear flag on any MSHRs we will be forwarding
200    // responses to
201    targets->clearDownstreamPending();
202}
203
204bool
205MSHR::markInService(PacketPtr pkt)
206{
207    assert(!inService);
208    if (isForwardNoResponse()) {
209        // we just forwarded the request packet & don't expect a
210        // response, so get rid of it
211        assert(getNumTargets() == 1);
212        popTarget();
213        return true;
214    }
215    inService = true;
216    pendingDirty = (targets->needsExclusive ||
217                    (!pkt->sharedAsserted() && pkt->memInhibitAsserted()));
218    postInvalidate = postDowngrade = false;
219
220    if (!downstreamPending) {
221        // let upstream caches know that the request has made it to a
222        // level where it's going to get a response
223        targets->clearDownstreamPending();
224    }
225    return false;
226}
227
228
229void
230MSHR::deallocate()
231{
232    assert(targets->empty());
233    targets->resetFlags();
234    assert(deferredTargets->isReset());
235    assert(ntargets == 0);
236    inService = false;
237}
238
239/*
240 * Adds a target to an MSHR
241 */
242void
243MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order)
244{
245    // if there's a request already in service for this MSHR, we will
246    // have to defer the new target until after the response if any of
247    // the following are true:
248    // - there are other targets already deferred
249    // - there's a pending invalidate to be applied after the response
250    //   comes back (but before this target is processed)
251    // - this target requires an exclusive block and either we're not
252    //   getting an exclusive block back or we have already snooped
253    //   another read request that will downgrade our exclusive block
254    //   to shared
255
256    // assume we'd never issue a prefetch when we've got an
257    // outstanding miss
258    assert(pkt->cmd != MemCmd::HardPFReq);
259
260    if (inService &&
261        (!deferredTargets->empty() || hasPostInvalidate() ||
262         (pkt->needsExclusive() &&
263          (!isPendingDirty() || hasPostDowngrade() || isForward)))) {
264        // need to put on deferred list
265        if (hasPostInvalidate())
266            replaceUpgrade(pkt);
267        deferredTargets->add(pkt, whenReady, _order, Target::FromCPU, true);
268    } else {
269        // No request outstanding, or still OK to append to
270        // outstanding request: append to regular target list.  Only
271        // mark pending if current request hasn't been issued yet
272        // (isn't in service).
273        targets->add(pkt, whenReady, _order, Target::FromCPU, !inService);
274    }
275
276    ++ntargets;
277}
278
279bool
280MSHR::handleSnoop(PacketPtr pkt, Counter _order)
281{
282    if (!inService || (pkt->isExpressSnoop() && downstreamPending)) {
283        // Request has not been issued yet, or it's been issued
284        // locally but is buffered unissued at some downstream cache
285        // which is forwarding us this snoop.  Either way, the packet
286        // we're snooping logically precedes this MSHR's request, so
287        // the snoop has no impact on the MSHR, but must be processed
288        // in the standard way by the cache.  The only exception is
289        // that if we're an L2+ cache buffering an UpgradeReq from a
290        // higher-level cache, and the snoop is invalidating, then our
291        // buffered upgrades must be converted to read exclusives,
292        // since the upper-level cache no longer has a valid copy.
293        // That is, even though the upper-level cache got out on its
294        // local bus first, some other invalidating transaction
295        // reached the global bus before the upgrade did.
296        if (pkt->needsExclusive()) {
297            targets->replaceUpgrades();
298            deferredTargets->replaceUpgrades();
299        }
300
301        return false;
302    }
303
304    // From here on down, the request issued by this MSHR logically
305    // precedes the request we're snooping.
306    if (pkt->needsExclusive()) {
307        // snooped request still precedes the re-request we'll have to
308        // issue for deferred targets, if any...
309        deferredTargets->replaceUpgrades();
310    }
311
312    if (hasPostInvalidate()) {
313        // a prior snoop has already appended an invalidation, so
314        // logically we don't have the block anymore; no need for
315        // further snooping.
316        return true;
317    }
318
319    if (isPendingDirty() || pkt->isInvalidate()) {
320        // We need to save and replay the packet in two cases:
321        // 1. We're awaiting an exclusive copy, so ownership is pending,
322        //    and we need to respond after we receive data.
323        // 2. It's an invalidation (e.g., UpgradeReq), and we need
324        //    to forward the snoop up the hierarchy after the current
325        //    transaction completes.
326
327        // Actual target device (typ. PhysicalMemory) will delete the
328        // packet on reception, so we need to save a copy here.
329        PacketPtr cp_pkt = new Packet(pkt, true);
330        targets->add(cp_pkt, curTick, _order, Target::FromSnoop,
331                     downstreamPending && targets->needsExclusive);
332        ++ntargets;
333
334        if (isPendingDirty()) {
335            pkt->assertMemInhibit();
336            pkt->setSupplyExclusive();
337        }
338
339        if (pkt->needsExclusive()) {
340            // This transaction will take away our pending copy
341            postInvalidate = true;
342        }
343    }
344
345    if (!pkt->needsExclusive()) {
346        // This transaction will get a read-shared copy, downgrading
347        // our copy if we had an exclusive one
348        postDowngrade = true;
349        pkt->assertShared();
350    }
351
352    return true;
353}
354
355
356bool
357MSHR::promoteDeferredTargets()
358{
359    assert(targets->empty());
360    if (deferredTargets->empty()) {
361        return false;
362    }
363
364    // swap targets & deferredTargets lists
365    TargetList *tmp = targets;
366    targets = deferredTargets;
367    deferredTargets = tmp;
368
369    assert(targets->size() == ntargets);
370
371    // clear deferredTargets flags
372    deferredTargets->resetFlags();
373
374    order = targets->front().order;
375    readyTime = std::max(curTick, targets->front().readyTime);
376
377    return true;
378}
379
380
381void
382MSHR::handleFill(Packet *pkt, CacheBlk *blk)
383{
384    if (!pkt->sharedAsserted()
385        && !(hasPostInvalidate() || hasPostDowngrade())
386        && deferredTargets->needsExclusive) {
387        // We got an exclusive response, but we have deferred targets
388        // which are waiting to request an exclusive copy (not because
389        // of a pending invalidate).  This can happen if the original
390        // request was for a read-only (non-exclusive) block, but we
391        // got an exclusive copy anyway because of the E part of the
392        // MOESI/MESI protocol.  Since we got the exclusive copy
393        // there's no need to defer the targets, so move them up to
394        // the regular target list.
395        assert(!targets->needsExclusive);
396        targets->needsExclusive = true;
397        // if any of the deferred targets were upper-level cache
398        // requests marked downstreamPending, need to clear that
399        assert(!downstreamPending);  // not pending here anymore
400        deferredTargets->clearDownstreamPending();
401        // this clears out deferredTargets too
402        targets->splice(targets->end(), *deferredTargets);
403        deferredTargets->resetFlags();
404    }
405}
406
407
408bool
409MSHR::checkFunctional(PacketPtr pkt)
410{
411    // For printing, we treat the MSHR as a whole as single entity.
412    // For other requests, we iterate over the individual targets
413    // since that's where the actual data lies.
414    if (pkt->isPrint()) {
415        pkt->checkFunctional(this, addr, size, NULL);
416        return false;
417    } else {
418        return (targets->checkFunctional(pkt) ||
419                deferredTargets->checkFunctional(pkt));
420    }
421}
422
423
424void
425MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const
426{
427    ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n",
428             prefix, addr, addr+size-1,
429             isForward ? "Forward" : "",
430             isForwardNoResponse() ? "ForwNoResp" : "",
431             needsExclusive() ? "Excl" : "",
432             _isUncacheable ? "Unc" : "",
433             inService ? "InSvc" : "",
434             downstreamPending ? "DwnPend" : "",
435             hasPostInvalidate() ? "PostInv" : "",
436             hasPostDowngrade() ? "PostDowngr" : "");
437
438    ccprintf(os, "%s  Targets:\n", prefix);
439    targets->print(os, verbosity, prefix + "    ");
440    if (!deferredTargets->empty()) {
441        ccprintf(os, "%s  Deferred Targets:\n", prefix);
442        deferredTargets->print(os, verbosity, prefix + "      ");
443    }
444}
445
446MSHR::~MSHR()
447{
448}
449