114039Sstacze01@arm.com/* 214039Sstacze01@arm.com * Copyright (c) 2013, 2018-2019 ARM Limited 314039Sstacze01@arm.com * All rights reserved 414039Sstacze01@arm.com * 514039Sstacze01@arm.com * The license below extends only to copyright in the software and shall 614039Sstacze01@arm.com * not be construed as granting a license to any other intellectual 714039Sstacze01@arm.com * property including but not limited to intellectual property relating 814039Sstacze01@arm.com * to a hardware implementation of the functionality of the software 914039Sstacze01@arm.com * licensed hereunder. You may use the software subject to the license 1014039Sstacze01@arm.com * terms below provided that you ensure that this notice is replicated 1114039Sstacze01@arm.com * unmodified and in its entirety in all distributions of the software, 1214039Sstacze01@arm.com * modified or unmodified, in source code or in binary form. 1314039Sstacze01@arm.com * 1414039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without 1514039Sstacze01@arm.com * modification, are permitted provided that the following conditions are 1614039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright 1714039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer; 1814039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright 1914039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the 2014039Sstacze01@arm.com * documentation and/or other materials provided with the distribution; 2114039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its 2214039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from 2314039Sstacze01@arm.com * this software without specific prior written permission. 2414039Sstacze01@arm.com * 2514039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2614039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2714039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2814039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2914039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3014039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3114039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3214039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3314039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3414039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3514039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3614039Sstacze01@arm.com * 3714039Sstacze01@arm.com * Authors: Stan Czerniawski 3814039Sstacze01@arm.com */ 3914039Sstacze01@arm.com 4014039Sstacze01@arm.com#include "dev/arm/smmu_v3.hh" 4114039Sstacze01@arm.com 4214039Sstacze01@arm.com#include <cstddef> 4314039Sstacze01@arm.com#include <cstring> 4414039Sstacze01@arm.com 4514039Sstacze01@arm.com#include "base/bitfield.hh" 4614039Sstacze01@arm.com#include "base/cast.hh" 4714039Sstacze01@arm.com#include "base/logging.hh" 4814039Sstacze01@arm.com#include "base/trace.hh" 4914039Sstacze01@arm.com#include "base/types.hh" 5014039Sstacze01@arm.com#include "debug/Checkpoint.hh" 5114039Sstacze01@arm.com#include "debug/SMMUv3.hh" 5214039Sstacze01@arm.com#include "dev/arm/smmu_v3_transl.hh" 5314039Sstacze01@arm.com#include "mem/packet_access.hh" 5414039Sstacze01@arm.com#include "sim/system.hh" 5514039Sstacze01@arm.com 5614039Sstacze01@arm.comSMMUv3::SMMUv3(SMMUv3Params *params) : 5714252Sgabeblack@google.com ClockedObject(params), 5814039Sstacze01@arm.com system(*params->system), 5914039Sstacze01@arm.com masterId(params->system->getMasterId(this)), 6014039Sstacze01@arm.com masterPort(name() + ".master", *this), 6114039Sstacze01@arm.com masterTableWalkPort(name() + ".master_walker", *this), 6214039Sstacze01@arm.com controlPort(name() + ".control", *this, params->reg_map), 6314039Sstacze01@arm.com tlb(params->tlb_entries, params->tlb_assoc, params->tlb_policy), 6414039Sstacze01@arm.com configCache(params->cfg_entries, params->cfg_assoc, params->cfg_policy), 6514039Sstacze01@arm.com ipaCache(params->ipa_entries, params->ipa_assoc, params->ipa_policy), 6614039Sstacze01@arm.com walkCache({ { params->walk_S1L0, params->walk_S1L1, 6714039Sstacze01@arm.com params->walk_S1L2, params->walk_S1L3, 6814039Sstacze01@arm.com params->walk_S2L0, params->walk_S2L1, 6914039Sstacze01@arm.com params->walk_S2L2, params->walk_S2L3 } }, 7014039Sstacze01@arm.com params->walk_assoc, params->walk_policy), 7114039Sstacze01@arm.com tlbEnable(params->tlb_enable), 7214039Sstacze01@arm.com configCacheEnable(params->cfg_enable), 7314039Sstacze01@arm.com ipaCacheEnable(params->ipa_enable), 7414039Sstacze01@arm.com walkCacheEnable(params->walk_enable), 7514039Sstacze01@arm.com tableWalkPortEnable(false), 7614039Sstacze01@arm.com walkCacheNonfinalEnable(params->wc_nonfinal_enable), 7714039Sstacze01@arm.com walkCacheS1Levels(params->wc_s1_levels), 7814039Sstacze01@arm.com walkCacheS2Levels(params->wc_s2_levels), 7914039Sstacze01@arm.com masterPortWidth(params->master_port_width), 8014039Sstacze01@arm.com tlbSem(params->tlb_slots), 8114039Sstacze01@arm.com ifcSmmuSem(1), 8214039Sstacze01@arm.com smmuIfcSem(1), 8314039Sstacze01@arm.com configSem(params->cfg_slots), 8414039Sstacze01@arm.com ipaSem(params->ipa_slots), 8514039Sstacze01@arm.com walkSem(params->walk_slots), 8614039Sstacze01@arm.com masterPortSem(1), 8714039Sstacze01@arm.com transSem(params->xlate_slots), 8814039Sstacze01@arm.com ptwSem(params->ptw_slots), 8914039Sstacze01@arm.com cycleSem(1), 9014039Sstacze01@arm.com tlbLat(params->tlb_lat), 9114039Sstacze01@arm.com ifcSmmuLat(params->ifc_smmu_lat), 9214039Sstacze01@arm.com smmuIfcLat(params->smmu_ifc_lat), 9314039Sstacze01@arm.com configLat(params->cfg_lat), 9414039Sstacze01@arm.com ipaLat(params->ipa_lat), 9514039Sstacze01@arm.com walkLat(params->walk_lat), 9614039Sstacze01@arm.com slaveInterfaces(params->slave_interfaces), 9714039Sstacze01@arm.com commandExecutor(name() + ".cmd_exec", *this), 9814039Sstacze01@arm.com regsMap(params->reg_map), 9914039Sstacze01@arm.com processCommandsEvent(this) 10014039Sstacze01@arm.com{ 10114039Sstacze01@arm.com fatal_if(regsMap.size() != SMMU_REG_SIZE, 10214039Sstacze01@arm.com "Invalid register map size: %#x different than SMMU_REG_SIZE = %#x\n", 10314039Sstacze01@arm.com regsMap.size(), SMMU_REG_SIZE); 10414039Sstacze01@arm.com 10514039Sstacze01@arm.com // Init smmu registers to 0 10614039Sstacze01@arm.com memset(®s, 0, sizeof(regs)); 10714039Sstacze01@arm.com 10814039Sstacze01@arm.com // Setup RO ID registers 10914039Sstacze01@arm.com regs.idr0 = params->smmu_idr0; 11014039Sstacze01@arm.com regs.idr1 = params->smmu_idr1; 11114039Sstacze01@arm.com regs.idr2 = params->smmu_idr2; 11214039Sstacze01@arm.com regs.idr3 = params->smmu_idr3; 11314039Sstacze01@arm.com regs.idr4 = params->smmu_idr4; 11414039Sstacze01@arm.com regs.idr5 = params->smmu_idr5; 11514039Sstacze01@arm.com regs.iidr = params->smmu_iidr; 11614039Sstacze01@arm.com regs.aidr = params->smmu_aidr; 11714039Sstacze01@arm.com 11814039Sstacze01@arm.com // TODO: At the moment it possible to set the ID registers to hold 11914039Sstacze01@arm.com // any possible value. It would be nice to have a sanity check here 12014039Sstacze01@arm.com // at construction time in case some idx registers are programmed to 12114039Sstacze01@arm.com // store an unallowed values or if the are configuration conflicts. 12214039Sstacze01@arm.com warn("SMMUv3 IDx register values unchecked\n"); 12314039Sstacze01@arm.com 12414039Sstacze01@arm.com for (auto ifc : slaveInterfaces) 12514039Sstacze01@arm.com ifc->setSMMU(this); 12614039Sstacze01@arm.com} 12714039Sstacze01@arm.com 12814039Sstacze01@arm.combool 12914039Sstacze01@arm.comSMMUv3::masterRecvTimingResp(PacketPtr pkt) 13014039Sstacze01@arm.com{ 13114039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master resp addr=%#x size=%#x\n", 13214039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 13314039Sstacze01@arm.com 13414039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 13514039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 13614039Sstacze01@arm.com 13714039Sstacze01@arm.com SMMUProcess *proc = 13814039Sstacze01@arm.com safe_cast<SMMUProcess *>(pkt->popSenderState()); 13914039Sstacze01@arm.com 14014039Sstacze01@arm.com runProcessTiming(proc, pkt); 14114039Sstacze01@arm.com 14214039Sstacze01@arm.com return true; 14314039Sstacze01@arm.com} 14414039Sstacze01@arm.com 14514039Sstacze01@arm.comvoid 14614039Sstacze01@arm.comSMMUv3::masterRecvReqRetry() 14714039Sstacze01@arm.com{ 14814039Sstacze01@arm.com assert(!packetsToRetry.empty()); 14914039Sstacze01@arm.com 15014039Sstacze01@arm.com while (!packetsToRetry.empty()) { 15114039Sstacze01@arm.com SMMUAction a = packetsToRetry.front(); 15214039Sstacze01@arm.com 15314039Sstacze01@arm.com assert(a.type==ACTION_SEND_REQ || a.type==ACTION_SEND_REQ_FINAL); 15414039Sstacze01@arm.com 15514039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master retr addr=%#x size=%#x\n", 15614039Sstacze01@arm.com a.pkt->getAddr(), a.pkt->getSize()); 15714039Sstacze01@arm.com 15814039Sstacze01@arm.com if (!masterPort.sendTimingReq(a.pkt)) 15914039Sstacze01@arm.com break; 16014039Sstacze01@arm.com 16114039Sstacze01@arm.com packetsToRetry.pop(); 16214039Sstacze01@arm.com 16314039Sstacze01@arm.com /* 16414039Sstacze01@arm.com * ACTION_SEND_REQ_FINAL means that we have just forwarded the packet 16514039Sstacze01@arm.com * on the master interface; this means that we no longer hold on to 16614039Sstacze01@arm.com * that transaction and therefore can accept a new one. 16714039Sstacze01@arm.com * If the slave port was stalled then unstall it (send retry). 16814039Sstacze01@arm.com */ 16914039Sstacze01@arm.com if (a.type == ACTION_SEND_REQ_FINAL) 17014039Sstacze01@arm.com scheduleSlaveRetries(); 17114039Sstacze01@arm.com } 17214039Sstacze01@arm.com} 17314039Sstacze01@arm.com 17414039Sstacze01@arm.combool 17514039Sstacze01@arm.comSMMUv3::masterTableWalkRecvTimingResp(PacketPtr pkt) 17614039Sstacze01@arm.com{ 17714039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master HWTW resp addr=%#x size=%#x\n", 17814039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 17914039Sstacze01@arm.com 18014039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 18114039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 18214039Sstacze01@arm.com 18314039Sstacze01@arm.com SMMUProcess *proc = 18414039Sstacze01@arm.com safe_cast<SMMUProcess *>(pkt->popSenderState()); 18514039Sstacze01@arm.com 18614039Sstacze01@arm.com runProcessTiming(proc, pkt); 18714039Sstacze01@arm.com 18814039Sstacze01@arm.com return true; 18914039Sstacze01@arm.com} 19014039Sstacze01@arm.com 19114039Sstacze01@arm.comvoid 19214039Sstacze01@arm.comSMMUv3::masterTableWalkRecvReqRetry() 19314039Sstacze01@arm.com{ 19414039Sstacze01@arm.com assert(tableWalkPortEnable); 19514039Sstacze01@arm.com assert(!packetsTableWalkToRetry.empty()); 19614039Sstacze01@arm.com 19714039Sstacze01@arm.com while (!packetsTableWalkToRetry.empty()) { 19814039Sstacze01@arm.com SMMUAction a = packetsTableWalkToRetry.front(); 19914039Sstacze01@arm.com 20014039Sstacze01@arm.com assert(a.type==ACTION_SEND_REQ); 20114039Sstacze01@arm.com 20214039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master HWTW retr addr=%#x size=%#x\n", 20314039Sstacze01@arm.com a.pkt->getAddr(), a.pkt->getSize()); 20414039Sstacze01@arm.com 20514039Sstacze01@arm.com if (!masterTableWalkPort.sendTimingReq(a.pkt)) 20614039Sstacze01@arm.com break; 20714039Sstacze01@arm.com 20814039Sstacze01@arm.com packetsTableWalkToRetry.pop(); 20914039Sstacze01@arm.com } 21014039Sstacze01@arm.com} 21114039Sstacze01@arm.com 21214039Sstacze01@arm.comvoid 21314039Sstacze01@arm.comSMMUv3::scheduleSlaveRetries() 21414039Sstacze01@arm.com{ 21514039Sstacze01@arm.com for (auto ifc : slaveInterfaces) { 21614039Sstacze01@arm.com ifc->scheduleDeviceRetry(); 21714039Sstacze01@arm.com } 21814039Sstacze01@arm.com} 21914039Sstacze01@arm.com 22014039Sstacze01@arm.comSMMUAction 22114039Sstacze01@arm.comSMMUv3::runProcess(SMMUProcess *proc, PacketPtr pkt) 22214039Sstacze01@arm.com{ 22314039Sstacze01@arm.com if (system.isAtomicMode()) { 22414039Sstacze01@arm.com return runProcessAtomic(proc, pkt); 22514039Sstacze01@arm.com } else if (system.isTimingMode()) { 22614039Sstacze01@arm.com return runProcessTiming(proc, pkt); 22714039Sstacze01@arm.com } else { 22814039Sstacze01@arm.com panic("Not in timing or atomic mode!"); 22914039Sstacze01@arm.com } 23014039Sstacze01@arm.com} 23114039Sstacze01@arm.com 23214039Sstacze01@arm.comSMMUAction 23314039Sstacze01@arm.comSMMUv3::runProcessAtomic(SMMUProcess *proc, PacketPtr pkt) 23414039Sstacze01@arm.com{ 23514039Sstacze01@arm.com SMMUAction action; 23614039Sstacze01@arm.com Tick delay = 0; 23714039Sstacze01@arm.com bool finished = false; 23814039Sstacze01@arm.com 23914039Sstacze01@arm.com do { 24014039Sstacze01@arm.com action = proc->run(pkt); 24114039Sstacze01@arm.com 24214039Sstacze01@arm.com switch (action.type) { 24314039Sstacze01@arm.com case ACTION_SEND_REQ: 24414039Sstacze01@arm.com // Send an MMU initiated request on the table walk port if it is 24514039Sstacze01@arm.com // enabled. Otherwise, fall through and handle same as the final 24614039Sstacze01@arm.com // ACTION_SEND_REQ_FINAL request. 24714039Sstacze01@arm.com if (tableWalkPortEnable) { 24814039Sstacze01@arm.com delay += masterTableWalkPort.sendAtomic(action.pkt); 24914039Sstacze01@arm.com pkt = action.pkt; 25014039Sstacze01@arm.com break; 25114039Sstacze01@arm.com } 25214039Sstacze01@arm.com M5_FALLTHROUGH; 25314039Sstacze01@arm.com case ACTION_SEND_REQ_FINAL: 25414039Sstacze01@arm.com delay += masterPort.sendAtomic(action.pkt); 25514039Sstacze01@arm.com pkt = action.pkt; 25614039Sstacze01@arm.com break; 25714039Sstacze01@arm.com 25814039Sstacze01@arm.com case ACTION_SEND_RESP: 25914039Sstacze01@arm.com case ACTION_SEND_RESP_ATS: 26014039Sstacze01@arm.com case ACTION_SLEEP: 26114039Sstacze01@arm.com finished = true; 26214039Sstacze01@arm.com break; 26314039Sstacze01@arm.com 26414039Sstacze01@arm.com case ACTION_DELAY: 26514039Sstacze01@arm.com delay += action.delay; 26614039Sstacze01@arm.com break; 26714039Sstacze01@arm.com 26814039Sstacze01@arm.com case ACTION_TERMINATE: 26914039Sstacze01@arm.com panic("ACTION_TERMINATE in atomic mode\n"); 27014039Sstacze01@arm.com 27114039Sstacze01@arm.com default: 27214039Sstacze01@arm.com panic("Unknown action\n"); 27314039Sstacze01@arm.com } 27414039Sstacze01@arm.com } while (!finished); 27514039Sstacze01@arm.com 27614039Sstacze01@arm.com action.delay = delay; 27714039Sstacze01@arm.com 27814039Sstacze01@arm.com return action; 27914039Sstacze01@arm.com} 28014039Sstacze01@arm.com 28114039Sstacze01@arm.comSMMUAction 28214039Sstacze01@arm.comSMMUv3::runProcessTiming(SMMUProcess *proc, PacketPtr pkt) 28314039Sstacze01@arm.com{ 28414039Sstacze01@arm.com SMMUAction action = proc->run(pkt); 28514039Sstacze01@arm.com 28614039Sstacze01@arm.com switch (action.type) { 28714039Sstacze01@arm.com case ACTION_SEND_REQ: 28814039Sstacze01@arm.com // Send an MMU initiated request on the table walk port if it is 28914039Sstacze01@arm.com // enabled. Otherwise, fall through and handle same as the final 29014039Sstacze01@arm.com // ACTION_SEND_REQ_FINAL request. 29114039Sstacze01@arm.com if (tableWalkPortEnable) { 29214039Sstacze01@arm.com action.pkt->pushSenderState(proc); 29314039Sstacze01@arm.com 29414039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master HWTW req addr=%#x size=%#x\n", 29514039Sstacze01@arm.com action.pkt->getAddr(), action.pkt->getSize()); 29614039Sstacze01@arm.com 29714039Sstacze01@arm.com if (packetsTableWalkToRetry.empty() 29814039Sstacze01@arm.com && masterTableWalkPort.sendTimingReq(action.pkt)) { 29914039Sstacze01@arm.com scheduleSlaveRetries(); 30014039Sstacze01@arm.com } else { 30114039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master HWTW req needs retry," 30214039Sstacze01@arm.com " qlen=%d\n", packetsTableWalkToRetry.size()); 30314039Sstacze01@arm.com packetsTableWalkToRetry.push(action); 30414039Sstacze01@arm.com } 30514039Sstacze01@arm.com 30614039Sstacze01@arm.com break; 30714039Sstacze01@arm.com } 30814039Sstacze01@arm.com M5_FALLTHROUGH; 30914039Sstacze01@arm.com case ACTION_SEND_REQ_FINAL: 31014039Sstacze01@arm.com action.pkt->pushSenderState(proc); 31114039Sstacze01@arm.com 31214039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master req addr=%#x size=%#x\n", 31314039Sstacze01@arm.com action.pkt->getAddr(), action.pkt->getSize()); 31414039Sstacze01@arm.com 31514039Sstacze01@arm.com if (packetsToRetry.empty() && masterPort.sendTimingReq(action.pkt)) { 31614039Sstacze01@arm.com scheduleSlaveRetries(); 31714039Sstacze01@arm.com } else { 31814039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] master req needs retry, qlen=%d\n", 31914039Sstacze01@arm.com packetsToRetry.size()); 32014039Sstacze01@arm.com packetsToRetry.push(action); 32114039Sstacze01@arm.com } 32214039Sstacze01@arm.com 32314039Sstacze01@arm.com break; 32414039Sstacze01@arm.com 32514039Sstacze01@arm.com case ACTION_SEND_RESP: 32614039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 32714039Sstacze01@arm.com action.pkt->headerDelay = action.pkt->payloadDelay = 0; 32814039Sstacze01@arm.com 32914039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] slave resp addr=%#x size=%#x\n", 33014039Sstacze01@arm.com action.pkt->getAddr(), 33114039Sstacze01@arm.com action.pkt->getSize()); 33214039Sstacze01@arm.com 33314039Sstacze01@arm.com assert(action.ifc); 33414039Sstacze01@arm.com action.ifc->schedTimingResp(action.pkt); 33514039Sstacze01@arm.com 33614039Sstacze01@arm.com delete proc; 33714039Sstacze01@arm.com break; 33814039Sstacze01@arm.com 33914039Sstacze01@arm.com case ACTION_SEND_RESP_ATS: 34014039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 34114039Sstacze01@arm.com action.pkt->headerDelay = action.pkt->payloadDelay = 0; 34214039Sstacze01@arm.com 34314039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] ATS slave resp addr=%#x size=%#x\n", 34414039Sstacze01@arm.com action.pkt->getAddr(), action.pkt->getSize()); 34514039Sstacze01@arm.com 34614039Sstacze01@arm.com assert(action.ifc); 34714039Sstacze01@arm.com action.ifc->schedAtsTimingResp(action.pkt); 34814039Sstacze01@arm.com 34914039Sstacze01@arm.com delete proc; 35014039Sstacze01@arm.com break; 35114039Sstacze01@arm.com 35214039Sstacze01@arm.com case ACTION_DELAY: 35314039Sstacze01@arm.com case ACTION_SLEEP: 35414039Sstacze01@arm.com break; 35514039Sstacze01@arm.com 35614039Sstacze01@arm.com case ACTION_TERMINATE: 35714039Sstacze01@arm.com delete proc; 35814039Sstacze01@arm.com break; 35914039Sstacze01@arm.com 36014039Sstacze01@arm.com default: 36114039Sstacze01@arm.com panic("Unknown action\n"); 36214039Sstacze01@arm.com } 36314039Sstacze01@arm.com 36414039Sstacze01@arm.com return action; 36514039Sstacze01@arm.com} 36614039Sstacze01@arm.com 36714039Sstacze01@arm.comvoid 36814039Sstacze01@arm.comSMMUv3::processCommands() 36914039Sstacze01@arm.com{ 37014039Sstacze01@arm.com DPRINTF(SMMUv3, "processCommands()\n"); 37114039Sstacze01@arm.com 37214039Sstacze01@arm.com if (system.isAtomicMode()) { 37314039Sstacze01@arm.com SMMUAction a = runProcessAtomic(&commandExecutor, NULL); 37414039Sstacze01@arm.com (void) a; 37514039Sstacze01@arm.com } else if (system.isTimingMode()) { 37614039Sstacze01@arm.com if (!commandExecutor.isBusy()) 37714039Sstacze01@arm.com runProcessTiming(&commandExecutor, NULL); 37814039Sstacze01@arm.com } else { 37914039Sstacze01@arm.com panic("Not in timing or atomic mode!"); 38014039Sstacze01@arm.com } 38114039Sstacze01@arm.com} 38214039Sstacze01@arm.com 38314039Sstacze01@arm.comvoid 38414039Sstacze01@arm.comSMMUv3::processCommand(const SMMUCommand &cmd) 38514039Sstacze01@arm.com{ 38614116Sgiacomo.travaglini@arm.com switch (cmd.dw0.type) { 38714039Sstacze01@arm.com case CMD_PRF_CONFIG: 38814039Sstacze01@arm.com DPRINTF(SMMUv3, "CMD_PREFETCH_CONFIG - ignored\n"); 38914039Sstacze01@arm.com break; 39014039Sstacze01@arm.com 39114039Sstacze01@arm.com case CMD_PRF_ADDR: 39214039Sstacze01@arm.com DPRINTF(SMMUv3, "CMD_PREFETCH_ADDR - ignored\n"); 39314039Sstacze01@arm.com break; 39414039Sstacze01@arm.com 39514116Sgiacomo.travaglini@arm.com case CMD_CFGI_STE: { 39614116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_CFGI_STE sid=%#x\n", cmd.dw0.sid); 39714116Sgiacomo.travaglini@arm.com configCache.invalidateSID(cmd.dw0.sid); 39814132Sgiacomo.travaglini@arm.com 39914132Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 40014132Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateSID(cmd.dw0.sid); 40114132Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateSID(cmd.dw0.sid); 40214132Sgiacomo.travaglini@arm.com } 40314039Sstacze01@arm.com break; 40414116Sgiacomo.travaglini@arm.com } 40514039Sstacze01@arm.com 40614116Sgiacomo.travaglini@arm.com case CMD_CFGI_STE_RANGE: { 40714116Sgiacomo.travaglini@arm.com const auto range = cmd.dw1.range; 40814116Sgiacomo.travaglini@arm.com if (range == 31) { 40914116Sgiacomo.travaglini@arm.com // CMD_CFGI_ALL is an alias of CMD_CFGI_STE_RANGE with 41014116Sgiacomo.travaglini@arm.com // range = 31 41114116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_CFGI_ALL\n"); 41214116Sgiacomo.travaglini@arm.com configCache.invalidateAll(); 41314132Sgiacomo.travaglini@arm.com 41414132Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 41514132Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateAll(); 41614132Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateAll(); 41714132Sgiacomo.travaglini@arm.com } 41814116Sgiacomo.travaglini@arm.com } else { 41914116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_CFGI_STE_RANGE\n"); 42014116Sgiacomo.travaglini@arm.com const auto start_sid = cmd.dw0.sid & ~((1 << (range + 1)) - 1); 42114116Sgiacomo.travaglini@arm.com const auto end_sid = start_sid + (1 << (range + 1)) - 1; 42214132Sgiacomo.travaglini@arm.com for (auto sid = start_sid; sid <= end_sid; sid++) { 42314116Sgiacomo.travaglini@arm.com configCache.invalidateSID(sid); 42414132Sgiacomo.travaglini@arm.com 42514132Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 42614132Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateSID(sid); 42714132Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateSID(sid); 42814132Sgiacomo.travaglini@arm.com } 42914132Sgiacomo.travaglini@arm.com } 43014116Sgiacomo.travaglini@arm.com } 43114039Sstacze01@arm.com break; 43214116Sgiacomo.travaglini@arm.com } 43314039Sstacze01@arm.com 43414116Sgiacomo.travaglini@arm.com case CMD_CFGI_CD: { 43514116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_CFGI_CD sid=%#x ssid=%#x\n", 43614116Sgiacomo.travaglini@arm.com cmd.dw0.sid, cmd.dw0.ssid); 43714116Sgiacomo.travaglini@arm.com configCache.invalidateSSID(cmd.dw0.sid, cmd.dw0.ssid); 43814132Sgiacomo.travaglini@arm.com 43914132Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 44014132Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateSSID( 44114132Sgiacomo.travaglini@arm.com cmd.dw0.sid, cmd.dw0.ssid); 44214132Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateSSID( 44314132Sgiacomo.travaglini@arm.com cmd.dw0.sid, cmd.dw0.ssid); 44414132Sgiacomo.travaglini@arm.com } 44514039Sstacze01@arm.com break; 44614116Sgiacomo.travaglini@arm.com } 44714039Sstacze01@arm.com 44814116Sgiacomo.travaglini@arm.com case CMD_CFGI_CD_ALL: { 44914116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_CFGI_CD_ALL sid=%#x\n", cmd.dw0.sid); 45014116Sgiacomo.travaglini@arm.com configCache.invalidateSID(cmd.dw0.sid); 45114132Sgiacomo.travaglini@arm.com 45214132Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 45314132Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateSID(cmd.dw0.sid); 45414132Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateSID(cmd.dw0.sid); 45514132Sgiacomo.travaglini@arm.com } 45614039Sstacze01@arm.com break; 45714116Sgiacomo.travaglini@arm.com } 45814039Sstacze01@arm.com 45914116Sgiacomo.travaglini@arm.com case CMD_TLBI_NH_ALL: { 46014116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_NH_ALL vmid=%#x\n", cmd.dw0.vmid); 46114116Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 46214116Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateVMID(cmd.dw0.vmid); 46314116Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateVMID(cmd.dw0.vmid); 46414116Sgiacomo.travaglini@arm.com } 46514116Sgiacomo.travaglini@arm.com tlb.invalidateVMID(cmd.dw0.vmid); 46614116Sgiacomo.travaglini@arm.com walkCache.invalidateVMID(cmd.dw0.vmid); 46714116Sgiacomo.travaglini@arm.com break; 46814116Sgiacomo.travaglini@arm.com } 46914116Sgiacomo.travaglini@arm.com 47014116Sgiacomo.travaglini@arm.com case CMD_TLBI_NH_ASID: { 47114116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_NH_ASID asid=%#x vmid=%#x\n", 47214116Sgiacomo.travaglini@arm.com cmd.dw0.asid, cmd.dw0.vmid); 47314116Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 47414116Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateASID( 47514116Sgiacomo.travaglini@arm.com cmd.dw0.asid, cmd.dw0.vmid); 47614116Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateASID( 47714116Sgiacomo.travaglini@arm.com cmd.dw0.asid, cmd.dw0.vmid); 47814116Sgiacomo.travaglini@arm.com } 47914116Sgiacomo.travaglini@arm.com tlb.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid); 48014116Sgiacomo.travaglini@arm.com walkCache.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid); 48114116Sgiacomo.travaglini@arm.com break; 48214116Sgiacomo.travaglini@arm.com } 48314116Sgiacomo.travaglini@arm.com 48414116Sgiacomo.travaglini@arm.com case CMD_TLBI_NH_VAA: { 48514116Sgiacomo.travaglini@arm.com const Addr addr = cmd.addr(); 48614116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_NH_VAA va=%#08x vmid=%#x\n", 48714116Sgiacomo.travaglini@arm.com addr, cmd.dw0.vmid); 48814116Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 48914116Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateVAA( 49014116Sgiacomo.travaglini@arm.com addr, cmd.dw0.vmid); 49114116Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateVAA( 49214116Sgiacomo.travaglini@arm.com addr, cmd.dw0.vmid); 49314116Sgiacomo.travaglini@arm.com } 49414116Sgiacomo.travaglini@arm.com tlb.invalidateVAA(addr, cmd.dw0.vmid); 49514221Sadrian.herrera@arm.com const bool leaf_only = cmd.dw1.leaf ? true : false; 49614221Sadrian.herrera@arm.com walkCache.invalidateVAA(addr, cmd.dw0.vmid, leaf_only); 49714116Sgiacomo.travaglini@arm.com break; 49814116Sgiacomo.travaglini@arm.com } 49914116Sgiacomo.travaglini@arm.com 50014116Sgiacomo.travaglini@arm.com case CMD_TLBI_NH_VA: { 50114116Sgiacomo.travaglini@arm.com const Addr addr = cmd.addr(); 50214116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_NH_VA va=%#08x asid=%#x vmid=%#x\n", 50314116Sgiacomo.travaglini@arm.com addr, cmd.dw0.asid, cmd.dw0.vmid); 50414116Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 50514116Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateVA( 50614116Sgiacomo.travaglini@arm.com addr, cmd.dw0.asid, cmd.dw0.vmid); 50714116Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateVA( 50814116Sgiacomo.travaglini@arm.com addr, cmd.dw0.asid, cmd.dw0.vmid); 50914116Sgiacomo.travaglini@arm.com } 51014116Sgiacomo.travaglini@arm.com tlb.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid); 51114221Sadrian.herrera@arm.com const bool leaf_only = cmd.dw1.leaf ? true : false; 51214221Sadrian.herrera@arm.com walkCache.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid, 51314221Sadrian.herrera@arm.com leaf_only); 51414116Sgiacomo.travaglini@arm.com break; 51514116Sgiacomo.travaglini@arm.com } 51614116Sgiacomo.travaglini@arm.com 51714116Sgiacomo.travaglini@arm.com case CMD_TLBI_S2_IPA: { 51814116Sgiacomo.travaglini@arm.com const Addr addr = cmd.addr(); 51914116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_S2_IPA ipa=%#08x vmid=%#x\n", 52014116Sgiacomo.travaglini@arm.com addr, cmd.dw0.vmid); 52114116Sgiacomo.travaglini@arm.com // This does not invalidate TLBs containing 52214116Sgiacomo.travaglini@arm.com // combined Stage1 + Stage2 translations, as per the spec. 52314116Sgiacomo.travaglini@arm.com ipaCache.invalidateIPA(addr, cmd.dw0.vmid); 52414116Sgiacomo.travaglini@arm.com 52514116Sgiacomo.travaglini@arm.com if (!cmd.dw1.leaf) 52614116Sgiacomo.travaglini@arm.com walkCache.invalidateVMID(cmd.dw0.vmid); 52714116Sgiacomo.travaglini@arm.com break; 52814116Sgiacomo.travaglini@arm.com } 52914116Sgiacomo.travaglini@arm.com 53014116Sgiacomo.travaglini@arm.com case CMD_TLBI_S12_VMALL: { 53114116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_S12_VMALL vmid=%#x\n", cmd.dw0.vmid); 53214116Sgiacomo.travaglini@arm.com for (auto slave_interface : slaveInterfaces) { 53314116Sgiacomo.travaglini@arm.com slave_interface->microTLB->invalidateVMID(cmd.dw0.vmid); 53414116Sgiacomo.travaglini@arm.com slave_interface->mainTLB->invalidateVMID(cmd.dw0.vmid); 53514116Sgiacomo.travaglini@arm.com } 53614116Sgiacomo.travaglini@arm.com tlb.invalidateVMID(cmd.dw0.vmid); 53714116Sgiacomo.travaglini@arm.com ipaCache.invalidateVMID(cmd.dw0.vmid); 53814116Sgiacomo.travaglini@arm.com walkCache.invalidateVMID(cmd.dw0.vmid); 53914116Sgiacomo.travaglini@arm.com break; 54014116Sgiacomo.travaglini@arm.com } 54114116Sgiacomo.travaglini@arm.com 54214116Sgiacomo.travaglini@arm.com case CMD_TLBI_NSNH_ALL: { 54314116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_TLBI_NSNH_ALL\n"); 54414039Sstacze01@arm.com for (auto slave_interface : slaveInterfaces) { 54514039Sstacze01@arm.com slave_interface->microTLB->invalidateAll(); 54614039Sstacze01@arm.com slave_interface->mainTLB->invalidateAll(); 54714039Sstacze01@arm.com } 54814039Sstacze01@arm.com tlb.invalidateAll(); 54914039Sstacze01@arm.com ipaCache.invalidateAll(); 55014039Sstacze01@arm.com walkCache.invalidateAll(); 55114039Sstacze01@arm.com break; 55214116Sgiacomo.travaglini@arm.com } 55314039Sstacze01@arm.com 55414116Sgiacomo.travaglini@arm.com case CMD_RESUME: 55514116Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "CMD_RESUME\n"); 55614039Sstacze01@arm.com panic("resume unimplemented"); 55714039Sstacze01@arm.com break; 55814039Sstacze01@arm.com 55914039Sstacze01@arm.com default: 56014116Sgiacomo.travaglini@arm.com warn("Unimplemented command %#x\n", cmd.dw0.type); 56114039Sstacze01@arm.com break; 56214039Sstacze01@arm.com } 56314039Sstacze01@arm.com} 56414039Sstacze01@arm.com 56514039Sstacze01@arm.comconst PageTableOps* 56614039Sstacze01@arm.comSMMUv3::getPageTableOps(uint8_t trans_granule) 56714039Sstacze01@arm.com{ 56814039Sstacze01@arm.com static V8PageTableOps4k ptOps4k; 56914098Smichiel.vantol@arm.com static V8PageTableOps16k ptOps16k; 57014039Sstacze01@arm.com static V8PageTableOps64k ptOps64k; 57114039Sstacze01@arm.com 57214039Sstacze01@arm.com switch (trans_granule) { 57314039Sstacze01@arm.com case TRANS_GRANULE_4K: return &ptOps4k; 57414098Smichiel.vantol@arm.com case TRANS_GRANULE_16K: return &ptOps16k; 57514039Sstacze01@arm.com case TRANS_GRANULE_64K: return &ptOps64k; 57614039Sstacze01@arm.com default: 57714039Sstacze01@arm.com panic("Unknown translation granule size %d", trans_granule); 57814039Sstacze01@arm.com } 57914039Sstacze01@arm.com} 58014039Sstacze01@arm.com 58114039Sstacze01@arm.comTick 58214039Sstacze01@arm.comSMMUv3::readControl(PacketPtr pkt) 58314039Sstacze01@arm.com{ 58414039Sstacze01@arm.com DPRINTF(SMMUv3, "readControl: addr=%08x size=%d\n", 58514039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 58614039Sstacze01@arm.com 58714039Sstacze01@arm.com int offset = pkt->getAddr() - regsMap.start(); 58814039Sstacze01@arm.com assert(offset >= 0 && offset < SMMU_REG_SIZE); 58914039Sstacze01@arm.com 59014039Sstacze01@arm.com if (inSecureBlock(offset)) { 59114039Sstacze01@arm.com warn("smmu: secure registers (0x%x) are not implemented\n", 59214039Sstacze01@arm.com offset); 59314039Sstacze01@arm.com } 59414039Sstacze01@arm.com 59514039Sstacze01@arm.com auto reg_ptr = regs.data + offset; 59614039Sstacze01@arm.com 59714039Sstacze01@arm.com switch (pkt->getSize()) { 59814039Sstacze01@arm.com case sizeof(uint32_t): 59914039Sstacze01@arm.com pkt->setLE<uint32_t>(*reinterpret_cast<uint32_t *>(reg_ptr)); 60014039Sstacze01@arm.com break; 60114039Sstacze01@arm.com case sizeof(uint64_t): 60214039Sstacze01@arm.com pkt->setLE<uint64_t>(*reinterpret_cast<uint64_t *>(reg_ptr)); 60314039Sstacze01@arm.com break; 60414039Sstacze01@arm.com default: 60514039Sstacze01@arm.com panic("smmu: unallowed access size: %d bytes\n", pkt->getSize()); 60614039Sstacze01@arm.com break; 60714039Sstacze01@arm.com } 60814039Sstacze01@arm.com 60914039Sstacze01@arm.com pkt->makeAtomicResponse(); 61014039Sstacze01@arm.com 61114039Sstacze01@arm.com return 0; 61214039Sstacze01@arm.com} 61314039Sstacze01@arm.com 61414039Sstacze01@arm.comTick 61514039Sstacze01@arm.comSMMUv3::writeControl(PacketPtr pkt) 61614039Sstacze01@arm.com{ 61714039Sstacze01@arm.com int offset = pkt->getAddr() - regsMap.start(); 61814039Sstacze01@arm.com assert(offset >= 0 && offset < SMMU_REG_SIZE); 61914039Sstacze01@arm.com 62014039Sstacze01@arm.com DPRINTF(SMMUv3, "writeControl: addr=%08x size=%d data=%16x\n", 62114039Sstacze01@arm.com pkt->getAddr(), pkt->getSize(), 62214039Sstacze01@arm.com pkt->getSize() == sizeof(uint64_t) ? 62314039Sstacze01@arm.com pkt->getLE<uint64_t>() : pkt->getLE<uint32_t>()); 62414039Sstacze01@arm.com 62514039Sstacze01@arm.com switch (offset) { 62614039Sstacze01@arm.com case offsetof(SMMURegs, cr0): 62714039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint32_t)); 62814039Sstacze01@arm.com regs.cr0 = regs.cr0ack = pkt->getLE<uint32_t>(); 62914039Sstacze01@arm.com break; 63014039Sstacze01@arm.com 63114039Sstacze01@arm.com case offsetof(SMMURegs, cr1): 63214039Sstacze01@arm.com case offsetof(SMMURegs, cr2): 63314039Sstacze01@arm.com case offsetof(SMMURegs, strtab_base_cfg): 63414039Sstacze01@arm.com case offsetof(SMMURegs, eventq_cons): 63514039Sstacze01@arm.com case offsetof(SMMURegs, eventq_irq_cfg1): 63614039Sstacze01@arm.com case offsetof(SMMURegs, priq_cons): 63714039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint32_t)); 63814039Sstacze01@arm.com *reinterpret_cast<uint32_t *>(regs.data + offset) = 63914039Sstacze01@arm.com pkt->getLE<uint32_t>(); 64014039Sstacze01@arm.com break; 64114039Sstacze01@arm.com 64214103Sgiacomo.travaglini@arm.com case offsetof(SMMURegs, cmdq_cons): 64314103Sgiacomo.travaglini@arm.com assert(pkt->getSize() == sizeof(uint32_t)); 64414103Sgiacomo.travaglini@arm.com if (regs.cr0 & CR0_CMDQEN_MASK) { 64514103Sgiacomo.travaglini@arm.com warn("CMDQ is enabled: ignoring write to CMDQ_CONS\n"); 64614103Sgiacomo.travaglini@arm.com } else { 64714103Sgiacomo.travaglini@arm.com *reinterpret_cast<uint32_t *>(regs.data + offset) = 64814103Sgiacomo.travaglini@arm.com pkt->getLE<uint32_t>(); 64914103Sgiacomo.travaglini@arm.com } 65014103Sgiacomo.travaglini@arm.com break; 65114103Sgiacomo.travaglini@arm.com 65214039Sstacze01@arm.com case offsetof(SMMURegs, cmdq_prod): 65314039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint32_t)); 65414039Sstacze01@arm.com *reinterpret_cast<uint32_t *>(regs.data + offset) = 65514039Sstacze01@arm.com pkt->getLE<uint32_t>(); 65614039Sstacze01@arm.com schedule(processCommandsEvent, nextCycle()); 65714039Sstacze01@arm.com break; 65814039Sstacze01@arm.com 65914039Sstacze01@arm.com case offsetof(SMMURegs, strtab_base): 66014039Sstacze01@arm.com case offsetof(SMMURegs, eventq_irq_cfg0): 66114039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint64_t)); 66214039Sstacze01@arm.com *reinterpret_cast<uint64_t *>(regs.data + offset) = 66314039Sstacze01@arm.com pkt->getLE<uint64_t>(); 66414039Sstacze01@arm.com break; 66514039Sstacze01@arm.com 66614039Sstacze01@arm.com case offsetof(SMMURegs, cmdq_base): 66714039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint64_t)); 66814103Sgiacomo.travaglini@arm.com if (regs.cr0 & CR0_CMDQEN_MASK) { 66914103Sgiacomo.travaglini@arm.com warn("CMDQ is enabled: ignoring write to CMDQ_BASE\n"); 67014103Sgiacomo.travaglini@arm.com } else { 67114103Sgiacomo.travaglini@arm.com *reinterpret_cast<uint64_t *>(regs.data + offset) = 67214103Sgiacomo.travaglini@arm.com pkt->getLE<uint64_t>(); 67314103Sgiacomo.travaglini@arm.com regs.cmdq_cons = 0; 67414103Sgiacomo.travaglini@arm.com regs.cmdq_prod = 0; 67514103Sgiacomo.travaglini@arm.com } 67614039Sstacze01@arm.com break; 67714039Sstacze01@arm.com 67814039Sstacze01@arm.com case offsetof(SMMURegs, eventq_base): 67914039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint64_t)); 68014039Sstacze01@arm.com *reinterpret_cast<uint64_t *>(regs.data + offset) = 68114039Sstacze01@arm.com pkt->getLE<uint64_t>(); 68214039Sstacze01@arm.com regs.eventq_cons = 0; 68314039Sstacze01@arm.com regs.eventq_prod = 0; 68414039Sstacze01@arm.com break; 68514039Sstacze01@arm.com 68614039Sstacze01@arm.com case offsetof(SMMURegs, priq_base): 68714039Sstacze01@arm.com assert(pkt->getSize() == sizeof(uint64_t)); 68814039Sstacze01@arm.com *reinterpret_cast<uint64_t *>(regs.data + offset) = 68914039Sstacze01@arm.com pkt->getLE<uint64_t>(); 69014039Sstacze01@arm.com regs.priq_cons = 0; 69114039Sstacze01@arm.com regs.priq_prod = 0; 69214039Sstacze01@arm.com break; 69314039Sstacze01@arm.com 69414039Sstacze01@arm.com default: 69514039Sstacze01@arm.com if (inSecureBlock(offset)) { 69614039Sstacze01@arm.com warn("smmu: secure registers (0x%x) are not implemented\n", 69714039Sstacze01@arm.com offset); 69814039Sstacze01@arm.com } else { 69914039Sstacze01@arm.com warn("smmu: write to read-only/undefined register at 0x%x\n", 70014039Sstacze01@arm.com offset); 70114039Sstacze01@arm.com } 70214039Sstacze01@arm.com } 70314039Sstacze01@arm.com 70414039Sstacze01@arm.com pkt->makeAtomicResponse(); 70514039Sstacze01@arm.com 70614039Sstacze01@arm.com return 0; 70714039Sstacze01@arm.com} 70814039Sstacze01@arm.com 70914039Sstacze01@arm.combool 71014039Sstacze01@arm.comSMMUv3::inSecureBlock(uint32_t offs) const 71114039Sstacze01@arm.com{ 71214039Sstacze01@arm.com if (offs >= offsetof(SMMURegs, _secure_regs) && offs < SMMU_SECURE_SZ) 71314039Sstacze01@arm.com return true; 71414039Sstacze01@arm.com else 71514039Sstacze01@arm.com return false; 71614039Sstacze01@arm.com} 71714039Sstacze01@arm.com 71814039Sstacze01@arm.comvoid 71914039Sstacze01@arm.comSMMUv3::init() 72014039Sstacze01@arm.com{ 72114039Sstacze01@arm.com // make sure both sides are connected and have the same block size 72214039Sstacze01@arm.com if (!masterPort.isConnected()) 72314039Sstacze01@arm.com fatal("Master port is not connected.\n"); 72414039Sstacze01@arm.com 72514039Sstacze01@arm.com // If the second master port is connected for the table walks, enable 72614039Sstacze01@arm.com // the mode to send table walks through this port instead 72714039Sstacze01@arm.com if (masterTableWalkPort.isConnected()) 72814039Sstacze01@arm.com tableWalkPortEnable = true; 72914039Sstacze01@arm.com 73014039Sstacze01@arm.com // notify the master side of our address ranges 73114039Sstacze01@arm.com for (auto ifc : slaveInterfaces) { 73214039Sstacze01@arm.com ifc->sendRange(); 73314039Sstacze01@arm.com } 73414039Sstacze01@arm.com 73514039Sstacze01@arm.com if (controlPort.isConnected()) 73614039Sstacze01@arm.com controlPort.sendRangeChange(); 73714039Sstacze01@arm.com} 73814039Sstacze01@arm.com 73914039Sstacze01@arm.comvoid 74014039Sstacze01@arm.comSMMUv3::regStats() 74114039Sstacze01@arm.com{ 74214252Sgabeblack@google.com ClockedObject::regStats(); 74314039Sstacze01@arm.com 74414039Sstacze01@arm.com using namespace Stats; 74514039Sstacze01@arm.com 74614039Sstacze01@arm.com for (size_t i = 0; i < slaveInterfaces.size(); i++) { 74714039Sstacze01@arm.com slaveInterfaces[i]->microTLB->regStats( 74814039Sstacze01@arm.com csprintf("%s.utlb%d", name(), i)); 74914039Sstacze01@arm.com slaveInterfaces[i]->mainTLB->regStats( 75014039Sstacze01@arm.com csprintf("%s.maintlb%d", name(), i)); 75114039Sstacze01@arm.com } 75214039Sstacze01@arm.com 75314039Sstacze01@arm.com tlb.regStats(name() + ".tlb"); 75414039Sstacze01@arm.com configCache.regStats(name() + ".cfg"); 75514039Sstacze01@arm.com ipaCache.regStats(name() + ".ipa"); 75614039Sstacze01@arm.com walkCache.regStats(name() + ".walk"); 75714039Sstacze01@arm.com 75814039Sstacze01@arm.com steL1Fetches 75914039Sstacze01@arm.com .name(name() + ".steL1Fetches") 76014039Sstacze01@arm.com .desc("STE L1 fetches") 76114039Sstacze01@arm.com .flags(pdf); 76214039Sstacze01@arm.com 76314039Sstacze01@arm.com steFetches 76414039Sstacze01@arm.com .name(name() + ".steFetches") 76514039Sstacze01@arm.com .desc("STE fetches") 76614039Sstacze01@arm.com .flags(pdf); 76714039Sstacze01@arm.com 76814039Sstacze01@arm.com cdL1Fetches 76914039Sstacze01@arm.com .name(name() + ".cdL1Fetches") 77014039Sstacze01@arm.com .desc("CD L1 fetches") 77114039Sstacze01@arm.com .flags(pdf); 77214039Sstacze01@arm.com 77314039Sstacze01@arm.com cdFetches 77414039Sstacze01@arm.com .name(name() + ".cdFetches") 77514039Sstacze01@arm.com .desc("CD fetches") 77614039Sstacze01@arm.com .flags(pdf); 77714039Sstacze01@arm.com 77814039Sstacze01@arm.com translationTimeDist 77914039Sstacze01@arm.com .init(0, 2000000, 2000) 78014039Sstacze01@arm.com .name(name() + ".translationTimeDist") 78114039Sstacze01@arm.com .desc("Time to translate address") 78214039Sstacze01@arm.com .flags(pdf); 78314039Sstacze01@arm.com 78414039Sstacze01@arm.com ptwTimeDist 78514039Sstacze01@arm.com .init(0, 2000000, 2000) 78614039Sstacze01@arm.com .name(name() + ".ptwTimeDist") 78714039Sstacze01@arm.com .desc("Time to walk page tables") 78814039Sstacze01@arm.com .flags(pdf); 78914039Sstacze01@arm.com} 79014039Sstacze01@arm.com 79114039Sstacze01@arm.comDrainState 79214039Sstacze01@arm.comSMMUv3::drain() 79314039Sstacze01@arm.com{ 79414064Sadrian.herrera@arm.com // Wait until the Command Executor is not busy 79514064Sadrian.herrera@arm.com if (commandExecutor.isBusy()) { 79614064Sadrian.herrera@arm.com return DrainState::Draining; 79714064Sadrian.herrera@arm.com } 79814064Sadrian.herrera@arm.com return DrainState::Drained; 79914039Sstacze01@arm.com} 80014039Sstacze01@arm.com 80114039Sstacze01@arm.comvoid 80214039Sstacze01@arm.comSMMUv3::serialize(CheckpointOut &cp) const 80314039Sstacze01@arm.com{ 80414039Sstacze01@arm.com DPRINTF(Checkpoint, "Serializing SMMUv3\n"); 80514039Sstacze01@arm.com 80614039Sstacze01@arm.com SERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0])); 80714039Sstacze01@arm.com} 80814039Sstacze01@arm.com 80914039Sstacze01@arm.comvoid 81014039Sstacze01@arm.comSMMUv3::unserialize(CheckpointIn &cp) 81114039Sstacze01@arm.com{ 81214039Sstacze01@arm.com DPRINTF(Checkpoint, "Unserializing SMMUv3\n"); 81314039Sstacze01@arm.com 81414039Sstacze01@arm.com UNSERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0])); 81514039Sstacze01@arm.com} 81614039Sstacze01@arm.com 81714039Sstacze01@arm.comPort& 81814039Sstacze01@arm.comSMMUv3::getPort(const std::string &name, PortID id) 81914039Sstacze01@arm.com{ 82014039Sstacze01@arm.com if (name == "master") { 82114039Sstacze01@arm.com return masterPort; 82214039Sstacze01@arm.com } else if (name == "master_walker") { 82314039Sstacze01@arm.com return masterTableWalkPort; 82414039Sstacze01@arm.com } else if (name == "control") { 82514039Sstacze01@arm.com return controlPort; 82614039Sstacze01@arm.com } else { 82714252Sgabeblack@google.com return ClockedObject::getPort(name, id); 82814039Sstacze01@arm.com } 82914039Sstacze01@arm.com} 83014039Sstacze01@arm.com 83114039Sstacze01@arm.comSMMUv3* 83214039Sstacze01@arm.comSMMUv3Params::create() 83314039Sstacze01@arm.com{ 83414039Sstacze01@arm.com return new SMMUv3(this); 83514039Sstacze01@arm.com} 836