gic_v3_its.hh revision 14168:2a96e30b9400
1/*
2 * Copyright (c) 2019 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 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Travaglini
38 */
39
40#ifndef __DEV_ARM_GICV3_ITS_H__
41#define __DEV_ARM_GICV3_ITS_H__
42
43#include <queue>
44
45#include "base/coroutine.hh"
46#include "dev/dma_device.hh"
47#include "params/Gicv3Its.hh"
48
49class Gicv3;
50class Gicv3Redistributor;
51class ItsProcess;
52class ItsTranslation;
53class ItsCommand;
54
55enum class ItsActionType
56{
57    INITIAL_NOP,
58    SEND_REQ,
59    TERMINATE,
60};
61
62struct ItsAction
63{
64    ItsActionType type;
65    PacketPtr pkt;
66    Tick delay;
67};
68
69/**
70 * GICv3 ITS module. This class is just modelling a pio device with its
71 * memory mapped registers. Most of the ITS functionalities are
72 * implemented as processes (ItsProcess) objects, like ItsTranslation or
73 * ItsCommand.
74 * Main job of Gicv3Its is to spawn those processes upon receival of packets.
75 */
76class Gicv3Its : public BasicPioDevice
77{
78    friend class ::ItsProcess;
79    friend class ::ItsTranslation;
80    friend class ::ItsCommand;
81  public:
82    class DataPort : public MasterPort
83    {
84      protected:
85        Gicv3Its &its;
86
87      public:
88        DataPort(const std::string &_name, Gicv3Its &_its) :
89            MasterPort(_name, &_its),
90            its(_its)
91        {}
92
93        virtual ~DataPort() {}
94
95        bool recvTimingResp(PacketPtr pkt) { return its.recvTimingResp(pkt); }
96        void recvReqRetry() { return its.recvReqRetry(); }
97    };
98
99    DataPort dmaPort;
100
101    Port & getPort(const std::string &if_name, PortID idx) override;
102    bool recvTimingResp(PacketPtr pkt);
103    void recvReqRetry();
104
105    Gicv3Its(const Gicv3ItsParams *params);
106
107    void setGIC(Gicv3 *_gic);
108
109    static const uint32_t itsControl = 0x0;
110    static const uint32_t itsTranslate = 0x10000;
111
112    // Address range part of Control frame
113    static const AddrRange GITS_BASER;
114
115    static const uint32_t NUM_BASER_REGS = 8;
116
117    enum : Addr
118    {
119        // Control frame
120        GITS_CTLR    = itsControl + 0x0000,
121        GITS_IIDR    = itsControl + 0x0004,
122        GITS_TYPER   = itsControl + 0x0008,
123        GITS_CBASER  = itsControl + 0x0080,
124        GITS_CWRITER = itsControl + 0x0088,
125        GITS_CREADR  = itsControl + 0x0090,
126        GITS_PIDR2 = itsControl + 0xffe8,
127
128        // Translation frame
129        GITS_TRANSLATER = itsTranslate + 0x0040
130    };
131
132    AddrRangeList getAddrRanges() const override;
133
134    Tick read(PacketPtr pkt) override;
135    Tick write(PacketPtr pkt) override;
136
137    DrainState drain() override;
138    void serialize(CheckpointOut & cp) const override;
139    void unserialize(CheckpointIn & cp) override;
140
141    void translate(PacketPtr pkt);
142
143    BitUnion32(CTLR)
144        Bitfield<31> quiescent;
145        Bitfield<7, 4> itsNumber;
146        Bitfield<1> imDe;
147        Bitfield<0> enabled;
148    EndBitUnion(CTLR)
149
150    // Command read/write, (CREADR, CWRITER)
151    BitUnion64(CRDWR)
152        Bitfield<19, 5> offset;
153        Bitfield<0> retry;
154        Bitfield<0> stalled;
155    EndBitUnion(CRDWR)
156
157    BitUnion64(CBASER)
158        Bitfield<63> valid;
159        Bitfield<61, 59> innerCache;
160        Bitfield<55, 53> outerCache;
161        Bitfield<51, 12> physAddr;
162        Bitfield<11, 10> shareability;
163        Bitfield<7, 0> size;
164    EndBitUnion(CBASER)
165
166    BitUnion64(BASER)
167        Bitfield<63> valid;
168        Bitfield<62> indirect;
169        Bitfield<61, 59> innerCache;
170        Bitfield<58, 56> type;
171        Bitfield<55, 53> outerCache;
172        Bitfield<52, 48> entrySize;
173        Bitfield<47, 12> physAddr;
174        Bitfield<11, 10> shareability;
175        Bitfield<9, 8> pageSize;
176        Bitfield<7, 0> size;
177    EndBitUnion(BASER)
178
179    BitUnion64(TYPER)
180        Bitfield<37> vmovp;
181        Bitfield<36> cil;
182        Bitfield<35, 32> cidBits;
183        Bitfield<31, 24> hcc;
184        Bitfield<19> pta;
185        Bitfield<18> seis;
186        Bitfield<17, 13> devBits;
187        Bitfield<12, 8> idBits;
188        Bitfield<7, 4> ittEntrySize;
189        Bitfield<2> cct;
190        Bitfield<1> _virtual;
191        Bitfield<0> physical;
192    EndBitUnion(TYPER)
193
194    CTLR     gitsControl;
195    TYPER    gitsTyper;
196    CBASER   gitsCbaser;
197    CRDWR    gitsCreadr;
198    CRDWR    gitsCwriter;
199    uint32_t gitsIidr;
200    uint32_t gitsTranslater;
201
202    std::vector<BASER> tableBases;
203
204    /**
205     * Returns TRUE if the eventID supplied has bits above the implemented
206     * size or above the itt_range
207     */
208    bool idOutOfRange(uint32_t event_id, uint8_t itt_range) const;
209
210    /**
211     * Returns TRUE if the value supplied has bits above the implemented range
212     * or if the value supplied exceeds the maximum configured size in the
213     * appropriate GITS_BASER<n>
214     */
215    bool deviceOutOfRange(uint32_t device_id) const;
216
217    /**
218     * Returns TRUE if the value (size) supplied exceeds the maximum
219     * allowed by GITS_TYPER.ID_bits. Size is the parameter which is
220     * passed to the ITS via the MAPD command and is stored in the
221     * DTE.ittRange field.
222     */
223    bool sizeOutOfRange(uint32_t size) const;
224
225    /**
226     * Returns TRUE if the value supplied has bits above the implemented range
227     * or if the value exceeds the total number of collections supported in
228     * hardware and external memory
229     */
230    bool collectionOutOfRange(uint32_t collection_id) const;
231
232    /**
233     * Returns TRUE if the value supplied is larger than that permitted by
234     * GICD_TYPER.IDbits or not in the LPI range and is not 1023
235     */
236    bool lpiOutOfRange(uint32_t intid) const;
237
238  private: // Command
239    void checkCommandQueue();
240    void incrementReadPointer();
241
242  public: // TableWalk
243    BitUnion64(DTE)
244        Bitfield<57, 53> ittRange;
245        Bitfield<52, 1> ittAddress;
246        Bitfield<0> valid;
247    EndBitUnion(DTE)
248
249    BitUnion64(ITTE)
250        Bitfield<59, 46> vpeid;
251        Bitfield<45, 30> icid;
252        Bitfield<29, 16> intNumHyp;
253        Bitfield<15, 2> intNum;
254        Bitfield<1> intType;
255        Bitfield<0> valid;
256    EndBitUnion(ITTE)
257
258    BitUnion64(CTE)
259        Bitfield<40, 1> rdBase;
260        Bitfield<0> valid;
261    EndBitUnion(CTE)
262
263    enum InterruptType
264    {
265        VIRTUAL_INTERRUPT = 0,
266        PHYSICAL_INTERRUPT = 1
267    };
268
269  private:
270    Gicv3Redistributor* getRedistributor(uint64_t rd_base);
271    Gicv3Redistributor* getRedistributor(CTE cte)
272    {
273        return getRedistributor(cte.rdBase);
274    }
275
276    ItsAction runProcess(ItsProcess *proc, PacketPtr pkt);
277    ItsAction runProcessTiming(ItsProcess *proc, PacketPtr pkt);
278    ItsAction runProcessAtomic(ItsProcess *proc, PacketPtr pkt);
279
280    enum ItsTables
281    {
282        DEVICE_TABLE = 1,
283        VPE_TABLE = 2,
284        TRANSLATION_TABLE = 3,
285        COLLECTION_TABLE = 4
286    };
287
288    enum PageSize
289    {
290        SIZE_4K,
291        SIZE_16K,
292        SIZE_64K
293    };
294
295    Addr pageAddress(enum ItsTables table);
296
297    void moveAllPendingState(
298        Gicv3Redistributor *rd1, Gicv3Redistributor *rd2);
299
300  private:
301    std::queue<ItsAction> packetsToRetry;
302    uint32_t masterId;
303    Gicv3 *gic;
304    EventFunctionWrapper commandEvent;
305
306    bool pendingCommands;
307    uint32_t pendingTranslations;
308};
309
310/**
311 * ItsProcess is a base coroutine wrapper which is spawned by
312 * the Gicv3Its module when the latter needs to perform different
313 * actions, like translating a peripheral's MSI into an LPI
314 * (See derived ItsTranslation) or processing a Command from the
315 * ITS queue (ItsCommand).
316 * The action to take is implemented by the method:
317 *
318 * virtual void main(Yield &yield) = 0;
319 * It's inheriting from Packet::SenderState since the generic process
320 * will be stopped (we are using coroutines) and sent with the packet
321 * to memory when doing table walks.
322 * When Gicv3Its receives a response, it will resume the coroutine from
323 * the point it stopped when yielding.
324 */
325class ItsProcess : public Packet::SenderState
326{
327  public:
328    using DTE = Gicv3Its::DTE;
329    using ITTE = Gicv3Its::ITTE;
330    using CTE = Gicv3Its::CTE;
331    using Coroutine = m5::Coroutine<PacketPtr, ItsAction>;
332    using Yield = Coroutine::CallerType;
333
334    ItsProcess(Gicv3Its &_its);
335    virtual ~ItsProcess();
336
337    /** Returns the Gicv3Its name. Mainly used for DPRINTS */
338    const std::string name() const;
339
340    ItsAction run(PacketPtr pkt);
341
342  protected:
343    void reinit();
344    virtual void main(Yield &yield) = 0;
345
346    void writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte);
347
348    void writeIrqTranslationTable(
349        Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte);
350
351    void writeIrqCollectionTable(
352        Yield &yield, uint32_t collection_id, CTE cte);
353
354    uint64_t readDeviceTable(
355        Yield &yield, uint32_t device_id);
356
357    uint64_t readIrqTranslationTable(
358        Yield &yield, const Addr itt_base, uint32_t event_id);
359
360    uint64_t readIrqCollectionTable(Yield &yield, uint32_t collection_id);
361
362    void doRead(Yield &yield, Addr addr, void *ptr, size_t size);
363    void doWrite(Yield &yield, Addr addr, void *ptr, size_t size);
364    void terminate(Yield &yield);
365
366  protected:
367    Gicv3Its &its;
368
369  private:
370    std::unique_ptr<Coroutine> coroutine;
371};
372
373/**
374 * An ItsTranslation is created whenever a peripheral writes a message in
375 * GITS_TRANSLATER (MSI). In this case main will simply do the table walks
376 * until it gets a redistributor and an INTID. It will then raise the
377 * LPI interrupt to the target redistributor.
378 */
379class ItsTranslation : public ItsProcess
380{
381  public:
382    ItsTranslation(Gicv3Its &_its);
383    ~ItsTranslation();
384
385  protected:
386    void main(Yield &yield) override;
387
388    std::pair<uint32_t, Gicv3Redistributor *>
389    translateLPI(Yield &yield, uint32_t device_id, uint32_t event_id);
390};
391
392/**
393 * An ItsCommand is created whenever there is a new command in the command
394 * queue. Only one command can be executed per time.
395 * main will firstly read the command from memory and then it will process
396 * it.
397 */
398class ItsCommand : public ItsProcess
399{
400  public:
401    union CommandEntry
402    {
403        struct
404        {
405            uint32_t type;
406            uint32_t deviceId;
407            uint32_t eventId;
408            uint32_t pintId;
409
410            uint32_t data[4];
411        };
412        uint64_t raw[4];
413    };
414
415    enum CommandType : uint32_t
416    {
417        CLEAR = 0x04,
418        DISCARD = 0x0F,
419        INT = 0x03,
420        INV = 0x0C,
421        INVALL = 0x0D,
422        MAPC = 0x09,
423        MAPD = 0x08,
424        MAPI = 0x0B,
425        MAPTI = 0x0A,
426        MOVALL = 0x0E,
427        MOVI = 0x01,
428        SYNC = 0x05,
429        VINVALL = 0x2D,
430        VMAPI = 0x2B,
431        VMAPP = 0x29,
432        VMAPTI = 0x2A,
433        VMOVI = 0x21,
434        VMOVP = 0x22,
435        VSYNC = 0x25
436    };
437
438    ItsCommand(Gicv3Its &_its);
439    ~ItsCommand();
440
441  protected:
442    /**
443     * Dispatch entry is a metadata struct which contains information about
444     * the command (like the name) and the function object implementing
445     * the command.
446     */
447    struct DispatchEntry
448    {
449        using ExecFn = std::function<void(ItsCommand*, Yield&, CommandEntry&)>;
450
451        DispatchEntry(std::string _name, ExecFn _exec)
452          : name(_name), exec(_exec)
453        {}
454
455        std::string name;
456        ExecFn exec;
457    };
458
459    using DispatchTable = std::unordered_map<
460        std::underlying_type<enum CommandType>::type, DispatchEntry>;
461
462    static DispatchTable cmdDispatcher;
463
464    static std::string commandName(uint32_t cmd);
465
466    void main(Yield &yield) override;
467
468    void readCommand(Yield &yield, CommandEntry &command);
469    void processCommand(Yield &yield, CommandEntry &command);
470
471    // Commands
472    void clear(Yield &yield, CommandEntry &command);
473    void discard(Yield &yield, CommandEntry &command);
474    void mapc(Yield &yield, CommandEntry &command);
475    void mapd(Yield &yield, CommandEntry &command);
476    void mapi(Yield &yield, CommandEntry &command);
477    void mapti(Yield &yield, CommandEntry &command);
478    void movall(Yield &yield, CommandEntry &command);
479    void movi(Yield &yield, CommandEntry &command);
480    void sync(Yield &yield, CommandEntry &command);
481    void doInt(Yield &yield, CommandEntry &command);
482    void inv(Yield &yield, CommandEntry &command);
483    void invall(Yield &yield, CommandEntry &command);
484    void vinvall(Yield &yield, CommandEntry &command);
485    void vmapi(Yield &yield, CommandEntry &command);
486    void vmapp(Yield &yield, CommandEntry &command);
487    void vmapti(Yield &yield, CommandEntry &command);
488    void vmovi(Yield &yield, CommandEntry &command);
489    void vmovp(Yield &yield, CommandEntry &command);
490    void vsync(Yield &yield, CommandEntry &command);
491
492  protected: // Helpers
493    bool idOutOfRange(CommandEntry &command, DTE dte) const
494    {
495        return its.idOutOfRange(command.eventId, dte.ittRange);
496    }
497
498    bool deviceOutOfRange(CommandEntry &command) const
499    {
500        return its.deviceOutOfRange(command.deviceId);
501    }
502
503    bool sizeOutOfRange(CommandEntry &command) const
504    {
505        const auto size = bits(command.raw[1], 4, 0);
506        const auto valid = bits(command.raw[2], 63);
507        if (valid)
508            return its.sizeOutOfRange(size);
509        else
510            return false;
511    }
512
513    bool collectionOutOfRange(CommandEntry &command) const
514    {
515        return its.collectionOutOfRange(bits(command.raw[2], 15, 0));
516    }
517};
518
519#endif
520