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