gic_v3_its.cc revision 14255
12810SN/A/*
212599Snikos.nikoleris@arm.com * Copyright (c) 2019 ARM Limited
39663Suri.wiener@arm.com * All rights reserved
49663Suri.wiener@arm.com *
59663Suri.wiener@arm.com * The license below extends only to copyright in the software and shall
69663Suri.wiener@arm.com * not be construed as granting a license to any other intellectual
79663Suri.wiener@arm.com * property including but not limited to intellectual property relating
89663Suri.wiener@arm.com * to a hardware implementation of the functionality of the software
99663Suri.wiener@arm.com * licensed hereunder.  You may use the software subject to the license
109663Suri.wiener@arm.com * terms below provided that you ensure that this notice is replicated
119663Suri.wiener@arm.com * unmodified and in its entirety in all distributions of the software,
129663Suri.wiener@arm.com * modified or unmodified, in source code or in binary form.
139663Suri.wiener@arm.com *
142810SN/A * Redistribution and use in source and binary forms, with or without
152810SN/A * modification, are permitted provided that the following conditions are
162810SN/A * met: redistributions of source code must retain the above copyright
172810SN/A * notice, this list of conditions and the following disclaimer;
182810SN/A * redistributions in binary form must reproduce the above copyright
192810SN/A * notice, this list of conditions and the following disclaimer in the
202810SN/A * documentation and/or other materials provided with the distribution;
212810SN/A * neither the name of the copyright holders nor the names of its
222810SN/A * contributors may be used to endorse or promote products derived from
232810SN/A * this software without specific prior written permission.
242810SN/A *
252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362810SN/A *
372810SN/A * Authors: Giacomo Travaglini
382810SN/A */
392810SN/A
402810SN/A#include "dev/arm/gic_v3_its.hh"
412810SN/A
422810SN/A#include "debug/AddrRanges.hh"
432810SN/A#include "debug/Drain.hh"
442810SN/A#include "debug/GIC.hh"
452810SN/A#include "debug/ITS.hh"
462810SN/A#include "dev/arm/gic_v3.hh"
472810SN/A#include "dev/arm/gic_v3_distributor.hh"
4810764Sandreas.hansson@arm.com#include "dev/arm/gic_v3_redistributor.hh"
4910764Sandreas.hansson@arm.com#include "mem/packet_access.hh"
502810SN/A
5112727Snikos.nikoleris@arm.com#define COMMAND(x, method) { x, DispatchEntry(#x, method) }
5212727Snikos.nikoleris@arm.com
534626SN/Aconst AddrRange Gicv3Its::GITS_BASER(0x0100, 0x0138);
5412727Snikos.nikoleris@arm.com
554626SN/Aconst uint32_t Gicv3Its::CTLR_QUIESCENT = 0x80000000;
565314SN/A
5712727Snikos.nikoleris@arm.comItsProcess::ItsProcess(Gicv3Its &_its)
5811375Sandreas.hansson@arm.com  : its(_its), coroutine(nullptr)
5912727Snikos.nikoleris@arm.com{
6012727Snikos.nikoleris@arm.com}
612810SN/A
6212724Snikos.nikoleris@arm.comItsProcess::~ItsProcess()
632810SN/A{
642810SN/A}
652810SN/A
663374SN/Avoid
679264Sdjordje.kovacevic@arm.comItsProcess::reinit()
682810SN/A{
6911375Sandreas.hansson@arm.com    coroutine.reset(new Coroutine(
704626SN/A        std::bind(&ItsProcess::main, this, std::placeholders::_1)));
714626SN/A}
729725Sandreas.hansson@arm.com
7311375Sandreas.hansson@arm.comconst std::string
749725Sandreas.hansson@arm.comItsProcess::name() const
7511375Sandreas.hansson@arm.com{
7611375Sandreas.hansson@arm.com    return its.name();
779725Sandreas.hansson@arm.com}
789725Sandreas.hansson@arm.com
799725Sandreas.hansson@arm.comItsAction
809725Sandreas.hansson@arm.comItsProcess::run(PacketPtr pkt)
819725Sandreas.hansson@arm.com{
829725Sandreas.hansson@arm.com    assert(coroutine != nullptr);
839725Sandreas.hansson@arm.com    assert(*coroutine);
8411284Sandreas.hansson@arm.com    return (*coroutine)(pkt).get();
8511284Sandreas.hansson@arm.com}
8611284Sandreas.hansson@arm.com
8711284Sandreas.hansson@arm.comvoid
8811284Sandreas.hansson@arm.comItsProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size)
8911284Sandreas.hansson@arm.com{
9011284Sandreas.hansson@arm.com    ItsAction a;
9111284Sandreas.hansson@arm.com    a.type = ItsActionType::SEND_REQ;
9211284Sandreas.hansson@arm.com
9311284Sandreas.hansson@arm.com    RequestPtr req = std::make_shared<Request>(
9411284Sandreas.hansson@arm.com        addr, size, 0, its.masterId);
9511284Sandreas.hansson@arm.com
9611284Sandreas.hansson@arm.com    req->taskId(ContextSwitchTaskId::DMA);
9711284Sandreas.hansson@arm.com
9811284Sandreas.hansson@arm.com    a.pkt = new Packet(req, MemCmd::ReadReq);
9911284Sandreas.hansson@arm.com    a.pkt->dataStatic(ptr);
10011284Sandreas.hansson@arm.com
10111284Sandreas.hansson@arm.com    a.delay = 0;
10211284Sandreas.hansson@arm.com
10311284Sandreas.hansson@arm.com    PacketPtr pkt = yield(a).get();
10411284Sandreas.hansson@arm.com
10511284Sandreas.hansson@arm.com    assert(pkt);
10611284Sandreas.hansson@arm.com    assert(pkt->getSize() >= size);
10711284Sandreas.hansson@arm.com
10811284Sandreas.hansson@arm.com    delete pkt;
1099725Sandreas.hansson@arm.com}
1109725Sandreas.hansson@arm.com
1119725Sandreas.hansson@arm.comvoid
1129725Sandreas.hansson@arm.comItsProcess::doWrite(Yield &yield, Addr addr, void *ptr, size_t size)
1139725Sandreas.hansson@arm.com{
1149725Sandreas.hansson@arm.com    ItsAction a;
1159725Sandreas.hansson@arm.com    a.type = ItsActionType::SEND_REQ;
1162810SN/A
1174626SN/A    RequestPtr req = std::make_shared<Request>(
11811375Sandreas.hansson@arm.com        addr, size, 0, its.masterId);
11911375Sandreas.hansson@arm.com
12011375Sandreas.hansson@arm.com    req->taskId(ContextSwitchTaskId::DMA);
1214626SN/A
1224626SN/A    a.pkt = new Packet(req, MemCmd::WriteReq);
1235875Ssteve.reinhardt@amd.com    a.pkt->dataStatic(ptr);
1245875Ssteve.reinhardt@amd.com
1255875Ssteve.reinhardt@amd.com    a.delay = 0;
1265875Ssteve.reinhardt@amd.com
1275875Ssteve.reinhardt@amd.com    PacketPtr pkt = yield(a).get();
1285875Ssteve.reinhardt@amd.com
1295875Ssteve.reinhardt@amd.com    assert(pkt);
13010766Sandreas.hansson@arm.com    assert(pkt->getSize() >= size);
13110766Sandreas.hansson@arm.com
13210766Sandreas.hansson@arm.com    delete pkt;
13310766Sandreas.hansson@arm.com}
13410766Sandreas.hansson@arm.com
13511742Snikos.nikoleris@arm.comvoid
13611742Snikos.nikoleris@arm.comItsProcess::terminate(Yield &yield)
13711742Snikos.nikoleris@arm.com{
13811742Snikos.nikoleris@arm.com    ItsAction a;
13911742Snikos.nikoleris@arm.com    a.type = ItsActionType::TERMINATE;
14011742Snikos.nikoleris@arm.com    a.pkt = NULL;
14111742Snikos.nikoleris@arm.com    a.delay = 0;
14211742Snikos.nikoleris@arm.com    yield(a);
14311742Snikos.nikoleris@arm.com}
14411742Snikos.nikoleris@arm.com
14511742Snikos.nikoleris@arm.comvoid
14611742Snikos.nikoleris@arm.comItsProcess::writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte)
14711742Snikos.nikoleris@arm.com{
14811742Snikos.nikoleris@arm.com    const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE);
14911742Snikos.nikoleris@arm.com    const Addr address = base + (device_id * sizeof(dte));
15011742Snikos.nikoleris@arm.com
15111742Snikos.nikoleris@arm.com    DPRINTF(ITS, "Writing DTE at address %#x: %#x\n", address, dte);
15211742Snikos.nikoleris@arm.com
15311741Snikos.nikoleris@arm.com    doWrite(yield, address, &dte, sizeof(dte));
15411741Snikos.nikoleris@arm.com}
1554626SN/A
1565318SN/Avoid
15711741Snikos.nikoleris@arm.comItsProcess::writeIrqTranslationTable(
1587823Ssteve.reinhardt@amd.com    Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte)
15911741Snikos.nikoleris@arm.com{
16011741Snikos.nikoleris@arm.com    const Addr address = itt_base + (event_id * sizeof(itte));
1614626SN/A
1624626SN/A    doWrite(yield, address, &itte, sizeof(itte));
1634626SN/A
1644903SN/A    DPRINTF(ITS, "Writing ITTE at address %#x: %#x\n", address, itte);
1654903SN/A}
1664903SN/A
16711284Sandreas.hansson@arm.comvoid
1684903SN/AItsProcess::writeIrqCollectionTable(
16911741Snikos.nikoleris@arm.com    Yield &yield, uint32_t collection_id, CTE cte)
17011741Snikos.nikoleris@arm.com{
17112715Snikos.nikoleris@arm.com    const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE);
17212715Snikos.nikoleris@arm.com    const Addr address = base + (collection_id * sizeof(cte));
17312715Snikos.nikoleris@arm.com
17412715Snikos.nikoleris@arm.com    doWrite(yield, address, &cte, sizeof(cte));
17512715Snikos.nikoleris@arm.com
1764903SN/A    DPRINTF(ITS, "Writing CTE at address %#x: %#x\n", address, cte);
1774903SN/A}
17811740Snikos.nikoleris@arm.com
17911740Snikos.nikoleris@arm.comuint64_t
18011740Snikos.nikoleris@arm.comItsProcess::readDeviceTable(Yield &yield, uint32_t device_id)
18111740Snikos.nikoleris@arm.com{
18211740Snikos.nikoleris@arm.com    uint64_t dte;
18311740Snikos.nikoleris@arm.com    const Addr base = its.pageAddress(Gicv3Its::DEVICE_TABLE);
18411740Snikos.nikoleris@arm.com    const Addr address = base + (device_id * sizeof(dte));
18511741Snikos.nikoleris@arm.com
18611740Snikos.nikoleris@arm.com    doRead(yield, address, &dte, sizeof(dte));
18711741Snikos.nikoleris@arm.com
18811741Snikos.nikoleris@arm.com    DPRINTF(ITS, "Reading DTE at address %#x: %#x\n", address, dte);
18911740Snikos.nikoleris@arm.com    return dte;
19012715Snikos.nikoleris@arm.com}
19112715Snikos.nikoleris@arm.com
19212715Snikos.nikoleris@arm.comuint64_t
19312715Snikos.nikoleris@arm.comItsProcess::readIrqTranslationTable(
19412715Snikos.nikoleris@arm.com    Yield &yield, const Addr itt_base, uint32_t event_id)
19512715Snikos.nikoleris@arm.com{
19611740Snikos.nikoleris@arm.com    uint64_t itte;
19711740Snikos.nikoleris@arm.com    const Addr address = itt_base + (event_id * sizeof(itte));
19811740Snikos.nikoleris@arm.com
19911740Snikos.nikoleris@arm.com    doRead(yield, address, &itte, sizeof(itte));
20011740Snikos.nikoleris@arm.com
20111740Snikos.nikoleris@arm.com    DPRINTF(ITS, "Reading ITTE at address %#x: %#x\n", address, itte);
20211740Snikos.nikoleris@arm.com    return itte;
20311740Snikos.nikoleris@arm.com}
20411740Snikos.nikoleris@arm.com
20511741Snikos.nikoleris@arm.comuint64_t
20611741Snikos.nikoleris@arm.comItsProcess::readIrqCollectionTable(Yield &yield, uint32_t collection_id)
20711741Snikos.nikoleris@arm.com{
20811741Snikos.nikoleris@arm.com    uint64_t cte;
20911741Snikos.nikoleris@arm.com    const Addr base = its.pageAddress(Gicv3Its::COLLECTION_TABLE);
21012715Snikos.nikoleris@arm.com    const Addr address = base + (collection_id * sizeof(cte));
21112715Snikos.nikoleris@arm.com
21211741Snikos.nikoleris@arm.com    doRead(yield, address, &cte, sizeof(cte));
21311741Snikos.nikoleris@arm.com
21411741Snikos.nikoleris@arm.com    DPRINTF(ITS, "Reading CTE at address %#x: %#x\n", address, cte);
21511741Snikos.nikoleris@arm.com    return cte;
21611741Snikos.nikoleris@arm.com}
21711741Snikos.nikoleris@arm.com
21811741Snikos.nikoleris@arm.comItsTranslation::ItsTranslation(Gicv3Its &_its)
21911741Snikos.nikoleris@arm.com  : ItsProcess(_its)
22011741Snikos.nikoleris@arm.com{
22111741Snikos.nikoleris@arm.com    reinit();
22211741Snikos.nikoleris@arm.com    its.pendingTranslations++;
22311741Snikos.nikoleris@arm.com    its.gitsControl.quiescent = 0;
22411741Snikos.nikoleris@arm.com}
22511741Snikos.nikoleris@arm.com
2265318SN/AItsTranslation::~ItsTranslation()
22711741Snikos.nikoleris@arm.com{
22811741Snikos.nikoleris@arm.com    assert(its.pendingTranslations >= 1);
22911357Sstephan.diestelhorst@arm.com    its.pendingTranslations--;
23011357Sstephan.diestelhorst@arm.com    if (!its.pendingTranslations && !its.pendingCommands)
23111357Sstephan.diestelhorst@arm.com        its.gitsControl.quiescent = 1;
23211357Sstephan.diestelhorst@arm.com}
23311357Sstephan.diestelhorst@arm.com
2344903SN/Avoid
23511357Sstephan.diestelhorst@arm.comItsTranslation::main(Yield &yield)
2364908SN/A{
23712791Snikos.nikoleris@arm.com    PacketPtr pkt = yield.get();
23812823Srmk35@cl.cam.ac.uk
2395314SN/A    const uint32_t device_id = pkt->req->streamId();
2405314SN/A    const uint32_t event_id = pkt->getLE<uint32_t>();
2414903SN/A
2424903SN/A    auto result = translateLPI(yield, device_id, event_id);
2432810SN/A
2442810SN/A    uint32_t intid = result.first;
2452810SN/A    Gicv3Redistributor *redist = result.second;
2462810SN/A
2474903SN/A    // Set the LPI in the redistributor
2487667Ssteve.reinhardt@amd.com    redist->setClrLPI(intid, true);
2497667Ssteve.reinhardt@amd.com
2507667Ssteve.reinhardt@amd.com    // Update the value in GITS_TRANSLATER only once we know
2517667Ssteve.reinhardt@amd.com    // there was no error in the tranlation process (before
2527667Ssteve.reinhardt@amd.com    // terminating the translation
25311284Sandreas.hansson@arm.com    its.gitsTranslater = event_id;
25411284Sandreas.hansson@arm.com
2559725Sandreas.hansson@arm.com    terminate(yield);
25612599Snikos.nikoleris@arm.com}
25712599Snikos.nikoleris@arm.com
25812599Snikos.nikoleris@arm.comstd::pair<uint32_t, Gicv3Redistributor *>
25912599Snikos.nikoleris@arm.comItsTranslation::translateLPI(Yield &yield, uint32_t device_id,
26012599Snikos.nikoleris@arm.com                             uint32_t event_id)
26111284Sandreas.hansson@arm.com{
26211284Sandreas.hansson@arm.com    if (its.deviceOutOfRange(device_id)) {
2637667Ssteve.reinhardt@amd.com        terminate(yield);
2647667Ssteve.reinhardt@amd.com    }
2657667Ssteve.reinhardt@amd.com
2667667Ssteve.reinhardt@amd.com    DTE dte = readDeviceTable(yield, device_id);
2677667Ssteve.reinhardt@amd.com
2687667Ssteve.reinhardt@amd.com    if (!dte.valid || its.idOutOfRange(event_id, dte.ittRange)) {
2697667Ssteve.reinhardt@amd.com        terminate(yield);
2707667Ssteve.reinhardt@amd.com    }
2717667Ssteve.reinhardt@amd.com
2724665SN/A    ITTE itte = readIrqTranslationTable(yield, dte.ittAddress, event_id);
27312724Snikos.nikoleris@arm.com    const auto collection_id = itte.icid;
27411375Sandreas.hansson@arm.com
27511741Snikos.nikoleris@arm.com    if (!itte.valid || its.collectionOutOfRange(collection_id)) {
27611741Snikos.nikoleris@arm.com        terminate(yield);
27711741Snikos.nikoleris@arm.com    }
27812715Snikos.nikoleris@arm.com
27912715Snikos.nikoleris@arm.com    CTE cte = readIrqCollectionTable(yield, collection_id);
28012715Snikos.nikoleris@arm.com
28112715Snikos.nikoleris@arm.com    if (!cte.valid) {
28212715Snikos.nikoleris@arm.com        terminate(yield);
28312715Snikos.nikoleris@arm.com    }
28412715Snikos.nikoleris@arm.com
28512715Snikos.nikoleris@arm.com    // Returning the INTID and the target Redistributor
28612715Snikos.nikoleris@arm.com    return std::make_pair(itte.intNum, its.getRedistributor(cte));
28712715Snikos.nikoleris@arm.com}
2889725Sandreas.hansson@arm.com
28912793Snikos.nikoleris@arm.comItsCommand::DispatchTable ItsCommand::cmdDispatcher =
29012793Snikos.nikoleris@arm.com{
29112793Snikos.nikoleris@arm.com    COMMAND(CLEAR, &ItsCommand::clear),
29212793Snikos.nikoleris@arm.com    COMMAND(DISCARD, &ItsCommand::discard),
29312793Snikos.nikoleris@arm.com    COMMAND(INT, &ItsCommand::doInt),
29412793Snikos.nikoleris@arm.com    COMMAND(INV, &ItsCommand::inv),
29512793Snikos.nikoleris@arm.com    COMMAND(INVALL, &ItsCommand::invall),
29612793Snikos.nikoleris@arm.com    COMMAND(MAPC, &ItsCommand::mapc),
29712793Snikos.nikoleris@arm.com    COMMAND(MAPD, &ItsCommand::mapd),
29812793Snikos.nikoleris@arm.com    COMMAND(MAPI, &ItsCommand::mapi),
2994668SN/A    COMMAND(MAPTI, &ItsCommand::mapti),
3002810SN/A    COMMAND(MOVALL, &ItsCommand::movall),
3012810SN/A    COMMAND(MOVI, &ItsCommand::movi),
3022810SN/A    COMMAND(SYNC, &ItsCommand::sync),
3032810SN/A    COMMAND(VINVALL, &ItsCommand::vinvall),
3042810SN/A    COMMAND(VMAPI, &ItsCommand::vmapi),
3054626SN/A    COMMAND(VMAPP, &ItsCommand::vmapp),
3062810SN/A    COMMAND(VMAPTI, &ItsCommand::vmapti),
3072810SN/A    COMMAND(VMOVI, &ItsCommand::vmovi),
3082810SN/A    COMMAND(VMOVP, &ItsCommand::vmovp),
3092810SN/A    COMMAND(VSYNC, &ItsCommand::vsync),
3102810SN/A};
3112810SN/A
3123374SN/AItsCommand::ItsCommand(Gicv3Its &_its)
3139725Sandreas.hansson@arm.com  : ItsProcess(_its)
3142810SN/A{
3159725Sandreas.hansson@arm.com    reinit();
3164665SN/A    its.pendingCommands = true;
3179725Sandreas.hansson@arm.com
3184626SN/A    its.gitsControl.quiescent = 0;
3192810SN/A}
3202810SN/A
32110764Sandreas.hansson@arm.comItsCommand::~ItsCommand()
32210764Sandreas.hansson@arm.com{
32310764Sandreas.hansson@arm.com    its.pendingCommands = false;
32410764Sandreas.hansson@arm.com
32510764Sandreas.hansson@arm.com    if (!its.pendingTranslations)
32611197Sandreas.hansson@arm.com        its.gitsControl.quiescent = 1;
3272810SN/A}
32810764Sandreas.hansson@arm.com
32911197Sandreas.hansson@arm.comstd::string
3302810SN/AItsCommand::commandName(uint32_t cmd)
33111375Sandreas.hansson@arm.com{
3324908SN/A    const auto entry = cmdDispatcher.find(cmd);
3335318SN/A    return entry != cmdDispatcher.end() ? entry->second.name : "INVALID";
3345318SN/A}
3352810SN/A
3362810SN/Avoid
3372810SN/AItsCommand::main(Yield &yield)
3382810SN/A{
3392810SN/A    ItsAction a;
3402810SN/A    a.type = ItsActionType::INITIAL_NOP;
3413374SN/A    a.pkt = nullptr;
3422810SN/A    a.delay = 0;
3432810SN/A    yield(a);
34411197Sandreas.hansson@arm.com
34511197Sandreas.hansson@arm.com    while (its.gitsCwriter.offset != its.gitsCreadr.offset) {
3464902SN/A        CommandEntry command;
3472810SN/A
3482810SN/A        // Reading the command from CMDQ
3492810SN/A        readCommand(yield, command);
3502810SN/A
3512810SN/A        processCommand(yield, command);
3522810SN/A
3532810SN/A        its.incrementReadPointer();
3542810SN/A    }
3559725Sandreas.hansson@arm.com
3569725Sandreas.hansson@arm.com    terminate(yield);
3572810SN/A}
3582810SN/A
35911742Snikos.nikoleris@arm.comvoid
36011742Snikos.nikoleris@arm.comItsCommand::readCommand(Yield &yield, CommandEntry &command)
36111742Snikos.nikoleris@arm.com{
36211742Snikos.nikoleris@arm.com    // read the command pointed by GITS_CREADR
36311742Snikos.nikoleris@arm.com    const Addr cmd_addr =
36411742Snikos.nikoleris@arm.com        (its.gitsCbaser.physAddr << 12) + (its.gitsCreadr.offset << 5);
36511742Snikos.nikoleris@arm.com
36611742Snikos.nikoleris@arm.com    doRead(yield, cmd_addr, &command, sizeof(command));
36711742Snikos.nikoleris@arm.com
36811742Snikos.nikoleris@arm.com    DPRINTF(ITS, "Command %s read from queue at address: %#x\n",
36911742Snikos.nikoleris@arm.com            commandName(command.type), cmd_addr);
37011742Snikos.nikoleris@arm.com    DPRINTF(ITS, "dw0: %#x dw1: %#x dw2: %#x dw3: %#x\n",
37111742Snikos.nikoleris@arm.com            command.raw[0], command.raw[1], command.raw[2], command.raw[3]);
37211742Snikos.nikoleris@arm.com}
3734899SN/A
3744899SN/Avoid
3754899SN/AItsCommand::processCommand(Yield &yield, CommandEntry &command)
3769725Sandreas.hansson@arm.com{
3774899SN/A    const auto entry = cmdDispatcher.find(command.type);
3784899SN/A
3792810SN/A    if (entry != cmdDispatcher.end()) {
3802810SN/A        // Execute the command
3812810SN/A        entry->second.exec(this, yield, command);
3829725Sandreas.hansson@arm.com    } else {
3835730SSteve.Reinhardt@amd.com        panic("Unrecognized command type: %u", command.type);
3845730SSteve.Reinhardt@amd.com    }
3859725Sandreas.hansson@arm.com}
3865730SSteve.Reinhardt@amd.com
3872810SN/Avoid
3882810SN/AItsCommand::clear(Yield &yield, CommandEntry &command)
3892810SN/A{
3902810SN/A    if (deviceOutOfRange(command)) {
3912810SN/A        its.incrementReadPointer();
3922810SN/A        terminate(yield);
3939725Sandreas.hansson@arm.com    }
3942810SN/A
3952810SN/A    DTE dte = readDeviceTable(yield, command.deviceId);
3964665SN/A
3974665SN/A    if (!dte.valid || idOutOfRange(command, dte)) {
39812792Snikos.nikoleris@arm.com        its.incrementReadPointer();
39912792Snikos.nikoleris@arm.com        terminate(yield);
40012792Snikos.nikoleris@arm.com    }
40112793Snikos.nikoleris@arm.com
40212793Snikos.nikoleris@arm.com    ITTE itte = readIrqTranslationTable(
40312793Snikos.nikoleris@arm.com        yield, dte.ittAddress, command.eventId);
40412793Snikos.nikoleris@arm.com
40512793Snikos.nikoleris@arm.com    if (!itte.valid) {
40612793Snikos.nikoleris@arm.com        its.incrementReadPointer();
40712793Snikos.nikoleris@arm.com        terminate(yield);
40812793Snikos.nikoleris@arm.com    }
40912793Snikos.nikoleris@arm.com
41012793Snikos.nikoleris@arm.com    const auto collection_id = itte.icid;
41112792Snikos.nikoleris@arm.com    CTE cte = readIrqCollectionTable(yield, collection_id);
41212792Snikos.nikoleris@arm.com
41312792Snikos.nikoleris@arm.com    if (!cte.valid) {
41412792Snikos.nikoleris@arm.com        its.incrementReadPointer();
41511284Sandreas.hansson@arm.com        terminate(yield);
4164668SN/A    }
41712823Srmk35@cl.cam.ac.uk
4184920SN/A    // Clear the LPI in the redistributor
4192810SN/A    its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
4205314SN/A}
4212810SN/A
4225314SN/Avoid
4235314SN/AItsCommand::discard(Yield &yield, CommandEntry &command)
4245314SN/A{
4259663Suri.wiener@arm.com    if (deviceOutOfRange(command)) {
4269663Suri.wiener@arm.com        its.incrementReadPointer();
4279663Suri.wiener@arm.com        terminate(yield);
4289663Suri.wiener@arm.com    }
4299663Suri.wiener@arm.com
4309663Suri.wiener@arm.com    DTE dte = readDeviceTable(yield, command.deviceId);
4319663Suri.wiener@arm.com
4322810SN/A    if (!dte.valid || idOutOfRange(command, dte)) {
4332810SN/A        its.incrementReadPointer();
43410764Sandreas.hansson@arm.com        terminate(yield);
435    }
436
437    ITTE itte = readIrqTranslationTable(
438        yield, dte.ittAddress, command.eventId);
439
440    if (!itte.valid) {
441        its.incrementReadPointer();
442        terminate(yield);
443    }
444
445    const auto collection_id = itte.icid;
446    Gicv3Its::CTE cte = readIrqCollectionTable(yield, collection_id);
447
448    if (!cte.valid) {
449        its.incrementReadPointer();
450        terminate(yield);
451    }
452
453    its.getRedistributor(cte)->setClrLPI(itte.intNum, false);
454
455    // Then removes the mapping from the ITT (invalidating)
456    itte.valid = 0;
457    writeIrqTranslationTable(
458        yield, dte.ittAddress, command.eventId, itte);
459}
460
461void
462ItsCommand::doInt(Yield &yield, CommandEntry &command)
463{
464    if (deviceOutOfRange(command)) {
465        its.incrementReadPointer();
466        terminate(yield);
467    }
468
469    DTE dte = readDeviceTable(yield, command.deviceId);
470
471    if (!dte.valid || idOutOfRange(command, dte)) {
472        its.incrementReadPointer();
473        terminate(yield);
474    }
475
476    ITTE itte = readIrqTranslationTable(
477        yield, dte.ittAddress, command.eventId);
478
479    if (!itte.valid) {
480        its.incrementReadPointer();
481        terminate(yield);
482    }
483
484    const auto collection_id = itte.icid;
485    CTE cte = readIrqCollectionTable(yield, collection_id);
486
487    if (!cte.valid) {
488        its.incrementReadPointer();
489        terminate(yield);
490    }
491
492    // Set the LPI in the redistributor
493    its.getRedistributor(cte)->setClrLPI(itte.intNum, true);
494}
495
496void
497ItsCommand::inv(Yield &yield, CommandEntry &command)
498{
499    if (deviceOutOfRange(command)) {
500        its.incrementReadPointer();
501        terminate(yield);
502    }
503
504    DTE dte = readDeviceTable(yield, command.deviceId);
505
506    if (!dte.valid || idOutOfRange(command, dte)) {
507        its.incrementReadPointer();
508        terminate(yield);
509    }
510
511    ITTE itte = readIrqTranslationTable(
512        yield, dte.ittAddress, command.eventId);
513
514    if (!itte.valid) {
515        its.incrementReadPointer();
516        terminate(yield);
517    }
518
519    const auto collection_id = itte.icid;
520    CTE cte = readIrqCollectionTable(yield, collection_id);
521
522    if (!cte.valid) {
523        its.incrementReadPointer();
524        terminate(yield);
525    }
526    // Do nothing since caching is currently not supported in
527    // Redistributor
528}
529
530void
531ItsCommand::invall(Yield &yield, CommandEntry &command)
532{
533    if (collectionOutOfRange(command)) {
534        its.incrementReadPointer();
535        terminate(yield);
536    }
537
538    const auto icid = bits(command.raw[2], 15, 0);
539
540    CTE cte = readIrqCollectionTable(yield, icid);
541
542    if (!cte.valid) {
543        its.incrementReadPointer();
544        terminate(yield);
545    }
546    // Do nothing since caching is currently not supported in
547    // Redistributor
548}
549
550void
551ItsCommand::mapc(Yield &yield, CommandEntry &command)
552{
553    if (collectionOutOfRange(command)) {
554        its.incrementReadPointer();
555        terminate(yield);
556    }
557
558    CTE cte = 0;
559    cte.valid = bits(command.raw[2], 63);
560    cte.rdBase = bits(command.raw[2], 50, 16);
561
562    const auto icid = bits(command.raw[2], 15, 0);
563
564    writeIrqCollectionTable(yield, icid, cte);
565}
566
567void
568ItsCommand::mapd(Yield &yield, CommandEntry &command)
569{
570    if (deviceOutOfRange(command) || sizeOutOfRange(command)) {
571        its.incrementReadPointer();
572        terminate(yield);
573    }
574
575    DTE dte = 0;
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);
579
580    writeDeviceTable(yield, command.deviceId, dte);
581}
582
583void
584ItsCommand::mapi(Yield &yield, CommandEntry &command)
585{
586    if (deviceOutOfRange(command)) {
587        its.incrementReadPointer();
588        terminate(yield);
589    }
590
591    if (collectionOutOfRange(command)) {
592        its.incrementReadPointer();
593        terminate(yield);
594    }
595
596    DTE dte = readDeviceTable(yield, command.deviceId);
597
598    if (!dte.valid || idOutOfRange(command, dte) ||
599        its.lpiOutOfRange(command.eventId)) {
600
601        its.incrementReadPointer();
602        terminate(yield);
603    }
604
605    Gicv3Its::ITTE itte = readIrqTranslationTable(
606        yield, dte.ittAddress, command.eventId);
607
608    itte.valid = 1;
609    itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
610    itte.intNum = command.eventId;
611    itte.icid = bits(command.raw[2], 15, 0);
612
613    writeIrqTranslationTable(
614        yield, dte.ittAddress, command.eventId, itte);
615}
616
617void
618ItsCommand::mapti(Yield &yield, CommandEntry &command)
619{
620    if (deviceOutOfRange(command)) {
621        its.incrementReadPointer();
622        terminate(yield);
623    }
624
625    if (collectionOutOfRange(command)) {
626        its.incrementReadPointer();
627        terminate(yield);
628    }
629
630    DTE dte = readDeviceTable(yield, command.deviceId);
631
632    const auto pintid = bits(command.raw[1], 63, 32);
633
634    if (!dte.valid || idOutOfRange(command, dte) ||
635        its.lpiOutOfRange(pintid)) {
636
637        its.incrementReadPointer();
638        terminate(yield);
639    }
640
641    ITTE itte = readIrqTranslationTable(
642        yield, dte.ittAddress, command.eventId);
643
644    itte.valid = 1;
645    itte.intType = Gicv3Its::PHYSICAL_INTERRUPT;
646    itte.intNum = pintid;
647    itte.icid = bits(command.raw[2], 15, 0);
648
649    writeIrqTranslationTable(
650        yield, dte.ittAddress, command.eventId, itte);
651}
652
653void
654ItsCommand::movall(Yield &yield, CommandEntry &command)
655{
656    const uint64_t rd1 = bits(command.raw[2], 50, 16);
657    const uint64_t rd2 = bits(command.raw[3], 50, 16);
658
659    if (rd1 != rd2) {
660        Gicv3Redistributor * redist1 = its.getRedistributor(rd1);
661        Gicv3Redistributor * redist2 = its.getRedistributor(rd2);
662
663        its.moveAllPendingState(redist1, redist2);
664    }
665}
666
667void
668ItsCommand::movi(Yield &yield, CommandEntry &command)
669{
670    if (deviceOutOfRange(command)) {
671        its.incrementReadPointer();
672        terminate(yield);
673    }
674
675    if (collectionOutOfRange(command)) {
676        its.incrementReadPointer();
677        terminate(yield);
678    }
679
680    DTE dte = readDeviceTable(yield, command.deviceId);
681
682    if (!dte.valid || idOutOfRange(command, dte)) {
683        its.incrementReadPointer();
684        terminate(yield);
685    }
686
687    ITTE itte = readIrqTranslationTable(
688        yield, dte.ittAddress, command.eventId);
689
690    if (!itte.valid || itte.intType == Gicv3Its::VIRTUAL_INTERRUPT) {
691        its.incrementReadPointer();
692        terminate(yield);
693    }
694
695    const auto collection_id1 = itte.icid;
696    CTE cte1 = readIrqCollectionTable(yield, collection_id1);
697
698    if (!cte1.valid) {
699        its.incrementReadPointer();
700        terminate(yield);
701    }
702
703    const auto collection_id2 = bits(command.raw[2], 15, 0);
704    CTE cte2 = readIrqCollectionTable(yield, collection_id2);
705
706    if (!cte2.valid) {
707        its.incrementReadPointer();
708        terminate(yield);
709    }
710
711    Gicv3Redistributor *first_redist = its.getRedistributor(cte1);
712    Gicv3Redistributor *second_redist = its.getRedistributor(cte2);
713
714    if (second_redist != first_redist) {
715        // move pending state of the interrupt from one redistributor
716        // to the other.
717        if (first_redist->isPendingLPI(itte.intNum)) {
718            first_redist->setClrLPI(itte.intNum, false);
719            second_redist->setClrLPI(itte.intNum, true);
720        }
721    }
722
723    itte.icid = collection_id2;
724    writeIrqTranslationTable(
725        yield, dte.ittAddress, command.eventId, itte);
726}
727
728void
729ItsCommand::sync(Yield &yield, CommandEntry &command)
730{
731    warn("ITS %s command unimplemented", __func__);
732}
733
734void
735ItsCommand::vinvall(Yield &yield, CommandEntry &command)
736{
737    panic("ITS %s command unimplemented", __func__);
738}
739
740void
741ItsCommand::vmapi(Yield &yield, CommandEntry &command)
742{
743    panic("ITS %s command unimplemented", __func__);
744}
745
746void
747ItsCommand::vmapp(Yield &yield, CommandEntry &command)
748{
749    panic("ITS %s command unimplemented", __func__);
750}
751
752void
753ItsCommand::vmapti(Yield &yield, CommandEntry &command)
754{
755    panic("ITS %s command unimplemented", __func__);
756}
757
758void
759ItsCommand::vmovi(Yield &yield, CommandEntry &command)
760{
761    panic("ITS %s command unimplemented", __func__);
762}
763
764void
765ItsCommand::vmovp(Yield &yield, CommandEntry &command)
766{
767    panic("ITS %s command unimplemented", __func__);
768}
769
770void
771ItsCommand::vsync(Yield &yield, CommandEntry &command)
772{
773    panic("ITS %s command unimplemented", __func__);
774}
775
776Gicv3Its::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)),
785   gic(nullptr),
786   commandEvent([this] { checkCommandQueue(); }, name()),
787   pendingCommands(false),
788   pendingTranslations(0)
789{
790    BASER device_baser = 0;
791    device_baser.type = DEVICE_TABLE;
792    device_baser.entrySize = sizeof(uint64_t) - 1;
793    tableBases[0] = device_baser;
794
795    BASER icollect_baser = 0;
796    icollect_baser.type = COLLECTION_TABLE;
797    icollect_baser.entrySize = sizeof(uint64_t) - 1;
798    tableBases[1] = icollect_baser;
799}
800
801void
802Gicv3Its::setGIC(Gicv3 *_gic)
803{
804    assert(!gic);
805    gic = _gic;
806}
807
808AddrRangeList
809Gicv3Its::getAddrRanges() const
810{
811    assert(pioSize != 0);
812    AddrRangeList ranges;
813    DPRINTF(AddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
814    ranges.push_back(RangeSize(pioAddr, pioSize));
815    return ranges;
816}
817
818Tick
819Gicv3Its::read(PacketPtr pkt)
820{
821    const Addr addr = pkt->getAddr() - pioAddr;
822    uint64_t value = 0;
823
824    DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
825
826    switch (addr) {
827      case GITS_CTLR:
828        value = gitsControl;
829        break;
830
831      case GITS_IIDR:
832        value = gitsIidr;
833        break;
834
835      case GITS_TYPER:
836        value = gitsTyper;
837        break;
838
839      case GITS_TYPER + 4:
840        value = gitsTyper.high;
841        break;
842
843      case GITS_CBASER:
844        value = gitsCbaser;
845        break;
846
847      case GITS_CBASER + 4:
848        value = gitsCbaser.high;
849        break;
850
851      case GITS_CWRITER:
852        value = gitsCwriter;
853        break;
854
855      case GITS_CWRITER + 4:
856        value = gitsCwriter.high;
857        break;
858
859      case GITS_CREADR:
860        value = gitsCreadr;
861        break;
862
863      case GITS_CREADR + 4:
864        value = gitsCreadr.high;
865        break;
866
867      case GITS_PIDR2:
868        value = gic->getDistributor()->gicdPidr2;
869        break;
870
871      case GITS_TRANSLATER:
872        value = gitsTranslater;
873        break;
874
875      default:
876        if (GITS_BASER.contains(addr)) {
877            auto relative_addr = addr - GITS_BASER.start();
878            auto baser_index = relative_addr / sizeof(uint64_t);
879
880            value = tableBases[baser_index];
881            break;
882        } else {
883            panic("Unrecognized register access\n");
884        }
885    }
886
887    pkt->setUintX(value, LittleEndianByteOrder);
888    pkt->makeAtomicResponse();
889    return pioDelay;
890}
891
892Tick
893Gicv3Its::write(PacketPtr pkt)
894{
895    Addr addr = pkt->getAddr() - pioAddr;
896
897    DPRINTF(GIC, "%s register at addr: %#x\n", __func__, addr);
898
899    switch (addr) {
900      case GITS_CTLR:
901        assert(pkt->getSize() == sizeof(uint32_t));
902        gitsControl = (pkt->getLE<uint32_t>() & ~CTLR_QUIESCENT);
903        // We should check here if the ITS has been disabled, and if
904        // that's the case, flush GICv3 caches to external memory.
905        // This is not happening now, since LPI caching is not
906        // currently implemented in gem5.
907        break;
908
909      case GITS_IIDR:
910        panic("GITS_IIDR is Read Only\n");
911
912      case GITS_TYPER:
913        panic("GITS_TYPER is Read Only\n");
914
915      case GITS_CBASER:
916        if (pkt->getSize() == sizeof(uint32_t)) {
917            gitsCbaser.low = pkt->getLE<uint32_t>();
918        } else {
919            assert(pkt->getSize() == sizeof(uint64_t));
920            gitsCbaser = pkt->getLE<uint64_t>();
921        }
922
923        gitsCreadr = 0; // Cleared when CBASER gets written
924
925        checkCommandQueue();
926        break;
927
928      case GITS_CBASER + 4:
929        assert(pkt->getSize() == sizeof(uint32_t));
930        gitsCbaser.high = pkt->getLE<uint32_t>();
931
932        gitsCreadr = 0; // Cleared when CBASER gets written
933
934        checkCommandQueue();
935        break;
936
937      case GITS_CWRITER:
938        if (pkt->getSize() == sizeof(uint32_t)) {
939            gitsCwriter.low = pkt->getLE<uint32_t>();
940        } else {
941            assert(pkt->getSize() == sizeof(uint64_t));
942            gitsCwriter = pkt->getLE<uint64_t>();
943        }
944
945        checkCommandQueue();
946        break;
947
948      case GITS_CWRITER + 4:
949        assert(pkt->getSize() == sizeof(uint32_t));
950        gitsCwriter.high = pkt->getLE<uint32_t>();
951
952        checkCommandQueue();
953        break;
954
955      case GITS_CREADR:
956        panic("GITS_READR is Read Only\n");
957
958      case GITS_TRANSLATER:
959        if (gitsControl.enabled) {
960            translate(pkt);
961        }
962        break;
963
964      default:
965        if (GITS_BASER.contains(addr)) {
966            auto relative_addr = addr - GITS_BASER.start();
967            auto baser_index = relative_addr / sizeof(uint64_t);
968
969            const uint64_t table_base = tableBases[baser_index];
970            const uint64_t w_mask = tableBases[baser_index].type ?
971                BASER_WMASK : BASER_WMASK_UNIMPL;
972            const uint64_t val = pkt->getLE<uint64_t>() & w_mask;
973
974            tableBases[baser_index] = table_base | val;
975            break;
976        } else {
977            panic("Unrecognized register access\n");
978        }
979    }
980
981    pkt->makeAtomicResponse();
982    return pioDelay;
983}
984
985bool
986Gicv3Its::idOutOfRange(uint32_t event_id, uint8_t itt_range) const
987{
988    const uint32_t id_bits = gitsTyper.idBits;
989    return event_id >= (1ULL << (id_bits + 1)) ||
990        event_id >= ((1ULL << itt_range) + 1);
991}
992
993bool
994Gicv3Its::deviceOutOfRange(uint32_t device_id) const
995{
996    return device_id >= (1ULL << (gitsTyper.devBits + 1));
997}
998
999bool
1000Gicv3Its::sizeOutOfRange(uint32_t size) const
1001{
1002    return size > gitsTyper.idBits;
1003}
1004
1005bool
1006Gicv3Its::collectionOutOfRange(uint32_t collection_id) const
1007{
1008    // If GITS_TYPER.CIL == 0, ITS supports 16-bit CollectionID
1009    // Otherwise, #bits is specified by GITS_TYPER.CIDbits
1010    const auto cid_bits = gitsTyper.cil == 0 ?
1011        16 : gitsTyper.cidBits + 1;
1012
1013    return collection_id >= (1ULL << cid_bits);
1014}
1015
1016bool
1017Gicv3Its::lpiOutOfRange(uint32_t intid) const
1018{
1019    return intid >= (1ULL << (Gicv3Distributor::IDBITS + 1)) ||
1020           (intid < Gicv3Redistributor::SMALLEST_LPI_ID &&
1021            intid != Gicv3::INTID_SPURIOUS);
1022}
1023
1024DrainState
1025Gicv3Its::drain()
1026{
1027    if (!pendingCommands && !pendingTranslations) {
1028        return DrainState::Drained;
1029    } else {
1030        DPRINTF(Drain, "GICv3 ITS not drained\n");
1031        return DrainState::Draining;
1032    }
1033}
1034
1035void
1036Gicv3Its::serialize(CheckpointOut & cp) const
1037{
1038    SERIALIZE_SCALAR(gitsControl);
1039    SERIALIZE_SCALAR(gitsTyper);
1040    SERIALIZE_SCALAR(gitsCbaser);
1041    SERIALIZE_SCALAR(gitsCreadr);
1042    SERIALIZE_SCALAR(gitsCwriter);
1043    SERIALIZE_SCALAR(gitsIidr);
1044
1045    SERIALIZE_CONTAINER(tableBases);
1046}
1047
1048void
1049Gicv3Its::unserialize(CheckpointIn & cp)
1050{
1051    UNSERIALIZE_SCALAR(gitsControl);
1052    UNSERIALIZE_SCALAR(gitsTyper);
1053    UNSERIALIZE_SCALAR(gitsCbaser);
1054    UNSERIALIZE_SCALAR(gitsCreadr);
1055    UNSERIALIZE_SCALAR(gitsCwriter);
1056    UNSERIALIZE_SCALAR(gitsIidr);
1057
1058    UNSERIALIZE_CONTAINER(tableBases);
1059}
1060
1061void
1062Gicv3Its::incrementReadPointer()
1063{
1064    // Make the reader point to the next element
1065    gitsCreadr.offset = gitsCreadr.offset + 1;
1066
1067    // Check for wrapping
1068    if (gitsCreadr.offset == maxCommands()) {
1069        gitsCreadr.offset = 0;
1070    }
1071}
1072
1073uint64_t
1074Gicv3Its::maxCommands() const
1075{
1076    return (4096 * (gitsCbaser.size + 1)) / sizeof(ItsCommand::CommandEntry);
1077}
1078
1079void
1080Gicv3Its::checkCommandQueue()
1081{
1082    if (!gitsControl.enabled || !gitsCbaser.valid)
1083        return;
1084
1085    // If GITS_CWRITER gets set by sw to a value bigger than the
1086    // allowed one, the command queue should stop processing commands
1087    // until the register gets reset to an allowed one
1088    if (gitsCwriter.offset >= maxCommands()) {
1089        return;
1090    }
1091
1092    if (gitsCwriter.offset != gitsCreadr.offset) {
1093        // writer and reader pointing to different command
1094        // entries: queue not empty.
1095        DPRINTF(ITS, "Reading command from queue\n");
1096
1097        if (!pendingCommands) {
1098            auto *cmd_proc = new ItsCommand(*this);
1099
1100            runProcess(cmd_proc, nullptr);
1101        } else {
1102            DPRINTF(ITS, "Waiting for pending command to finish\n");
1103        }
1104    }
1105}
1106
1107Port &
1108Gicv3Its::getPort(const std::string &if_name, PortID idx)
1109{
1110    if (if_name == "dma") {
1111        return dmaPort;
1112    }
1113    return BasicPioDevice::getPort(if_name, idx);
1114}
1115
1116void
1117Gicv3Its::recvReqRetry()
1118{
1119    assert(!packetsToRetry.empty());
1120
1121    while (!packetsToRetry.empty()) {
1122        ItsAction a = packetsToRetry.front();
1123
1124        assert(a.type == ItsActionType::SEND_REQ);
1125
1126        if (!dmaPort.sendTimingReq(a.pkt))
1127            break;
1128
1129        packetsToRetry.pop();
1130    }
1131}
1132
1133bool
1134Gicv3Its::recvTimingResp(PacketPtr pkt)
1135{
1136    // @todo: We need to pay for this and not just zero it out
1137    pkt->headerDelay = pkt->payloadDelay = 0;
1138
1139    ItsProcess *proc =
1140        safe_cast<ItsProcess *>(pkt->popSenderState());
1141
1142    runProcessTiming(proc, pkt);
1143
1144    return true;
1145}
1146
1147ItsAction
1148Gicv3Its::runProcess(ItsProcess *proc, PacketPtr pkt)
1149{
1150    if (sys->isAtomicMode()) {
1151        return runProcessAtomic(proc, pkt);
1152    } else if (sys->isTimingMode()) {
1153        return runProcessTiming(proc, pkt);
1154    } else {
1155        panic("Not in timing or atomic mode\n");
1156    }
1157}
1158
1159ItsAction
1160Gicv3Its::runProcessTiming(ItsProcess *proc, PacketPtr pkt)
1161{
1162    ItsAction action = proc->run(pkt);
1163
1164    switch (action.type) {
1165      case ItsActionType::SEND_REQ:
1166        action.pkt->pushSenderState(proc);
1167
1168        if (packetsToRetry.empty() &&
1169            dmaPort.sendTimingReq(action.pkt)) {
1170
1171        } else {
1172            packetsToRetry.push(action);
1173        }
1174        break;
1175
1176      case ItsActionType::TERMINATE:
1177        delete proc;
1178        if (!pendingCommands && !commandEvent.scheduled()) {
1179            schedule(commandEvent, clockEdge());
1180        }
1181        break;
1182
1183      default:
1184        panic("Unknown action\n");
1185    }
1186
1187    return action;
1188}
1189
1190ItsAction
1191Gicv3Its::runProcessAtomic(ItsProcess *proc, PacketPtr pkt)
1192{
1193    ItsAction action;
1194    Tick delay = 0;
1195    bool terminate = false;
1196
1197    do {
1198        action = proc->run(pkt);
1199
1200        switch (action.type) {
1201          case ItsActionType::SEND_REQ:
1202            delay += dmaPort.sendAtomic(action.pkt);
1203            pkt = action.pkt;
1204            break;
1205
1206          case ItsActionType::TERMINATE:
1207            delete proc;
1208            terminate = true;
1209            break;
1210
1211          default:
1212            panic("Unknown action\n");
1213        }
1214
1215    } while (!terminate);
1216
1217    action.delay = delay;
1218
1219    return action;
1220}
1221
1222void
1223Gicv3Its::translate(PacketPtr pkt)
1224{
1225    DPRINTF(ITS, "Starting Translation Request\n");
1226
1227    auto *proc = new ItsTranslation(*this);
1228    runProcess(proc, pkt);
1229}
1230
1231Gicv3Redistributor*
1232Gicv3Its::getRedistributor(uint64_t rd_base)
1233{
1234    if (gitsTyper.pta == 1) {
1235        // RDBase is a redistributor address
1236        return gic->getRedistributorByAddr(rd_base << 16);
1237    } else {
1238        // RDBase is a redistributor number
1239        return gic->getRedistributor(rd_base);
1240    }
1241}
1242
1243Addr
1244Gicv3Its::pageAddress(Gicv3Its::ItsTables table)
1245{
1246    auto base_it = std::find_if(
1247        tableBases.begin(), tableBases.end(),
1248        [table] (const BASER &b) { return b.type == table; }
1249    );
1250
1251    panic_if(base_it == tableBases.end(),
1252        "ITS Table not recognised\n");
1253
1254    const BASER base = *base_it;
1255
1256    // real address depends on page size
1257    switch (base.pageSize) {
1258      case SIZE_4K:
1259      case SIZE_16K:
1260        return mbits(base, 47, 12);
1261      case SIZE_64K:
1262        return mbits(base, 47, 16) | (bits(base, 15, 12) << 48);
1263      default:
1264        panic("Unsupported page size\n");
1265    }
1266}
1267
1268void
1269Gicv3Its::moveAllPendingState(
1270    Gicv3Redistributor *rd1, Gicv3Redistributor *rd2)
1271{
1272    const uint64_t largest_lpi_id = 1ULL << (rd1->lpiIDBits + 1);
1273    uint8_t lpi_pending_table[largest_lpi_id / 8];
1274
1275    // Copying the pending table from redistributor 1 to redistributor 2
1276    rd1->memProxy->readBlob(
1277        rd1->lpiPendingTablePtr, (uint8_t *)lpi_pending_table,
1278        sizeof(lpi_pending_table));
1279
1280    rd2->memProxy->writeBlob(
1281        rd2->lpiPendingTablePtr, (uint8_t *)lpi_pending_table,
1282        sizeof(lpi_pending_table));
1283
1284    // Clearing pending table in redistributor 2
1285    rd1->memProxy->memsetBlob(
1286        rd1->lpiPendingTablePtr,
1287        0, sizeof(lpi_pending_table));
1288
1289    rd2->updateDistributor();
1290}
1291
1292Gicv3Its *
1293Gicv3ItsParams::create()
1294{
1295    return new Gicv3Its(this);
1296}
1297