Deleted Added
sdiff udiff text old ( 13996:8a567118e670 ) new ( 14168:2a96e30b9400 )
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<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