ed349ac00295d59d0a664029edac1d260ef9eb84
2 * Copyright (c) 2019 ARM Limited
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.
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.
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.
38 #include "dev/arm/gic_v3_its.hh"
40 #include "debug/AddrRanges.hh"
41 #include "debug/Drain.hh"
42 #include "debug/GIC.hh"
43 #include "debug/ITS.hh"
44 #include "dev/arm/gic_v3.hh"
45 #include "dev/arm/gic_v3_distributor.hh"
46 #include "dev/arm/gic_v3_redistributor.hh"
47 #include "mem/packet_access.hh"
49 #define COMMAND(x, method) { x, DispatchEntry(#x, method) }
51 const AddrRange
Gicv3Its::GITS_BASER(0x0100, 0x0140);
53 const uint32_t Gicv3Its::CTLR_QUIESCENT
= 0x80000000;
55 ItsProcess::ItsProcess(Gicv3Its
&_its
)
56 : its(_its
), coroutine(nullptr)
60 ItsProcess::~ItsProcess()
67 coroutine
.reset(new Coroutine(
68 std::bind(&ItsProcess::main
, this, std::placeholders::_1
)));
72 ItsProcess::name() const
78 ItsProcess::run(PacketPtr pkt
)
80 assert(coroutine
!= nullptr);
82 return (*coroutine
)(pkt
).get();
86 ItsProcess::doRead(Yield
&yield
, Addr addr
, void *ptr
, size_t size
)
89 a
.type
= ItsActionType::SEND_REQ
;
91 RequestPtr req
= std::make_shared
<Request
>(
92 addr
, size
, 0, its
.requestorId
);
94 req
->taskId(ContextSwitchTaskId::DMA
);
96 a
.pkt
= new Packet(req
, MemCmd::ReadReq
);
97 a
.pkt
->dataStatic(ptr
);
101 PacketPtr pkt
= yield(a
).get();
104 assert(pkt
->getSize() >= size
);
110 ItsProcess::doWrite(Yield
&yield
, Addr addr
, void *ptr
, size_t size
)
113 a
.type
= ItsActionType::SEND_REQ
;
115 RequestPtr req
= std::make_shared
<Request
>(
116 addr
, size
, 0, its
.requestorId
);
118 req
->taskId(ContextSwitchTaskId::DMA
);
120 a
.pkt
= new Packet(req
, MemCmd::WriteReq
);
121 a
.pkt
->dataStatic(ptr
);
125 PacketPtr pkt
= yield(a
).get();
128 assert(pkt
->getSize() >= size
);
134 ItsProcess::terminate(Yield
&yield
)
137 a
.type
= ItsActionType::TERMINATE
;
144 ItsProcess::writeDeviceTable(Yield
&yield
, uint32_t device_id
, DTE dte
)
146 const Addr base
= its
.pageAddress(Gicv3Its::DEVICE_TABLE
);
147 const Addr address
= base
+ (device_id
* sizeof(dte
));
149 DPRINTF(ITS
, "Writing DTE at address %#x: %#x\n", address
, dte
);
151 doWrite(yield
, address
, &dte
, sizeof(dte
));
155 ItsProcess::writeIrqTranslationTable(
156 Yield
&yield
, const Addr itt_base
, uint32_t event_id
, ITTE itte
)
158 const Addr address
= itt_base
+ (event_id
* sizeof(itte
));
160 doWrite(yield
, address
, &itte
, sizeof(itte
));
162 DPRINTF(ITS
, "Writing ITTE at address %#x: %#x\n", address
, itte
);
166 ItsProcess::writeIrqCollectionTable(
167 Yield
&yield
, uint32_t collection_id
, CTE cte
)
169 const Addr base
= its
.pageAddress(Gicv3Its::COLLECTION_TABLE
);
170 const Addr address
= base
+ (collection_id
* sizeof(cte
));
172 doWrite(yield
, address
, &cte
, sizeof(cte
));
174 DPRINTF(ITS
, "Writing CTE at address %#x: %#x\n", address
, cte
);
178 ItsProcess::readDeviceTable(Yield
&yield
, uint32_t device_id
)
181 const Addr base
= its
.pageAddress(Gicv3Its::DEVICE_TABLE
);
182 const Addr address
= base
+ (device_id
* sizeof(dte
));
184 doRead(yield
, address
, &dte
, sizeof(dte
));
186 DPRINTF(ITS
, "Reading DTE at address %#x: %#x\n", address
, dte
);
191 ItsProcess::readIrqTranslationTable(
192 Yield
&yield
, const Addr itt_base
, uint32_t event_id
)
195 const Addr address
= itt_base
+ (event_id
* sizeof(itte
));
197 doRead(yield
, address
, &itte
, sizeof(itte
));
199 DPRINTF(ITS
, "Reading ITTE at address %#x: %#x\n", address
, itte
);
204 ItsProcess::readIrqCollectionTable(Yield
&yield
, uint32_t collection_id
)
207 const Addr base
= its
.pageAddress(Gicv3Its::COLLECTION_TABLE
);
208 const Addr address
= base
+ (collection_id
* sizeof(cte
));
210 doRead(yield
, address
, &cte
, sizeof(cte
));
212 DPRINTF(ITS
, "Reading CTE at address %#x: %#x\n", address
, cte
);
216 ItsTranslation::ItsTranslation(Gicv3Its
&_its
)
220 its
.pendingTranslations
++;
221 its
.gitsControl
.quiescent
= 0;
224 ItsTranslation::~ItsTranslation()
226 assert(its
.pendingTranslations
>= 1);
227 its
.pendingTranslations
--;
228 if (!its
.pendingTranslations
&& !its
.pendingCommands
)
229 its
.gitsControl
.quiescent
= 1;
233 ItsTranslation::main(Yield
&yield
)
235 PacketPtr pkt
= yield
.get();
237 const uint32_t device_id
= pkt
->req
->streamId();
238 const uint32_t event_id
= pkt
->getLE
<uint32_t>();
240 auto result
= translateLPI(yield
, device_id
, event_id
);
242 uint32_t intid
= result
.first
;
243 Gicv3Redistributor
*redist
= result
.second
;
245 // Set the LPI in the redistributor
246 redist
->setClrLPI(intid
, true);
248 // Update the value in GITS_TRANSLATER only once we know
249 // there was no error in the tranlation process (before
250 // terminating the translation
251 its
.gitsTranslater
= event_id
;
256 std::pair
<uint32_t, Gicv3Redistributor
*>
257 ItsTranslation::translateLPI(Yield
&yield
, uint32_t device_id
,
260 if (its
.deviceOutOfRange(device_id
)) {
264 DTE dte
= readDeviceTable(yield
, device_id
);
266 if (!dte
.valid
|| its
.idOutOfRange(event_id
, dte
.ittRange
)) {
270 ITTE itte
= readIrqTranslationTable(yield
, dte
.ittAddress
, event_id
);
271 const auto collection_id
= itte
.icid
;
273 if (!itte
.valid
|| its
.collectionOutOfRange(collection_id
)) {
277 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
283 // Returning the INTID and the target Redistributor
284 return std::make_pair(itte
.intNum
, its
.getRedistributor(cte
));
287 ItsCommand::DispatchTable
ItsCommand::cmdDispatcher
=
289 COMMAND(CLEAR
, &ItsCommand::clear
),
290 COMMAND(DISCARD
, &ItsCommand::discard
),
291 COMMAND(INT
, &ItsCommand::doInt
),
292 COMMAND(INV
, &ItsCommand::inv
),
293 COMMAND(INVALL
, &ItsCommand::invall
),
294 COMMAND(MAPC
, &ItsCommand::mapc
),
295 COMMAND(MAPD
, &ItsCommand::mapd
),
296 COMMAND(MAPI
, &ItsCommand::mapi
),
297 COMMAND(MAPTI
, &ItsCommand::mapti
),
298 COMMAND(MOVALL
, &ItsCommand::movall
),
299 COMMAND(MOVI
, &ItsCommand::movi
),
300 COMMAND(SYNC
, &ItsCommand::sync
),
301 COMMAND(VINVALL
, &ItsCommand::vinvall
),
302 COMMAND(VMAPI
, &ItsCommand::vmapi
),
303 COMMAND(VMAPP
, &ItsCommand::vmapp
),
304 COMMAND(VMAPTI
, &ItsCommand::vmapti
),
305 COMMAND(VMOVI
, &ItsCommand::vmovi
),
306 COMMAND(VMOVP
, &ItsCommand::vmovp
),
307 COMMAND(VSYNC
, &ItsCommand::vsync
),
310 ItsCommand::ItsCommand(Gicv3Its
&_its
)
314 its
.pendingCommands
= true;
316 its
.gitsControl
.quiescent
= 0;
319 ItsCommand::~ItsCommand()
321 its
.pendingCommands
= false;
323 if (!its
.pendingTranslations
)
324 its
.gitsControl
.quiescent
= 1;
328 ItsCommand::commandName(uint32_t cmd
)
330 const auto entry
= cmdDispatcher
.find(cmd
);
331 return entry
!= cmdDispatcher
.end() ? entry
->second
.name
: "INVALID";
335 ItsCommand::main(Yield
&yield
)
338 a
.type
= ItsActionType::INITIAL_NOP
;
343 while (its
.gitsCwriter
.offset
!= its
.gitsCreadr
.offset
) {
344 CommandEntry command
;
346 // Reading the command from CMDQ
347 readCommand(yield
, command
);
349 processCommand(yield
, command
);
351 its
.incrementReadPointer();
358 ItsCommand::readCommand(Yield
&yield
, CommandEntry
&command
)
360 // read the command pointed by GITS_CREADR
361 const Addr cmd_addr
=
362 (its
.gitsCbaser
.physAddr
<< 12) + (its
.gitsCreadr
.offset
<< 5);
364 doRead(yield
, cmd_addr
, &command
, sizeof(command
));
366 DPRINTF(ITS
, "Command %s read from queue at address: %#x\n",
367 commandName(command
.type
), cmd_addr
);
368 DPRINTF(ITS
, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n",
369 command
.raw
[0], command
.raw
[1], command
.raw
[2], command
.raw
[3]);
373 ItsCommand::processCommand(Yield
&yield
, CommandEntry
&command
)
375 const auto entry
= cmdDispatcher
.find(command
.type
);
377 if (entry
!= cmdDispatcher
.end()) {
378 // Execute the command
379 entry
->second
.exec(this, yield
, command
);
381 panic("Unrecognized command type: %u", command
.type
);
386 ItsCommand::clear(Yield
&yield
, CommandEntry
&command
)
388 if (deviceOutOfRange(command
)) {
389 its
.incrementReadPointer();
393 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
395 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
396 its
.incrementReadPointer();
400 ITTE itte
= readIrqTranslationTable(
401 yield
, dte
.ittAddress
, command
.eventId
);
404 its
.incrementReadPointer();
408 const auto collection_id
= itte
.icid
;
409 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
412 its
.incrementReadPointer();
416 // Clear the LPI in the redistributor
417 its
.getRedistributor(cte
)->setClrLPI(itte
.intNum
, false);
421 ItsCommand::discard(Yield
&yield
, CommandEntry
&command
)
423 if (deviceOutOfRange(command
)) {
424 its
.incrementReadPointer();
428 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
430 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
431 its
.incrementReadPointer();
435 ITTE itte
= readIrqTranslationTable(
436 yield
, dte
.ittAddress
, command
.eventId
);
439 its
.incrementReadPointer();
443 const auto collection_id
= itte
.icid
;
444 Gicv3Its::CTE cte
= readIrqCollectionTable(yield
, collection_id
);
447 its
.incrementReadPointer();
451 its
.getRedistributor(cte
)->setClrLPI(itte
.intNum
, false);
453 // Then removes the mapping from the ITT (invalidating)
455 writeIrqTranslationTable(
456 yield
, dte
.ittAddress
, command
.eventId
, itte
);
460 ItsCommand::doInt(Yield
&yield
, CommandEntry
&command
)
462 if (deviceOutOfRange(command
)) {
463 its
.incrementReadPointer();
467 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
469 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
470 its
.incrementReadPointer();
474 ITTE itte
= readIrqTranslationTable(
475 yield
, dte
.ittAddress
, command
.eventId
);
478 its
.incrementReadPointer();
482 const auto collection_id
= itte
.icid
;
483 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
486 its
.incrementReadPointer();
490 // Set the LPI in the redistributor
491 its
.getRedistributor(cte
)->setClrLPI(itte
.intNum
, true);
495 ItsCommand::inv(Yield
&yield
, CommandEntry
&command
)
497 if (deviceOutOfRange(command
)) {
498 its
.incrementReadPointer();
502 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
504 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
505 its
.incrementReadPointer();
509 ITTE itte
= readIrqTranslationTable(
510 yield
, dte
.ittAddress
, command
.eventId
);
513 its
.incrementReadPointer();
517 const auto collection_id
= itte
.icid
;
518 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
521 its
.incrementReadPointer();
524 // Do nothing since caching is currently not supported in
529 ItsCommand::invall(Yield
&yield
, CommandEntry
&command
)
531 if (collectionOutOfRange(command
)) {
532 its
.incrementReadPointer();
536 const auto icid
= bits(command
.raw
[2], 15, 0);
538 CTE cte
= readIrqCollectionTable(yield
, icid
);
541 its
.incrementReadPointer();
544 // Do nothing since caching is currently not supported in
549 ItsCommand::mapc(Yield
&yield
, CommandEntry
&command
)
551 if (collectionOutOfRange(command
)) {
552 its
.incrementReadPointer();
557 cte
.valid
= bits(command
.raw
[2], 63);
558 cte
.rdBase
= bits(command
.raw
[2], 50, 16);
560 const auto icid
= bits(command
.raw
[2], 15, 0);
562 writeIrqCollectionTable(yield
, icid
, cte
);
566 ItsCommand::mapd(Yield
&yield
, CommandEntry
&command
)
568 if (deviceOutOfRange(command
) || sizeOutOfRange(command
)) {
569 its
.incrementReadPointer();
574 dte
.valid
= bits(command
.raw
[2], 63);
575 dte
.ittAddress
= mbits(command
.raw
[2], 51, 8);
576 dte
.ittRange
= bits(command
.raw
[1], 4, 0);
578 writeDeviceTable(yield
, command
.deviceId
, dte
);
582 ItsCommand::mapi(Yield
&yield
, CommandEntry
&command
)
584 if (deviceOutOfRange(command
)) {
585 its
.incrementReadPointer();
589 if (collectionOutOfRange(command
)) {
590 its
.incrementReadPointer();
594 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
596 if (!dte
.valid
|| idOutOfRange(command
, dte
) ||
597 its
.lpiOutOfRange(command
.eventId
)) {
599 its
.incrementReadPointer();
603 Gicv3Its::ITTE itte
= readIrqTranslationTable(
604 yield
, dte
.ittAddress
, command
.eventId
);
607 itte
.intType
= Gicv3Its::PHYSICAL_INTERRUPT
;
608 itte
.intNum
= command
.eventId
;
609 itte
.icid
= bits(command
.raw
[2], 15, 0);
611 writeIrqTranslationTable(
612 yield
, dte
.ittAddress
, command
.eventId
, itte
);
616 ItsCommand::mapti(Yield
&yield
, CommandEntry
&command
)
618 if (deviceOutOfRange(command
)) {
619 its
.incrementReadPointer();
623 if (collectionOutOfRange(command
)) {
624 its
.incrementReadPointer();
628 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
630 const auto pintid
= bits(command
.raw
[1], 63, 32);
632 if (!dte
.valid
|| idOutOfRange(command
, dte
) ||
633 its
.lpiOutOfRange(pintid
)) {
635 its
.incrementReadPointer();
639 ITTE itte
= readIrqTranslationTable(
640 yield
, dte
.ittAddress
, command
.eventId
);
643 itte
.intType
= Gicv3Its::PHYSICAL_INTERRUPT
;
644 itte
.intNum
= pintid
;
645 itte
.icid
= bits(command
.raw
[2], 15, 0);
647 writeIrqTranslationTable(
648 yield
, dte
.ittAddress
, command
.eventId
, itte
);
652 ItsCommand::movall(Yield
&yield
, CommandEntry
&command
)
654 const uint64_t rd1
= bits(command
.raw
[2], 50, 16);
655 const uint64_t rd2
= bits(command
.raw
[3], 50, 16);
658 Gicv3Redistributor
* redist1
= its
.getRedistributor(rd1
);
659 Gicv3Redistributor
* redist2
= its
.getRedistributor(rd2
);
661 its
.moveAllPendingState(redist1
, redist2
);
666 ItsCommand::movi(Yield
&yield
, CommandEntry
&command
)
668 if (deviceOutOfRange(command
)) {
669 its
.incrementReadPointer();
673 if (collectionOutOfRange(command
)) {
674 its
.incrementReadPointer();
678 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
680 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
681 its
.incrementReadPointer();
685 ITTE itte
= readIrqTranslationTable(
686 yield
, dte
.ittAddress
, command
.eventId
);
688 if (!itte
.valid
|| itte
.intType
== Gicv3Its::VIRTUAL_INTERRUPT
) {
689 its
.incrementReadPointer();
693 const auto collection_id1
= itte
.icid
;
694 CTE cte1
= readIrqCollectionTable(yield
, collection_id1
);
697 its
.incrementReadPointer();
701 const auto collection_id2
= bits(command
.raw
[2], 15, 0);
702 CTE cte2
= readIrqCollectionTable(yield
, collection_id2
);
705 its
.incrementReadPointer();
709 Gicv3Redistributor
*first_redist
= its
.getRedistributor(cte1
);
710 Gicv3Redistributor
*second_redist
= its
.getRedistributor(cte2
);
712 if (second_redist
!= first_redist
) {
713 // move pending state of the interrupt from one redistributor
715 if (first_redist
->isPendingLPI(itte
.intNum
)) {
716 first_redist
->setClrLPI(itte
.intNum
, false);
717 second_redist
->setClrLPI(itte
.intNum
, true);
721 itte
.icid
= collection_id2
;
722 writeIrqTranslationTable(
723 yield
, dte
.ittAddress
, command
.eventId
, itte
);
727 ItsCommand::sync(Yield
&yield
, CommandEntry
&command
)
729 warn("ITS %s command unimplemented", __func__
);
733 ItsCommand::vinvall(Yield
&yield
, CommandEntry
&command
)
735 panic("ITS %s command unimplemented", __func__
);
739 ItsCommand::vmapi(Yield
&yield
, CommandEntry
&command
)
741 panic("ITS %s command unimplemented", __func__
);
745 ItsCommand::vmapp(Yield
&yield
, CommandEntry
&command
)
747 panic("ITS %s command unimplemented", __func__
);
751 ItsCommand::vmapti(Yield
&yield
, CommandEntry
&command
)
753 panic("ITS %s command unimplemented", __func__
);
757 ItsCommand::vmovi(Yield
&yield
, CommandEntry
&command
)
759 panic("ITS %s command unimplemented", __func__
);
763 ItsCommand::vmovp(Yield
&yield
, CommandEntry
&command
)
765 panic("ITS %s command unimplemented", __func__
);
769 ItsCommand::vsync(Yield
&yield
, CommandEntry
&command
)
771 panic("ITS %s command unimplemented", __func__
);
774 Gicv3Its::Gicv3Its(const Gicv3ItsParams
¶ms
)
775 : BasicPioDevice(params
, params
.pio_size
),
776 dmaPort(name() + ".dma", *this),
777 gitsControl(CTLR_QUIESCENT
),
778 gitsTyper(params
.gits_typer
),
779 gitsCbaser(0), gitsCreadr(0),
780 gitsCwriter(0), gitsIidr(0),
781 tableBases(NUM_BASER_REGS
, 0),
782 requestorId(params
.system
->getRequestorId(this)),
784 commandEvent([this] { checkCommandQueue(); }, name()),
785 pendingCommands(false),
786 pendingTranslations(0)
788 BASER device_baser
= 0;
789 device_baser
.type
= DEVICE_TABLE
;
790 device_baser
.entrySize
= sizeof(uint64_t) - 1;
791 tableBases
[0] = device_baser
;
793 BASER icollect_baser
= 0;
794 icollect_baser
.type
= COLLECTION_TABLE
;
795 icollect_baser
.entrySize
= sizeof(uint64_t) - 1;
796 tableBases
[1] = icollect_baser
;
800 Gicv3Its::setGIC(Gicv3
*_gic
)
807 Gicv3Its::getAddrRanges() const
809 assert(pioSize
!= 0);
810 AddrRangeList ranges
;
811 DPRINTF(AddrRanges
, "registering range: %#x-%#x\n", pioAddr
, pioSize
);
812 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
817 Gicv3Its::read(PacketPtr pkt
)
819 const Addr addr
= pkt
->getAddr() - pioAddr
;
822 DPRINTF(GIC
, "%s register at addr: %#x\n", __func__
, addr
);
838 value
= gitsTyper
.high
;
845 case GITS_CBASER
+ 4:
846 value
= gitsCbaser
.high
;
853 case GITS_CWRITER
+ 4:
854 value
= gitsCwriter
.high
;
861 case GITS_CREADR
+ 4:
862 value
= gitsCreadr
.high
;
866 value
= gic
->getDistributor()->gicdPidr2
;
869 case GITS_TRANSLATER
:
870 value
= gitsTranslater
;
874 if (GITS_BASER
.contains(addr
)) {
875 auto relative_addr
= addr
- GITS_BASER
.start();
876 auto baser_index
= relative_addr
/ sizeof(uint64_t);
878 value
= tableBases
[baser_index
];
881 panic("Unrecognized register access\n");
885 pkt
->setUintX(value
, ByteOrder::little
);
886 pkt
->makeAtomicResponse();
891 Gicv3Its::write(PacketPtr pkt
)
893 Addr addr
= pkt
->getAddr() - pioAddr
;
895 DPRINTF(GIC
, "%s register at addr: %#x\n", __func__
, addr
);
899 assert(pkt
->getSize() == sizeof(uint32_t));
900 gitsControl
= (pkt
->getLE
<uint32_t>() & ~CTLR_QUIESCENT
);
901 // We should check here if the ITS has been disabled, and if
902 // that's the case, flush GICv3 caches to external memory.
903 // This is not happening now, since LPI caching is not
904 // currently implemented in gem5.
908 panic("GITS_IIDR is Read Only\n");
911 panic("GITS_TYPER is Read Only\n");
914 if (pkt
->getSize() == sizeof(uint32_t)) {
915 gitsCbaser
.low
= pkt
->getLE
<uint32_t>();
917 assert(pkt
->getSize() == sizeof(uint64_t));
918 gitsCbaser
= pkt
->getLE
<uint64_t>();
921 gitsCreadr
= 0; // Cleared when CBASER gets written
926 case GITS_CBASER
+ 4:
927 assert(pkt
->getSize() == sizeof(uint32_t));
928 gitsCbaser
.high
= pkt
->getLE
<uint32_t>();
930 gitsCreadr
= 0; // Cleared when CBASER gets written
936 if (pkt
->getSize() == sizeof(uint32_t)) {
937 gitsCwriter
.low
= pkt
->getLE
<uint32_t>();
939 assert(pkt
->getSize() == sizeof(uint64_t));
940 gitsCwriter
= pkt
->getLE
<uint64_t>();
946 case GITS_CWRITER
+ 4:
947 assert(pkt
->getSize() == sizeof(uint32_t));
948 gitsCwriter
.high
= pkt
->getLE
<uint32_t>();
954 panic("GITS_READR is Read Only\n");
956 case GITS_TRANSLATER
:
957 if (gitsControl
.enabled
) {
963 if (GITS_BASER
.contains(addr
)) {
964 auto relative_addr
= addr
- GITS_BASER
.start();
965 auto baser_index
= relative_addr
/ sizeof(uint64_t);
967 const uint64_t table_base
= tableBases
[baser_index
];
968 const uint64_t w_mask
= tableBases
[baser_index
].type
?
969 BASER_WMASK
: BASER_WMASK_UNIMPL
;
970 const uint64_t val
= pkt
->getLE
<uint64_t>() & w_mask
;
972 tableBases
[baser_index
] = table_base
| val
;
975 panic("Unrecognized register access\n");
979 pkt
->makeAtomicResponse();
984 Gicv3Its::idOutOfRange(uint32_t event_id
, uint8_t itt_range
) const
986 const uint32_t id_bits
= gitsTyper
.idBits
;
987 return event_id
>= (1ULL << (id_bits
+ 1)) ||
988 event_id
>= ((1ULL << itt_range
) + 1);
992 Gicv3Its::deviceOutOfRange(uint32_t device_id
) const
994 return device_id
>= (1ULL << (gitsTyper
.devBits
+ 1));
998 Gicv3Its::sizeOutOfRange(uint32_t size
) const
1000 return size
> gitsTyper
.idBits
;
1004 Gicv3Its::collectionOutOfRange(uint32_t collection_id
) const
1006 // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID
1007 // Otherwise, #bits is specified by GITS_TYPER.CIDbits
1008 const auto cid_bits
= gitsTyper
.cil
== 0 ?
1009 16 : gitsTyper
.cidBits
+ 1;
1011 return collection_id
>= (1ULL << cid_bits
);
1015 Gicv3Its::lpiOutOfRange(uint32_t intid
) const
1017 return intid
>= (1ULL << (Gicv3Distributor::IDBITS
+ 1)) ||
1018 (intid
< Gicv3Redistributor::SMALLEST_LPI_ID
&&
1019 intid
!= Gicv3::INTID_SPURIOUS
);
1025 if (!pendingCommands
&& !pendingTranslations
) {
1026 return DrainState::Drained
;
1028 DPRINTF(Drain
, "GICv3 ITS not drained\n");
1029 return DrainState::Draining
;
1034 Gicv3Its::serialize(CheckpointOut
& cp
) const
1036 SERIALIZE_SCALAR(gitsControl
);
1037 SERIALIZE_SCALAR(gitsTyper
);
1038 SERIALIZE_SCALAR(gitsCbaser
);
1039 SERIALIZE_SCALAR(gitsCreadr
);
1040 SERIALIZE_SCALAR(gitsCwriter
);
1041 SERIALIZE_SCALAR(gitsIidr
);
1043 SERIALIZE_CONTAINER(tableBases
);
1047 Gicv3Its::unserialize(CheckpointIn
& cp
)
1049 UNSERIALIZE_SCALAR(gitsControl
);
1050 UNSERIALIZE_SCALAR(gitsTyper
);
1051 UNSERIALIZE_SCALAR(gitsCbaser
);
1052 UNSERIALIZE_SCALAR(gitsCreadr
);
1053 UNSERIALIZE_SCALAR(gitsCwriter
);
1054 UNSERIALIZE_SCALAR(gitsIidr
);
1056 UNSERIALIZE_CONTAINER(tableBases
);
1060 Gicv3Its::incrementReadPointer()
1062 // Make the reader point to the next element
1063 gitsCreadr
.offset
= gitsCreadr
.offset
+ 1;
1065 // Check for wrapping
1066 if (gitsCreadr
.offset
== maxCommands()) {
1067 gitsCreadr
.offset
= 0;
1072 Gicv3Its::maxCommands() const
1074 return (4096 * (gitsCbaser
.size
+ 1)) / sizeof(ItsCommand::CommandEntry
);
1078 Gicv3Its::checkCommandQueue()
1080 if (!gitsControl
.enabled
|| !gitsCbaser
.valid
)
1083 // If GITS_CWRITER gets set by sw to a value bigger than the
1084 // allowed one, the command queue should stop processing commands
1085 // until the register gets reset to an allowed one
1086 if (gitsCwriter
.offset
>= maxCommands()) {
1090 if (gitsCwriter
.offset
!= gitsCreadr
.offset
) {
1091 // writer and reader pointing to different command
1092 // entries: queue not empty.
1093 DPRINTF(ITS
, "Reading command from queue\n");
1095 if (!pendingCommands
) {
1096 auto *cmd_proc
= new ItsCommand(*this);
1098 runProcess(cmd_proc
, nullptr);
1100 DPRINTF(ITS
, "Waiting for pending command to finish\n");
1106 Gicv3Its::getPort(const std::string
&if_name
, PortID idx
)
1108 if (if_name
== "dma") {
1111 return BasicPioDevice::getPort(if_name
, idx
);
1115 Gicv3Its::recvReqRetry()
1117 assert(!packetsToRetry
.empty());
1119 while (!packetsToRetry
.empty()) {
1120 ItsAction a
= packetsToRetry
.front();
1122 assert(a
.type
== ItsActionType::SEND_REQ
);
1124 if (!dmaPort
.sendTimingReq(a
.pkt
))
1127 packetsToRetry
.pop();
1132 Gicv3Its::recvTimingResp(PacketPtr pkt
)
1134 // @todo: We need to pay for this and not just zero it out
1135 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
1138 safe_cast
<ItsProcess
*>(pkt
->popSenderState());
1140 runProcessTiming(proc
, pkt
);
1146 Gicv3Its::runProcess(ItsProcess
*proc
, PacketPtr pkt
)
1148 if (sys
->isAtomicMode()) {
1149 return runProcessAtomic(proc
, pkt
);
1150 } else if (sys
->isTimingMode()) {
1151 return runProcessTiming(proc
, pkt
);
1153 panic("Not in timing or atomic mode\n");
1158 Gicv3Its::runProcessTiming(ItsProcess
*proc
, PacketPtr pkt
)
1160 ItsAction action
= proc
->run(pkt
);
1162 switch (action
.type
) {
1163 case ItsActionType::SEND_REQ
:
1164 action
.pkt
->pushSenderState(proc
);
1166 if (packetsToRetry
.empty() &&
1167 dmaPort
.sendTimingReq(action
.pkt
)) {
1170 packetsToRetry
.push(action
);
1174 case ItsActionType::TERMINATE
:
1176 if (!pendingCommands
&& !commandEvent
.scheduled()) {
1177 schedule(commandEvent
, clockEdge());
1182 panic("Unknown action\n");
1189 Gicv3Its::runProcessAtomic(ItsProcess
*proc
, PacketPtr pkt
)
1193 bool terminate
= false;
1196 action
= proc
->run(pkt
);
1198 switch (action
.type
) {
1199 case ItsActionType::SEND_REQ
:
1200 delay
+= dmaPort
.sendAtomic(action
.pkt
);
1204 case ItsActionType::TERMINATE
:
1210 panic("Unknown action\n");
1213 } while (!terminate
);
1215 action
.delay
= delay
;
1221 Gicv3Its::translate(PacketPtr pkt
)
1223 DPRINTF(ITS
, "Starting Translation Request\n");
1225 auto *proc
= new ItsTranslation(*this);
1226 runProcess(proc
, pkt
);
1230 Gicv3Its::getRedistributor(uint64_t rd_base
)
1232 if (gitsTyper
.pta
== 1) {
1233 // RDBase is a redistributor address
1234 return gic
->getRedistributorByAddr(rd_base
<< 16);
1236 // RDBase is a redistributor number
1237 return gic
->getRedistributor(rd_base
);
1242 Gicv3Its::pageAddress(Gicv3Its::ItsTables table
)
1244 auto base_it
= std::find_if(
1245 tableBases
.begin(), tableBases
.end(),
1246 [table
] (const BASER
&b
) { return b
.type
== table
; }
1249 panic_if(base_it
== tableBases
.end(),
1250 "ITS Table not recognised\n");
1252 const BASER base
= *base_it
;
1254 // real address depends on page size
1255 switch (base
.pageSize
) {
1258 return mbits(base
, 47, 12);
1260 return mbits(base
, 47, 16) | (bits(base
, 15, 12) << 48);
1262 panic("Unsupported page size\n");
1267 Gicv3Its::moveAllPendingState(
1268 Gicv3Redistributor
*rd1
, Gicv3Redistributor
*rd2
)
1270 const uint64_t largest_lpi_id
= 1ULL << (rd1
->lpiIDBits
+ 1);
1271 uint8_t lpi_pending_table
[largest_lpi_id
/ 8];
1273 // Copying the pending table from redistributor 1 to redistributor 2
1274 rd1
->memProxy
->readBlob(
1275 rd1
->lpiPendingTablePtr
, (uint8_t *)lpi_pending_table
,
1276 sizeof(lpi_pending_table
));
1278 rd2
->memProxy
->writeBlob(
1279 rd2
->lpiPendingTablePtr
, (uint8_t *)lpi_pending_table
,
1280 sizeof(lpi_pending_table
));
1282 // Clearing pending table in redistributor 2
1283 rd1
->memProxy
->memsetBlob(
1284 rd1
->lpiPendingTablePtr
,
1285 0, sizeof(lpi_pending_table
));
1287 rd2
->updateDistributor();
1291 Gicv3ItsParams::create() const
1293 return new Gicv3Its(*this);