gem5 [DEVELOP-FOR-25.1]
Loading...
Searching...
No Matches
gic_v3_its.cc
Go to the documentation of this file.
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
38#include "dev/arm/gic_v3_its.hh"
39
40#include <cassert>
41#include <functional>
42
43#include "base/logging.hh"
44#include "base/trace.hh"
45#include "debug/AddrRanges.hh"
46#include "debug/Drain.hh"
47#include "debug/GIC.hh"
48#include "debug/ITS.hh"
49#include "dev/arm/gic_v3.hh"
52#include "mem/packet_access.hh"
53#include "params/Gicv3Its.hh"
54
55#define COMMAND(x, method) { x, DispatchEntry(#x, method) }
56
57namespace gem5
58{
59
60const AddrRange Gicv3Its::GITS_BASER(0x0100, 0x0140);
61
62const uint32_t Gicv3Its::CTLR_QUIESCENT = 0x80000000;
63
65 : its(_its), coroutine(nullptr)
66{
67}
68
72
73void
75{
76 coroutine.reset(new Coroutine(
77 std::bind(&ItsProcess::main, this, std::placeholders::_1)));
78}
79
80const std::string
82{
83 return its.name();
84}
85
88{
89 assert(coroutine != nullptr);
90 assert(*coroutine);
91 return (*coroutine)(pkt).get();
92}
93
94void
95ItsProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size)
96{
99
100 RequestPtr req = std::make_shared<Request>(
101 addr, size, 0, its.requestorId);
102
103 req->taskId(context_switch_task_id::DMA);
104
105 a.pkt = new Packet(req, MemCmd::ReadReq);
106 a.pkt->dataStatic(ptr);
107
108 a.delay = 0;
109
110 PacketPtr pkt = yield(a).get();
111
112 assert(pkt);
113 assert(pkt->getSize() >= size);
114
115 delete pkt;
116}
117
118void
119ItsProcess::doWrite(Yield &yield, Addr addr, void *ptr, size_t size)
120{
121 ItsAction a;
123
124 RequestPtr req = std::make_shared<Request>(
125 addr, size, 0, its.requestorId);
126
127 req->taskId(context_switch_task_id::DMA);
128
129 a.pkt = new Packet(req, MemCmd::WriteReq);
130 a.pkt->dataStatic(ptr);
131
132 a.delay = 0;
133
134 PacketPtr pkt = yield(a).get();
135
136 assert(pkt);
137 assert(pkt->getSize() >= size);
138
139 delete pkt;
140}
141
142void
144{
145 ItsAction a;
147 a.pkt = NULL;
148 a.delay = 0;
149 yield(a);
150}
151
152void
153ItsProcess::writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte)
154{
155 const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE);
156 const Addr address = base + (device_id * sizeof(dte));
157
158 DPRINTF(ITS, "Writing DTE at address %#x: %#x\n", address, dte);
159
160 doWrite(yield, address, &dte, sizeof(dte));
161}
162
163void
165 Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte)
166{
167 const Addr address = itt_base + (event_id * sizeof(itte));
168
169 doWrite(yield, address, &itte, sizeof(itte));
170
171 DPRINTF(ITS, "Writing ITTE at address %#x: %#x\n", address, itte);
172}
173
174void
176 Yield &yield, uint32_t collection_id, CTE cte)
177{
178 const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE);
179 const Addr address = base + (collection_id * sizeof(cte));
180
181 doWrite(yield, address, &cte, sizeof(cte));
182
183 DPRINTF(ITS, "Writing CTE at address %#x: %#x\n", address, cte);
184}
185
186uint64_t
187ItsProcess::readDeviceTable(Yield &yield, uint32_t device_id)
188{
189 uint64_t dte;
190 const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE);
191 const Addr address = base + (device_id * sizeof(dte));
192
193 doRead(yield, address, &dte, sizeof(dte));
194
195 DPRINTF(ITS, "Reading DTE at address %#x: %#x\n", address, dte);
196 return dte;
197}
198
199uint64_t
201 Yield &yield, const Addr itt_base, uint32_t event_id)
202{
203 uint64_t itte;
204 const Addr address = itt_base + (event_id * sizeof(itte));
205
206 doRead(yield, address, &itte, sizeof(itte));
207
208 DPRINTF(ITS, "Reading ITTE at address %#x: %#x\n", address, itte);
209 return itte;
210}
211
212uint64_t
213ItsProcess::readIrqCollectionTable(Yield &yield, uint32_t collection_id)
214{
215 uint64_t cte;
216 const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE);
217 const Addr address = base + (collection_id * sizeof(cte));
218
219 doRead(yield, address, &cte, sizeof(cte));
220
221 DPRINTF(ITS, "Reading CTE at address %#x: %#x\n", address, cte);
222 return cte;
223}
224
226 : ItsProcess(_its)
227{
228 reinit();
229 its.pendingTranslations++;
230 its.gitsControl.quiescent = 0;
231}
232
234{
235 assert(its.pendingTranslations >= 1);
236 its.pendingTranslations--;
237 if (!its.pendingTranslations && !its.pendingCommands)
238 its.gitsControl.quiescent = 1;
239}
240
241void
243{
244 PacketPtr pkt = yield.get();
245
246 const uint32_t device_id = pkt->req->streamId();
247 const uint32_t event_id = pkt->getLE<uint32_t>();
248
249 auto result = translateLPI(yield, device_id, event_id);
250
251 uint32_t intid = result.first;
252 Gicv3Redistributor *redist = result.second;
253
254 // Set the LPI in the redistributor
255 redist->setClrLPI(intid, true);
256
257 // Update the value in GITS_TRANSLATER only once we know
258 // there was no error in the tranlation process (before
259 // terminating the translation
260 its.gitsTranslater = event_id;
261
262 terminate(yield);
263}
264
266ItsTranslation::translateLPI(Yield &yield, uint32_t device_id,
267 uint32_t event_id)
268{
269 if (its.deviceOutOfRange(device_id)) {
270 terminate(yield);
271 }
272
273 DTE dte = readDeviceTable(yield, device_id);
274
275 if (!dte.valid || its.idOutOfRange(event_id, dte.ittRange)) {
276 terminate(yield);
277 }
278
279 ITTE itte = readIrqTranslationTable(yield, dte.ittAddress, event_id);
280 const auto collection_id = itte.icid;
281
282 if (!itte.valid || its.collectionOutOfRange(collection_id)) {
283 terminate(yield);
284 }
285
286 CTE cte = readIrqCollectionTable(yield, collection_id);
287
288 if (!cte.valid) {
289 terminate(yield);
290 }
291
292 // Returning the INTID and the target Redistributor
293 return std::make_pair(itte.intNum, its.getRedistributor(cte));
294}
295
297{
298 COMMAND(CLEAR, &ItsCommand::clear),
299 COMMAND(DISCARD, &ItsCommand::discard),
302 COMMAND(INVALL, &ItsCommand::invall),
306 COMMAND(MAPTI, &ItsCommand::mapti),
307 COMMAND(MOVALL, &ItsCommand::movall),
310 COMMAND(VINVALL, &ItsCommand::vinvall),
311 COMMAND(VMAPI, &ItsCommand::vmapi),
312 COMMAND(VMAPP, &ItsCommand::vmapp),
313 COMMAND(VMAPTI, &ItsCommand::vmapti),
314 COMMAND(VMOVI, &ItsCommand::vmovi),
315 COMMAND(VMOVP, &ItsCommand::vmovp),
316 COMMAND(VSYNC, &ItsCommand::vsync),
317};
318
320 : ItsProcess(_its)
321{
322 reinit();
323 its.pendingCommands = true;
324
325 its.gitsControl.quiescent = 0;
326}
327
329{
330 its.pendingCommands = false;
331
332 if (!its.pendingTranslations)
333 its.gitsControl.quiescent = 1;
334}
335
336std::string
338{
339 const auto entry = cmdDispatcher.find(cmd);
340 return entry != cmdDispatcher.end() ? entry->second.name : "INVALID";
341}
342
343void
345{
346 ItsAction a;
348 a.pkt = nullptr;
349 a.delay = 0;
350 yield(a);
351
352 while (its.gitsCwriter.offset != its.gitsCreadr.offset) {
353 CommandEntry command;
354
355 // Reading the command from CMDQ
356 readCommand(yield, command);
357
358 processCommand(yield, command);
359
360 its.incrementReadPointer();
361 }
362
363 terminate(yield);
364}
365
366void
368{
369 // read the command pointed by GITS_CREADR
370 const Addr cmd_addr =
371 (its.gitsCbaser.physAddr << 12) + (its.gitsCreadr.offset << 5);
372
373 doRead(yield, cmd_addr, &command, sizeof(command));
374
375 DPRINTF(ITS, "Command %s read from queue at address: %#x\n",
376 commandName(command.type), cmd_addr);
377 DPRINTF(ITS, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n",
378 command.raw[0], command.raw[1], command.raw[2], command.raw[3]);
379}
380
381void
383{
384 const auto entry = cmdDispatcher.find(command.type);
385
386 if (entry != cmdDispatcher.end()) {
387 // Execute the command
388 entry->second.exec(this, yield, command);
389 } else {
390 panic("Unrecognized command type: %u", command.type);
391 }
392}
393
394void
396{
397 if (deviceOutOfRange(command)) {
398 its.incrementReadPointer();
399 terminate(yield);
400 }
401
402 DTE dte = readDeviceTable(yield, command.deviceId);
403
404 if (!dte.valid || idOutOfRange(command, dte)) {
405 its.incrementReadPointer();
406 terminate(yield);
407 }
408
410 yield, dte.ittAddress, command.eventId);
411
412 if (!itte.valid) {
413 its.incrementReadPointer();
414 terminate(yield);
415 }
416
417 const auto collection_id = itte.icid;
418 CTE cte = readIrqCollectionTable(yield, collection_id);
419
420 if (!cte.valid) {
421 its.incrementReadPointer();
422 terminate(yield);
423 }
424
425 // Clear the LPI in the redistributor
426 its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
427}
428
429void
431{
432 if (deviceOutOfRange(command)) {
433 its.incrementReadPointer();
434 terminate(yield);
435 }
436
437 DTE dte = readDeviceTable(yield, command.deviceId);
438
439 if (!dte.valid || idOutOfRange(command, dte)) {
440 its.incrementReadPointer();
441 terminate(yield);
442 }
443
445 yield, dte.ittAddress, command.eventId);
446
447 if (!itte.valid) {
448 its.incrementReadPointer();
449 terminate(yield);
450 }
451
452 const auto collection_id = itte.icid;
453 Gicv3Its::CTE cte = readIrqCollectionTable(yield, collection_id);
454
455 if (!cte.valid) {
456 its.incrementReadPointer();
457 terminate(yield);
458 }
459
460 its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
461
462 // Then removes the mapping from the ITT (invalidating)
463 itte.valid = 0;
465 yield, dte.ittAddress, command.eventId, itte);
466}
467
468void
470{
471 if (deviceOutOfRange(command)) {
472 its.incrementReadPointer();
473 terminate(yield);
474 }
475
476 DTE dte = readDeviceTable(yield, command.deviceId);
477
478 if (!dte.valid || idOutOfRange(command, dte)) {
479 its.incrementReadPointer();
480 terminate(yield);
481 }
482
484 yield, dte.ittAddress, command.eventId);
485
486 if (!itte.valid) {
487 its.incrementReadPointer();
488 terminate(yield);
489 }
490
491 const auto collection_id = itte.icid;
492 CTE cte = readIrqCollectionTable(yield, collection_id);
493
494 if (!cte.valid) {
495 its.incrementReadPointer();
496 terminate(yield);
497 }
498
499 // Set the LPI in the redistributor
500 its.getRedistributor(cte)->setClrLPI(itte.intNum, true);
501}
502
503void
505{
506 if (deviceOutOfRange(command)) {
507 its.incrementReadPointer();
508 terminate(yield);
509 }
510
511 DTE dte = readDeviceTable(yield, command.deviceId);
512
513 if (!dte.valid || idOutOfRange(command, dte)) {
514 its.incrementReadPointer();
515 terminate(yield);
516 }
517
519 yield, dte.ittAddress, command.eventId);
520
521 if (!itte.valid) {
522 its.incrementReadPointer();
523 terminate(yield);
524 }
525
526 const auto collection_id = itte.icid;
527 CTE cte = readIrqCollectionTable(yield, collection_id);
528
529 if (!cte.valid) {
530 its.incrementReadPointer();
531 terminate(yield);
532 }
533 // Do nothing since caching is currently not supported in
534 // Redistributor
535}
536
537void
539{
540 if (collectionOutOfRange(command)) {
541 its.incrementReadPointer();
542 terminate(yield);
543 }
544
545 const auto icid = bits(command.raw[2], 15, 0);
546
547 CTE cte = readIrqCollectionTable(yield, icid);
548
549 if (!cte.valid) {
550 its.incrementReadPointer();
551 terminate(yield);
552 }
553 // Do nothing since caching is currently not supported in
554 // Redistributor
555}
556
557void
559{
560 if (collectionOutOfRange(command)) {
561 its.incrementReadPointer();
562 terminate(yield);
563 }
564
565 CTE cte = 0;
566 cte.valid = bits(command.raw[2], 63);
567 cte.rdBase = bits(command.raw[2], 50, 16);
568
569 const auto icid = bits(command.raw[2], 15, 0);
570
571 writeIrqCollectionTable(yield, icid, cte);
572}
573
574void
576{
577 if (deviceOutOfRange(command) || sizeOutOfRange(command)) {
578 its.incrementReadPointer();
579 terminate(yield);
580 }
581
582 DTE dte = 0;
583 dte.valid = bits(command.raw[2], 63);
584 dte.ittAddress = mbits(command.raw[2], 51, 8);
585 dte.ittRange = bits(command.raw[1], 4, 0);
586
587 writeDeviceTable(yield, command.deviceId, dte);
588}
589
590void
592{
593 if (deviceOutOfRange(command)) {
594 its.incrementReadPointer();
595 terminate(yield);
596 }
597
598 if (collectionOutOfRange(command)) {
599 its.incrementReadPointer();
600 terminate(yield);
601 }
602
603 DTE dte = readDeviceTable(yield, command.deviceId);
604
605 if (!dte.valid || idOutOfRange(command, dte) ||
606 its.lpiOutOfRange(command.eventId)) {
607
608 its.incrementReadPointer();
609 terminate(yield);
610 }
611
612 Gicv3Its::ITTE itte = readIrqTranslationTable(
613 yield, dte.ittAddress, command.eventId);
614
615 itte.valid = 1;
616 itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
617 itte.intNum = command.eventId;
618 itte.icid = bits(command.raw[2], 15, 0);
619
621 yield, dte.ittAddress, command.eventId, itte);
622}
623
624void
626{
627 if (deviceOutOfRange(command)) {
628 its.incrementReadPointer();
629 terminate(yield);
630 }
631
632 if (collectionOutOfRange(command)) {
633 its.incrementReadPointer();
634 terminate(yield);
635 }
636
637 DTE dte = readDeviceTable(yield, command.deviceId);
638
639 const auto pintid = bits(command.raw[1], 63, 32);
640
641 if (!dte.valid || idOutOfRange(command, dte) ||
642 its.lpiOutOfRange(pintid)) {
643
644 its.incrementReadPointer();
645 terminate(yield);
646 }
647
649 yield, dte.ittAddress, command.eventId);
650
651 itte.valid = 1;
652 itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
653 itte.intNum = pintid;
654 itte.icid = bits(command.raw[2], 15, 0);
655
657 yield, dte.ittAddress, command.eventId, itte);
658}
659
660void
662{
663 const uint64_t rd1 = bits(command.raw[2], 50, 16);
664 const uint64_t rd2 = bits(command.raw[3], 50, 16);
665
666 if (rd1 != rd2) {
667 Gicv3Redistributor * redist1 = its.getRedistributor(rd1);
668 Gicv3Redistributor * redist2 = its.getRedistributor(rd2);
669
670 its.moveAllPendingState(redist1, redist2);
671 }
672}
673
674void
676{
677 if (deviceOutOfRange(command)) {
678 its.incrementReadPointer();
679 terminate(yield);
680 }
681
682 if (collectionOutOfRange(command)) {
683 its.incrementReadPointer();
684 terminate(yield);
685 }
686
687 DTE dte = readDeviceTable(yield, command.deviceId);
688
689 if (!dte.valid || idOutOfRange(command, dte)) {
690 its.incrementReadPointer();
691 terminate(yield);
692 }
693
695 yield, dte.ittAddress, command.eventId);
696
697 if (!itte.valid || itte.intType == Gicv3Its::VIRTUAL_INTERRUPT) {
698 its.incrementReadPointer();
699 terminate(yield);
700 }
701
702 const auto collection_id1 = itte.icid;
703 CTE cte1 = readIrqCollectionTable(yield, collection_id1);
704
705 if (!cte1.valid) {
706 its.incrementReadPointer();
707 terminate(yield);
708 }
709
710 const auto collection_id2 = bits(command.raw[2], 15, 0);
711 CTE cte2 = readIrqCollectionTable(yield, collection_id2);
712
713 if (!cte2.valid) {
714 its.incrementReadPointer();
715 terminate(yield);
716 }
717
718 Gicv3Redistributor *first_redist = its.getRedistributor(cte1);
719 Gicv3Redistributor *second_redist = its.getRedistributor(cte2);
720
721 if (second_redist != first_redist) {
722 // move pending state of the interrupt from one redistributor
723 // to the other.
724 if (first_redist->isPendingLPI(itte.intNum)) {
725 first_redist->setClrLPI(itte.intNum, false);
726 second_redist->setClrLPI(itte.intNum, true);
727 }
728 }
729
730 itte.icid = collection_id2;
732 yield, dte.ittAddress, command.eventId, itte);
733}
734
735void
737{
738 warn("ITS %s command unimplemented", __func__);
739}
740
741void
743{
744 panic("ITS %s command unimplemented", __func__);
745}
746
747void
749{
750 panic("ITS %s command unimplemented", __func__);
751}
752
753void
755{
756 panic("ITS %s command unimplemented", __func__);
757}
758
759void
761{
762 panic("ITS %s command unimplemented", __func__);
763}
764
765void
767{
768 panic("ITS %s command unimplemented", __func__);
769}
770
771void
773{
774 panic("ITS %s command unimplemented", __func__);
775}
776
777void
779{
780 panic("ITS %s command unimplemented", __func__);
781}
782
783Gicv3Its::Gicv3Its(const Gicv3ItsParams &params)
784 : BasicPioDevice(params, params.pio_size),
785 dmaPort(name() + ".dma", *this),
786 gitsControl(CTLR_QUIESCENT),
787 gitsTyper(params.gits_typer),
788 gitsCbaser(0), gitsCreadr(0),
789 gitsCwriter(0), gitsIidr(0),
791 requestorId(params.system->getRequestorId(this)),
792 gic(nullptr),
793 commandEvent([this] { checkCommandQueue(); }, name()),
794 pendingCommands(false),
795 pendingTranslations(0)
796{
797 BASER device_baser = 0;
798 device_baser.type = DEVICE_TABLE;
799 device_baser.entrySize = sizeof(uint64_t) - 1;
800 tableBases[0] = device_baser;
801
802 BASER icollect_baser = 0;
803 icollect_baser.type = COLLECTION_TABLE;
804 icollect_baser.entrySize = sizeof(uint64_t) - 1;
805 tableBases[1] = icollect_baser;
806}
807
808void
810{
811 assert(!gic);
812 gic = _gic;
813}
814
817{
818 assert(pioSize != 0);
819 AddrRangeList ranges;
820 DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
821 ranges.push_back(RangeSize(pioAddr, pioSize));
822 return ranges;
823}
824
825Tick
827{
828 const Addr addr = pkt->getAddr() - pioAddr;
829 uint64_t value = 0;
830
831 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
832
833 switch (addr) {
834 case GITS_CTLR:
835 value = gitsControl;
836 break;
837
838 case GITS_IIDR:
839 value = gitsIidr;
840 break;
841
842 case GITS_TYPER:
843 value = gitsTyper;
844 break;
845
846 case GITS_TYPER + 4:
847 value = gitsTyper.high;
848 break;
849
850 case GITS_CBASER:
851 value = gitsCbaser;
852 break;
853
854 case GITS_CBASER + 4:
855 value = gitsCbaser.high;
856 break;
857
858 case GITS_CWRITER:
859 value = gitsCwriter;
860 break;
861
862 case GITS_CWRITER + 4:
863 value = gitsCwriter.high;
864 break;
865
866 case GITS_CREADR:
867 value = gitsCreadr;
868 break;
869
870 case GITS_CREADR + 4:
871 value = gitsCreadr.high;
872 break;
873
874 case GITS_PIDR2:
875 value = gic->getDistributor()->gicdPidr2;
876 break;
877
878 case GITS_TRANSLATER:
879 value = gitsTranslater;
880 break;
881
882 default:
883 if (GITS_BASER.contains(addr)) {
884 auto relative_addr = addr - GITS_BASER.start();
885 auto baser_index = relative_addr / sizeof(uint64_t);
886
887 value = tableBases[baser_index];
888 break;
889 } else {
890 panic("Unrecognized register access\n");
891 }
892 }
893
894 pkt->setUintX(value, ByteOrder::little);
895 pkt->makeAtomicResponse();
896 return pioDelay;
897}
898
899Tick
901{
902 Addr addr = pkt->getAddr() - pioAddr;
903
904 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
905
906 switch (addr) {
907 case GITS_CTLR:
908 assert(pkt->getSize() == sizeof(uint32_t));
909 gitsControl = (pkt->getLE<uint32_t>() & ~CTLR_QUIESCENT);
910 // We should check here if the ITS has been disabled, and if
911 // that's the case, flush GICv3 caches to external memory.
912 // This is not happening now, since LPI caching is not
913 // currently implemented in gem5.
914 break;
915
916 case GITS_IIDR:
917 panic("GITS_IIDR is Read Only\n");
918
919 case GITS_TYPER:
920 panic("GITS_TYPER is Read Only\n");
921
922 case GITS_CBASER:
923 if (pkt->getSize() == sizeof(uint32_t)) {
924 gitsCbaser.low = pkt->getLE<uint32_t>();
925 } else {
926 assert(pkt->getSize() == sizeof(uint64_t));
927 gitsCbaser = pkt->getLE<uint64_t>();
928 }
929
930 gitsCreadr = 0; // Cleared when CBASER gets written
931
933 break;
934
935 case GITS_CBASER + 4:
936 assert(pkt->getSize() == sizeof(uint32_t));
937 gitsCbaser.high = pkt->getLE<uint32_t>();
938
939 gitsCreadr = 0; // Cleared when CBASER gets written
940
942 break;
943
944 case GITS_CWRITER:
945 if (pkt->getSize() == sizeof(uint32_t)) {
946 gitsCwriter.low = pkt->getLE<uint32_t>();
947 } else {
948 assert(pkt->getSize() == sizeof(uint64_t));
949 gitsCwriter = pkt->getLE<uint64_t>();
950 }
951
953 break;
954
955 case GITS_CWRITER + 4:
956 assert(pkt->getSize() == sizeof(uint32_t));
957 gitsCwriter.high = pkt->getLE<uint32_t>();
958
960 break;
961
962 case GITS_CREADR:
963 panic("GITS_READR is Read Only\n");
964
965 case GITS_TRANSLATER:
966 if (gitsControl.enabled) {
967 translate(pkt);
968 }
969 break;
970
971 default:
972 if (GITS_BASER.contains(addr)) {
973 auto relative_addr = addr - GITS_BASER.start();
974 auto baser_index = relative_addr / sizeof(uint64_t);
975
976 const uint64_t table_base = tableBases[baser_index];
977 const uint64_t w_mask = tableBases[baser_index].type ?
979 const uint64_t val = pkt->getLE<uint64_t>() & w_mask;
980
981 tableBases[baser_index] = table_base | val;
982 break;
983 } else {
984 panic("Unrecognized register access\n");
985 }
986 }
987
988 pkt->makeAtomicResponse();
989 return pioDelay;
990}
991
992bool
993Gicv3Its::idOutOfRange(uint32_t event_id, uint8_t itt_range) const
994{
995 const uint32_t id_bits = gitsTyper.idBits;
996 return event_id >= (1ULL << (id_bits + 1)) ||
997 event_id >= ((1ULL << itt_range) + 1);
998}
999
1000bool
1001Gicv3Its::deviceOutOfRange(uint32_t device_id) const
1002{
1003 return device_id >= (1ULL << (gitsTyper.devBits + 1));
1004}
1005
1006bool
1008{
1009 return size > gitsTyper.idBits;
1010}
1011
1012bool
1013Gicv3Its::collectionOutOfRange(uint32_t collection_id) const
1014{
1015 // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID
1016 // Otherwise, #bits is specified by GITS_TYPER.CIDbits
1017 const auto cid_bits = gitsTyper.cil == 0 ?
1018 16 : gitsTyper.cidBits + 1;
1019
1020 return collection_id >= (1ULL << cid_bits);
1021}
1022
1023bool
1024Gicv3Its::lpiOutOfRange(uint32_t intid) const
1025{
1026 return intid >= (1ULL << (Gicv3Distributor::IDBITS + 1)) ||
1028 intid != Gicv3::INTID_SPURIOUS);
1029}
1030
1033{
1035 return DrainState::Drained;
1036 } else {
1037 DPRINTF(Drain, "GICv3 ITS not drained\n");
1038 return DrainState::Draining;
1039 }
1040}
1041
1042void
1054
1055void
1067
1068void
1070{
1071 // Make the reader point to the next element
1072 gitsCreadr.offset = gitsCreadr.offset + 1;
1073
1074 // Check for wrapping
1075 if (gitsCreadr.offset == maxCommands()) {
1076 gitsCreadr.offset = 0;
1077 }
1078}
1079
1080uint64_t
1082{
1083 return (4096 * (gitsCbaser.size + 1)) / sizeof(ItsCommand::CommandEntry);
1084}
1085
1086void
1088{
1089 if (!gitsControl.enabled || !gitsCbaser.valid)
1090 return;
1091
1092 // If GITS_CWRITER gets set by sw to a value bigger than the
1093 // allowed one, the command queue should stop processing commands
1094 // until the register gets reset to an allowed one
1095 if (gitsCwriter.offset >= maxCommands()) {
1096 return;
1097 }
1098
1099 if (gitsCwriter.offset != gitsCreadr.offset) {
1100 // writer and reader pointing to different command
1101 // entries: queue not empty.
1102 DPRINTF(ITS, "Reading command from queue\n");
1103
1104 if (!pendingCommands) {
1105 auto *cmd_proc = new ItsCommand(*this);
1106
1107 runProcess(cmd_proc, nullptr);
1108 } else {
1109 DPRINTF(ITS, "Waiting for pending command to finish\n");
1110 }
1111 }
1112}
1113
1114Port &
1115Gicv3Its::getPort(const std::string &if_name, PortID idx)
1116{
1117 if (if_name == "dma") {
1118 return dmaPort;
1119 }
1120 return BasicPioDevice::getPort(if_name, idx);
1121}
1122
1123void
1125{
1126 assert(!packetsToRetry.empty());
1127
1128 while (!packetsToRetry.empty()) {
1129 ItsAction a = packetsToRetry.front();
1130
1131 assert(a.type == ItsActionType::SEND_REQ);
1132
1133 if (!dmaPort.sendTimingReq(a.pkt))
1134 break;
1135
1136 packetsToRetry.pop();
1137 }
1138}
1139
1140bool
1142{
1143 // @todo: We need to pay for this and not just zero it out
1144 pkt->headerDelay = pkt->payloadDelay = 0;
1145
1146 ItsProcess *proc =
1148
1149 runProcessTiming(proc, pkt);
1150
1151 return true;
1152}
1153
1156{
1157 if (sys->isAtomicMode()) {
1158 return runProcessAtomic(proc, pkt);
1159 } else if (sys->isTimingMode()) {
1160 return runProcessTiming(proc, pkt);
1161 } else {
1162 panic("Not in timing or atomic mode\n");
1163 }
1164}
1165
1168{
1169 ItsAction action = proc->run(pkt);
1170
1171 switch (action.type) {
1173 action.pkt->pushSenderState(proc);
1174
1175 if (packetsToRetry.empty() &&
1176 dmaPort.sendTimingReq(action.pkt)) {
1177
1178 } else {
1179 packetsToRetry.push(action);
1180 }
1181 break;
1182
1184 delete proc;
1185 if (!pendingCommands && !commandEvent.scheduled()) {
1187 }
1188 break;
1189
1190 default:
1191 panic("Unknown action\n");
1192 }
1193
1194 return action;
1195}
1196
1199{
1200 ItsAction action;
1201 Tick delay = 0;
1202 bool terminate = false;
1203
1204 do {
1205 action = proc->run(pkt);
1206
1207 switch (action.type) {
1209 delay += dmaPort.sendAtomic(action.pkt);
1210 pkt = action.pkt;
1211 break;
1212
1214 delete proc;
1215 terminate = true;
1216 break;
1217
1218 default:
1219 panic("Unknown action\n");
1220 }
1221
1222 } while (!terminate);
1223
1224 action.delay = delay;
1225
1226 return action;
1227}
1228
1229void
1231{
1232 DPRINTF(ITS, "Starting Translation Request\n");
1233
1234 auto *proc = new ItsTranslation(*this);
1235 runProcess(proc, pkt);
1236}
1237
1240{
1241 if (gitsTyper.pta == 1) {
1242 // RDBase is a redistributor address
1243 return gic->getRedistributorByAddr(rd_base << 16);
1244 } else {
1245 // RDBase is a redistributor number
1246 return gic->getRedistributor(rd_base);
1247 }
1248}
1249
1250Addr
1252{
1253 auto base_it = std::find_if(
1254 tableBases.begin(), tableBases.end(),
1255 [table] (const BASER &b) { return b.type == table; }
1256 );
1257
1258 panic_if(base_it == tableBases.end(),
1259 "ITS Table not recognised\n");
1260
1261 const BASER base = *base_it;
1262
1263 // real address depends on page size
1264 switch (base.pageSize) {
1265 case SIZE_4K:
1266 case SIZE_16K:
1267 return mbits(base, 47, 12);
1268 case SIZE_64K:
1269 return mbits(base, 47, 16) | (bits(base, 15, 12) << 48);
1270 default:
1271 panic("Unsupported page size\n");
1272 }
1273}
1274
1275void
1278{
1279 const uint64_t largest_lpi_id = 1ULL << (rd1->lpiIDBits + 1);
1280 const uint64_t table_size = largest_lpi_id / 8;
1281 auto lpi_pending_table = std::make_unique<uint8_t[]>(table_size);
1282
1283 // Copying the pending table from redistributor 1 to redistributor 2
1284 rd1->memProxy->readBlob(
1285 rd1->lpiPendingTablePtr, lpi_pending_table.get(),
1286 table_size);
1287
1288 rd2->memProxy->writeBlob(
1289 rd2->lpiPendingTablePtr, lpi_pending_table.get(),
1290 table_size);
1291
1292 // Clearing pending table in redistributor 2
1293 rd1->memProxy->memsetBlob(
1294 rd1->lpiPendingTablePtr, 0,
1295 table_size);
1296
1297 rd2->updateDistributor();
1298}
1299
1300} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
Addr pioAddr
Address that the device listens to.
Definition io_device.hh:151
BasicPioDevice(const Params &p, Addr size)
Definition io_device.cc:75
Tick pioDelay
Delay that the device experinces on an access.
Definition io_device.hh:157
Addr pioSize
Size that the device's address range.
Definition io_device.hh:154
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
static const uint32_t IDBITS
GICv3 ITS module.
Definition gic_v3_its.hh:85
static const uint32_t CTLR_QUIESCENT
uint32_t gitsTranslater
friend class gem5::ItsTranslation
Definition gic_v3_its.hh:87
void moveAllPendingState(Gicv3Redistributor *rd1, Gicv3Redistributor *rd2)
void checkCommandQueue()
uint32_t gitsIidr
bool lpiOutOfRange(uint32_t intid) const
Returns TRUE if the value supplied is larger than that permitted by GICD_TYPER.IDbits or not in the L...
Port & getPort(const std::string &if_name, PortID idx) override
Get a port with a given name and index.
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
bool deviceOutOfRange(uint32_t device_id) const
Returns TRUE if the value supplied has bits above the implemented range or if the value supplied exce...
Bitfield< 7, 0 > size
static const uint64_t BASER_WMASK_UNIMPL
static const uint32_t NUM_BASER_REGS
bool collectionOutOfRange(uint32_t collection_id) const
Returns TRUE if the value supplied has bits above the implemented range or if the value exceeds the t...
void translate(PacketPtr pkt)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
EventFunctionWrapper commandEvent
Gicv3Redistributor * getRedistributor(uint64_t rd_base)
DataPort dmaPort
std::vector< BASER > tableBases
bool idOutOfRange(uint32_t event_id, uint8_t itt_range) const
Returns TRUE if the eventID supplied has bits above the implemented size or above the itt_range.
ItsAction runProcessTiming(ItsProcess *proc, PacketPtr pkt)
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
ItsAction runProcess(ItsProcess *proc, PacketPtr pkt)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
void serialize(CheckpointOut &cp) const override
Serialize an object.
Gicv3Its(const Gicv3ItsParams &params)
ItsAction runProcessAtomic(ItsProcess *proc, PacketPtr pkt)
friend class gem5::ItsCommand
Definition gic_v3_its.hh:88
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
Addr pageAddress(enum ItsTables table)
bool sizeOutOfRange(uint32_t size) const
Returns TRUE if the value (size) supplied exceeds the maximum allowed by GITS_TYPER....
friend class gem5::ItsProcess
Definition gic_v3_its.hh:86
uint32_t requestorId
uint64_t maxCommands() const
static const uint64_t BASER_WMASK
static const AddrRange GITS_BASER
void setGIC(Gicv3 *_gic)
bool recvTimingResp(PacketPtr pkt)
std::queue< ItsAction > packetsToRetry
void incrementReadPointer()
uint32_t pendingTranslations
bool isPendingLPI(uint32_t intid)
static const uint32_t SMALLEST_LPI_ID
void setClrLPI(uint64_t data, bool set)
static const int INTID_SPURIOUS
Definition gic_v3.hh:117
void movall(Yield &yield, CommandEntry &command)
bool sizeOutOfRange(CommandEntry &command) const
void doInt(Yield &yield, CommandEntry &command)
bool idOutOfRange(CommandEntry &command, DTE dte) const
void main(Yield &yield) override
ItsCommand(Gicv3Its &_its)
void sync(Yield &yield, CommandEntry &command)
void vsync(Yield &yield, CommandEntry &command)
void invall(Yield &yield, CommandEntry &command)
void vmapp(Yield &yield, CommandEntry &command)
void readCommand(Yield &yield, CommandEntry &command)
void mapd(Yield &yield, CommandEntry &command)
void discard(Yield &yield, CommandEntry &command)
void processCommand(Yield &yield, CommandEntry &command)
void vmovp(Yield &yield, CommandEntry &command)
void vmovi(Yield &yield, CommandEntry &command)
void vmapti(Yield &yield, CommandEntry &command)
void clear(Yield &yield, CommandEntry &command)
void movi(Yield &yield, CommandEntry &command)
void mapc(Yield &yield, CommandEntry &command)
void vinvall(Yield &yield, CommandEntry &command)
void inv(Yield &yield, CommandEntry &command)
void vmapi(Yield &yield, CommandEntry &command)
static std::string commandName(uint32_t cmd)
bool deviceOutOfRange(CommandEntry &command) const
static DispatchTable cmdDispatcher
std::unordered_map< std::underlying_type< enum CommandType >::type, DispatchEntry > DispatchTable
bool collectionOutOfRange(CommandEntry &command) const
void mapi(Yield &yield, CommandEntry &command)
void mapti(Yield &yield, CommandEntry &command)
void writeIrqTranslationTable(Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte)
uint64_t readIrqCollectionTable(Yield &yield, uint32_t collection_id)
const std::string name() const
Returns the Gicv3Its name.
Definition gic_v3_its.cc:81
void terminate(Yield &yield)
Gicv3Its::DTE DTE
virtual ~ItsProcess()
Definition gic_v3_its.cc:69
Coroutine::CallerType Yield
ItsAction run(PacketPtr pkt)
Definition gic_v3_its.cc:87
void writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte)
void doWrite(Yield &yield, Addr addr, void *ptr, size_t size)
ItsProcess(Gicv3Its &_its)
Definition gic_v3_its.cc:64
std::unique_ptr< Coroutine > coroutine
void doRead(Yield &yield, Addr addr, void *ptr, size_t size)
Definition gic_v3_its.cc:95
gem5::Coroutine< PacketPtr, ItsAction > Coroutine
uint64_t readIrqTranslationTable(Yield &yield, const Addr itt_base, uint32_t event_id)
Gicv3Its::CTE CTE
virtual void main(Yield &yield)=0
uint64_t readDeviceTable(Yield &yield, uint32_t device_id)
void writeIrqCollectionTable(Yield &yield, uint32_t collection_id, CTE cte)
Gicv3Its::ITTE ITTE
void main(Yield &yield) override
ItsTranslation(Gicv3Its &_its)
std::pair< uint32_t, Gicv3Redistributor * > translateLPI(Yield &yield, uint32_t device_id, uint32_t event_id)
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
Addr getAddr() const
Definition packet.hh:807
void setUintX(uint64_t w, ByteOrder endian)
Set the value in the word w after truncating it to the length of the packet and then byteswapping it ...
Definition packet.cc:361
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition packet.hh:449
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition packet.hh:431
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
Definition packet.cc:334
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
Definition packet.cc:342
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
unsigned getSize() const
Definition packet.hh:817
void makeAtomicResponse()
Definition packet.hh:1074
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition io_device.cc:67
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
void writeBlob(Addr addr, const void *p, uint64_t size) const
Same as tryWriteBlob, but insists on success.
void memsetBlob(Addr addr, uint8_t v, uint64_t size) const
Same as tryMemsetBlob, but insists on success.
Ports are used to interface objects to each other.
Definition port.hh:62
STL pair class.
Definition stl.hh:58
#define COMMAND(x, method)
Definition gic_v3_its.cc:55
AddrRange RangeSize(Addr start, Addr size)
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
Definition addr_range.hh:64
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
Definition bitfield.hh:106
DrainState
Object drain/handover states.
Definition drain.hh:76
@ Draining
Draining buffers pending serialization/handover.
Definition drain.hh:78
@ Drained
Buffers drained, ready for serialization/handover.
Definition drain.hh:79
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:246
#define UNSERIALIZE_CONTAINER(member)
Definition serialize.hh:651
#define SERIALIZE_CONTAINER(member)
Definition serialize.hh:643
const Params & params() const
#define warn(...)
Definition logging.hh:288
Bitfield< 7 > b
Bitfield< 8 > a
Definition misc_types.hh:66
Bitfield< 15 > system
Definition misc.hh:1032
Bitfield< 63 > val
Definition misc.hh:804
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
T safe_cast(U &&ref_or_ptr)
Definition cast.hh:74
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
uint64_t Tick
Tick count type.
Definition types.hh:58
Packet * PacketPtr
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
PacketPtr pkt
Definition gic_v3_its.hh:73
ItsActionType type
Definition gic_v3_its.hh:72
const std::string & name()
Definition trace.cc:48

Generated on Mon Oct 27 2025 04:13:01 for gem5 by doxygen 1.14.0