gic_v3_its.cc revision 14168:2a96e30b9400
1/*
2 * Copyright (c) 2019 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Travaglini
38 */
39
40#include "dev/arm/gic_v3_its.hh"
41
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"
50
51#define COMMAND(x, method) { x, DispatchEntry(#x, method) }
52
53const AddrRange Gicv3Its::GITS_BASER(0x0100, 0x0138);
54
55ItsProcess::ItsProcess(Gicv3Its &_its)
56  : its(_its), coroutine(nullptr)
57{
58}
59
60ItsProcess::~ItsProcess()
61{
62}
63
64void
65ItsProcess::reinit()
66{
67    coroutine.reset(new Coroutine(
68        std::bind(&ItsProcess::main, this, std::placeholders::_1)));
69}
70
71const std::string
72ItsProcess::name() const
73{
74    return its.name();
75}
76
77ItsAction
78ItsProcess::run(PacketPtr pkt)
79{
80    assert(coroutine != nullptr);
81    assert(*coroutine);
82    return (*coroutine)(pkt).get();
83}
84
85void
86ItsProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size)
87{
88    ItsAction a;
89    a.type = ItsActionType::SEND_REQ;
90
91    RequestPtr req = std::make_shared<Request>(
92        addr, size, 0, its.masterId);
93
94    req->taskId(ContextSwitchTaskId::DMA);
95
96    a.pkt = new Packet(req, MemCmd::ReadReq);
97    a.pkt->dataStatic(ptr);
98
99    a.delay = 0;
100
101    PacketPtr pkt = yield(a).get();
102
103    assert(pkt);
104    assert(pkt->getSize() >= size);
105
106    delete pkt;
107}
108
109void
110ItsProcess::doWrite(Yield &yield, Addr addr, void *ptr, size_t size)
111{
112    ItsAction a;
113    a.type = ItsActionType::SEND_REQ;
114
115    RequestPtr req = std::make_shared<Request>(
116        addr, size, 0, its.masterId);
117
118    req->taskId(ContextSwitchTaskId::DMA);
119
120    a.pkt = new Packet(req, MemCmd::WriteReq);
121    a.pkt->dataStatic(ptr);
122
123    a.delay = 0;
124
125    PacketPtr pkt = yield(a).get();
126
127    assert(pkt);
128    assert(pkt->getSize() >= size);
129
130    delete pkt;
131}
132
133void
134ItsProcess::terminate(Yield &yield)
135{
136    ItsAction a;
137    a.type = ItsActionType::TERMINATE;
138    a.pkt = NULL;
139    a.delay = 0;
140    yield(a);
141}
142
143void
144ItsProcess::writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte)
145{
146    const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE);
147    const Addr address = base + device_id;
148
149    DPRINTF(ITS, "Writing DTE at address %#x: %#x\n", address, dte);
150
151    doWrite(yield, address, &dte, sizeof(dte));
152}
153
154void
155ItsProcess::writeIrqTranslationTable(
156    Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte)
157{
158    const Addr address = itt_base + event_id;
159
160    doWrite(yield, address, &itte, sizeof(itte));
161
162    DPRINTF(ITS, "Writing ITTE at address %#x: %#x\n", address, itte);
163}
164
165void
166ItsProcess::writeIrqCollectionTable(
167    Yield &yield, uint32_t collection_id, CTE cte)
168{
169    const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE);
170    const Addr address = base + collection_id;
171
172    doWrite(yield, address, &cte, sizeof(cte));
173
174    DPRINTF(ITS, "Writing CTE at address %#x: %#x\n", address, cte);
175}
176
177uint64_t
178ItsProcess::readDeviceTable(Yield &yield, uint32_t device_id)
179{
180    const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE);
181    const Addr address = base + device_id;
182
183    uint64_t dte;
184    doRead(yield, address, &dte, sizeof(dte));
185
186    DPRINTF(ITS, "Reading DTE at address %#x: %#x\n", address, dte);
187    return dte;
188}
189
190uint64_t
191ItsProcess::readIrqTranslationTable(
192    Yield &yield, const Addr itt_base, uint32_t event_id)
193{
194    const Addr address = itt_base + event_id;
195
196    uint64_t itte;
197    doRead(yield, address, &itte, sizeof(itte));
198
199    DPRINTF(ITS, "Reading ITTE at address %#x: %#x\n", address, itte);
200    return itte;
201}
202
203uint64_t
204ItsProcess::readIrqCollectionTable(Yield &yield, uint32_t collection_id)
205{
206    const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE);
207    const Addr address = base + collection_id;
208
209    uint64_t cte;
210    doRead(yield, address, &cte, sizeof(cte));
211
212    DPRINTF(ITS, "Reading CTE at address %#x: %#x\n", address, cte);
213    return cte;
214}
215
216ItsTranslation::ItsTranslation(Gicv3Its &_its)
217  : ItsProcess(_its)
218{
219    reinit();
220    its.pendingTranslations++;
221}
222
223ItsTranslation::~ItsTranslation()
224{
225    assert(its.pendingTranslations >= 1);
226    its.pendingTranslations--;
227}
228
229void
230ItsTranslation::main(Yield &yield)
231{
232    PacketPtr pkt = yield.get();
233
234    const uint32_t device_id = pkt->req->streamId();
235    const uint32_t event_id = pkt->getLE<uint32_t>();
236
237    auto result = translateLPI(yield, device_id, event_id);
238
239    uint32_t intid = result.first;
240    Gicv3Redistributor *redist = result.second;
241
242    // Set the LPI in the redistributor
243    redist->setClrLPI(intid, true);
244
245    // Update the value in GITS_TRANSLATER only once we know
246    // there was no error in the tranlation process (before
247    // terminating the translation
248    its.gitsTranslater = event_id;
249
250    terminate(yield);
251}
252
253std::pair<uint32_t, Gicv3Redistributor *>
254ItsTranslation::translateLPI(Yield &yield, uint32_t device_id,
255                             uint32_t event_id)
256{
257    if (its.deviceOutOfRange(device_id)) {
258        terminate(yield);
259    }
260
261    DTE dte = readDeviceTable(yield, device_id);
262
263    if (!dte.valid || its.idOutOfRange(event_id, dte.ittRange)) {
264        terminate(yield);
265    }
266
267    ITTE itte = readIrqTranslationTable(yield, dte.ittAddress, event_id);
268    const auto collection_id = itte.icid;
269
270    if (!itte.valid || its.collectionOutOfRange(collection_id)) {
271        terminate(yield);
272    }
273
274    CTE cte = readIrqCollectionTable(yield, collection_id);
275
276    if (!cte.valid) {
277        terminate(yield);
278    }
279
280    // Returning the INTID and the target Redistributor
281    return std::make_pair(itte.intNum, its.getRedistributor(cte));
282}
283
284ItsCommand::DispatchTable ItsCommand::cmdDispatcher =
285{
286    COMMAND(CLEAR, &ItsCommand::clear),
287    COMMAND(DISCARD, &ItsCommand::discard),
288    COMMAND(INT, &ItsCommand::doInt),
289    COMMAND(INV, &ItsCommand::inv),
290    COMMAND(INVALL, &ItsCommand::invall),
291    COMMAND(MAPC, &ItsCommand::mapc),
292    COMMAND(MAPD, &ItsCommand::mapd),
293    COMMAND(MAPI, &ItsCommand::mapi),
294    COMMAND(MAPTI, &ItsCommand::mapti),
295    COMMAND(MOVALL, &ItsCommand::movall),
296    COMMAND(MOVI, &ItsCommand::movi),
297    COMMAND(SYNC, &ItsCommand::sync),
298    COMMAND(VINVALL, &ItsCommand::vinvall),
299    COMMAND(VMAPI, &ItsCommand::vmapi),
300    COMMAND(VMAPP, &ItsCommand::vmapp),
301    COMMAND(VMAPTI, &ItsCommand::vmapti),
302    COMMAND(VMOVI, &ItsCommand::vmovi),
303    COMMAND(VMOVP, &ItsCommand::vmovp),
304    COMMAND(VSYNC, &ItsCommand::vsync),
305};
306
307ItsCommand::ItsCommand(Gicv3Its &_its)
308  : ItsProcess(_its)
309{
310    reinit();
311    its.pendingCommands = true;
312}
313
314ItsCommand::~ItsCommand()
315{
316    its.pendingCommands = false;
317}
318
319std::string
320ItsCommand::commandName(uint32_t cmd)
321{
322    const auto entry = cmdDispatcher.find(cmd);
323    return entry != cmdDispatcher.end() ? entry->second.name : "INVALID";
324}
325
326void
327ItsCommand::main(Yield &yield)
328{
329    ItsAction a;
330    a.type = ItsActionType::INITIAL_NOP;
331    a.pkt = nullptr;
332    a.delay = 0;
333    yield(a);
334
335    while (its.gitsCwriter.offset != its.gitsCreadr.offset) {
336        CommandEntry command;
337
338        // Reading the command from CMDQ
339        readCommand(yield, command);
340
341        processCommand(yield, command);
342
343        its.incrementReadPointer();
344    }
345
346    terminate(yield);
347}
348
349void
350ItsCommand::readCommand(Yield &yield, CommandEntry &command)
351{
352    // read the command pointed by GITS_CREADR
353    const Addr cmd_addr =
354        (its.gitsCbaser.physAddr << 12) + (its.gitsCreadr.offset << 5);
355
356    doRead(yield, cmd_addr, &command, sizeof(command));
357
358    DPRINTF(ITS, "Command %s read from queue at address: %#x\n",
359            commandName(command.type), cmd_addr);
360    DPRINTF(ITS, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n",
361            command.raw[0], command.raw[1], command.raw[2], command.raw[3]);
362}
363
364void
365ItsCommand::processCommand(Yield &yield, CommandEntry &command)
366{
367    const auto entry = cmdDispatcher.find(command.type);
368
369    if (entry != cmdDispatcher.end()) {
370        // Execute the command
371        entry->second.exec(this, yield, command);
372    } else {
373        panic("Unrecognized command type: %u", command.type);
374    }
375}
376
377void
378ItsCommand::clear(Yield &yield, CommandEntry &command)
379{
380    if (deviceOutOfRange(command)) {
381        its.incrementReadPointer();
382        terminate(yield);
383    }
384
385    DTE dte = readDeviceTable(yield, command.deviceId);
386
387    if (!dte.valid || idOutOfRange(command, dte)) {
388        its.incrementReadPointer();
389        terminate(yield);
390    }
391
392    ITTE itte = readIrqTranslationTable(
393        yield, dte.ittAddress, command.eventId);
394
395    if (!itte.valid) {
396        its.incrementReadPointer();
397        terminate(yield);
398    }
399
400    const auto collection_id = itte.icid;
401    CTE cte = readIrqCollectionTable(yield, collection_id);
402
403    if (!cte.valid) {
404        its.incrementReadPointer();
405        terminate(yield);
406    }
407
408    // Clear the LPI in the redistributor
409    its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
410}
411
412void
413ItsCommand::discard(Yield &yield, CommandEntry &command)
414{
415    if (deviceOutOfRange(command)) {
416        its.incrementReadPointer();
417        terminate(yield);
418    }
419
420    DTE dte = readDeviceTable(yield, command.deviceId);
421
422    if (!dte.valid || idOutOfRange(command, dte)) {
423        its.incrementReadPointer();
424        terminate(yield);
425    }
426
427    ITTE itte = readIrqTranslationTable(
428        yield, dte.ittAddress, command.eventId);
429
430    if (!itte.valid) {
431        its.incrementReadPointer();
432        terminate(yield);
433    }
434
435    const auto collection_id = itte.icid;
436    Gicv3Its::CTE cte = readIrqCollectionTable(yield, collection_id);
437
438    if (!cte.valid) {
439        its.incrementReadPointer();
440        terminate(yield);
441    }
442
443    its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
444
445    // Then removes the mapping from the ITT (invalidating)
446    itte.valid = 0;
447    writeIrqTranslationTable(
448        yield, dte.ittAddress, command.eventId, itte);
449}
450
451void
452ItsCommand::doInt(Yield &yield, CommandEntry &command)
453{
454    if (deviceOutOfRange(command)) {
455        its.incrementReadPointer();
456        terminate(yield);
457    }
458
459    DTE dte = readDeviceTable(yield, command.deviceId);
460
461    if (!dte.valid || idOutOfRange(command, dte)) {
462        its.incrementReadPointer();
463        terminate(yield);
464    }
465
466    ITTE itte = readIrqTranslationTable(
467        yield, dte.ittAddress, command.eventId);
468
469    if (!itte.valid) {
470        its.incrementReadPointer();
471        terminate(yield);
472    }
473
474    const auto collection_id = itte.icid;
475    CTE cte = readIrqCollectionTable(yield, collection_id);
476
477    if (!cte.valid) {
478        its.incrementReadPointer();
479        terminate(yield);
480    }
481
482    // Set the LPI in the redistributor
483    its.getRedistributor(cte)->setClrLPI(itte.intNum, true);
484}
485
486void
487ItsCommand::inv(Yield &yield, CommandEntry &command)
488{
489    if (deviceOutOfRange(command)) {
490        its.incrementReadPointer();
491        terminate(yield);
492    }
493
494    DTE dte = readDeviceTable(yield, command.deviceId);
495
496    if (!dte.valid || idOutOfRange(command, dte)) {
497        its.incrementReadPointer();
498        terminate(yield);
499    }
500
501    ITTE itte = readIrqTranslationTable(
502        yield, dte.ittAddress, command.eventId);
503
504    if (!itte.valid) {
505        its.incrementReadPointer();
506        terminate(yield);
507    }
508
509    const auto collection_id = itte.icid;
510    CTE cte = readIrqCollectionTable(yield, collection_id);
511
512    if (!cte.valid) {
513        its.incrementReadPointer();
514        terminate(yield);
515    }
516    // Do nothing since caching is currently not supported in
517    // Redistributor
518}
519
520void
521ItsCommand::invall(Yield &yield, CommandEntry &command)
522{
523    if (collectionOutOfRange(command)) {
524        its.incrementReadPointer();
525        terminate(yield);
526    }
527
528    const auto icid = bits(command.raw[2], 15, 0);
529
530    CTE cte = readIrqCollectionTable(yield, icid);
531
532    if (!cte.valid) {
533        its.incrementReadPointer();
534        terminate(yield);
535    }
536    // Do nothing since caching is currently not supported in
537    // Redistributor
538}
539
540void
541ItsCommand::mapc(Yield &yield, CommandEntry &command)
542{
543    if (collectionOutOfRange(command)) {
544        its.incrementReadPointer();
545        terminate(yield);
546    }
547
548    CTE cte = 0;
549    cte.valid = bits(command.raw[2], 63);
550    cte.rdBase = bits(command.raw[2], 50, 16);
551
552    const auto icid = bits(command.raw[2], 15, 0);
553
554    writeIrqCollectionTable(yield, icid, cte);
555}
556
557void
558ItsCommand::mapd(Yield &yield, CommandEntry &command)
559{
560    if (deviceOutOfRange(command) || sizeOutOfRange(command)) {
561        its.incrementReadPointer();
562        terminate(yield);
563    }
564
565    DTE dte = 0;
566    dte.valid = bits(command.raw[2], 63);
567    dte.ittAddress = mbits(command.raw[2], 51, 8);
568    dte.ittRange = bits(command.raw[1], 4, 0);
569
570    writeDeviceTable(yield, command.deviceId, dte);
571}
572
573void
574ItsCommand::mapi(Yield &yield, CommandEntry &command)
575{
576    if (deviceOutOfRange(command)) {
577        its.incrementReadPointer();
578        terminate(yield);
579    }
580
581    if (collectionOutOfRange(command)) {
582        its.incrementReadPointer();
583        terminate(yield);
584    }
585
586    DTE dte = readDeviceTable(yield, command.deviceId);
587
588    if (!dte.valid || idOutOfRange(command, dte) ||
589        its.lpiOutOfRange(command.eventId)) {
590
591        its.incrementReadPointer();
592        terminate(yield);
593    }
594
595    Gicv3Its::ITTE itte = readIrqTranslationTable(
596        yield, dte.ittAddress, command.eventId);
597
598    itte.valid = 1;
599    itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
600    itte.intNum = command.eventId;
601    itte.icid = bits(command.raw[2], 15, 0);
602
603    writeIrqTranslationTable(
604        yield, dte.ittAddress, command.eventId, itte);
605}
606
607void
608ItsCommand::mapti(Yield &yield, CommandEntry &command)
609{
610    if (deviceOutOfRange(command)) {
611        its.incrementReadPointer();
612        terminate(yield);
613    }
614
615    if (collectionOutOfRange(command)) {
616        its.incrementReadPointer();
617        terminate(yield);
618    }
619
620    DTE dte = readDeviceTable(yield, command.deviceId);
621
622    const auto pintid = bits(command.raw[1], 63, 32);
623
624    if (!dte.valid || idOutOfRange(command, dte) ||
625        its.lpiOutOfRange(pintid)) {
626
627        its.incrementReadPointer();
628        terminate(yield);
629    }
630
631    ITTE itte = readIrqTranslationTable(
632        yield, dte.ittAddress, command.eventId);
633
634    itte.valid = 1;
635    itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
636    itte.intNum = pintid;
637    itte.icid = bits(command.raw[2], 15, 0);
638
639    writeIrqTranslationTable(
640        yield, dte.ittAddress, command.eventId, itte);
641}
642
643void
644ItsCommand::movall(Yield &yield, CommandEntry &command)
645{
646    const uint64_t rd1 = bits(command.raw[2], 50, 16);
647    const uint64_t rd2 = bits(command.raw[3], 50, 16);
648
649    if (rd1 != rd2) {
650        Gicv3Redistributor * redist1 = its.getRedistributor(rd1);
651        Gicv3Redistributor * redist2 = its.getRedistributor(rd2);
652
653        its.moveAllPendingState(redist1, redist2);
654    }
655}
656
657void
658ItsCommand::movi(Yield &yield, CommandEntry &command)
659{
660    if (deviceOutOfRange(command)) {
661        its.incrementReadPointer();
662        terminate(yield);
663    }
664
665    if (collectionOutOfRange(command)) {
666        its.incrementReadPointer();
667        terminate(yield);
668    }
669
670    DTE dte = readDeviceTable(yield, command.deviceId);
671
672    if (!dte.valid || idOutOfRange(command, dte)) {
673        its.incrementReadPointer();
674        terminate(yield);
675    }
676
677    ITTE itte = readIrqTranslationTable(
678        yield, dte.ittAddress, command.eventId);
679
680    if (!itte.valid || itte.intType == Gicv3Its::VIRTUAL_INTERRUPT) {
681        its.incrementReadPointer();
682        terminate(yield);
683    }
684
685    const auto collection_id1 = itte.icid;
686    CTE cte1 = readIrqCollectionTable(yield, collection_id1);
687
688    if (!cte1.valid) {
689        its.incrementReadPointer();
690        terminate(yield);
691    }
692
693    const auto collection_id2 = bits(command.raw[2], 15, 0);
694    CTE cte2 = readIrqCollectionTable(yield, collection_id2);
695
696    if (!cte2.valid) {
697        its.incrementReadPointer();
698        terminate(yield);
699    }
700
701    Gicv3Redistributor *first_redist = its.getRedistributor(cte1);
702    Gicv3Redistributor *second_redist = its.getRedistributor(cte2);
703
704    if (second_redist != first_redist) {
705        // move pending state of the interrupt from one redistributor
706        // to the other.
707        if (first_redist->isPendingLPI(itte.intNum)) {
708            first_redist->setClrLPI(itte.intNum, false);
709            second_redist->setClrLPI(itte.intNum, true);
710        }
711    }
712
713    itte.icid = collection_id2;
714    writeIrqTranslationTable(
715        yield, dte.ittAddress, command.eventId, itte);
716}
717
718void
719ItsCommand::sync(Yield &yield, CommandEntry &command)
720{
721    warn("ITS %s command unimplemented", __func__);
722}
723
724void
725ItsCommand::vinvall(Yield &yield, CommandEntry &command)
726{
727    panic("ITS %s command unimplemented", __func__);
728}
729
730void
731ItsCommand::vmapi(Yield &yield, CommandEntry &command)
732{
733    panic("ITS %s command unimplemented", __func__);
734}
735
736void
737ItsCommand::vmapp(Yield &yield, CommandEntry &command)
738{
739    panic("ITS %s command unimplemented", __func__);
740}
741
742void
743ItsCommand::vmapti(Yield &yield, CommandEntry &command)
744{
745    panic("ITS %s command unimplemented", __func__);
746}
747
748void
749ItsCommand::vmovi(Yield &yield, CommandEntry &command)
750{
751    panic("ITS %s command unimplemented", __func__);
752}
753
754void
755ItsCommand::vmovp(Yield &yield, CommandEntry &command)
756{
757    panic("ITS %s command unimplemented", __func__);
758}
759
760void
761ItsCommand::vsync(Yield &yield, CommandEntry &command)
762{
763    panic("ITS %s command unimplemented", __func__);
764}
765
766Gicv3Its::Gicv3Its(const Gicv3ItsParams *params)
767 : BasicPioDevice(params, params->pio_size),
768   dmaPort(name() + ".dma", *this),
769   gitsControl(0x1),
770   gitsTyper(params->gits_typer),
771   gitsCbaser(0), gitsCreadr(0),
772   gitsCwriter(0), gitsIidr(0),
773   masterId(params->system->getMasterId(this)),
774   gic(nullptr),
775   commandEvent([this] { checkCommandQueue(); }, name()),
776   pendingCommands(false),
777   pendingTranslations(0)
778{
779    for (auto idx = 0; idx < NUM_BASER_REGS; idx++) {
780        BASER gits_baser = 0;
781        gits_baser.type = idx;
782        gits_baser.entrySize = sizeof(uint64_t) - 1;
783        tableBases.push_back(gits_baser);
784    }
785}
786
787void
788Gicv3Its::setGIC(Gicv3 *_gic)
789{
790    assert(!gic);
791    gic = _gic;
792}
793
794AddrRangeList
795Gicv3Its::getAddrRanges() const
796{
797    assert(pioSize != 0);
798    AddrRangeList ranges;
799    DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
800    ranges.push_back(RangeSize(pioAddr, pioSize));
801    return ranges;
802}
803
804Tick
805Gicv3Its::read(PacketPtr pkt)
806{
807    const Addr addr = pkt->getAddr() - pioAddr;
808    uint64_t value = 0;
809
810    DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
811
812    switch (addr) {
813      case GITS_CTLR:
814        value = gitsControl;
815        break;
816
817      case GITS_IIDR:
818        value = gitsIidr;
819        break;
820
821      case GITS_TYPER:
822        value = gitsTyper;
823        break;
824
825      case GITS_CBASER:
826        value = gitsCbaser;
827        break;
828
829      case GITS_CWRITER:
830        value = gitsCwriter;
831        break;
832
833      case GITS_CREADR:
834        value = gitsCreadr;
835        break;
836
837      case GITS_PIDR2:
838        value = gic->getDistributor()->gicdPidr2;
839        break;
840
841      case GITS_TRANSLATER:
842        value = gitsTranslater;
843        break;
844
845      default:
846        if (GITS_BASER.contains(addr)) {
847            auto relative_addr = addr - GITS_BASER.start();
848            auto baser_index = relative_addr / sizeof(uint64_t);
849
850            value = tableBases[baser_index];
851            break;
852        } else {
853            panic("Unrecognized register access\n");
854        }
855    }
856
857    pkt->setUintX(value, LittleEndianByteOrder);
858    pkt->makeAtomicResponse();
859    return pioDelay;
860}
861
862Tick
863Gicv3Its::write(PacketPtr pkt)
864{
865    Addr addr = pkt->getAddr() - pioAddr;
866
867    DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
868
869    switch (addr) {
870      case GITS_CTLR:
871        assert(pkt->getSize() == sizeof(uint32_t));
872        gitsControl = pkt->getLE<uint32_t>();
873        break;
874
875      case GITS_IIDR:
876        panic("GITS_IIDR is Read Only\n");
877
878      case GITS_TYPER:
879        panic("GITS_TYPER is Read Only\n");
880
881      case GITS_CBASER:
882        assert(pkt->getSize() == sizeof(uint64_t));
883        gitsCbaser = pkt->getLE<uint64_t>();
884        gitsCreadr = 0; // Cleared when CBASER gets written
885
886        checkCommandQueue();
887        break;
888
889      case GITS_CWRITER:
890        assert(pkt->getSize() == sizeof(uint64_t));
891        gitsCwriter = pkt->getLE<uint64_t>();
892
893        checkCommandQueue();
894        break;
895
896      case GITS_CREADR:
897        panic("GITS_READR is Read Only\n");
898
899      case GITS_TRANSLATER:
900        if (gitsControl.enabled) {
901            translate(pkt);
902        }
903        break;
904
905      default:
906        if (GITS_BASER.contains(addr)) {
907            auto relative_addr = addr - GITS_BASER.start();
908            auto baser_index = relative_addr / sizeof(uint64_t);
909
910            BASER val = pkt->getLE<uint64_t>();
911
912            panic_if(val.indirect,
913                "We currently don't support two level ITS tables");
914
915            tableBases[baser_index] = val;
916            break;
917        } else {
918            panic("Unrecognized register access\n");
919        }
920    }
921
922    pkt->makeAtomicResponse();
923    return pioDelay;
924}
925
926bool
927Gicv3Its::idOutOfRange(uint32_t event_id, uint8_t itt_range) const
928{
929    const uint32_t id_bits = gitsTyper.idBits;
930    return event_id >= (1ULL << (id_bits + 1)) ||
931        event_id >= ((1ULL << itt_range) + 1);
932}
933
934bool
935Gicv3Its::deviceOutOfRange(uint32_t device_id) const
936{
937    return device_id >= (1ULL << (gitsTyper.devBits + 1));
938}
939
940bool
941Gicv3Its::sizeOutOfRange(uint32_t size) const
942{
943    return size > gitsTyper.idBits;
944}
945
946bool
947Gicv3Its::collectionOutOfRange(uint32_t collection_id) const
948{
949    // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID
950    // Otherwise, #bits is specified by GITS_TYPER.CIDbits
951    const auto cid_bits = gitsTyper.cil == 0 ?
952        16 : gitsTyper.cidBits + 1;
953
954    return collection_id >= (1ULL << cid_bits);
955}
956
957bool
958Gicv3Its::lpiOutOfRange(uint32_t intid) const
959{
960    return intid >= (1ULL << (Gicv3Distributor::IDBITS + 1)) ||
961           (intid < Gicv3Redistributor::SMALLEST_LPI_ID &&
962            intid != Gicv3::INTID_SPURIOUS);
963}
964
965DrainState
966Gicv3Its::drain()
967{
968    if (!pendingCommands && !pendingTranslations) {
969        return DrainState::Drained;
970    } else {
971        DPRINTF(Drain, "GICv3 ITS not drained\n");
972        return DrainState::Draining;
973    }
974}
975
976void
977Gicv3Its::serialize(CheckpointOut & cp) const
978{
979    SERIALIZE_SCALAR(gitsControl);
980    SERIALIZE_SCALAR(gitsTyper);
981    SERIALIZE_SCALAR(gitsCbaser);
982    SERIALIZE_SCALAR(gitsCreadr);
983    SERIALIZE_SCALAR(gitsCwriter);
984    SERIALIZE_SCALAR(gitsIidr);
985
986    SERIALIZE_CONTAINER(tableBases);
987}
988
989void
990Gicv3Its::unserialize(CheckpointIn & cp)
991{
992    UNSERIALIZE_SCALAR(gitsControl);
993    UNSERIALIZE_SCALAR(gitsTyper);
994    UNSERIALIZE_SCALAR(gitsCbaser);
995    UNSERIALIZE_SCALAR(gitsCreadr);
996    UNSERIALIZE_SCALAR(gitsCwriter);
997    UNSERIALIZE_SCALAR(gitsIidr);
998
999    UNSERIALIZE_CONTAINER(tableBases);
1000}
1001
1002void
1003Gicv3Its::incrementReadPointer()
1004{
1005    // Make the reader point to the next element
1006    gitsCreadr.offset = gitsCreadr.offset + 1;
1007
1008    // Check for wrapping
1009    auto queue_end = (4096 * (gitsCbaser.size + 1));
1010
1011    if (gitsCreadr.offset == queue_end) {
1012        gitsCreadr.offset = 0;
1013    }
1014}
1015
1016void
1017Gicv3Its::checkCommandQueue()
1018{
1019    if (!gitsControl.enabled || !gitsCbaser.valid)
1020        return;
1021
1022    if (gitsCwriter.offset != gitsCreadr.offset) {
1023        // writer and reader pointing to different command
1024        // entries: queue not empty.
1025        DPRINTF(ITS, "Reading command from queue\n");
1026
1027        if (!pendingCommands) {
1028            auto *cmd_proc = new ItsCommand(*this);
1029
1030            runProcess(cmd_proc, nullptr);
1031        } else {
1032            DPRINTF(ITS, "Waiting for pending command to finish\n");
1033        }
1034    }
1035}
1036
1037Port &
1038Gicv3Its::getPort(const std::string &if_name, PortID idx)
1039{
1040    if (if_name == "dma") {
1041        return dmaPort;
1042    }
1043    return BasicPioDevice::getPort(if_name, idx);
1044}
1045
1046void
1047Gicv3Its::recvReqRetry()
1048{
1049    assert(!packetsToRetry.empty());
1050
1051    while (!packetsToRetry.empty()) {
1052        ItsAction a = packetsToRetry.front();
1053
1054        assert(a.type == ItsActionType::SEND_REQ);
1055
1056        if (!dmaPort.sendTimingReq(a.pkt))
1057            break;
1058
1059        packetsToRetry.pop();
1060    }
1061}
1062
1063bool
1064Gicv3Its::recvTimingResp(PacketPtr pkt)
1065{
1066    // @todo: We need to pay for this and not just zero it out
1067    pkt->headerDelay = pkt->payloadDelay = 0;
1068
1069    ItsProcess *proc =
1070        safe_cast<ItsProcess *>(pkt->popSenderState());
1071
1072    runProcessTiming(proc, pkt);
1073
1074    return true;
1075}
1076
1077ItsAction
1078Gicv3Its::runProcess(ItsProcess *proc, PacketPtr pkt)
1079{
1080    if (sys->isAtomicMode()) {
1081        return runProcessAtomic(proc, pkt);
1082    } else if (sys->isTimingMode()) {
1083        return runProcessTiming(proc, pkt);
1084    } else {
1085        panic("Not in timing or atomic mode\n");
1086    }
1087}
1088
1089ItsAction
1090Gicv3Its::runProcessTiming(ItsProcess *proc, PacketPtr pkt)
1091{
1092    ItsAction action = proc->run(pkt);
1093
1094    switch (action.type) {
1095      case ItsActionType::SEND_REQ:
1096        action.pkt->pushSenderState(proc);
1097
1098        if (packetsToRetry.empty() &&
1099            dmaPort.sendTimingReq(action.pkt)) {
1100
1101        } else {
1102            packetsToRetry.push(action);
1103        }
1104        break;
1105
1106      case ItsActionType::TERMINATE:
1107        delete proc;
1108        if (!pendingCommands && !commandEvent.scheduled()) {
1109            schedule(commandEvent, clockEdge());
1110        }
1111        break;
1112
1113      default:
1114        panic("Unknown action\n");
1115    }
1116
1117    return action;
1118}
1119
1120ItsAction
1121Gicv3Its::runProcessAtomic(ItsProcess *proc, PacketPtr pkt)
1122{
1123    ItsAction action;
1124    Tick delay = 0;
1125    bool terminate = false;
1126
1127    do {
1128        action = proc->run(pkt);
1129
1130        switch (action.type) {
1131          case ItsActionType::SEND_REQ:
1132            delay += dmaPort.sendAtomic(action.pkt);
1133            pkt = action.pkt;
1134            break;
1135
1136          case ItsActionType::TERMINATE:
1137            delete proc;
1138            terminate = true;
1139            break;
1140
1141          default:
1142            panic("Unknown action\n");
1143        }
1144
1145    } while (!terminate);
1146
1147    action.delay = delay;
1148
1149    return action;
1150}
1151
1152void
1153Gicv3Its::translate(PacketPtr pkt)
1154{
1155    DPRINTF(ITS, "Starting Translation Request\n");
1156
1157    auto *proc = new ItsTranslation(*this);
1158    runProcess(proc, pkt);
1159}
1160
1161Gicv3Redistributor*
1162Gicv3Its::getRedistributor(uint64_t rd_base)
1163{
1164    if (gitsTyper.pta == 1) {
1165        // RDBase is a redistributor address
1166        return gic->getRedistributorByAddr(rd_base << 16);
1167    } else {
1168        // RDBase is a redistributor number
1169        return gic->getRedistributor(rd_base);
1170    }
1171}
1172
1173Addr
1174Gicv3Its::pageAddress(Gicv3Its::ItsTables table)
1175{
1176    const BASER base = tableBases[table];
1177    // real address depends on page size
1178    switch (base.pageSize) {
1179      case SIZE_4K:
1180      case SIZE_16K:
1181        return mbits(base, 47, 12);
1182      case SIZE_64K:
1183        return mbits(base, 47, 16) | (bits(base, 15, 12) << 48);
1184      default:
1185        panic("Unsupported page size\n");
1186    }
1187}
1188
1189void
1190Gicv3Its::moveAllPendingState(
1191    Gicv3Redistributor *rd1, Gicv3Redistributor *rd2)
1192{
1193    const uint64_t largest_lpi_id = 1ULL << (rd1->lpiIDBits + 1);
1194    uint8_t lpi_pending_table[largest_lpi_id / 8];
1195
1196    // Copying the pending table from redistributor 1 to redistributor 2
1197    rd1->memProxy->readBlob(
1198        rd1->lpiPendingTablePtr, (uint8_t *)lpi_pending_table,
1199        sizeof(lpi_pending_table));
1200
1201    rd2->memProxy->writeBlob(
1202        rd2->lpiPendingTablePtr, (uint8_t *)lpi_pending_table,
1203        sizeof(lpi_pending_table));
1204
1205    // Clearing pending table in redistributor 2
1206    rd1->memProxy->memsetBlob(
1207        rd1->lpiPendingTablePtr,
1208        0, sizeof(lpi_pending_table));
1209
1210    rd2->updateAndInformCPUInterface();
1211}
1212
1213Gicv3Its *
1214Gicv3ItsParams::create()
1215{
1216    return new Gicv3Its(this);
1217}
1218