gic_v3_its.hh revision 14235:3c7ca56da5a1
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    // We currently don't support two level ITS tables
118    // The indirect bit is RAZ/WI for implementations that only
119    // support flat tables.
120    static const uint64_t BASER_INDIRECT = 0x4000000000000000;
121    static const uint64_t BASER_TYPE = 0x0700000000000000;
122    static const uint64_t BASER_ESZ = 0x001F000000000000;
123    static const uint64_t BASER_SZ = 0x00000000000000FF;
124    static const uint64_t BASER_WMASK =
125        ~(BASER_INDIRECT | BASER_TYPE | BASER_ESZ);
126    static const uint64_t BASER_WMASK_UNIMPL =
127        ~(BASER_INDIRECT | BASER_TYPE | BASER_ESZ | BASER_SZ);
128
129    // GITS_CTLR.quiescent mask
130    static const uint32_t CTLR_QUIESCENT;
131
132    enum : Addr
133    {
134        // Control frame
135        GITS_CTLR    = itsControl + 0x0000,
136        GITS_IIDR    = itsControl + 0x0004,
137        GITS_TYPER   = itsControl + 0x0008,
138        GITS_CBASER  = itsControl + 0x0080,
139        GITS_CWRITER = itsControl + 0x0088,
140        GITS_CREADR  = itsControl + 0x0090,
141        GITS_PIDR2 = itsControl + 0xffe8,
142
143        // Translation frame
144        GITS_TRANSLATER = itsTranslate + 0x0040
145    };
146
147    AddrRangeList getAddrRanges() const override;
148
149    Tick read(PacketPtr pkt) override;
150    Tick write(PacketPtr pkt) override;
151
152    DrainState drain() override;
153    void serialize(CheckpointOut & cp) const override;
154    void unserialize(CheckpointIn & cp) override;
155
156    void translate(PacketPtr pkt);
157
158    BitUnion32(CTLR)
159        Bitfield<31> quiescent;
160        Bitfield<7, 4> itsNumber;
161        Bitfield<1> imDe;
162        Bitfield<0> enabled;
163    EndBitUnion(CTLR)
164
165    // Command read/write, (CREADR, CWRITER)
166    BitUnion64(CRDWR)
167        Bitfield<63, 32> high;
168        Bitfield<31, 0> low;
169        Bitfield<19, 5> offset;
170        Bitfield<0> retry;
171        Bitfield<0> stalled;
172    EndBitUnion(CRDWR)
173
174    BitUnion64(CBASER)
175        Bitfield<63, 32> high;
176        Bitfield<31, 0> low;
177        Bitfield<63> valid;
178        Bitfield<61, 59> innerCache;
179        Bitfield<55, 53> outerCache;
180        Bitfield<51, 12> physAddr;
181        Bitfield<11, 10> shareability;
182        Bitfield<7, 0> size;
183    EndBitUnion(CBASER)
184
185    BitUnion64(BASER)
186        Bitfield<63> valid;
187        Bitfield<62> indirect;
188        Bitfield<61, 59> innerCache;
189        Bitfield<58, 56> type;
190        Bitfield<55, 53> outerCache;
191        Bitfield<52, 48> entrySize;
192        Bitfield<47, 12> physAddr;
193        Bitfield<11, 10> shareability;
194        Bitfield<9, 8> pageSize;
195        Bitfield<7, 0> size;
196    EndBitUnion(BASER)
197
198    BitUnion64(TYPER)
199        Bitfield<63, 32> high;
200        Bitfield<31, 0> low;
201        Bitfield<37> vmovp;
202        Bitfield<36> cil;
203        Bitfield<35, 32> cidBits;
204        Bitfield<31, 24> hcc;
205        Bitfield<19> pta;
206        Bitfield<18> seis;
207        Bitfield<17, 13> devBits;
208        Bitfield<12, 8> idBits;
209        Bitfield<7, 4> ittEntrySize;
210        Bitfield<2> cct;
211        Bitfield<1> _virtual;
212        Bitfield<0> physical;
213    EndBitUnion(TYPER)
214
215    CTLR     gitsControl;
216    TYPER    gitsTyper;
217    CBASER   gitsCbaser;
218    CRDWR    gitsCreadr;
219    CRDWR    gitsCwriter;
220    uint32_t gitsIidr;
221    uint32_t gitsTranslater;
222
223    std::vector<BASER> tableBases;
224
225    /**
226     * Returns TRUE if the eventID supplied has bits above the implemented
227     * size or above the itt_range
228     */
229    bool idOutOfRange(uint32_t event_id, uint8_t itt_range) const;
230
231    /**
232     * Returns TRUE if the value supplied has bits above the implemented range
233     * or if the value supplied exceeds the maximum configured size in the
234     * appropriate GITS_BASER<n>
235     */
236    bool deviceOutOfRange(uint32_t device_id) const;
237
238    /**
239     * Returns TRUE if the value (size) supplied exceeds the maximum
240     * allowed by GITS_TYPER.ID_bits. Size is the parameter which is
241     * passed to the ITS via the MAPD command and is stored in the
242     * DTE.ittRange field.
243     */
244    bool sizeOutOfRange(uint32_t size) const;
245
246    /**
247     * Returns TRUE if the value supplied has bits above the implemented range
248     * or if the value exceeds the total number of collections supported in
249     * hardware and external memory
250     */
251    bool collectionOutOfRange(uint32_t collection_id) const;
252
253    /**
254     * Returns TRUE if the value supplied is larger than that permitted by
255     * GICD_TYPER.IDbits or not in the LPI range and is not 1023
256     */
257    bool lpiOutOfRange(uint32_t intid) const;
258
259  private: // Command
260    void checkCommandQueue();
261    void incrementReadPointer();
262
263  public: // TableWalk
264    BitUnion64(DTE)
265        Bitfield<57, 53> ittRange;
266        Bitfield<52, 1> ittAddress;
267        Bitfield<0> valid;
268    EndBitUnion(DTE)
269
270    BitUnion64(ITTE)
271        Bitfield<59, 46> vpeid;
272        Bitfield<45, 30> icid;
273        Bitfield<29, 16> intNumHyp;
274        Bitfield<15, 2> intNum;
275        Bitfield<1> intType;
276        Bitfield<0> valid;
277    EndBitUnion(ITTE)
278
279    BitUnion64(CTE)
280        Bitfield<40, 1> rdBase;
281        Bitfield<0> valid;
282    EndBitUnion(CTE)
283
284    enum InterruptType
285    {
286        VIRTUAL_INTERRUPT = 0,
287        PHYSICAL_INTERRUPT = 1
288    };
289
290  private:
291    Gicv3Redistributor* getRedistributor(uint64_t rd_base);
292    Gicv3Redistributor* getRedistributor(CTE cte)
293    {
294        return getRedistributor(cte.rdBase);
295    }
296
297    ItsAction runProcess(ItsProcess *proc, PacketPtr pkt);
298    ItsAction runProcessTiming(ItsProcess *proc, PacketPtr pkt);
299    ItsAction runProcessAtomic(ItsProcess *proc, PacketPtr pkt);
300
301    enum ItsTables
302    {
303        DEVICE_TABLE = 1,
304        VPE_TABLE = 2,
305        TRANSLATION_TABLE = 3,
306        COLLECTION_TABLE = 4
307    };
308
309    enum PageSize
310    {
311        SIZE_4K,
312        SIZE_16K,
313        SIZE_64K
314    };
315
316    Addr pageAddress(enum ItsTables table);
317
318    void moveAllPendingState(
319        Gicv3Redistributor *rd1, Gicv3Redistributor *rd2);
320
321  private:
322    std::queue<ItsAction> packetsToRetry;
323    uint32_t masterId;
324    Gicv3 *gic;
325    EventFunctionWrapper commandEvent;
326
327    bool pendingCommands;
328    uint32_t pendingTranslations;
329};
330
331/**
332 * ItsProcess is a base coroutine wrapper which is spawned by
333 * the Gicv3Its module when the latter needs to perform different
334 * actions, like translating a peripheral's MSI into an LPI
335 * (See derived ItsTranslation) or processing a Command from the
336 * ITS queue (ItsCommand).
337 * The action to take is implemented by the method:
338 *
339 * virtual void main(Yield &yield) = 0;
340 * It's inheriting from Packet::SenderState since the generic process
341 * will be stopped (we are using coroutines) and sent with the packet
342 * to memory when doing table walks.
343 * When Gicv3Its receives a response, it will resume the coroutine from
344 * the point it stopped when yielding.
345 */
346class ItsProcess : public Packet::SenderState
347{
348  public:
349    using DTE = Gicv3Its::DTE;
350    using ITTE = Gicv3Its::ITTE;
351    using CTE = Gicv3Its::CTE;
352    using Coroutine = m5::Coroutine<PacketPtr, ItsAction>;
353    using Yield = Coroutine::CallerType;
354
355    ItsProcess(Gicv3Its &_its);
356    virtual ~ItsProcess();
357
358    /** Returns the Gicv3Its name. Mainly used for DPRINTS */
359    const std::string name() const;
360
361    ItsAction run(PacketPtr pkt);
362
363  protected:
364    void reinit();
365    virtual void main(Yield &yield) = 0;
366
367    void writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte);
368
369    void writeIrqTranslationTable(
370        Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte);
371
372    void writeIrqCollectionTable(
373        Yield &yield, uint32_t collection_id, CTE cte);
374
375    uint64_t readDeviceTable(
376        Yield &yield, uint32_t device_id);
377
378    uint64_t readIrqTranslationTable(
379        Yield &yield, const Addr itt_base, uint32_t event_id);
380
381    uint64_t readIrqCollectionTable(Yield &yield, uint32_t collection_id);
382
383    void doRead(Yield &yield, Addr addr, void *ptr, size_t size);
384    void doWrite(Yield &yield, Addr addr, void *ptr, size_t size);
385    void terminate(Yield &yield);
386
387  protected:
388    Gicv3Its &its;
389
390  private:
391    std::unique_ptr<Coroutine> coroutine;
392};
393
394/**
395 * An ItsTranslation is created whenever a peripheral writes a message in
396 * GITS_TRANSLATER (MSI). In this case main will simply do the table walks
397 * until it gets a redistributor and an INTID. It will then raise the
398 * LPI interrupt to the target redistributor.
399 */
400class ItsTranslation : public ItsProcess
401{
402  public:
403    ItsTranslation(Gicv3Its &_its);
404    ~ItsTranslation();
405
406  protected:
407    void main(Yield &yield) override;
408
409    std::pair<uint32_t, Gicv3Redistributor *>
410    translateLPI(Yield &yield, uint32_t device_id, uint32_t event_id);
411};
412
413/**
414 * An ItsCommand is created whenever there is a new command in the command
415 * queue. Only one command can be executed per time.
416 * main will firstly read the command from memory and then it will process
417 * it.
418 */
419class ItsCommand : public ItsProcess
420{
421  public:
422    union CommandEntry
423    {
424        struct
425        {
426            uint32_t type;
427            uint32_t deviceId;
428            uint32_t eventId;
429            uint32_t pintId;
430
431            uint32_t data[4];
432        };
433        uint64_t raw[4];
434    };
435
436    enum CommandType : uint32_t
437    {
438        CLEAR = 0x04,
439        DISCARD = 0x0F,
440        INT = 0x03,
441        INV = 0x0C,
442        INVALL = 0x0D,
443        MAPC = 0x09,
444        MAPD = 0x08,
445        MAPI = 0x0B,
446        MAPTI = 0x0A,
447        MOVALL = 0x0E,
448        MOVI = 0x01,
449        SYNC = 0x05,
450        VINVALL = 0x2D,
451        VMAPI = 0x2B,
452        VMAPP = 0x29,
453        VMAPTI = 0x2A,
454        VMOVI = 0x21,
455        VMOVP = 0x22,
456        VSYNC = 0x25
457    };
458
459    ItsCommand(Gicv3Its &_its);
460    ~ItsCommand();
461
462  protected:
463    /**
464     * Dispatch entry is a metadata struct which contains information about
465     * the command (like the name) and the function object implementing
466     * the command.
467     */
468    struct DispatchEntry
469    {
470        using ExecFn = std::function<void(ItsCommand*, Yield&, CommandEntry&)>;
471
472        DispatchEntry(std::string _name, ExecFn _exec)
473          : name(_name), exec(_exec)
474        {}
475
476        std::string name;
477        ExecFn exec;
478    };
479
480    using DispatchTable = std::unordered_map<
481        std::underlying_type<enum CommandType>::type, DispatchEntry>;
482
483    static DispatchTable cmdDispatcher;
484
485    static std::string commandName(uint32_t cmd);
486
487    void main(Yield &yield) override;
488
489    void readCommand(Yield &yield, CommandEntry &command);
490    void processCommand(Yield &yield, CommandEntry &command);
491
492    // Commands
493    void clear(Yield &yield, CommandEntry &command);
494    void discard(Yield &yield, CommandEntry &command);
495    void mapc(Yield &yield, CommandEntry &command);
496    void mapd(Yield &yield, CommandEntry &command);
497    void mapi(Yield &yield, CommandEntry &command);
498    void mapti(Yield &yield, CommandEntry &command);
499    void movall(Yield &yield, CommandEntry &command);
500    void movi(Yield &yield, CommandEntry &command);
501    void sync(Yield &yield, CommandEntry &command);
502    void doInt(Yield &yield, CommandEntry &command);
503    void inv(Yield &yield, CommandEntry &command);
504    void invall(Yield &yield, CommandEntry &command);
505    void vinvall(Yield &yield, CommandEntry &command);
506    void vmapi(Yield &yield, CommandEntry &command);
507    void vmapp(Yield &yield, CommandEntry &command);
508    void vmapti(Yield &yield, CommandEntry &command);
509    void vmovi(Yield &yield, CommandEntry &command);
510    void vmovp(Yield &yield, CommandEntry &command);
511    void vsync(Yield &yield, CommandEntry &command);
512
513  protected: // Helpers
514    bool idOutOfRange(CommandEntry &command, DTE dte) const
515    {
516        return its.idOutOfRange(command.eventId, dte.ittRange);
517    }
518
519    bool deviceOutOfRange(CommandEntry &command) const
520    {
521        return its.deviceOutOfRange(command.deviceId);
522    }
523
524    bool sizeOutOfRange(CommandEntry &command) const
525    {
526        const auto size = bits(command.raw[1], 4, 0);
527        const auto valid = bits(command.raw[2], 63);
528        if (valid)
529            return its.sizeOutOfRange(size);
530        else
531            return false;
532    }
533
534    bool collectionOutOfRange(CommandEntry &command) const
535    {
536        return its.collectionOutOfRange(bits(command.raw[2], 15, 0));
537    }
538};
539
540#endif
541