gem5 v24.0.0.0
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
54#define COMMAND(x, method) { x, DispatchEntry(#x, method) }
55
56namespace gem5
57{
58
59const AddrRange Gicv3Its::GITS_BASER(0x0100, 0x0140);
60
61const uint32_t Gicv3Its::CTLR_QUIESCENT = 0x80000000;
62
64 : its(_its), coroutine(nullptr)
65{
66}
67
71
72void
74{
75 coroutine.reset(new Coroutine(
76 std::bind(&ItsProcess::main, this, std::placeholders::_1)));
77}
78
79const std::string
81{
82 return its.name();
83}
84
87{
88 assert(coroutine != nullptr);
89 assert(*coroutine);
90 return (*coroutine)(pkt).get();
91}
92
93void
94ItsProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size)
95{
98
99 RequestPtr req = std::make_shared<Request>(
100 addr, size, 0, its.requestorId);
101
102 req->taskId(context_switch_task_id::DMA);
103
104 a.pkt = new Packet(req, MemCmd::ReadReq);
105 a.pkt->dataStatic(ptr);
106
107 a.delay = 0;
108
109 PacketPtr pkt = yield(a).get();
110
111 assert(pkt);
112 assert(pkt->getSize() >= size);
113
114 delete pkt;
115}
116
117void
118ItsProcess::doWrite(Yield &yield, Addr addr, void *ptr, size_t size)
119{
120 ItsAction a;
122
123 RequestPtr req = std::make_shared<Request>(
124 addr, size, 0, its.requestorId);
125
126 req->taskId(context_switch_task_id::DMA);
127
128 a.pkt = new Packet(req, MemCmd::WriteReq);
129 a.pkt->dataStatic(ptr);
130
131 a.delay = 0;
132
133 PacketPtr pkt = yield(a).get();
134
135 assert(pkt);
136 assert(pkt->getSize() >= size);
137
138 delete pkt;
139}
140
141void
143{
144 ItsAction a;
146 a.pkt = NULL;
147 a.delay = 0;
148 yield(a);
149}
150
151void
152ItsProcess::writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte)
153{
155 const Addr address = base + (device_id * sizeof(dte));
156
157 DPRINTF(ITS, "Writing DTE at address %#x: %#x\n", address, dte);
158
159 doWrite(yield, address, &dte, sizeof(dte));
160}
161
162void
164 Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte)
165{
166 const Addr address = itt_base + (event_id * sizeof(itte));
167
168 doWrite(yield, address, &itte, sizeof(itte));
169
170 DPRINTF(ITS, "Writing ITTE at address %#x: %#x\n", address, itte);
171}
172
173void
175 Yield &yield, uint32_t collection_id, CTE cte)
176{
178 const Addr address = base + (collection_id * sizeof(cte));
179
180 doWrite(yield, address, &cte, sizeof(cte));
181
182 DPRINTF(ITS, "Writing CTE at address %#x: %#x\n", address, cte);
183}
184
185uint64_t
186ItsProcess::readDeviceTable(Yield &yield, uint32_t device_id)
187{
188 uint64_t dte;
190 const Addr address = base + (device_id * sizeof(dte));
191
192 doRead(yield, address, &dte, sizeof(dte));
193
194 DPRINTF(ITS, "Reading DTE at address %#x: %#x\n", address, dte);
195 return dte;
196}
197
198uint64_t
200 Yield &yield, const Addr itt_base, uint32_t event_id)
201{
202 uint64_t itte;
203 const Addr address = itt_base + (event_id * sizeof(itte));
204
205 doRead(yield, address, &itte, sizeof(itte));
206
207 DPRINTF(ITS, "Reading ITTE at address %#x: %#x\n", address, itte);
208 return itte;
209}
210
211uint64_t
212ItsProcess::readIrqCollectionTable(Yield &yield, uint32_t collection_id)
213{
214 uint64_t cte;
216 const Addr address = base + (collection_id * sizeof(cte));
217
218 doRead(yield, address, &cte, sizeof(cte));
219
220 DPRINTF(ITS, "Reading CTE at address %#x: %#x\n", address, cte);
221 return cte;
222}
223
225 : ItsProcess(_its)
226{
227 reinit();
229 its.gitsControl.quiescent = 0;
230}
231
233{
234 assert(its.pendingTranslations >= 1);
237 its.gitsControl.quiescent = 1;
238}
239
240void
242{
243 PacketPtr pkt = yield.get();
244
245 const uint32_t device_id = pkt->req->streamId();
246 const uint32_t event_id = pkt->getLE<uint32_t>();
247
248 auto result = translateLPI(yield, device_id, event_id);
249
250 uint32_t intid = result.first;
251 Gicv3Redistributor *redist = result.second;
252
253 // Set the LPI in the redistributor
254 redist->setClrLPI(intid, true);
255
256 // Update the value in GITS_TRANSLATER only once we know
257 // there was no error in the tranlation process (before
258 // terminating the translation
259 its.gitsTranslater = event_id;
260
261 terminate(yield);
262}
263
265ItsTranslation::translateLPI(Yield &yield, uint32_t device_id,
266 uint32_t event_id)
267{
268 if (its.deviceOutOfRange(device_id)) {
269 terminate(yield);
270 }
271
272 DTE dte = readDeviceTable(yield, device_id);
273
274 if (!dte.valid || its.idOutOfRange(event_id, dte.ittRange)) {
275 terminate(yield);
276 }
277
278 ITTE itte = readIrqTranslationTable(yield, dte.ittAddress, event_id);
279 const auto collection_id = itte.icid;
280
281 if (!itte.valid || its.collectionOutOfRange(collection_id)) {
282 terminate(yield);
283 }
284
285 CTE cte = readIrqCollectionTable(yield, collection_id);
286
287 if (!cte.valid) {
288 terminate(yield);
289 }
290
291 // Returning the INTID and the target Redistributor
292 return std::make_pair(itte.intNum, its.getRedistributor(cte));
293}
294
296{
297 COMMAND(CLEAR, &ItsCommand::clear),
298 COMMAND(DISCARD, &ItsCommand::discard),
301 COMMAND(INVALL, &ItsCommand::invall),
305 COMMAND(MAPTI, &ItsCommand::mapti),
306 COMMAND(MOVALL, &ItsCommand::movall),
309 COMMAND(VINVALL, &ItsCommand::vinvall),
310 COMMAND(VMAPI, &ItsCommand::vmapi),
311 COMMAND(VMAPP, &ItsCommand::vmapp),
312 COMMAND(VMAPTI, &ItsCommand::vmapti),
313 COMMAND(VMOVI, &ItsCommand::vmovi),
314 COMMAND(VMOVP, &ItsCommand::vmovp),
315 COMMAND(VSYNC, &ItsCommand::vsync),
316};
317
319 : ItsProcess(_its)
320{
321 reinit();
322 its.pendingCommands = true;
323
324 its.gitsControl.quiescent = 0;
325}
326
328{
329 its.pendingCommands = false;
330
332 its.gitsControl.quiescent = 1;
333}
334
335std::string
337{
338 const auto entry = cmdDispatcher.find(cmd);
339 return entry != cmdDispatcher.end() ? entry->second.name : "INVALID";
340}
341
342void
344{
345 ItsAction a;
347 a.pkt = nullptr;
348 a.delay = 0;
349 yield(a);
350
351 while (its.gitsCwriter.offset != its.gitsCreadr.offset) {
352 CommandEntry command;
353
354 // Reading the command from CMDQ
355 readCommand(yield, command);
356
357 processCommand(yield, command);
358
360 }
361
362 terminate(yield);
363}
364
365void
367{
368 // read the command pointed by GITS_CREADR
369 const Addr cmd_addr =
370 (its.gitsCbaser.physAddr << 12) + (its.gitsCreadr.offset << 5);
371
372 doRead(yield, cmd_addr, &command, sizeof(command));
373
374 DPRINTF(ITS, "Command %s read from queue at address: %#x\n",
375 commandName(command.type), cmd_addr);
376 DPRINTF(ITS, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n",
377 command.raw[0], command.raw[1], command.raw[2], command.raw[3]);
378}
379
380void
382{
383 const auto entry = cmdDispatcher.find(command.type);
384
385 if (entry != cmdDispatcher.end()) {
386 // Execute the command
387 entry->second.exec(this, yield, command);
388 } else {
389 panic("Unrecognized command type: %u", command.type);
390 }
391}
392
393void
395{
396 if (deviceOutOfRange(command)) {
398 terminate(yield);
399 }
400
401 DTE dte = readDeviceTable(yield, command.deviceId);
402
403 if (!dte.valid || idOutOfRange(command, dte)) {
405 terminate(yield);
406 }
407
409 yield, dte.ittAddress, command.eventId);
410
411 if (!itte.valid) {
413 terminate(yield);
414 }
415
416 const auto collection_id = itte.icid;
417 CTE cte = readIrqCollectionTable(yield, collection_id);
418
419 if (!cte.valid) {
421 terminate(yield);
422 }
423
424 // Clear the LPI in the redistributor
425 its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
426}
427
428void
430{
431 if (deviceOutOfRange(command)) {
433 terminate(yield);
434 }
435
436 DTE dte = readDeviceTable(yield, command.deviceId);
437
438 if (!dte.valid || idOutOfRange(command, dte)) {
440 terminate(yield);
441 }
442
444 yield, dte.ittAddress, command.eventId);
445
446 if (!itte.valid) {
448 terminate(yield);
449 }
450
451 const auto collection_id = itte.icid;
452 Gicv3Its::CTE cte = readIrqCollectionTable(yield, collection_id);
453
454 if (!cte.valid) {
456 terminate(yield);
457 }
458
459 its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
460
461 // Then removes the mapping from the ITT (invalidating)
462 itte.valid = 0;
464 yield, dte.ittAddress, command.eventId, itte);
465}
466
467void
469{
470 if (deviceOutOfRange(command)) {
472 terminate(yield);
473 }
474
475 DTE dte = readDeviceTable(yield, command.deviceId);
476
477 if (!dte.valid || idOutOfRange(command, dte)) {
479 terminate(yield);
480 }
481
483 yield, dte.ittAddress, command.eventId);
484
485 if (!itte.valid) {
487 terminate(yield);
488 }
489
490 const auto collection_id = itte.icid;
491 CTE cte = readIrqCollectionTable(yield, collection_id);
492
493 if (!cte.valid) {
495 terminate(yield);
496 }
497
498 // Set the LPI in the redistributor
499 its.getRedistributor(cte)->setClrLPI(itte.intNum, true);
500}
501
502void
504{
505 if (deviceOutOfRange(command)) {
507 terminate(yield);
508 }
509
510 DTE dte = readDeviceTable(yield, command.deviceId);
511
512 if (!dte.valid || idOutOfRange(command, dte)) {
514 terminate(yield);
515 }
516
518 yield, dte.ittAddress, command.eventId);
519
520 if (!itte.valid) {
522 terminate(yield);
523 }
524
525 const auto collection_id = itte.icid;
526 CTE cte = readIrqCollectionTable(yield, collection_id);
527
528 if (!cte.valid) {
530 terminate(yield);
531 }
532 // Do nothing since caching is currently not supported in
533 // Redistributor
534}
535
536void
538{
539 if (collectionOutOfRange(command)) {
541 terminate(yield);
542 }
543
544 const auto icid = bits(command.raw[2], 15, 0);
545
546 CTE cte = readIrqCollectionTable(yield, icid);
547
548 if (!cte.valid) {
550 terminate(yield);
551 }
552 // Do nothing since caching is currently not supported in
553 // Redistributor
554}
555
556void
558{
559 if (collectionOutOfRange(command)) {
561 terminate(yield);
562 }
563
564 CTE cte = 0;
565 cte.valid = bits(command.raw[2], 63);
566 cte.rdBase = bits(command.raw[2], 50, 16);
567
568 const auto icid = bits(command.raw[2], 15, 0);
569
570 writeIrqCollectionTable(yield, icid, cte);
571}
572
573void
575{
576 if (deviceOutOfRange(command) || sizeOutOfRange(command)) {
578 terminate(yield);
579 }
580
581 DTE dte = 0;
582 dte.valid = bits(command.raw[2], 63);
583 dte.ittAddress = mbits(command.raw[2], 51, 8);
584 dte.ittRange = bits(command.raw[1], 4, 0);
585
586 writeDeviceTable(yield, command.deviceId, dte);
587}
588
589void
591{
592 if (deviceOutOfRange(command)) {
594 terminate(yield);
595 }
596
597 if (collectionOutOfRange(command)) {
599 terminate(yield);
600 }
601
602 DTE dte = readDeviceTable(yield, command.deviceId);
603
604 if (!dte.valid || idOutOfRange(command, dte) ||
605 its.lpiOutOfRange(command.eventId)) {
606
608 terminate(yield);
609 }
610
611 Gicv3Its::ITTE itte = readIrqTranslationTable(
612 yield, dte.ittAddress, command.eventId);
613
614 itte.valid = 1;
615 itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
616 itte.intNum = command.eventId;
617 itte.icid = bits(command.raw[2], 15, 0);
618
620 yield, dte.ittAddress, command.eventId, itte);
621}
622
623void
625{
626 if (deviceOutOfRange(command)) {
628 terminate(yield);
629 }
630
631 if (collectionOutOfRange(command)) {
633 terminate(yield);
634 }
635
636 DTE dte = readDeviceTable(yield, command.deviceId);
637
638 const auto pintid = bits(command.raw[1], 63, 32);
639
640 if (!dte.valid || idOutOfRange(command, dte) ||
641 its.lpiOutOfRange(pintid)) {
642
644 terminate(yield);
645 }
646
648 yield, dte.ittAddress, command.eventId);
649
650 itte.valid = 1;
651 itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
652 itte.intNum = pintid;
653 itte.icid = bits(command.raw[2], 15, 0);
654
656 yield, dte.ittAddress, command.eventId, itte);
657}
658
659void
661{
662 const uint64_t rd1 = bits(command.raw[2], 50, 16);
663 const uint64_t rd2 = bits(command.raw[3], 50, 16);
664
665 if (rd1 != rd2) {
666 Gicv3Redistributor * redist1 = its.getRedistributor(rd1);
667 Gicv3Redistributor * redist2 = its.getRedistributor(rd2);
668
669 its.moveAllPendingState(redist1, redist2);
670 }
671}
672
673void
675{
676 if (deviceOutOfRange(command)) {
678 terminate(yield);
679 }
680
681 if (collectionOutOfRange(command)) {
683 terminate(yield);
684 }
685
686 DTE dte = readDeviceTable(yield, command.deviceId);
687
688 if (!dte.valid || idOutOfRange(command, dte)) {
690 terminate(yield);
691 }
692
694 yield, dte.ittAddress, command.eventId);
695
696 if (!itte.valid || itte.intType == Gicv3Its::VIRTUAL_INTERRUPT) {
698 terminate(yield);
699 }
700
701 const auto collection_id1 = itte.icid;
702 CTE cte1 = readIrqCollectionTable(yield, collection_id1);
703
704 if (!cte1.valid) {
706 terminate(yield);
707 }
708
709 const auto collection_id2 = bits(command.raw[2], 15, 0);
710 CTE cte2 = readIrqCollectionTable(yield, collection_id2);
711
712 if (!cte2.valid) {
714 terminate(yield);
715 }
716
717 Gicv3Redistributor *first_redist = its.getRedistributor(cte1);
718 Gicv3Redistributor *second_redist = its.getRedistributor(cte2);
719
720 if (second_redist != first_redist) {
721 // move pending state of the interrupt from one redistributor
722 // to the other.
723 if (first_redist->isPendingLPI(itte.intNum)) {
724 first_redist->setClrLPI(itte.intNum, false);
725 second_redist->setClrLPI(itte.intNum, true);
726 }
727 }
728
729 itte.icid = collection_id2;
731 yield, dte.ittAddress, command.eventId, itte);
732}
733
734void
736{
737 warn("ITS %s command unimplemented", __func__);
738}
739
740void
742{
743 panic("ITS %s command unimplemented", __func__);
744}
745
746void
748{
749 panic("ITS %s command unimplemented", __func__);
750}
751
752void
754{
755 panic("ITS %s command unimplemented", __func__);
756}
757
758void
760{
761 panic("ITS %s command unimplemented", __func__);
762}
763
764void
766{
767 panic("ITS %s command unimplemented", __func__);
768}
769
770void
772{
773 panic("ITS %s command unimplemented", __func__);
774}
775
776void
778{
779 panic("ITS %s command unimplemented", __func__);
780}
781
782Gicv3Its::Gicv3Its(const Gicv3ItsParams &params)
783 : BasicPioDevice(params, params.pio_size),
784 dmaPort(name() + ".dma", *this),
785 gitsControl(CTLR_QUIESCENT),
786 gitsTyper(params.gits_typer),
787 gitsCbaser(0), gitsCreadr(0),
788 gitsCwriter(0), gitsIidr(0),
789 tableBases(NUM_BASER_REGS, 0),
790 requestorId(params.system->getRequestorId(this)),
791 gic(nullptr),
792 commandEvent([this] { checkCommandQueue(); }, name()),
793 pendingCommands(false),
794 pendingTranslations(0)
795{
796 BASER device_baser = 0;
797 device_baser.type = DEVICE_TABLE;
798 device_baser.entrySize = sizeof(uint64_t) - 1;
799 tableBases[0] = device_baser;
800
801 BASER icollect_baser = 0;
802 icollect_baser.type = COLLECTION_TABLE;
803 icollect_baser.entrySize = sizeof(uint64_t) - 1;
804 tableBases[1] = icollect_baser;
805}
806
807void
809{
810 assert(!gic);
811 gic = _gic;
812}
813
816{
817 assert(pioSize != 0);
818 AddrRangeList ranges;
819 DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
820 ranges.push_back(RangeSize(pioAddr, pioSize));
821 return ranges;
822}
823
824Tick
826{
827 const Addr addr = pkt->getAddr() - pioAddr;
828 uint64_t value = 0;
829
830 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
831
832 switch (addr) {
833 case GITS_CTLR:
834 value = gitsControl;
835 break;
836
837 case GITS_IIDR:
838 value = gitsIidr;
839 break;
840
841 case GITS_TYPER:
842 value = gitsTyper;
843 break;
844
845 case GITS_TYPER + 4:
846 value = gitsTyper.high;
847 break;
848
849 case GITS_CBASER:
850 value = gitsCbaser;
851 break;
852
853 case GITS_CBASER + 4:
854 value = gitsCbaser.high;
855 break;
856
857 case GITS_CWRITER:
858 value = gitsCwriter;
859 break;
860
861 case GITS_CWRITER + 4:
862 value = gitsCwriter.high;
863 break;
864
865 case GITS_CREADR:
866 value = gitsCreadr;
867 break;
868
869 case GITS_CREADR + 4:
870 value = gitsCreadr.high;
871 break;
872
873 case GITS_PIDR2:
874 value = gic->getDistributor()->gicdPidr2;
875 break;
876
877 case GITS_TRANSLATER:
878 value = gitsTranslater;
879 break;
880
881 default:
882 if (GITS_BASER.contains(addr)) {
883 auto relative_addr = addr - GITS_BASER.start();
884 auto baser_index = relative_addr / sizeof(uint64_t);
885
886 value = tableBases[baser_index];
887 break;
888 } else {
889 panic("Unrecognized register access\n");
890 }
891 }
892
893 pkt->setUintX(value, ByteOrder::little);
894 pkt->makeAtomicResponse();
895 return pioDelay;
896}
897
898Tick
900{
901 Addr addr = pkt->getAddr() - pioAddr;
902
903 DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
904
905 switch (addr) {
906 case GITS_CTLR:
907 assert(pkt->getSize() == sizeof(uint32_t));
908 gitsControl = (pkt->getLE<uint32_t>() & ~CTLR_QUIESCENT);
909 // We should check here if the ITS has been disabled, and if
910 // that's the case, flush GICv3 caches to external memory.
911 // This is not happening now, since LPI caching is not
912 // currently implemented in gem5.
913 break;
914
915 case GITS_IIDR:
916 panic("GITS_IIDR is Read Only\n");
917
918 case GITS_TYPER:
919 panic("GITS_TYPER is Read Only\n");
920
921 case GITS_CBASER:
922 if (pkt->getSize() == sizeof(uint32_t)) {
923 gitsCbaser.low = pkt->getLE<uint32_t>();
924 } else {
925 assert(pkt->getSize() == sizeof(uint64_t));
926 gitsCbaser = pkt->getLE<uint64_t>();
927 }
928
929 gitsCreadr = 0; // Cleared when CBASER gets written
930
932 break;
933
934 case GITS_CBASER + 4:
935 assert(pkt->getSize() == sizeof(uint32_t));
936 gitsCbaser.high = pkt->getLE<uint32_t>();
937
938 gitsCreadr = 0; // Cleared when CBASER gets written
939
941 break;
942
943 case GITS_CWRITER:
944 if (pkt->getSize() == sizeof(uint32_t)) {
945 gitsCwriter.low = pkt->getLE<uint32_t>();
946 } else {
947 assert(pkt->getSize() == sizeof(uint64_t));
948 gitsCwriter = pkt->getLE<uint64_t>();
949 }
950
952 break;
953
954 case GITS_CWRITER + 4:
955 assert(pkt->getSize() == sizeof(uint32_t));
956 gitsCwriter.high = pkt->getLE<uint32_t>();
957
959 break;
960
961 case GITS_CREADR:
962 panic("GITS_READR is Read Only\n");
963
964 case GITS_TRANSLATER:
965 if (gitsControl.enabled) {
966 translate(pkt);
967 }
968 break;
969
970 default:
971 if (GITS_BASER.contains(addr)) {
972 auto relative_addr = addr - GITS_BASER.start();
973 auto baser_index = relative_addr / sizeof(uint64_t);
974
975 const uint64_t table_base = tableBases[baser_index];
976 const uint64_t w_mask = tableBases[baser_index].type ?
978 const uint64_t val = pkt->getLE<uint64_t>() & w_mask;
979
980 tableBases[baser_index] = table_base | val;
981 break;
982 } else {
983 panic("Unrecognized register access\n");
984 }
985 }
986
987 pkt->makeAtomicResponse();
988 return pioDelay;
989}
990
991bool
992Gicv3Its::idOutOfRange(uint32_t event_id, uint8_t itt_range) const
993{
994 const uint32_t id_bits = gitsTyper.idBits;
995 return event_id >= (1ULL << (id_bits + 1)) ||
996 event_id >= ((1ULL << itt_range) + 1);
997}
998
999bool
1000Gicv3Its::deviceOutOfRange(uint32_t device_id) const
1001{
1002 return device_id >= (1ULL << (gitsTyper.devBits + 1));
1003}
1004
1005bool
1006Gicv3Its::sizeOutOfRange(uint32_t size) const
1007{
1008 return size > gitsTyper.idBits;
1009}
1010
1011bool
1012Gicv3Its::collectionOutOfRange(uint32_t collection_id) const
1013{
1014 // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID
1015 // Otherwise, #bits is specified by GITS_TYPER.CIDbits
1016 const auto cid_bits = gitsTyper.cil == 0 ?
1017 16 : gitsTyper.cidBits + 1;
1018
1019 return collection_id >= (1ULL << cid_bits);
1020}
1021
1022bool
1023Gicv3Its::lpiOutOfRange(uint32_t intid) const
1024{
1025 return intid >= (1ULL << (Gicv3Distributor::IDBITS + 1)) ||
1027 intid != Gicv3::INTID_SPURIOUS);
1028}
1029
1032{
1034 return DrainState::Drained;
1035 } else {
1036 DPRINTF(Drain, "GICv3 ITS not drained\n");
1037 return DrainState::Draining;
1038 }
1039}
1040
1041void
1053
1054void
1066
1067void
1069{
1070 // Make the reader point to the next element
1071 gitsCreadr.offset = gitsCreadr.offset + 1;
1072
1073 // Check for wrapping
1074 if (gitsCreadr.offset == maxCommands()) {
1075 gitsCreadr.offset = 0;
1076 }
1077}
1078
1079uint64_t
1081{
1082 return (4096 * (gitsCbaser.size + 1)) / sizeof(ItsCommand::CommandEntry);
1083}
1084
1085void
1087{
1088 if (!gitsControl.enabled || !gitsCbaser.valid)
1089 return;
1090
1091 // If GITS_CWRITER gets set by sw to a value bigger than the
1092 // allowed one, the command queue should stop processing commands
1093 // until the register gets reset to an allowed one
1094 if (gitsCwriter.offset >= maxCommands()) {
1095 return;
1096 }
1097
1098 if (gitsCwriter.offset != gitsCreadr.offset) {
1099 // writer and reader pointing to different command
1100 // entries: queue not empty.
1101 DPRINTF(ITS, "Reading command from queue\n");
1102
1103 if (!pendingCommands) {
1104 auto *cmd_proc = new ItsCommand(*this);
1105
1106 runProcess(cmd_proc, nullptr);
1107 } else {
1108 DPRINTF(ITS, "Waiting for pending command to finish\n");
1109 }
1110 }
1111}
1112
1113Port &
1114Gicv3Its::getPort(const std::string &if_name, PortID idx)
1115{
1116 if (if_name == "dma") {
1117 return dmaPort;
1118 }
1119 return BasicPioDevice::getPort(if_name, idx);
1120}
1121
1122void
1124{
1125 assert(!packetsToRetry.empty());
1126
1127 while (!packetsToRetry.empty()) {
1128 ItsAction a = packetsToRetry.front();
1129
1130 assert(a.type == ItsActionType::SEND_REQ);
1131
1132 if (!dmaPort.sendTimingReq(a.pkt))
1133 break;
1134
1135 packetsToRetry.pop();
1136 }
1137}
1138
1139bool
1141{
1142 // @todo: We need to pay for this and not just zero it out
1143 pkt->headerDelay = pkt->payloadDelay = 0;
1144
1145 ItsProcess *proc =
1147
1148 runProcessTiming(proc, pkt);
1149
1150 return true;
1151}
1152
1155{
1156 if (sys->isAtomicMode()) {
1157 return runProcessAtomic(proc, pkt);
1158 } else if (sys->isTimingMode()) {
1159 return runProcessTiming(proc, pkt);
1160 } else {
1161 panic("Not in timing or atomic mode\n");
1162 }
1163}
1164
1167{
1168 ItsAction action = proc->run(pkt);
1169
1170 switch (action.type) {
1172 action.pkt->pushSenderState(proc);
1173
1174 if (packetsToRetry.empty() &&
1175 dmaPort.sendTimingReq(action.pkt)) {
1176
1177 } else {
1178 packetsToRetry.push(action);
1179 }
1180 break;
1181
1183 delete proc;
1186 }
1187 break;
1188
1189 default:
1190 panic("Unknown action\n");
1191 }
1192
1193 return action;
1194}
1195
1198{
1199 ItsAction action;
1200 Tick delay = 0;
1201 bool terminate = false;
1202
1203 do {
1204 action = proc->run(pkt);
1205
1206 switch (action.type) {
1208 delay += dmaPort.sendAtomic(action.pkt);
1209 pkt = action.pkt;
1210 break;
1211
1213 delete proc;
1214 terminate = true;
1215 break;
1216
1217 default:
1218 panic("Unknown action\n");
1219 }
1220
1221 } while (!terminate);
1222
1223 action.delay = delay;
1224
1225 return action;
1226}
1227
1228void
1230{
1231 DPRINTF(ITS, "Starting Translation Request\n");
1232
1233 auto *proc = new ItsTranslation(*this);
1234 runProcess(proc, pkt);
1235}
1236
1239{
1240 if (gitsTyper.pta == 1) {
1241 // RDBase is a redistributor address
1242 return gic->getRedistributorByAddr(rd_base << 16);
1243 } else {
1244 // RDBase is a redistributor number
1245 return gic->getRedistributor(rd_base);
1246 }
1247}
1248
1249Addr
1251{
1252 auto base_it = std::find_if(
1253 tableBases.begin(), tableBases.end(),
1254 [table] (const BASER &b) { return b.type == table; }
1255 );
1256
1257 panic_if(base_it == tableBases.end(),
1258 "ITS Table not recognised\n");
1259
1260 const BASER base = *base_it;
1261
1262 // real address depends on page size
1263 switch (base.pageSize) {
1264 case SIZE_4K:
1265 case SIZE_16K:
1266 return mbits(base, 47, 12);
1267 case SIZE_64K:
1268 return mbits(base, 47, 16) | (bits(base, 15, 12) << 48);
1269 default:
1270 panic("Unsupported page size\n");
1271 }
1272}
1273
1274void
1277{
1278 const uint64_t largest_lpi_id = 1ULL << (rd1->lpiIDBits + 1);
1279 uint8_t lpi_pending_table[largest_lpi_id / 8];
1280
1281 // Copying the pending table from redistributor 1 to redistributor 2
1282 rd1->memProxy->readBlob(
1283 rd1->lpiPendingTablePtr, (uint8_t *)lpi_pending_table,
1284 sizeof(lpi_pending_table));
1285
1286 rd2->memProxy->writeBlob(
1287 rd2->lpiPendingTablePtr, (uint8_t *)lpi_pending_table,
1288 sizeof(lpi_pending_table));
1289
1290 // Clearing pending table in redistributor 2
1291 rd1->memProxy->memsetBlob(
1292 rd1->lpiPendingTablePtr,
1293 0, sizeof(lpi_pending_table));
1294
1295 rd2->updateDistributor();
1296}
1297
1298} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
Addr pioAddr
Address that the device listens to.
Definition io_device.hh:151
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...
CallerType: A reference to an object of this class will be passed to the coroutine task.
Definition coroutine.hh:85
static const uint32_t IDBITS
GICv3 ITS module.
Definition gic_v3_its.hh:84
static const uint32_t CTLR_QUIESCENT
uint32_t gitsTranslater
friend class gem5::ItsTranslation
Definition gic_v3_its.hh:86
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
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:87
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....
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)
Gicv3Redistributor * getRedistributor(ContextID context_id) const
Definition gic_v3.hh:202
Gicv3Distributor * getDistributor() const
Definition gic_v3.hh:196
static const int INTID_SPURIOUS
Definition gic_v3.hh:116
Gicv3Redistributor * getRedistributorByAddr(Addr address) const
Definition gic_v3.cc:342
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)
ItsProcess is a base coroutine wrapper which is spawned by the Gicv3Its module when the latter needs ...
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:80
void terminate(Yield &yield)
Gicv3Its::DTE DTE
virtual ~ItsProcess()
Definition gic_v3_its.cc:68
ItsAction run(PacketPtr pkt)
Definition gic_v3_its.cc:86
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:63
std::unique_ptr< Coroutine > coroutine
void doRead(Yield &yield, Addr addr, void *ptr, size_t size)
Definition gic_v3_its.cc:94
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)
virtual std::string name() const
Definition named.hh:47
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
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
Definition port.hh:552
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
Definition port.hh:603
bool isAtomicMode() const
Is the system in atomic mode?
Definition system.hh:258
bool isTimingMode() const
Is the system in timing mode?
Definition system.hh:270
STL pair class.
Definition stl.hh:58
#define COMMAND(x, method)
Definition gic_v3_its.cc:54
AddrRange RangeSize(Addr start, Addr size)
bool contains(const Addr &a) const
Determine if the range contains an address.
Addr start() const
Get the start address of the range.
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
std::enable_if_t<!std::is_same_v< T, void >, T > get()
get() is the way we can extrapolate arguments from the coroutine caller.
Definition coroutine.hh:141
DrainState
Object drain/handover states.
Definition drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#define UNSERIALIZE_CONTAINER(member)
Definition serialize.hh:634
#define SERIALIZE_CONTAINER(member)
Definition serialize.hh:626
#define warn(...)
Definition logging.hh:256
Bitfield< 7 > b
Bitfield< 27, 24 > gic
Bitfield< 8 > a
Definition misc_types.hh:66
Bitfield< 15 > system
Definition misc.hh:1032
Bitfield< 51, 12 > base
Definition pagetable.hh:141
Bitfield< 63 > val
Definition misc.hh:804
Bitfield< 3 > addr
Definition types.hh:84
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria 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
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
PacketPtr pkt
Definition gic_v3_its.hh:72
ItsActionType type
Definition gic_v3_its.hh:71
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:24:02 for gem5 by doxygen 1.11.0