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(&regs, 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