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.
37 * Authors: Giacomo Travaglini
40 #include "dev/arm/gic_v3_its.hh"
42 #include "debug/AddrRanges.hh"
43 #include "debug/Drain.hh"
44 #include "debug/GIC.hh"
45 #include "debug/ITS.hh"
46 #include "dev/arm/gic_v3.hh"
47 #include "dev/arm/gic_v3_distributor.hh"
48 #include "dev/arm/gic_v3_redistributor.hh"
49 #include "mem/packet_access.hh"
51 #define COMMAND(x, method) { x, DispatchEntry(#x, method) }
53 const AddrRange
Gicv3Its::GITS_BASER(0x0100, 0x0138);
55 const uint32_t Gicv3Its::CTLR_QUIESCENT
= 0x80000000;
57 ItsProcess::ItsProcess(Gicv3Its
&_its
)
58 : its(_its
), coroutine(nullptr)
62 ItsProcess::~ItsProcess()
69 coroutine
.reset(new Coroutine(
70 std::bind(&ItsProcess::main
, this, std::placeholders::_1
)));
74 ItsProcess::name() const
80 ItsProcess::run(PacketPtr pkt
)
82 assert(coroutine
!= nullptr);
84 return (*coroutine
)(pkt
).get();
88 ItsProcess::doRead(Yield
&yield
, Addr addr
, void *ptr
, size_t size
)
91 a
.type
= ItsActionType::SEND_REQ
;
93 RequestPtr req
= std::make_shared
<Request
>(
94 addr
, size
, 0, its
.masterId
);
96 req
->taskId(ContextSwitchTaskId::DMA
);
98 a
.pkt
= new Packet(req
, MemCmd::ReadReq
);
99 a
.pkt
->dataStatic(ptr
);
103 PacketPtr pkt
= yield(a
).get();
106 assert(pkt
->getSize() >= size
);
112 ItsProcess::doWrite(Yield
&yield
, Addr addr
, void *ptr
, size_t size
)
115 a
.type
= ItsActionType::SEND_REQ
;
117 RequestPtr req
= std::make_shared
<Request
>(
118 addr
, size
, 0, its
.masterId
);
120 req
->taskId(ContextSwitchTaskId::DMA
);
122 a
.pkt
= new Packet(req
, MemCmd::WriteReq
);
123 a
.pkt
->dataStatic(ptr
);
127 PacketPtr pkt
= yield(a
).get();
130 assert(pkt
->getSize() >= size
);
136 ItsProcess::terminate(Yield
&yield
)
139 a
.type
= ItsActionType::TERMINATE
;
146 ItsProcess::writeDeviceTable(Yield
&yield
, uint32_t device_id
, DTE dte
)
148 const Addr base
= its
.pageAddress(Gicv3Its::DEVICE_TABLE
);
149 const Addr address
= base
+ device_id
;
151 DPRINTF(ITS
, "Writing DTE at address %#x: %#x\n", address
, dte
);
153 doWrite(yield
, address
, &dte
, sizeof(dte
));
157 ItsProcess::writeIrqTranslationTable(
158 Yield
&yield
, const Addr itt_base
, uint32_t event_id
, ITTE itte
)
160 const Addr address
= itt_base
+ event_id
;
162 doWrite(yield
, address
, &itte
, sizeof(itte
));
164 DPRINTF(ITS
, "Writing ITTE at address %#x: %#x\n", address
, itte
);
168 ItsProcess::writeIrqCollectionTable(
169 Yield
&yield
, uint32_t collection_id
, CTE cte
)
171 const Addr base
= its
.pageAddress(Gicv3Its::COLLECTION_TABLE
);
172 const Addr address
= base
+ collection_id
;
174 doWrite(yield
, address
, &cte
, sizeof(cte
));
176 DPRINTF(ITS
, "Writing CTE at address %#x: %#x\n", address
, cte
);
180 ItsProcess::readDeviceTable(Yield
&yield
, uint32_t device_id
)
182 const Addr base
= its
.pageAddress(Gicv3Its::DEVICE_TABLE
);
183 const Addr address
= base
+ device_id
;
186 doRead(yield
, address
, &dte
, sizeof(dte
));
188 DPRINTF(ITS
, "Reading DTE at address %#x: %#x\n", address
, dte
);
193 ItsProcess::readIrqTranslationTable(
194 Yield
&yield
, const Addr itt_base
, uint32_t event_id
)
196 const Addr address
= itt_base
+ event_id
;
199 doRead(yield
, address
, &itte
, sizeof(itte
));
201 DPRINTF(ITS
, "Reading ITTE at address %#x: %#x\n", address
, itte
);
206 ItsProcess::readIrqCollectionTable(Yield
&yield
, uint32_t collection_id
)
208 const Addr base
= its
.pageAddress(Gicv3Its::COLLECTION_TABLE
);
209 const Addr address
= base
+ collection_id
;
212 doRead(yield
, address
, &cte
, sizeof(cte
));
214 DPRINTF(ITS
, "Reading CTE at address %#x: %#x\n", address
, cte
);
218 ItsTranslation::ItsTranslation(Gicv3Its
&_its
)
222 its
.pendingTranslations
++;
223 its
.gitsControl
.quiescent
= 0;
226 ItsTranslation::~ItsTranslation()
228 assert(its
.pendingTranslations
>= 1);
229 its
.pendingTranslations
--;
230 if (!its
.pendingTranslations
&& !its
.pendingCommands
)
231 its
.gitsControl
.quiescent
= 1;
235 ItsTranslation::main(Yield
&yield
)
237 PacketPtr pkt
= yield
.get();
239 const uint32_t device_id
= pkt
->req
->streamId();
240 const uint32_t event_id
= pkt
->getLE
<uint32_t>();
242 auto result
= translateLPI(yield
, device_id
, event_id
);
244 uint32_t intid
= result
.first
;
245 Gicv3Redistributor
*redist
= result
.second
;
247 // Set the LPI in the redistributor
248 redist
->setClrLPI(intid
, true);
250 // Update the value in GITS_TRANSLATER only once we know
251 // there was no error in the tranlation process (before
252 // terminating the translation
253 its
.gitsTranslater
= event_id
;
258 std::pair
<uint32_t, Gicv3Redistributor
*>
259 ItsTranslation::translateLPI(Yield
&yield
, uint32_t device_id
,
262 if (its
.deviceOutOfRange(device_id
)) {
266 DTE dte
= readDeviceTable(yield
, device_id
);
268 if (!dte
.valid
|| its
.idOutOfRange(event_id
, dte
.ittRange
)) {
272 ITTE itte
= readIrqTranslationTable(yield
, dte
.ittAddress
, event_id
);
273 const auto collection_id
= itte
.icid
;
275 if (!itte
.valid
|| its
.collectionOutOfRange(collection_id
)) {
279 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
285 // Returning the INTID and the target Redistributor
286 return std::make_pair(itte
.intNum
, its
.getRedistributor(cte
));
289 ItsCommand::DispatchTable
ItsCommand::cmdDispatcher
=
291 COMMAND(CLEAR
, &ItsCommand::clear
),
292 COMMAND(DISCARD
, &ItsCommand::discard
),
293 COMMAND(INT
, &ItsCommand::doInt
),
294 COMMAND(INV
, &ItsCommand::inv
),
295 COMMAND(INVALL
, &ItsCommand::invall
),
296 COMMAND(MAPC
, &ItsCommand::mapc
),
297 COMMAND(MAPD
, &ItsCommand::mapd
),
298 COMMAND(MAPI
, &ItsCommand::mapi
),
299 COMMAND(MAPTI
, &ItsCommand::mapti
),
300 COMMAND(MOVALL
, &ItsCommand::movall
),
301 COMMAND(MOVI
, &ItsCommand::movi
),
302 COMMAND(SYNC
, &ItsCommand::sync
),
303 COMMAND(VINVALL
, &ItsCommand::vinvall
),
304 COMMAND(VMAPI
, &ItsCommand::vmapi
),
305 COMMAND(VMAPP
, &ItsCommand::vmapp
),
306 COMMAND(VMAPTI
, &ItsCommand::vmapti
),
307 COMMAND(VMOVI
, &ItsCommand::vmovi
),
308 COMMAND(VMOVP
, &ItsCommand::vmovp
),
309 COMMAND(VSYNC
, &ItsCommand::vsync
),
312 ItsCommand::ItsCommand(Gicv3Its
&_its
)
316 its
.pendingCommands
= true;
318 its
.gitsControl
.quiescent
= 0;
321 ItsCommand::~ItsCommand()
323 its
.pendingCommands
= false;
325 if (!its
.pendingTranslations
)
326 its
.gitsControl
.quiescent
= 1;
330 ItsCommand::commandName(uint32_t cmd
)
332 const auto entry
= cmdDispatcher
.find(cmd
);
333 return entry
!= cmdDispatcher
.end() ? entry
->second
.name
: "INVALID";
337 ItsCommand::main(Yield
&yield
)
340 a
.type
= ItsActionType::INITIAL_NOP
;
345 while (its
.gitsCwriter
.offset
!= its
.gitsCreadr
.offset
) {
346 CommandEntry command
;
348 // Reading the command from CMDQ
349 readCommand(yield
, command
);
351 processCommand(yield
, command
);
353 its
.incrementReadPointer();
360 ItsCommand::readCommand(Yield
&yield
, CommandEntry
&command
)
362 // read the command pointed by GITS_CREADR
363 const Addr cmd_addr
=
364 (its
.gitsCbaser
.physAddr
<< 12) + (its
.gitsCreadr
.offset
<< 5);
366 doRead(yield
, cmd_addr
, &command
, sizeof(command
));
368 DPRINTF(ITS
, "Command %s read from queue at address: %#x\n",
369 commandName(command
.type
), cmd_addr
);
370 DPRINTF(ITS
, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n",
371 command
.raw
[0], command
.raw
[1], command
.raw
[2], command
.raw
[3]);
375 ItsCommand::processCommand(Yield
&yield
, CommandEntry
&command
)
377 const auto entry
= cmdDispatcher
.find(command
.type
);
379 if (entry
!= cmdDispatcher
.end()) {
380 // Execute the command
381 entry
->second
.exec(this, yield
, command
);
383 panic("Unrecognized command type: %u", command
.type
);
388 ItsCommand::clear(Yield
&yield
, CommandEntry
&command
)
390 if (deviceOutOfRange(command
)) {
391 its
.incrementReadPointer();
395 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
397 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
398 its
.incrementReadPointer();
402 ITTE itte
= readIrqTranslationTable(
403 yield
, dte
.ittAddress
, command
.eventId
);
406 its
.incrementReadPointer();
410 const auto collection_id
= itte
.icid
;
411 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
414 its
.incrementReadPointer();
418 // Clear the LPI in the redistributor
419 its
.getRedistributor(cte
)->setClrLPI(itte
.intNum
, false);
423 ItsCommand::discard(Yield
&yield
, CommandEntry
&command
)
425 if (deviceOutOfRange(command
)) {
426 its
.incrementReadPointer();
430 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
432 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
433 its
.incrementReadPointer();
437 ITTE itte
= readIrqTranslationTable(
438 yield
, dte
.ittAddress
, command
.eventId
);
441 its
.incrementReadPointer();
445 const auto collection_id
= itte
.icid
;
446 Gicv3Its::CTE cte
= readIrqCollectionTable(yield
, collection_id
);
449 its
.incrementReadPointer();
453 its
.getRedistributor(cte
)->setClrLPI(itte
.intNum
, false);
455 // Then removes the mapping from the ITT (invalidating)
457 writeIrqTranslationTable(
458 yield
, dte
.ittAddress
, command
.eventId
, itte
);
462 ItsCommand::doInt(Yield
&yield
, CommandEntry
&command
)
464 if (deviceOutOfRange(command
)) {
465 its
.incrementReadPointer();
469 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
471 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
472 its
.incrementReadPointer();
476 ITTE itte
= readIrqTranslationTable(
477 yield
, dte
.ittAddress
, command
.eventId
);
480 its
.incrementReadPointer();
484 const auto collection_id
= itte
.icid
;
485 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
488 its
.incrementReadPointer();
492 // Set the LPI in the redistributor
493 its
.getRedistributor(cte
)->setClrLPI(itte
.intNum
, true);
497 ItsCommand::inv(Yield
&yield
, CommandEntry
&command
)
499 if (deviceOutOfRange(command
)) {
500 its
.incrementReadPointer();
504 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
506 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
507 its
.incrementReadPointer();
511 ITTE itte
= readIrqTranslationTable(
512 yield
, dte
.ittAddress
, command
.eventId
);
515 its
.incrementReadPointer();
519 const auto collection_id
= itte
.icid
;
520 CTE cte
= readIrqCollectionTable(yield
, collection_id
);
523 its
.incrementReadPointer();
526 // Do nothing since caching is currently not supported in
531 ItsCommand::invall(Yield
&yield
, CommandEntry
&command
)
533 if (collectionOutOfRange(command
)) {
534 its
.incrementReadPointer();
538 const auto icid
= bits(command
.raw
[2], 15, 0);
540 CTE cte
= readIrqCollectionTable(yield
, icid
);
543 its
.incrementReadPointer();
546 // Do nothing since caching is currently not supported in
551 ItsCommand::mapc(Yield
&yield
, CommandEntry
&command
)
553 if (collectionOutOfRange(command
)) {
554 its
.incrementReadPointer();
559 cte
.valid
= bits(command
.raw
[2], 63);
560 cte
.rdBase
= bits(command
.raw
[2], 50, 16);
562 const auto icid
= bits(command
.raw
[2], 15, 0);
564 writeIrqCollectionTable(yield
, icid
, cte
);
568 ItsCommand::mapd(Yield
&yield
, CommandEntry
&command
)
570 if (deviceOutOfRange(command
) || sizeOutOfRange(command
)) {
571 its
.incrementReadPointer();
576 dte
.valid
= bits(command
.raw
[2], 63);
577 dte
.ittAddress
= mbits(command
.raw
[2], 51, 8);
578 dte
.ittRange
= bits(command
.raw
[1], 4, 0);
580 writeDeviceTable(yield
, command
.deviceId
, dte
);
584 ItsCommand::mapi(Yield
&yield
, CommandEntry
&command
)
586 if (deviceOutOfRange(command
)) {
587 its
.incrementReadPointer();
591 if (collectionOutOfRange(command
)) {
592 its
.incrementReadPointer();
596 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
598 if (!dte
.valid
|| idOutOfRange(command
, dte
) ||
599 its
.lpiOutOfRange(command
.eventId
)) {
601 its
.incrementReadPointer();
605 Gicv3Its::ITTE itte
= readIrqTranslationTable(
606 yield
, dte
.ittAddress
, command
.eventId
);
609 itte
.intType
= Gicv3Its::PHYSICAL_INTERRUPT
;
610 itte
.intNum
= command
.eventId
;
611 itte
.icid
= bits(command
.raw
[2], 15, 0);
613 writeIrqTranslationTable(
614 yield
, dte
.ittAddress
, command
.eventId
, itte
);
618 ItsCommand::mapti(Yield
&yield
, CommandEntry
&command
)
620 if (deviceOutOfRange(command
)) {
621 its
.incrementReadPointer();
625 if (collectionOutOfRange(command
)) {
626 its
.incrementReadPointer();
630 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
632 const auto pintid
= bits(command
.raw
[1], 63, 32);
634 if (!dte
.valid
|| idOutOfRange(command
, dte
) ||
635 its
.lpiOutOfRange(pintid
)) {
637 its
.incrementReadPointer();
641 ITTE itte
= readIrqTranslationTable(
642 yield
, dte
.ittAddress
, command
.eventId
);
645 itte
.intType
= Gicv3Its::PHYSICAL_INTERRUPT
;
646 itte
.intNum
= pintid
;
647 itte
.icid
= bits(command
.raw
[2], 15, 0);
649 writeIrqTranslationTable(
650 yield
, dte
.ittAddress
, command
.eventId
, itte
);
654 ItsCommand::movall(Yield
&yield
, CommandEntry
&command
)
656 const uint64_t rd1
= bits(command
.raw
[2], 50, 16);
657 const uint64_t rd2
= bits(command
.raw
[3], 50, 16);
660 Gicv3Redistributor
* redist1
= its
.getRedistributor(rd1
);
661 Gicv3Redistributor
* redist2
= its
.getRedistributor(rd2
);
663 its
.moveAllPendingState(redist1
, redist2
);
668 ItsCommand::movi(Yield
&yield
, CommandEntry
&command
)
670 if (deviceOutOfRange(command
)) {
671 its
.incrementReadPointer();
675 if (collectionOutOfRange(command
)) {
676 its
.incrementReadPointer();
680 DTE dte
= readDeviceTable(yield
, command
.deviceId
);
682 if (!dte
.valid
|| idOutOfRange(command
, dte
)) {
683 its
.incrementReadPointer();
687 ITTE itte
= readIrqTranslationTable(
688 yield
, dte
.ittAddress
, command
.eventId
);
690 if (!itte
.valid
|| itte
.intType
== Gicv3Its::VIRTUAL_INTERRUPT
) {
691 its
.incrementReadPointer();
695 const auto collection_id1
= itte
.icid
;
696 CTE cte1
= readIrqCollectionTable(yield
, collection_id1
);
699 its
.incrementReadPointer();
703 const auto collection_id2
= bits(command
.raw
[2], 15, 0);
704 CTE cte2
= readIrqCollectionTable(yield
, collection_id2
);
707 its
.incrementReadPointer();
711 Gicv3Redistributor
*first_redist
= its
.getRedistributor(cte1
);
712 Gicv3Redistributor
*second_redist
= its
.getRedistributor(cte2
);
714 if (second_redist
!= first_redist
) {
715 // move pending state of the interrupt from one redistributor
717 if (first_redist
->isPendingLPI(itte
.intNum
)) {
718 first_redist
->setClrLPI(itte
.intNum
, false);
719 second_redist
->setClrLPI(itte
.intNum
, true);
723 itte
.icid
= collection_id2
;
724 writeIrqTranslationTable(
725 yield
, dte
.ittAddress
, command
.eventId
, itte
);
729 ItsCommand::sync(Yield
&yield
, CommandEntry
&command
)
731 warn("ITS %s command unimplemented", __func__
);
735 ItsCommand::vinvall(Yield
&yield
, CommandEntry
&command
)
737 panic("ITS %s command unimplemented", __func__
);
741 ItsCommand::vmapi(Yield
&yield
, CommandEntry
&command
)
743 panic("ITS %s command unimplemented", __func__
);
747 ItsCommand::vmapp(Yield
&yield
, CommandEntry
&command
)
749 panic("ITS %s command unimplemented", __func__
);
753 ItsCommand::vmapti(Yield
&yield
, CommandEntry
&command
)
755 panic("ITS %s command unimplemented", __func__
);
759 ItsCommand::vmovi(Yield
&yield
, CommandEntry
&command
)
761 panic("ITS %s command unimplemented", __func__
);
765 ItsCommand::vmovp(Yield
&yield
, CommandEntry
&command
)
767 panic("ITS %s command unimplemented", __func__
);
771 ItsCommand::vsync(Yield
&yield
, CommandEntry
&command
)
773 panic("ITS %s command unimplemented", __func__
);
776 Gicv3Its::Gicv3Its(const Gicv3ItsParams
*params
)
777 : BasicPioDevice(params
, params
->pio_size
),
778 dmaPort(name() + ".dma", *this),
779 gitsControl(CTLR_QUIESCENT
),
780 gitsTyper(params
->gits_typer
),
781 gitsCbaser(0), gitsCreadr(0),
782 gitsCwriter(0), gitsIidr(0),
783 tableBases(NUM_BASER_REGS
, 0),
784 masterId(params
->system
->getMasterId(this)),
786 commandEvent([this] { checkCommandQueue(); }, name()),
787 pendingCommands(false),
788 pendingTranslations(0)
790 BASER device_baser
= 0;
791 device_baser
.type
= DEVICE_TABLE
;
792 device_baser
.entrySize
= sizeof(uint64_t) - 1;
793 tableBases
[0] = device_baser
;
795 BASER icollect_baser
= 0;
796 icollect_baser
.type
= COLLECTION_TABLE
;
797 icollect_baser
.entrySize
= sizeof(uint64_t) - 1;
798 tableBases
[1] = icollect_baser
;
802 Gicv3Its::setGIC(Gicv3
*_gic
)
809 Gicv3Its::getAddrRanges() const
811 assert(pioSize
!= 0);
812 AddrRangeList ranges
;
813 DPRINTF(AddrRanges
, "registering range: %#x-%#x\n", pioAddr
, pioSize
);
814 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
819 Gicv3Its::read(PacketPtr pkt
)
821 const Addr addr
= pkt
->getAddr() - pioAddr
;
824 DPRINTF(GIC
, "%s register at addr: %#x\n", __func__
, addr
);
843 case GITS_CBASER
+ 4:
844 value
= gitsCbaser
.high
;
851 case GITS_CWRITER
+ 4:
852 value
= gitsCwriter
.high
;
859 case GITS_CREADR
+ 4:
860 value
= gitsCreadr
.high
;
864 value
= gic
->getDistributor()->gicdPidr2
;
867 case GITS_TRANSLATER
:
868 value
= gitsTranslater
;
872 if (GITS_BASER
.contains(addr
)) {
873 auto relative_addr
= addr
- GITS_BASER
.start();
874 auto baser_index
= relative_addr
/ sizeof(uint64_t);
876 value
= tableBases
[baser_index
];
879 panic("Unrecognized register access\n");
883 pkt
->setUintX(value
, LittleEndianByteOrder
);
884 pkt
->makeAtomicResponse();
889 Gicv3Its::write(PacketPtr pkt
)
891 Addr addr
= pkt
->getAddr() - pioAddr
;
893 DPRINTF(GIC
, "%s register at addr: %#x\n", __func__
, addr
);
897 assert(pkt
->getSize() == sizeof(uint32_t));
898 gitsControl
= (pkt
->getLE
<uint32_t>() & ~CTLR_QUIESCENT
);
899 // We should check here if the ITS has been disabled, and if
900 // that's the case, flush GICv3 caches to external memory.
901 // This is not happening now, since LPI caching is not
902 // currently implemented in gem5.
906 panic("GITS_IIDR is Read Only\n");
909 panic("GITS_TYPER is Read Only\n");
912 if (pkt
->getSize() == sizeof(uint32_t)) {
913 gitsCbaser
.low
= pkt
->getLE
<uint32_t>();
915 assert(pkt
->getSize() == sizeof(uint64_t));
916 gitsCbaser
= pkt
->getLE
<uint64_t>();
919 gitsCreadr
= 0; // Cleared when CBASER gets written
924 case GITS_CBASER
+ 4:
925 assert(pkt
->getSize() == sizeof(uint32_t));
926 gitsCbaser
.high
= pkt
->getLE
<uint32_t>();
928 gitsCreadr
= 0; // Cleared when CBASER gets written
934 if (pkt
->getSize() == sizeof(uint32_t)) {
935 gitsCwriter
.low
= pkt
->getLE
<uint32_t>();
937 assert(pkt
->getSize() == sizeof(uint64_t));
938 gitsCwriter
= pkt
->getLE
<uint64_t>();
944 case GITS_CWRITER
+ 4:
945 assert(pkt
->getSize() == sizeof(uint32_t));
946 gitsCwriter
.high
= pkt
->getLE
<uint32_t>();
952 panic("GITS_READR is Read Only\n");
954 case GITS_TRANSLATER
:
955 if (gitsControl
.enabled
) {
961 if (GITS_BASER
.contains(addr
)) {
962 auto relative_addr
= addr
- GITS_BASER
.start();
963 auto baser_index
= relative_addr
/ sizeof(uint64_t);
965 const uint64_t table_base
= tableBases
[baser_index
];
966 const uint64_t w_mask
= tableBases
[baser_index
].type
?
967 BASER_WMASK
: BASER_WMASK_UNIMPL
;
968 const uint64_t val
= pkt
->getLE
<uint64_t>() & w_mask
;
970 tableBases
[baser_index
] = table_base
| val
;
973 panic("Unrecognized register access\n");
977 pkt
->makeAtomicResponse();
982 Gicv3Its::idOutOfRange(uint32_t event_id
, uint8_t itt_range
) const
984 const uint32_t id_bits
= gitsTyper
.idBits
;
985 return event_id
>= (1ULL << (id_bits
+ 1)) ||
986 event_id
>= ((1ULL << itt_range
) + 1);
990 Gicv3Its::deviceOutOfRange(uint32_t device_id
) const
992 return device_id
>= (1ULL << (gitsTyper
.devBits
+ 1));
996 Gicv3Its::sizeOutOfRange(uint32_t size
) const
998 return size
> gitsTyper
.idBits
;
1002 Gicv3Its::collectionOutOfRange(uint32_t collection_id
) const
1004 // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID
1005 // Otherwise, #bits is specified by GITS_TYPER.CIDbits
1006 const auto cid_bits
= gitsTyper
.cil
== 0 ?
1007 16 : gitsTyper
.cidBits
+ 1;
1009 return collection_id
>= (1ULL << cid_bits
);
1013 Gicv3Its::lpiOutOfRange(uint32_t intid
) const
1015 return intid
>= (1ULL << (Gicv3Distributor::IDBITS
+ 1)) ||
1016 (intid
< Gicv3Redistributor::SMALLEST_LPI_ID
&&
1017 intid
!= Gicv3::INTID_SPURIOUS
);
1023 if (!pendingCommands
&& !pendingTranslations
) {
1024 return DrainState::Drained
;
1026 DPRINTF(Drain
, "GICv3 ITS not drained\n");
1027 return DrainState::Draining
;
1032 Gicv3Its::serialize(CheckpointOut
& cp
) const
1034 SERIALIZE_SCALAR(gitsControl
);
1035 SERIALIZE_SCALAR(gitsTyper
);
1036 SERIALIZE_SCALAR(gitsCbaser
);
1037 SERIALIZE_SCALAR(gitsCreadr
);
1038 SERIALIZE_SCALAR(gitsCwriter
);
1039 SERIALIZE_SCALAR(gitsIidr
);
1041 SERIALIZE_CONTAINER(tableBases
);
1045 Gicv3Its::unserialize(CheckpointIn
& cp
)
1047 UNSERIALIZE_SCALAR(gitsControl
);
1048 UNSERIALIZE_SCALAR(gitsTyper
);
1049 UNSERIALIZE_SCALAR(gitsCbaser
);
1050 UNSERIALIZE_SCALAR(gitsCreadr
);
1051 UNSERIALIZE_SCALAR(gitsCwriter
);
1052 UNSERIALIZE_SCALAR(gitsIidr
);
1054 UNSERIALIZE_CONTAINER(tableBases
);
1058 Gicv3Its::incrementReadPointer()
1060 // Make the reader point to the next element
1061 gitsCreadr
.offset
= gitsCreadr
.offset
+ 1;
1063 // Check for wrapping
1064 auto queue_end
= (4096 * (gitsCbaser
.size
+ 1));
1066 if (gitsCreadr
.offset
== queue_end
) {
1067 gitsCreadr
.offset
= 0;
1072 Gicv3Its::checkCommandQueue()
1074 if (!gitsControl
.enabled
|| !gitsCbaser
.valid
)
1077 if (gitsCwriter
.offset
!= gitsCreadr
.offset
) {
1078 // writer and reader pointing to different command
1079 // entries: queue not empty.
1080 DPRINTF(ITS
, "Reading command from queue\n");
1082 if (!pendingCommands
) {
1083 auto *cmd_proc
= new ItsCommand(*this);
1085 runProcess(cmd_proc
, nullptr);
1087 DPRINTF(ITS
, "Waiting for pending command to finish\n");
1093 Gicv3Its::getPort(const std::string
&if_name
, PortID idx
)
1095 if (if_name
== "dma") {
1098 return BasicPioDevice::getPort(if_name
, idx
);
1102 Gicv3Its::recvReqRetry()
1104 assert(!packetsToRetry
.empty());
1106 while (!packetsToRetry
.empty()) {
1107 ItsAction a
= packetsToRetry
.front();
1109 assert(a
.type
== ItsActionType::SEND_REQ
);
1111 if (!dmaPort
.sendTimingReq(a
.pkt
))
1114 packetsToRetry
.pop();
1119 Gicv3Its::recvTimingResp(PacketPtr pkt
)
1121 // @todo: We need to pay for this and not just zero it out
1122 pkt
->headerDelay
= pkt
->payloadDelay
= 0;
1125 safe_cast
<ItsProcess
*>(pkt
->popSenderState());
1127 runProcessTiming(proc
, pkt
);
1133 Gicv3Its::runProcess(ItsProcess
*proc
, PacketPtr pkt
)
1135 if (sys
->isAtomicMode()) {
1136 return runProcessAtomic(proc
, pkt
);
1137 } else if (sys
->isTimingMode()) {
1138 return runProcessTiming(proc
, pkt
);
1140 panic("Not in timing or atomic mode\n");
1145 Gicv3Its::runProcessTiming(ItsProcess
*proc
, PacketPtr pkt
)
1147 ItsAction action
= proc
->run(pkt
);
1149 switch (action
.type
) {
1150 case ItsActionType::SEND_REQ
:
1151 action
.pkt
->pushSenderState(proc
);
1153 if (packetsToRetry
.empty() &&
1154 dmaPort
.sendTimingReq(action
.pkt
)) {
1157 packetsToRetry
.push(action
);
1161 case ItsActionType::TERMINATE
:
1163 if (!pendingCommands
&& !commandEvent
.scheduled()) {
1164 schedule(commandEvent
, clockEdge());
1169 panic("Unknown action\n");
1176 Gicv3Its::runProcessAtomic(ItsProcess
*proc
, PacketPtr pkt
)
1180 bool terminate
= false;
1183 action
= proc
->run(pkt
);
1185 switch (action
.type
) {
1186 case ItsActionType::SEND_REQ
:
1187 delay
+= dmaPort
.sendAtomic(action
.pkt
);
1191 case ItsActionType::TERMINATE
:
1197 panic("Unknown action\n");
1200 } while (!terminate
);
1202 action
.delay
= delay
;
1208 Gicv3Its::translate(PacketPtr pkt
)
1210 DPRINTF(ITS
, "Starting Translation Request\n");
1212 auto *proc
= new ItsTranslation(*this);
1213 runProcess(proc
, pkt
);
1217 Gicv3Its::getRedistributor(uint64_t rd_base
)
1219 if (gitsTyper
.pta
== 1) {
1220 // RDBase is a redistributor address
1221 return gic
->getRedistributorByAddr(rd_base
<< 16);
1223 // RDBase is a redistributor number
1224 return gic
->getRedistributor(rd_base
);
1229 Gicv3Its::pageAddress(Gicv3Its::ItsTables table
)
1231 auto base_it
= std::find_if(
1232 tableBases
.begin(), tableBases
.end(),
1233 [table
] (const BASER
&b
) { return b
.type
== table
; }
1236 panic_if(base_it
== tableBases
.end(),
1237 "ITS Table not recognised\n");
1239 const BASER base
= *base_it
;
1241 // real address depends on page size
1242 switch (base
.pageSize
) {
1245 return mbits(base
, 47, 12);
1247 return mbits(base
, 47, 16) | (bits(base
, 15, 12) << 48);
1249 panic("Unsupported page size\n");
1254 Gicv3Its::moveAllPendingState(
1255 Gicv3Redistributor
*rd1
, Gicv3Redistributor
*rd2
)
1257 const uint64_t largest_lpi_id
= 1ULL << (rd1
->lpiIDBits
+ 1);
1258 uint8_t lpi_pending_table
[largest_lpi_id
/ 8];
1260 // Copying the pending table from redistributor 1 to redistributor 2
1261 rd1
->memProxy
->readBlob(
1262 rd1
->lpiPendingTablePtr
, (uint8_t *)lpi_pending_table
,
1263 sizeof(lpi_pending_table
));
1265 rd2
->memProxy
->writeBlob(
1266 rd2
->lpiPendingTablePtr
, (uint8_t *)lpi_pending_table
,
1267 sizeof(lpi_pending_table
));
1269 // Clearing pending table in redistributor 2
1270 rd1
->memProxy
->memsetBlob(
1271 rd1
->lpiPendingTablePtr
,
1272 0, sizeof(lpi_pending_table
));
1274 rd2
->updateAndInformCPUInterface();
1278 Gicv3ItsParams::create()
1280 return new Gicv3Its(this);