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