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