coherent_xbar.hh revision 12351
1/*
2 * Copyright (c) 2011-2015, 2017 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 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ron Dreslinski
41 *          Ali Saidi
42 *          Andreas Hansson
43 *          William Wang
44 */
45
46/**
47 * @file
48 * Declaration of a coherent crossbar.
49 */
50
51#ifndef __MEM_COHERENT_XBAR_HH__
52#define __MEM_COHERENT_XBAR_HH__
53
54#include <unordered_map>
55#include <unordered_set>
56
57#include "mem/snoop_filter.hh"
58#include "mem/xbar.hh"
59#include "params/CoherentXBar.hh"
60
61/**
62 * A coherent crossbar connects a number of (potentially) snooping
63 * masters and slaves, and routes the request and response packets
64 * based on the address, and also forwards all requests to the
65 * snoopers and deals with the snoop responses.
66 *
67 * The coherent crossbar can be used as a template for modelling QPI,
68 * HyperTransport, ACE and coherent OCP buses, and is typically used
69 * for the L1-to-L2 buses and as the main system interconnect.  @sa
70 * \ref gem5MemorySystem "gem5 Memory System"
71 */
72class CoherentXBar : public BaseXBar
73{
74
75  protected:
76
77    /**
78     * Declare the layers of this crossbar, one vector for requests,
79     * one for responses, and one for snoop responses
80     */
81    std::vector<ReqLayer*> reqLayers;
82    std::vector<RespLayer*> respLayers;
83    std::vector<SnoopRespLayer*> snoopLayers;
84
85    /**
86     * Declaration of the coherent crossbar slave port type, one will
87     * be instantiated for each of the master ports connecting to the
88     * crossbar.
89     */
90    class CoherentXBarSlavePort : public QueuedSlavePort
91    {
92
93      private:
94
95        /** A reference to the crossbar to which this port belongs. */
96        CoherentXBar &xbar;
97
98        /** A normal packet queue used to store responses. */
99        RespPacketQueue queue;
100
101      public:
102
103        CoherentXBarSlavePort(const std::string &_name,
104                             CoherentXBar &_xbar, PortID _id)
105            : QueuedSlavePort(_name, &_xbar, queue, _id), xbar(_xbar),
106              queue(_xbar, *this)
107        { }
108
109      protected:
110
111        /**
112         * When receiving a timing request, pass it to the crossbar.
113         */
114        virtual bool recvTimingReq(PacketPtr pkt)
115        { return xbar.recvTimingReq(pkt, id); }
116
117        /**
118         * When receiving a timing snoop response, pass it to the crossbar.
119         */
120        virtual bool recvTimingSnoopResp(PacketPtr pkt)
121        { return xbar.recvTimingSnoopResp(pkt, id); }
122
123        /**
124         * When receiving an atomic request, pass it to the crossbar.
125         */
126        virtual Tick recvAtomic(PacketPtr pkt)
127        { return xbar.recvAtomic(pkt, id); }
128
129        /**
130         * When receiving a functional request, pass it to the crossbar.
131         */
132        virtual void recvFunctional(PacketPtr pkt)
133        { xbar.recvFunctional(pkt, id); }
134
135        /**
136         * Return the union of all adress ranges seen by this crossbar.
137         */
138        virtual AddrRangeList getAddrRanges() const
139        { return xbar.getAddrRanges(); }
140
141    };
142
143    /**
144     * Declaration of the coherent crossbar master port type, one will be
145     * instantiated for each of the slave interfaces connecting to the
146     * crossbar.
147     */
148    class CoherentXBarMasterPort : public MasterPort
149    {
150      private:
151        /** A reference to the crossbar to which this port belongs. */
152        CoherentXBar &xbar;
153
154      public:
155
156        CoherentXBarMasterPort(const std::string &_name,
157                              CoherentXBar &_xbar, PortID _id)
158            : MasterPort(_name, &_xbar, _id), xbar(_xbar)
159        { }
160
161      protected:
162
163        /**
164         * Determine if this port should be considered a snooper. For
165         * a coherent crossbar master port this is always true.
166         *
167         * @return a boolean that is true if this port is snooping
168         */
169        virtual bool isSnooping() const
170        { return true; }
171
172        /**
173         * When receiving a timing response, pass it to the crossbar.
174         */
175        virtual bool recvTimingResp(PacketPtr pkt)
176        { return xbar.recvTimingResp(pkt, id); }
177
178        /**
179         * When receiving a timing snoop request, pass it to the crossbar.
180         */
181        virtual void recvTimingSnoopReq(PacketPtr pkt)
182        { return xbar.recvTimingSnoopReq(pkt, id); }
183
184        /**
185         * When receiving an atomic snoop request, pass it to the crossbar.
186         */
187        virtual Tick recvAtomicSnoop(PacketPtr pkt)
188        { return xbar.recvAtomicSnoop(pkt, id); }
189
190        /**
191         * When receiving a functional snoop request, pass it to the crossbar.
192         */
193        virtual void recvFunctionalSnoop(PacketPtr pkt)
194        { xbar.recvFunctionalSnoop(pkt, id); }
195
196        /** When reciving a range change from the peer port (at id),
197            pass it to the crossbar. */
198        virtual void recvRangeChange()
199        { xbar.recvRangeChange(id); }
200
201        /** When reciving a retry from the peer port (at id),
202            pass it to the crossbar. */
203        virtual void recvReqRetry()
204        { xbar.recvReqRetry(id); }
205
206    };
207
208    /**
209     * Internal class to bridge between an incoming snoop response
210     * from a slave port and forwarding it through an outgoing slave
211     * port. It is effectively a dangling master port.
212     */
213    class SnoopRespPort : public MasterPort
214    {
215
216      private:
217
218        /** The port which we mirror internally. */
219        QueuedSlavePort& slavePort;
220
221      public:
222
223        /**
224         * Create a snoop response port that mirrors a given slave port.
225         */
226        SnoopRespPort(QueuedSlavePort& slave_port, CoherentXBar& _xbar) :
227            MasterPort(slave_port.name() + ".snoopRespPort", &_xbar),
228            slavePort(slave_port) { }
229
230        /**
231         * Override the sending of retries and pass them on through
232         * the mirrored slave port.
233         */
234        void sendRetryResp() {
235            // forward it as a snoop response retry
236            slavePort.sendRetrySnoopResp();
237        }
238
239        /**
240         * Provided as necessary.
241         */
242        void recvReqRetry() { panic("SnoopRespPort should never see retry\n"); }
243
244        /**
245         * Provided as necessary.
246         */
247        bool recvTimingResp(PacketPtr pkt)
248        {
249            panic("SnoopRespPort should never see timing response\n");
250            return false;
251        }
252
253    };
254
255    std::vector<SnoopRespPort*> snoopRespPorts;
256
257    std::vector<QueuedSlavePort*> snoopPorts;
258
259    /**
260     * Store the outstanding requests that we are expecting snoop
261     * responses from so we can determine which snoop responses we
262     * generated and which ones were merely forwarded.
263     */
264    std::unordered_set<RequestPtr> outstandingSnoop;
265
266    /**
267     * Store the outstanding cache maintenance that we are expecting
268     * snoop responses from so we can determine when we received all
269     * snoop responses and if any of the agents satisfied the request.
270     */
271    std::unordered_map<PacketId, PacketPtr> outstandingCMO;
272
273    /**
274     * Keep a pointer to the system to be allow to querying memory system
275     * properties.
276     */
277    System *system;
278
279    /** A snoop filter that tracks cache line residency and can restrict the
280      * broadcast needed for probes.  NULL denotes an absent filter. */
281    SnoopFilter *snoopFilter;
282
283    /** Cycles of snoop response latency.*/
284    const Cycles snoopResponseLatency;
285
286    /** Is this crossbar the point of coherency? **/
287    const bool pointOfCoherency;
288
289    /** Is this crossbar the point of unification? **/
290    const bool pointOfUnification;
291
292    /**
293     * Upstream caches need this packet until true is returned, so
294     * hold it for deletion until a subsequent call
295     */
296    std::unique_ptr<Packet> pendingDelete;
297
298    /** Function called by the port when the crossbar is recieving a Timing
299      request packet.*/
300    bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
301
302    /** Function called by the port when the crossbar is recieving a Timing
303      response packet.*/
304    bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
305
306    /** Function called by the port when the crossbar is recieving a timing
307        snoop request.*/
308    void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);
309
310    /** Function called by the port when the crossbar is recieving a timing
311        snoop response.*/
312    bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);
313
314    /** Timing function called by port when it is once again able to process
315     * requests. */
316    void recvReqRetry(PortID master_port_id);
317
318    /**
319     * Forward a timing packet to our snoopers, potentially excluding
320     * one of the connected coherent masters to avoid sending a packet
321     * back to where it came from.
322     *
323     * @param pkt Packet to forward
324     * @param exclude_slave_port_id Id of slave port to exclude
325     */
326    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) {
327        forwardTiming(pkt, exclude_slave_port_id, snoopPorts);
328    }
329
330    /**
331     * Forward a timing packet to a selected list of snoopers, potentially
332     * excluding one of the connected coherent masters to avoid sending a packet
333     * back to where it came from.
334     *
335     * @param pkt Packet to forward
336     * @param exclude_slave_port_id Id of slave port to exclude
337     * @param dests Vector of destination ports for the forwarded pkt
338     */
339    void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
340                       const std::vector<QueuedSlavePort*>& dests);
341
342    /** Function called by the port when the crossbar is recieving a Atomic
343      transaction.*/
344    Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
345
346    /** Function called by the port when the crossbar is recieving an
347        atomic snoop transaction.*/
348    Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);
349
350    /**
351     * Forward an atomic packet to our snoopers, potentially excluding
352     * one of the connected coherent masters to avoid sending a packet
353     * back to where it came from.
354     *
355     * @param pkt Packet to forward
356     * @param exclude_slave_port_id Id of slave port to exclude
357     *
358     * @return a pair containing the snoop response and snoop latency
359     */
360    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
361                                          PortID exclude_slave_port_id)
362    {
363        return forwardAtomic(pkt, exclude_slave_port_id, InvalidPortID,
364                             snoopPorts);
365    }
366
367    /**
368     * Forward an atomic packet to a selected list of snoopers, potentially
369     * excluding one of the connected coherent masters to avoid sending a packet
370     * back to where it came from.
371     *
372     * @param pkt Packet to forward
373     * @param exclude_slave_port_id Id of slave port to exclude
374     * @param source_master_port_id Id of the master port for snoops from below
375     * @param dests Vector of destination ports for the forwarded pkt
376     *
377     * @return a pair containing the snoop response and snoop latency
378     */
379    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
380                                          PortID exclude_slave_port_id,
381                                          PortID source_master_port_id,
382                                          const std::vector<QueuedSlavePort*>&
383                                          dests);
384
385    /** Function called by the port when the crossbar is recieving a Functional
386        transaction.*/
387    void recvFunctional(PacketPtr pkt, PortID slave_port_id);
388
389    /** Function called by the port when the crossbar is recieving a functional
390        snoop transaction.*/
391    void recvFunctionalSnoop(PacketPtr pkt, PortID master_port_id);
392
393    /**
394     * Forward a functional packet to our snoopers, potentially
395     * excluding one of the connected coherent masters to avoid
396     * sending a packet back to where it came from.
397     *
398     * @param pkt Packet to forward
399     * @param exclude_slave_port_id Id of slave port to exclude
400     */
401    void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);
402
403    /**
404     * Determine if the crossbar should sink the packet, as opposed to
405     * forwarding it, or responding.
406     */
407    bool sinkPacket(const PacketPtr pkt) const;
408
409    /**
410     * Determine if the crossbar should forward the packet, as opposed to
411     * responding to it.
412     */
413    bool forwardPacket(const PacketPtr pkt);
414
415    /**
416     * Determine if the packet's destination is the memory below
417     *
418     * The memory below is the destination for a cache mainteance
419     * operation to the Point of Coherence/Unification if this is the
420     * Point of Coherence/Unification.
421     *
422     * @param pkt The processed packet
423     *
424     * @return Whether the memory below is the destination for the packet
425     */
426    bool isDestination(const PacketPtr pkt) const
427    {
428        return (pkt->req->isToPOC() && pointOfCoherency) ||
429            (pkt->req->isToPOU() && pointOfUnification);
430    }
431
432    Stats::Scalar snoops;
433    Stats::Scalar snoopTraffic;
434    Stats::Distribution snoopFanout;
435
436  public:
437
438    virtual void init();
439
440    CoherentXBar(const CoherentXBarParams *p);
441
442    virtual ~CoherentXBar();
443
444    virtual void regStats();
445};
446
447#endif //__MEM_COHERENT_XBAR_HH__
448