smmu_v3_transl.cc revision 14101
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_transl.hh"
4114039Sstacze01@arm.com
4214039Sstacze01@arm.com#include "debug/SMMUv3.hh"
4314039Sstacze01@arm.com#include "debug/SMMUv3Hazard.hh"
4414039Sstacze01@arm.com#include "dev/arm/amba.hh"
4514039Sstacze01@arm.com#include "dev/arm/smmu_v3.hh"
4614039Sstacze01@arm.com#include "sim/system.hh"
4714039Sstacze01@arm.com
4814039Sstacze01@arm.comSMMUTranslRequest
4914039Sstacze01@arm.comSMMUTranslRequest::fromPacket(PacketPtr pkt, bool ats)
5014039Sstacze01@arm.com{
5114039Sstacze01@arm.com    SMMUTranslRequest req;
5214039Sstacze01@arm.com    req.addr         = pkt->getAddr();
5314039Sstacze01@arm.com    req.size         = pkt->getSize();
5414039Sstacze01@arm.com    req.sid          = pkt->req->streamId();
5514039Sstacze01@arm.com    req.ssid         = pkt->req->hasSubstreamId() ?
5614039Sstacze01@arm.com        pkt->req->substreamId() : 0;
5714039Sstacze01@arm.com    req.isWrite      = pkt->isWrite();
5814039Sstacze01@arm.com    req.isPrefetch   = false;
5914039Sstacze01@arm.com    req.isAtsRequest = ats;
6014039Sstacze01@arm.com    req.pkt          = pkt;
6114039Sstacze01@arm.com
6214039Sstacze01@arm.com    return req;
6314039Sstacze01@arm.com}
6414039Sstacze01@arm.com
6514039Sstacze01@arm.comSMMUTranslRequest
6614039Sstacze01@arm.comSMMUTranslRequest::prefetch(Addr addr, uint32_t sid, uint32_t ssid)
6714039Sstacze01@arm.com{
6814039Sstacze01@arm.com    SMMUTranslRequest req;
6914039Sstacze01@arm.com    req.addr         = addr;
7014039Sstacze01@arm.com    req.size         = 0;
7114039Sstacze01@arm.com    req.sid          = sid;
7214039Sstacze01@arm.com    req.ssid         = ssid;
7314039Sstacze01@arm.com    req.isWrite      = false;
7414039Sstacze01@arm.com    req.isPrefetch   = true;
7514039Sstacze01@arm.com    req.isAtsRequest = false;
7614039Sstacze01@arm.com    req.pkt          = NULL;
7714039Sstacze01@arm.com
7814039Sstacze01@arm.com    return req;
7914039Sstacze01@arm.com}
8014039Sstacze01@arm.com
8114063Sadrian.herrera@arm.comSMMUTranslationProcess::SMMUTranslationProcess(const std::string &name,
8214063Sadrian.herrera@arm.com    SMMUv3 &_smmu, SMMUv3SlaveInterface &_ifc)
8314063Sadrian.herrera@arm.com  :
8414063Sadrian.herrera@arm.com    SMMUProcess(name, _smmu),
8514063Sadrian.herrera@arm.com    ifc(_ifc)
8614063Sadrian.herrera@arm.com{
8714063Sadrian.herrera@arm.com    // Decrease number of pending translation slots on the slave interface
8814063Sadrian.herrera@arm.com    assert(ifc.xlateSlotsRemaining > 0);
8914063Sadrian.herrera@arm.com    ifc.xlateSlotsRemaining--;
9014063Sadrian.herrera@arm.com    reinit();
9114063Sadrian.herrera@arm.com}
9214063Sadrian.herrera@arm.com
9314063Sadrian.herrera@arm.comSMMUTranslationProcess::~SMMUTranslationProcess()
9414063Sadrian.herrera@arm.com{
9514063Sadrian.herrera@arm.com    // Increase number of pending translation slots on the slave interface
9614063Sadrian.herrera@arm.com    ifc.xlateSlotsRemaining++;
9714064Sadrian.herrera@arm.com    // If no more SMMU translations are pending (all slots available),
9814064Sadrian.herrera@arm.com    // signal SMMU Slave Interface as drained
9914064Sadrian.herrera@arm.com    if (ifc.xlateSlotsRemaining == ifc.params()->xlate_slots) {
10014064Sadrian.herrera@arm.com        ifc.signalDrainDone();
10114064Sadrian.herrera@arm.com    }
10214063Sadrian.herrera@arm.com}
10314063Sadrian.herrera@arm.com
10414039Sstacze01@arm.comvoid
10514039Sstacze01@arm.comSMMUTranslationProcess::beginTransaction(const SMMUTranslRequest &req)
10614039Sstacze01@arm.com{
10714039Sstacze01@arm.com    request = req;
10814039Sstacze01@arm.com
10914039Sstacze01@arm.com    reinit();
11014039Sstacze01@arm.com}
11114039Sstacze01@arm.com
11214039Sstacze01@arm.comvoid
11314039Sstacze01@arm.comSMMUTranslationProcess::resumeTransaction()
11414039Sstacze01@arm.com{
11514039Sstacze01@arm.com    assert(smmu.system.isTimingMode());
11614039Sstacze01@arm.com
11714039Sstacze01@arm.com    assert(!"Stalls are broken");
11814039Sstacze01@arm.com
11914039Sstacze01@arm.com    Tick resumeTick = curTick();
12014039Sstacze01@arm.com
12114039Sstacze01@arm.com    (void) resumeTick;
12214039Sstacze01@arm.com    DPRINTF(SMMUv3, "Resume at tick = %d. Fault duration = %d (%.3fus)\n",
12314039Sstacze01@arm.com        resumeTick, resumeTick-faultTick, (resumeTick-faultTick) / 1e6);
12414039Sstacze01@arm.com
12514039Sstacze01@arm.com    beginTransaction(request);
12614039Sstacze01@arm.com
12714039Sstacze01@arm.com    smmu.runProcessTiming(this, request.pkt);
12814039Sstacze01@arm.com}
12914039Sstacze01@arm.com
13014039Sstacze01@arm.comvoid
13114039Sstacze01@arm.comSMMUTranslationProcess::main(Yield &yield)
13214039Sstacze01@arm.com{
13314039Sstacze01@arm.com    // Hack:
13414039Sstacze01@arm.com    // The coroutine starts running as soon as it's created.
13514039Sstacze01@arm.com    // But we need to wait for request data esp. in atomic mode.
13614039Sstacze01@arm.com    SMMUAction a;
13714039Sstacze01@arm.com    a.type = ACTION_INITIAL_NOP;
13814039Sstacze01@arm.com    a.pkt = NULL;
13914039Sstacze01@arm.com    yield(a);
14014039Sstacze01@arm.com
14114039Sstacze01@arm.com    const Addr next4k = (request.addr + 0x1000ULL) & ~0xfffULL;
14214039Sstacze01@arm.com
14314039Sstacze01@arm.com    if ((request.addr + request.size) > next4k)
14414039Sstacze01@arm.com        panic("Transaction crosses 4k boundary (addr=%#x size=%#x)!\n",
14514039Sstacze01@arm.com                request.addr, request.size);
14614039Sstacze01@arm.com
14714039Sstacze01@arm.com
14814039Sstacze01@arm.com    unsigned numSlaveBeats = request.isWrite ?
14914039Sstacze01@arm.com        (request.size + (ifc.portWidth - 1)) / ifc.portWidth : 1;
15014039Sstacze01@arm.com
15114039Sstacze01@arm.com    doSemaphoreDown(yield, ifc.slavePortSem);
15214039Sstacze01@arm.com    doDelay(yield, Cycles(numSlaveBeats));
15314039Sstacze01@arm.com    doSemaphoreUp(ifc.slavePortSem);
15414039Sstacze01@arm.com
15514039Sstacze01@arm.com
15614039Sstacze01@arm.com    recvTick = curTick();
15714039Sstacze01@arm.com
15814039Sstacze01@arm.com
15914039Sstacze01@arm.com    if (!(smmu.regs.cr0 & 0x1)) {
16014039Sstacze01@arm.com        // SMMU disabled
16114039Sstacze01@arm.com        doDelay(yield, Cycles(1));
16214039Sstacze01@arm.com        completeTransaction(yield, bypass(request.addr));
16314039Sstacze01@arm.com        return;
16414039Sstacze01@arm.com    }
16514039Sstacze01@arm.com
16614039Sstacze01@arm.com    TranslResult tr;
16714039Sstacze01@arm.com    bool wasPrefetched = false;
16814039Sstacze01@arm.com
16914039Sstacze01@arm.com    if (request.isPrefetch) {
17014039Sstacze01@arm.com        // Abort prefetch if:
17114039Sstacze01@arm.com        //   - there's already a transaction looking up the same 4k page, OR
17214039Sstacze01@arm.com        //   - requested address is already in the TLB.
17314039Sstacze01@arm.com        if (hazard4kCheck() || ifcTLBLookup(yield, tr, wasPrefetched))
17414039Sstacze01@arm.com            completePrefetch(yield); // this never returns
17514039Sstacze01@arm.com
17614039Sstacze01@arm.com        hazard4kRegister();
17714039Sstacze01@arm.com
17814039Sstacze01@arm.com        tr = smmuTranslation(yield);
17914039Sstacze01@arm.com
18014039Sstacze01@arm.com        if (tr.fault == FAULT_NONE)
18114039Sstacze01@arm.com            ifcTLBUpdate(yield, tr);
18214039Sstacze01@arm.com
18314039Sstacze01@arm.com        hazard4kRelease();
18414039Sstacze01@arm.com
18514039Sstacze01@arm.com        completePrefetch(yield);
18614039Sstacze01@arm.com    } else {
18714039Sstacze01@arm.com        hazardIdRegister();
18814039Sstacze01@arm.com
18914039Sstacze01@arm.com        if (!microTLBLookup(yield, tr)) {
19014039Sstacze01@arm.com            bool hit = ifcTLBLookup(yield, tr, wasPrefetched);
19114039Sstacze01@arm.com            if (!hit) {
19214039Sstacze01@arm.com                while (!hit && hazard4kCheck()) {
19314039Sstacze01@arm.com                    hazard4kHold(yield);
19414039Sstacze01@arm.com                    hit = ifcTLBLookup(yield, tr, wasPrefetched);
19514039Sstacze01@arm.com                }
19614039Sstacze01@arm.com            }
19714039Sstacze01@arm.com
19814039Sstacze01@arm.com            // Issue prefetch if:
19914039Sstacze01@arm.com            //   - there was a TLB hit and the entry was prefetched, OR
20014039Sstacze01@arm.com            //   - TLB miss was successfully serviced
20114039Sstacze01@arm.com            if (hit) {
20214039Sstacze01@arm.com                if (wasPrefetched)
20314039Sstacze01@arm.com                    issuePrefetch(next4k);
20414039Sstacze01@arm.com            } else {
20514039Sstacze01@arm.com                hazard4kRegister();
20614039Sstacze01@arm.com
20714039Sstacze01@arm.com                tr = smmuTranslation(yield);
20814039Sstacze01@arm.com
20914039Sstacze01@arm.com                if (tr.fault == FAULT_NONE) {
21014039Sstacze01@arm.com                    ifcTLBUpdate(yield, tr);
21114039Sstacze01@arm.com
21214039Sstacze01@arm.com                    issuePrefetch(next4k);
21314039Sstacze01@arm.com                }
21414039Sstacze01@arm.com
21514039Sstacze01@arm.com                hazard4kRelease();
21614039Sstacze01@arm.com            }
21714039Sstacze01@arm.com
21814039Sstacze01@arm.com            if (tr.fault == FAULT_NONE)
21914039Sstacze01@arm.com                microTLBUpdate(yield, tr);
22014039Sstacze01@arm.com        }
22114039Sstacze01@arm.com
22214039Sstacze01@arm.com        hazardIdHold(yield);
22314039Sstacze01@arm.com        hazardIdRelease();
22414039Sstacze01@arm.com
22514039Sstacze01@arm.com        if (tr.fault != FAULT_NONE)
22614039Sstacze01@arm.com            panic("fault\n");
22714039Sstacze01@arm.com
22814039Sstacze01@arm.com        completeTransaction(yield, tr);
22914039Sstacze01@arm.com    }
23014039Sstacze01@arm.com}
23114039Sstacze01@arm.com
23214039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
23314039Sstacze01@arm.comSMMUTranslationProcess::bypass(Addr addr) const
23414039Sstacze01@arm.com{
23514039Sstacze01@arm.com    TranslResult tr;
23614039Sstacze01@arm.com    tr.fault = FAULT_NONE;
23714039Sstacze01@arm.com    tr.addr = addr;
23814039Sstacze01@arm.com    tr.addrMask = 0;
23914039Sstacze01@arm.com    tr.writable = 1;
24014039Sstacze01@arm.com
24114039Sstacze01@arm.com    return tr;
24214039Sstacze01@arm.com}
24314039Sstacze01@arm.com
24414039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
24514039Sstacze01@arm.comSMMUTranslationProcess::smmuTranslation(Yield &yield)
24614039Sstacze01@arm.com{
24714039Sstacze01@arm.com    TranslResult tr;
24814039Sstacze01@arm.com
24914039Sstacze01@arm.com    // Need SMMU credit to proceed
25014039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.transSem);
25114039Sstacze01@arm.com
25214039Sstacze01@arm.com    // Simulate pipelined IFC->SMMU link
25314039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.ifcSmmuSem);
25414039Sstacze01@arm.com    doDelay(yield, Cycles(1)); // serialize transactions
25514039Sstacze01@arm.com    doSemaphoreUp(smmu.ifcSmmuSem);
25614039Sstacze01@arm.com    doDelay(yield, smmu.ifcSmmuLat - Cycles(1)); // remaining pipeline delay
25714039Sstacze01@arm.com
25814039Sstacze01@arm.com    bool haveConfig = true;
25914039Sstacze01@arm.com    if (!configCacheLookup(yield, context)) {
26014039Sstacze01@arm.com        if(findConfig(yield, context, tr)) {
26114039Sstacze01@arm.com            configCacheUpdate(yield, context);
26214039Sstacze01@arm.com        } else {
26314039Sstacze01@arm.com            haveConfig = false;
26414039Sstacze01@arm.com        }
26514039Sstacze01@arm.com    }
26614039Sstacze01@arm.com
26714039Sstacze01@arm.com    if (haveConfig && !smmuTLBLookup(yield, tr)) {
26814039Sstacze01@arm.com        // SMMU main TLB miss
26914039Sstacze01@arm.com
27014039Sstacze01@arm.com        // Need PTW slot to proceed
27114039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.ptwSem);
27214039Sstacze01@arm.com
27314039Sstacze01@arm.com        // Page table walk
27414039Sstacze01@arm.com        Tick ptwStartTick = curTick();
27514039Sstacze01@arm.com
27614039Sstacze01@arm.com        if (context.stage1Enable) {
27714039Sstacze01@arm.com            tr = translateStage1And2(yield, request.addr);
27814039Sstacze01@arm.com        } else if (context.stage2Enable) {
27914039Sstacze01@arm.com            tr = translateStage2(yield, request.addr, true);
28014039Sstacze01@arm.com        } else {
28114039Sstacze01@arm.com            tr = bypass(request.addr);
28214039Sstacze01@arm.com        }
28314039Sstacze01@arm.com
28414039Sstacze01@arm.com        if (context.stage1Enable || context.stage2Enable)
28514039Sstacze01@arm.com            smmu.ptwTimeDist.sample(curTick() - ptwStartTick);
28614039Sstacze01@arm.com
28714039Sstacze01@arm.com        // Free PTW slot
28814039Sstacze01@arm.com        doSemaphoreUp(smmu.ptwSem);
28914039Sstacze01@arm.com
29014039Sstacze01@arm.com        if (tr.fault == FAULT_NONE)
29114039Sstacze01@arm.com            smmuTLBUpdate(yield, tr);
29214039Sstacze01@arm.com    }
29314039Sstacze01@arm.com
29414039Sstacze01@arm.com    // Simulate pipelined SMMU->SLAVE INTERFACE link
29514039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.smmuIfcSem);
29614039Sstacze01@arm.com    doDelay(yield, Cycles(1)); // serialize transactions
29714039Sstacze01@arm.com    doSemaphoreUp(smmu.smmuIfcSem);
29814039Sstacze01@arm.com    doDelay(yield, smmu.smmuIfcLat - Cycles(1)); // remaining pipeline delay
29914039Sstacze01@arm.com
30014039Sstacze01@arm.com    // return SMMU credit
30114039Sstacze01@arm.com    doSemaphoreUp(smmu.transSem);
30214039Sstacze01@arm.com
30314039Sstacze01@arm.com    return tr;
30414039Sstacze01@arm.com}
30514039Sstacze01@arm.com
30614039Sstacze01@arm.combool
30714039Sstacze01@arm.comSMMUTranslationProcess::microTLBLookup(Yield &yield, TranslResult &tr)
30814039Sstacze01@arm.com{
30914039Sstacze01@arm.com    if (!ifc.microTLBEnable)
31014039Sstacze01@arm.com        return false;
31114039Sstacze01@arm.com
31214039Sstacze01@arm.com    doSemaphoreDown(yield, ifc.microTLBSem);
31314039Sstacze01@arm.com    doDelay(yield, ifc.microTLBLat);
31414039Sstacze01@arm.com    const SMMUTLB::Entry *e =
31514039Sstacze01@arm.com        ifc.microTLB->lookup(request.sid, request.ssid, request.addr);
31614039Sstacze01@arm.com    doSemaphoreUp(ifc.microTLBSem);
31714039Sstacze01@arm.com
31814039Sstacze01@arm.com    if (!e) {
31914039Sstacze01@arm.com        DPRINTF(SMMUv3, "micro TLB miss vaddr=%#x sid=%#x ssid=%#x\n",
32014039Sstacze01@arm.com            request.addr, request.sid, request.ssid);
32114039Sstacze01@arm.com
32214039Sstacze01@arm.com        return false;
32314039Sstacze01@arm.com    }
32414039Sstacze01@arm.com
32514039Sstacze01@arm.com    DPRINTF(SMMUv3,
32614039Sstacze01@arm.com        "micro TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x paddr=%#x\n",
32714039Sstacze01@arm.com        request.addr, e->vaMask, request.sid, request.ssid, e->pa);
32814039Sstacze01@arm.com
32914039Sstacze01@arm.com    tr.fault = FAULT_NONE;
33014039Sstacze01@arm.com    tr.addr = e->pa + (request.addr & ~e->vaMask);;
33114039Sstacze01@arm.com    tr.addrMask = e->vaMask;
33214039Sstacze01@arm.com    tr.writable = e->permissions;
33314039Sstacze01@arm.com
33414039Sstacze01@arm.com    return true;
33514039Sstacze01@arm.com}
33614039Sstacze01@arm.com
33714039Sstacze01@arm.combool
33814039Sstacze01@arm.comSMMUTranslationProcess::ifcTLBLookup(Yield &yield, TranslResult &tr,
33914039Sstacze01@arm.com                                     bool &wasPrefetched)
34014039Sstacze01@arm.com{
34114039Sstacze01@arm.com    if (!ifc.mainTLBEnable)
34214039Sstacze01@arm.com        return false;
34314039Sstacze01@arm.com
34414039Sstacze01@arm.com    doSemaphoreDown(yield, ifc.mainTLBSem);
34514039Sstacze01@arm.com    doDelay(yield, ifc.mainTLBLat);
34614039Sstacze01@arm.com    const SMMUTLB::Entry *e =
34714039Sstacze01@arm.com        ifc.mainTLB->lookup(request.sid, request.ssid, request.addr);
34814039Sstacze01@arm.com    doSemaphoreUp(ifc.mainTLBSem);
34914039Sstacze01@arm.com
35014039Sstacze01@arm.com    if (!e) {
35114039Sstacze01@arm.com        DPRINTF(SMMUv3,
35214039Sstacze01@arm.com                "SLAVE Interface TLB miss vaddr=%#x sid=%#x ssid=%#x\n",
35314039Sstacze01@arm.com                request.addr, request.sid, request.ssid);
35414039Sstacze01@arm.com
35514039Sstacze01@arm.com        return false;
35614039Sstacze01@arm.com    }
35714039Sstacze01@arm.com
35814039Sstacze01@arm.com    DPRINTF(SMMUv3,
35914039Sstacze01@arm.com            "SLAVE Interface TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x "
36014039Sstacze01@arm.com            "paddr=%#x\n", request.addr, e->vaMask, request.sid,
36114039Sstacze01@arm.com            request.ssid, e->pa);
36214039Sstacze01@arm.com
36314039Sstacze01@arm.com    tr.fault = FAULT_NONE;
36414039Sstacze01@arm.com    tr.addr = e->pa + (request.addr & ~e->vaMask);;
36514039Sstacze01@arm.com    tr.addrMask = e->vaMask;
36614039Sstacze01@arm.com    tr.writable = e->permissions;
36714039Sstacze01@arm.com    wasPrefetched = e->prefetched;
36814039Sstacze01@arm.com
36914039Sstacze01@arm.com    return true;
37014039Sstacze01@arm.com}
37114039Sstacze01@arm.com
37214039Sstacze01@arm.combool
37314039Sstacze01@arm.comSMMUTranslationProcess::smmuTLBLookup(Yield &yield, TranslResult &tr)
37414039Sstacze01@arm.com{
37514039Sstacze01@arm.com    if (!smmu.tlbEnable)
37614039Sstacze01@arm.com        return false;
37714039Sstacze01@arm.com
37814039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.tlbSem);
37914039Sstacze01@arm.com    doDelay(yield, smmu.tlbLat);
38014039Sstacze01@arm.com    const ARMArchTLB::Entry *e =
38114039Sstacze01@arm.com        smmu.tlb.lookup(request.addr, context.asid, context.vmid);
38214039Sstacze01@arm.com    doSemaphoreUp(smmu.tlbSem);
38314039Sstacze01@arm.com
38414039Sstacze01@arm.com    if (!e) {
38514039Sstacze01@arm.com        DPRINTF(SMMUv3, "SMMU TLB miss vaddr=%#x asid=%#x vmid=%#x\n",
38614039Sstacze01@arm.com            request.addr, context.asid, context.vmid);
38714039Sstacze01@arm.com
38814039Sstacze01@arm.com        return false;
38914039Sstacze01@arm.com    }
39014039Sstacze01@arm.com
39114039Sstacze01@arm.com    DPRINTF(SMMUv3,
39214039Sstacze01@arm.com            "SMMU TLB hit vaddr=%#x amask=%#x asid=%#x vmid=%#x paddr=%#x\n",
39314039Sstacze01@arm.com            request.addr, e->vaMask, context.asid, context.vmid, e->pa);
39414039Sstacze01@arm.com
39514039Sstacze01@arm.com    tr.fault = FAULT_NONE;
39614039Sstacze01@arm.com    tr.addr = e->pa + (request.addr & ~e->vaMask);;
39714039Sstacze01@arm.com    tr.addrMask = e->vaMask;
39814039Sstacze01@arm.com    tr.writable = e->permissions;
39914039Sstacze01@arm.com
40014039Sstacze01@arm.com    return true;
40114039Sstacze01@arm.com}
40214039Sstacze01@arm.com
40314039Sstacze01@arm.comvoid
40414039Sstacze01@arm.comSMMUTranslationProcess::microTLBUpdate(Yield &yield,
40514039Sstacze01@arm.com                                       const TranslResult &tr)
40614039Sstacze01@arm.com{
40714039Sstacze01@arm.com    assert(tr.fault == FAULT_NONE);
40814039Sstacze01@arm.com
40914039Sstacze01@arm.com    if (!ifc.microTLBEnable)
41014039Sstacze01@arm.com        return;
41114039Sstacze01@arm.com
41214039Sstacze01@arm.com    SMMUTLB::Entry e;
41314039Sstacze01@arm.com    e.valid = true;
41414039Sstacze01@arm.com    e.prefetched = false;
41514039Sstacze01@arm.com    e.sid = request.sid;
41614039Sstacze01@arm.com    e.ssid = request.ssid;
41714039Sstacze01@arm.com    e.vaMask = tr.addrMask;
41814039Sstacze01@arm.com    e.va = request.addr & e.vaMask;
41914039Sstacze01@arm.com    e.pa = tr.addr & e.vaMask;
42014039Sstacze01@arm.com    e.permissions = tr.writable;
42114039Sstacze01@arm.com    e.asid = context.asid;
42214039Sstacze01@arm.com    e.vmid = context.vmid;
42314039Sstacze01@arm.com
42414039Sstacze01@arm.com    doSemaphoreDown(yield, ifc.microTLBSem);
42514039Sstacze01@arm.com
42614039Sstacze01@arm.com    DPRINTF(SMMUv3,
42714039Sstacze01@arm.com        "micro TLB upd vaddr=%#x amask=%#x paddr=%#x sid=%#x ssid=%#x\n",
42814039Sstacze01@arm.com        e.va, e.vaMask, e.pa, e.sid, e.ssid);
42914039Sstacze01@arm.com
43014039Sstacze01@arm.com    ifc.microTLB->store(e, SMMUTLB::ALLOC_ANY_WAY);
43114039Sstacze01@arm.com
43214039Sstacze01@arm.com    doSemaphoreUp(ifc.microTLBSem);
43314039Sstacze01@arm.com}
43414039Sstacze01@arm.com
43514039Sstacze01@arm.comvoid
43614039Sstacze01@arm.comSMMUTranslationProcess::ifcTLBUpdate(Yield &yield,
43714039Sstacze01@arm.com                                     const TranslResult &tr)
43814039Sstacze01@arm.com{
43914039Sstacze01@arm.com    assert(tr.fault == FAULT_NONE);
44014039Sstacze01@arm.com
44114039Sstacze01@arm.com    if (!ifc.mainTLBEnable)
44214039Sstacze01@arm.com        return;
44314039Sstacze01@arm.com
44414039Sstacze01@arm.com    SMMUTLB::Entry e;
44514039Sstacze01@arm.com    e.valid = true;
44614039Sstacze01@arm.com    e.prefetched = request.isPrefetch;
44714039Sstacze01@arm.com    e.sid = request.sid;
44814039Sstacze01@arm.com    e.ssid = request.ssid;
44914039Sstacze01@arm.com    e.vaMask = tr.addrMask;
45014039Sstacze01@arm.com    e.va = request.addr & e.vaMask;
45114039Sstacze01@arm.com    e.pa = tr.addr & e.vaMask;
45214039Sstacze01@arm.com    e.permissions = tr.writable;
45314039Sstacze01@arm.com    e.asid = context.asid;
45414039Sstacze01@arm.com    e.vmid = context.vmid;
45514039Sstacze01@arm.com
45614039Sstacze01@arm.com    SMMUTLB::AllocPolicy alloc = SMMUTLB::ALLOC_ANY_WAY;
45714039Sstacze01@arm.com    if (ifc.prefetchEnable && ifc.prefetchReserveLastWay)
45814039Sstacze01@arm.com        alloc = request.isPrefetch ?
45914039Sstacze01@arm.com            SMMUTLB::ALLOC_LAST_WAY : SMMUTLB::ALLOC_ANY_BUT_LAST_WAY;
46014039Sstacze01@arm.com
46114039Sstacze01@arm.com    doSemaphoreDown(yield, ifc.mainTLBSem);
46214039Sstacze01@arm.com
46314039Sstacze01@arm.com    DPRINTF(SMMUv3,
46414039Sstacze01@arm.com            "SLAVE Interface upd vaddr=%#x amask=%#x paddr=%#x sid=%#x "
46514039Sstacze01@arm.com            "ssid=%#x\n", e.va, e.vaMask, e.pa, e.sid, e.ssid);
46614039Sstacze01@arm.com
46714039Sstacze01@arm.com    ifc.mainTLB->store(e, alloc);
46814039Sstacze01@arm.com
46914039Sstacze01@arm.com    doSemaphoreUp(ifc.mainTLBSem);
47014039Sstacze01@arm.com}
47114039Sstacze01@arm.com
47214039Sstacze01@arm.comvoid
47314039Sstacze01@arm.comSMMUTranslationProcess::smmuTLBUpdate(Yield &yield,
47414039Sstacze01@arm.com                                      const TranslResult &tr)
47514039Sstacze01@arm.com{
47614039Sstacze01@arm.com    assert(tr.fault == FAULT_NONE);
47714039Sstacze01@arm.com
47814039Sstacze01@arm.com    if (!smmu.tlbEnable)
47914039Sstacze01@arm.com        return;
48014039Sstacze01@arm.com
48114039Sstacze01@arm.com    ARMArchTLB::Entry e;
48214039Sstacze01@arm.com    e.valid = true;
48314039Sstacze01@arm.com    e.vaMask = tr.addrMask;
48414039Sstacze01@arm.com    e.va = request.addr & e.vaMask;
48514039Sstacze01@arm.com    e.asid = context.asid;
48614039Sstacze01@arm.com    e.vmid = context.vmid;
48714039Sstacze01@arm.com    e.pa = tr.addr & e.vaMask;
48814039Sstacze01@arm.com    e.permissions = tr.writable;
48914039Sstacze01@arm.com
49014039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.tlbSem);
49114039Sstacze01@arm.com
49214039Sstacze01@arm.com    DPRINTF(SMMUv3,
49314039Sstacze01@arm.com            "SMMU TLB upd vaddr=%#x amask=%#x paddr=%#x asid=%#x vmid=%#x\n",
49414039Sstacze01@arm.com            e.va, e.vaMask, e.pa, e.asid, e.vmid);
49514039Sstacze01@arm.com
49614039Sstacze01@arm.com    smmu.tlb.store(e);
49714039Sstacze01@arm.com
49814039Sstacze01@arm.com    doSemaphoreUp(smmu.tlbSem);
49914039Sstacze01@arm.com}
50014039Sstacze01@arm.com
50114039Sstacze01@arm.combool
50214039Sstacze01@arm.comSMMUTranslationProcess::configCacheLookup(Yield &yield, TranslContext &tc)
50314039Sstacze01@arm.com{
50414039Sstacze01@arm.com    if (!smmu.configCacheEnable)
50514039Sstacze01@arm.com        return false;
50614039Sstacze01@arm.com
50714039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.configSem);
50814039Sstacze01@arm.com    doDelay(yield, smmu.configLat);
50914039Sstacze01@arm.com    const ConfigCache::Entry *e =
51014039Sstacze01@arm.com        smmu.configCache.lookup(request.sid, request.ssid);
51114039Sstacze01@arm.com    doSemaphoreUp(smmu.configSem);
51214039Sstacze01@arm.com
51314039Sstacze01@arm.com    if (!e) {
51414039Sstacze01@arm.com        DPRINTF(SMMUv3, "Config miss sid=%#x ssid=%#x\n",
51514039Sstacze01@arm.com                request.sid, request.ssid);
51614039Sstacze01@arm.com
51714039Sstacze01@arm.com        return false;
51814039Sstacze01@arm.com    }
51914039Sstacze01@arm.com
52014039Sstacze01@arm.com    DPRINTF(SMMUv3, "Config hit sid=%#x ssid=%#x ttb=%#08x asid=%#x\n",
52114039Sstacze01@arm.com            request.sid, request.ssid, e->ttb0, e->asid);
52214039Sstacze01@arm.com
52314039Sstacze01@arm.com    tc.stage1Enable = e->stage1_en;
52414039Sstacze01@arm.com    tc.stage2Enable = e->stage2_en;
52514039Sstacze01@arm.com
52614039Sstacze01@arm.com    tc.ttb0 = e->ttb0;
52714039Sstacze01@arm.com    tc.ttb1 = e->ttb1;
52814039Sstacze01@arm.com    tc.asid = e->asid;
52914039Sstacze01@arm.com    tc.httb = e->httb;
53014039Sstacze01@arm.com    tc.vmid = e->vmid;
53114039Sstacze01@arm.com
53214039Sstacze01@arm.com    tc.stage1TranslGranule = e->stage1_tg;
53314039Sstacze01@arm.com    tc.stage2TranslGranule = e->stage2_tg;
53414039Sstacze01@arm.com
53514101Sgiacomo.travaglini@arm.com    tc.t0sz = e->t0sz;
53614101Sgiacomo.travaglini@arm.com    tc.s2t0sz = e->s2t0sz;
53714101Sgiacomo.travaglini@arm.com
53814039Sstacze01@arm.com    return true;
53914039Sstacze01@arm.com}
54014039Sstacze01@arm.com
54114039Sstacze01@arm.comvoid
54214039Sstacze01@arm.comSMMUTranslationProcess::configCacheUpdate(Yield &yield,
54314039Sstacze01@arm.com                                          const TranslContext &tc)
54414039Sstacze01@arm.com{
54514039Sstacze01@arm.com    if (!smmu.configCacheEnable)
54614039Sstacze01@arm.com        return;
54714039Sstacze01@arm.com
54814039Sstacze01@arm.com    ConfigCache::Entry e;
54914039Sstacze01@arm.com    e.valid = true;
55014039Sstacze01@arm.com    e.sid = request.sid;
55114039Sstacze01@arm.com    e.ssid = request.ssid;
55214039Sstacze01@arm.com    e.stage1_en = tc.stage1Enable;
55314039Sstacze01@arm.com    e.stage2_en = tc.stage2Enable;
55414039Sstacze01@arm.com    e.ttb0 = tc.ttb0;
55514039Sstacze01@arm.com    e.ttb1 = tc.ttb1;
55614039Sstacze01@arm.com    e.asid = tc.asid;
55714039Sstacze01@arm.com    e.httb = tc.httb;
55814039Sstacze01@arm.com    e.vmid = tc.vmid;
55914039Sstacze01@arm.com    e.stage1_tg = tc.stage1TranslGranule;
56014039Sstacze01@arm.com    e.stage2_tg = tc.stage2TranslGranule;
56114101Sgiacomo.travaglini@arm.com    e.t0sz = tc.t0sz;
56214101Sgiacomo.travaglini@arm.com    e.s2t0sz = tc.s2t0sz;
56314039Sstacze01@arm.com
56414039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.configSem);
56514039Sstacze01@arm.com
56614039Sstacze01@arm.com    DPRINTF(SMMUv3, "Config upd  sid=%#x ssid=%#x\n", e.sid, e.ssid);
56714039Sstacze01@arm.com
56814039Sstacze01@arm.com    smmu.configCache.store(e);
56914039Sstacze01@arm.com
57014039Sstacze01@arm.com    doSemaphoreUp(smmu.configSem);
57114039Sstacze01@arm.com}
57214039Sstacze01@arm.com
57314039Sstacze01@arm.combool
57414039Sstacze01@arm.comSMMUTranslationProcess::findConfig(Yield &yield,
57514039Sstacze01@arm.com                                   TranslContext &tc,
57614039Sstacze01@arm.com                                   TranslResult &tr)
57714039Sstacze01@arm.com{
57814039Sstacze01@arm.com    tc.stage1Enable = false;
57914039Sstacze01@arm.com    tc.stage2Enable = false;
58014039Sstacze01@arm.com
58114039Sstacze01@arm.com    StreamTableEntry ste;
58214039Sstacze01@arm.com    doReadSTE(yield, ste, request.sid);
58314039Sstacze01@arm.com
58414039Sstacze01@arm.com    switch (ste.dw0.config) {
58514039Sstacze01@arm.com        case STE_CONFIG_BYPASS:
58614039Sstacze01@arm.com            break;
58714039Sstacze01@arm.com
58814039Sstacze01@arm.com        case STE_CONFIG_STAGE1_ONLY:
58914039Sstacze01@arm.com            tc.stage1Enable = true;
59014039Sstacze01@arm.com            break;
59114039Sstacze01@arm.com
59214039Sstacze01@arm.com        case STE_CONFIG_STAGE2_ONLY:
59314039Sstacze01@arm.com            tc.stage2Enable = true;
59414039Sstacze01@arm.com            break;
59514039Sstacze01@arm.com
59614039Sstacze01@arm.com        case STE_CONFIG_STAGE1_AND_2:
59714039Sstacze01@arm.com            tc.stage1Enable = true;
59814039Sstacze01@arm.com            tc.stage2Enable = true;
59914039Sstacze01@arm.com            break;
60014039Sstacze01@arm.com
60114039Sstacze01@arm.com        default:
60214039Sstacze01@arm.com            panic("Bad or unimplemented STE config %d\n",
60314039Sstacze01@arm.com                ste.dw0.config);
60414039Sstacze01@arm.com    }
60514039Sstacze01@arm.com
60614039Sstacze01@arm.com
60714039Sstacze01@arm.com    // Establish stage 2 context first since
60814039Sstacze01@arm.com    // Context Descriptors can be in IPA space.
60914039Sstacze01@arm.com    if (tc.stage2Enable) {
61014039Sstacze01@arm.com        tc.httb = ste.dw3.s2ttb << STE_S2TTB_SHIFT;
61114039Sstacze01@arm.com        tc.vmid = ste.dw2.s2vmid;
61214039Sstacze01@arm.com        tc.stage2TranslGranule = ste.dw2.s2tg;
61314100Sgiacomo.travaglini@arm.com        tc.s2t0sz = ste.dw2.s2t0sz;
61414039Sstacze01@arm.com    } else {
61514039Sstacze01@arm.com        tc.httb = 0xdeadbeef;
61614039Sstacze01@arm.com        tc.vmid = 0;
61714039Sstacze01@arm.com        tc.stage2TranslGranule = TRANS_GRANULE_INVALID;
61814100Sgiacomo.travaglini@arm.com        tc.s2t0sz = 0;
61914039Sstacze01@arm.com    }
62014039Sstacze01@arm.com
62114039Sstacze01@arm.com
62214039Sstacze01@arm.com    // Now fetch stage 1 config.
62314039Sstacze01@arm.com    if (context.stage1Enable) {
62414039Sstacze01@arm.com        ContextDescriptor cd;
62514039Sstacze01@arm.com        doReadCD(yield, cd, ste, request.sid, request.ssid);
62614039Sstacze01@arm.com
62714039Sstacze01@arm.com        tc.ttb0 = cd.dw1.ttb0 << CD_TTB_SHIFT;
62814039Sstacze01@arm.com        tc.ttb1 = cd.dw2.ttb1 << CD_TTB_SHIFT;
62914039Sstacze01@arm.com        tc.asid = cd.dw0.asid;
63014039Sstacze01@arm.com        tc.stage1TranslGranule = cd.dw0.tg0;
63114100Sgiacomo.travaglini@arm.com        tc.t0sz = cd.dw0.t0sz;
63214039Sstacze01@arm.com    } else {
63314039Sstacze01@arm.com        tc.ttb0 = 0xcafebabe;
63414039Sstacze01@arm.com        tc.ttb1 = 0xcafed00d;
63514039Sstacze01@arm.com        tc.asid = 0;
63614039Sstacze01@arm.com        tc.stage1TranslGranule = TRANS_GRANULE_INVALID;
63714100Sgiacomo.travaglini@arm.com        tc.t0sz = 0;
63814039Sstacze01@arm.com    }
63914039Sstacze01@arm.com
64014039Sstacze01@arm.com    return true;
64114039Sstacze01@arm.com}
64214039Sstacze01@arm.com
64314039Sstacze01@arm.comvoid
64414039Sstacze01@arm.comSMMUTranslationProcess::walkCacheLookup(
64514039Sstacze01@arm.com        Yield &yield,
64614039Sstacze01@arm.com        const WalkCache::Entry *&walkEntry,
64714039Sstacze01@arm.com        Addr addr, uint16_t asid, uint16_t vmid,
64814039Sstacze01@arm.com        unsigned stage, unsigned level)
64914039Sstacze01@arm.com{
65014039Sstacze01@arm.com    const char *indent = stage==2 ? "  " : "";
65114039Sstacze01@arm.com    (void) indent; // this is only used in DPRINTFs
65214039Sstacze01@arm.com
65314039Sstacze01@arm.com    const PageTableOps *pt_ops =
65414039Sstacze01@arm.com        stage == 1 ?
65514039Sstacze01@arm.com            smmu.getPageTableOps(context.stage1TranslGranule) :
65614039Sstacze01@arm.com            smmu.getPageTableOps(context.stage2TranslGranule);
65714039Sstacze01@arm.com
65814039Sstacze01@arm.com    unsigned walkCacheLevels =
65914039Sstacze01@arm.com        smmu.walkCacheEnable ?
66014039Sstacze01@arm.com            (stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels) :
66114039Sstacze01@arm.com            0;
66214039Sstacze01@arm.com
66314039Sstacze01@arm.com    if ((1 << level) & walkCacheLevels) {
66414039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.walkSem);
66514039Sstacze01@arm.com        doDelay(yield, smmu.walkLat);
66614039Sstacze01@arm.com
66714039Sstacze01@arm.com        walkEntry = smmu.walkCache.lookup(addr, pt_ops->walkMask(level),
66814039Sstacze01@arm.com                                          asid, vmid, stage, level);
66914039Sstacze01@arm.com
67014039Sstacze01@arm.com        if (walkEntry) {
67114039Sstacze01@arm.com            DPRINTF(SMMUv3, "%sWalkCache hit  va=%#x asid=%#x vmid=%#x "
67214039Sstacze01@arm.com                            "base=%#x (S%d, L%d)\n",
67314039Sstacze01@arm.com                    indent, addr, asid, vmid, walkEntry->pa, stage, level);
67414039Sstacze01@arm.com        } else {
67514039Sstacze01@arm.com            DPRINTF(SMMUv3, "%sWalkCache miss va=%#x asid=%#x vmid=%#x "
67614039Sstacze01@arm.com                            "(S%d, L%d)\n",
67714039Sstacze01@arm.com                    indent, addr, asid, vmid, stage, level);
67814039Sstacze01@arm.com        }
67914039Sstacze01@arm.com
68014039Sstacze01@arm.com        doSemaphoreUp(smmu.walkSem);
68114039Sstacze01@arm.com    }
68214039Sstacze01@arm.com}
68314039Sstacze01@arm.com
68414039Sstacze01@arm.comvoid
68514039Sstacze01@arm.comSMMUTranslationProcess::walkCacheUpdate(Yield &yield, Addr va,
68614039Sstacze01@arm.com                                        Addr vaMask, Addr pa,
68714039Sstacze01@arm.com                                        unsigned stage, unsigned level,
68814039Sstacze01@arm.com                                        bool leaf, uint8_t permissions)
68914039Sstacze01@arm.com{
69014039Sstacze01@arm.com    unsigned walkCacheLevels =
69114039Sstacze01@arm.com        stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels;
69214039Sstacze01@arm.com
69314039Sstacze01@arm.com    if (smmu.walkCacheEnable && ((1<<level) & walkCacheLevels)) {
69414039Sstacze01@arm.com        WalkCache::Entry e;
69514039Sstacze01@arm.com        e.valid = true;
69614039Sstacze01@arm.com        e.va = va;
69714039Sstacze01@arm.com        e.vaMask = vaMask;
69814039Sstacze01@arm.com        e.asid = stage==1 ? context.asid : 0;
69914039Sstacze01@arm.com        e.vmid = context.vmid;
70014039Sstacze01@arm.com        e.stage = stage;
70114039Sstacze01@arm.com        e.level = level;
70214039Sstacze01@arm.com        e.leaf = leaf;
70314039Sstacze01@arm.com        e.pa = pa;
70414039Sstacze01@arm.com        e.permissions = permissions;
70514039Sstacze01@arm.com
70614039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.walkSem);
70714039Sstacze01@arm.com
70814039Sstacze01@arm.com        DPRINTF(SMMUv3, "%sWalkCache upd  va=%#x mask=%#x asid=%#x vmid=%#x "
70914039Sstacze01@arm.com                        "tpa=%#x leaf=%s (S%d, L%d)\n",
71014039Sstacze01@arm.com                e.stage==2 ? "  " : "",
71114039Sstacze01@arm.com                e.va, e.vaMask, e.asid, e.vmid,
71214039Sstacze01@arm.com                e.pa, e.leaf, e.stage, e.level);
71314039Sstacze01@arm.com
71414039Sstacze01@arm.com        smmu.walkCache.store(e);
71514039Sstacze01@arm.com
71614039Sstacze01@arm.com        doSemaphoreUp(smmu.walkSem);
71714039Sstacze01@arm.com    }
71814039Sstacze01@arm.com}
71914039Sstacze01@arm.com
72014039Sstacze01@arm.com/*
72114039Sstacze01@arm.com * Please note:
72214039Sstacze01@arm.com * This does not deal with the case where stage 1 page size
72314039Sstacze01@arm.com * is larger than stage 2 page size.
72414039Sstacze01@arm.com */
72514039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
72614039Sstacze01@arm.comSMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr,
72714039Sstacze01@arm.com                                       const PageTableOps *pt_ops,
72814039Sstacze01@arm.com                                       unsigned level, Addr walkPtr)
72914039Sstacze01@arm.com{
73014039Sstacze01@arm.com    PageTableOps::pte_t pte = 0;
73114039Sstacze01@arm.com
73214039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.cycleSem);
73314039Sstacze01@arm.com    doDelay(yield, Cycles(1));
73414039Sstacze01@arm.com    doSemaphoreUp(smmu.cycleSem);
73514039Sstacze01@arm.com
73614039Sstacze01@arm.com    for (; level <= pt_ops->lastLevel(); level++) {
73714039Sstacze01@arm.com        Addr pte_addr = walkPtr + pt_ops->index(addr, level);
73814039Sstacze01@arm.com
73914039Sstacze01@arm.com        DPRINTF(SMMUv3, "Fetching S1 L%d PTE from pa=%#08x\n",
74014039Sstacze01@arm.com                level, pte_addr);
74114039Sstacze01@arm.com
74214039Sstacze01@arm.com        doReadPTE(yield, addr, pte_addr, &pte, 1, level);
74314039Sstacze01@arm.com
74414039Sstacze01@arm.com        DPRINTF(SMMUv3, "Got S1 L%d PTE=%#x from pa=%#08x\n",
74514039Sstacze01@arm.com                level, pte, pte_addr);
74614039Sstacze01@arm.com
74714039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.cycleSem);
74814039Sstacze01@arm.com        doDelay(yield, Cycles(1));
74914039Sstacze01@arm.com        doSemaphoreUp(smmu.cycleSem);
75014039Sstacze01@arm.com
75114039Sstacze01@arm.com        bool valid = pt_ops->isValid(pte, level);
75214039Sstacze01@arm.com        bool leaf  = pt_ops->isLeaf(pte, level);
75314039Sstacze01@arm.com
75414039Sstacze01@arm.com        if (!valid) {
75514039Sstacze01@arm.com            DPRINTF(SMMUv3, "S1 PTE not valid - fault\n");
75614039Sstacze01@arm.com
75714039Sstacze01@arm.com            TranslResult tr;
75814039Sstacze01@arm.com            tr.fault = FAULT_TRANSLATION;
75914039Sstacze01@arm.com            return tr;
76014039Sstacze01@arm.com        }
76114039Sstacze01@arm.com
76214039Sstacze01@arm.com        if (valid && leaf && request.isWrite &&
76314039Sstacze01@arm.com            !pt_ops->isWritable(pte, level, false))
76414039Sstacze01@arm.com        {
76514039Sstacze01@arm.com            DPRINTF(SMMUv3, "S1 page not writable - fault\n");
76614039Sstacze01@arm.com
76714039Sstacze01@arm.com            TranslResult tr;
76814039Sstacze01@arm.com            tr.fault = FAULT_PERMISSION;
76914039Sstacze01@arm.com            return tr;
77014039Sstacze01@arm.com        }
77114039Sstacze01@arm.com
77214039Sstacze01@arm.com        walkPtr = pt_ops->nextLevelPointer(pte, level);
77314039Sstacze01@arm.com
77414039Sstacze01@arm.com        if (leaf)
77514039Sstacze01@arm.com            break;
77614039Sstacze01@arm.com
77714039Sstacze01@arm.com        if (context.stage2Enable) {
77814039Sstacze01@arm.com            TranslResult s2tr = translateStage2(yield, walkPtr, false);
77914039Sstacze01@arm.com            if (s2tr.fault != FAULT_NONE)
78014039Sstacze01@arm.com                return s2tr;
78114039Sstacze01@arm.com
78214039Sstacze01@arm.com            walkPtr = s2tr.addr;
78314039Sstacze01@arm.com        }
78414039Sstacze01@arm.com
78514039Sstacze01@arm.com        walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr,
78614039Sstacze01@arm.com                        1, level, leaf, 0);
78714039Sstacze01@arm.com    }
78814039Sstacze01@arm.com
78914039Sstacze01@arm.com    TranslResult tr;
79014039Sstacze01@arm.com    tr.fault    = FAULT_NONE;
79114039Sstacze01@arm.com    tr.addrMask = pt_ops->pageMask(pte, level);
79214039Sstacze01@arm.com    tr.addr     = walkPtr + (addr & ~tr.addrMask);
79314039Sstacze01@arm.com    tr.writable = pt_ops->isWritable(pte, level, false);
79414039Sstacze01@arm.com
79514039Sstacze01@arm.com    if (context.stage2Enable) {
79614039Sstacze01@arm.com        TranslResult s2tr = translateStage2(yield, tr.addr, true);
79714039Sstacze01@arm.com        if (s2tr.fault != FAULT_NONE)
79814039Sstacze01@arm.com            return s2tr;
79914039Sstacze01@arm.com
80014039Sstacze01@arm.com        tr = combineTranslations(tr, s2tr);
80114039Sstacze01@arm.com    }
80214039Sstacze01@arm.com
80314039Sstacze01@arm.com    walkCacheUpdate(yield, addr, tr.addrMask, tr.addr,
80414039Sstacze01@arm.com                    1, level, true, tr.writable);
80514039Sstacze01@arm.com
80614039Sstacze01@arm.com    return tr;
80714039Sstacze01@arm.com}
80814039Sstacze01@arm.com
80914039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
81014039Sstacze01@arm.comSMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr,
81114039Sstacze01@arm.com                                   const PageTableOps *pt_ops,
81214039Sstacze01@arm.com                                   unsigned level, Addr walkPtr)
81314039Sstacze01@arm.com{
81414039Sstacze01@arm.com    PageTableOps::pte_t pte;
81514039Sstacze01@arm.com
81614039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.cycleSem);
81714039Sstacze01@arm.com    doDelay(yield, Cycles(1));
81814039Sstacze01@arm.com    doSemaphoreUp(smmu.cycleSem);
81914039Sstacze01@arm.com
82014039Sstacze01@arm.com    for (; level <= pt_ops->lastLevel(); level++) {
82114039Sstacze01@arm.com        Addr pte_addr = walkPtr + pt_ops->index(addr, level);
82214039Sstacze01@arm.com
82314039Sstacze01@arm.com        DPRINTF(SMMUv3, "  Fetching S2 L%d PTE from pa=%#08x\n",
82414039Sstacze01@arm.com                level, pte_addr);
82514039Sstacze01@arm.com
82614039Sstacze01@arm.com        doReadPTE(yield, addr, pte_addr, &pte, 2, level);
82714039Sstacze01@arm.com
82814039Sstacze01@arm.com        DPRINTF(SMMUv3, "  Got S2 L%d PTE=%#x from pa=%#08x\n",
82914039Sstacze01@arm.com                level, pte, pte_addr);
83014039Sstacze01@arm.com
83114039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.cycleSem);
83214039Sstacze01@arm.com        doDelay(yield, Cycles(1));
83314039Sstacze01@arm.com        doSemaphoreUp(smmu.cycleSem);
83414039Sstacze01@arm.com
83514039Sstacze01@arm.com        bool valid = pt_ops->isValid(pte, level);
83614039Sstacze01@arm.com        bool leaf  = pt_ops->isLeaf(pte, level);
83714039Sstacze01@arm.com
83814039Sstacze01@arm.com        if (!valid) {
83914039Sstacze01@arm.com            DPRINTF(SMMUv3, "  S2 PTE not valid - fault\n");
84014039Sstacze01@arm.com
84114039Sstacze01@arm.com            TranslResult tr;
84214039Sstacze01@arm.com            tr.fault = FAULT_TRANSLATION;
84314039Sstacze01@arm.com            return tr;
84414039Sstacze01@arm.com        }
84514039Sstacze01@arm.com
84614039Sstacze01@arm.com        if (valid && leaf && request.isWrite &&
84714039Sstacze01@arm.com            !pt_ops->isWritable(pte, level, true))
84814039Sstacze01@arm.com        {
84914039Sstacze01@arm.com            DPRINTF(SMMUv3, "  S2 PTE not writable = fault\n");
85014039Sstacze01@arm.com
85114039Sstacze01@arm.com            TranslResult tr;
85214039Sstacze01@arm.com            tr.fault = FAULT_PERMISSION;
85314039Sstacze01@arm.com            return tr;
85414039Sstacze01@arm.com        }
85514039Sstacze01@arm.com
85614039Sstacze01@arm.com        walkPtr = pt_ops->nextLevelPointer(pte, level);
85714039Sstacze01@arm.com
85814039Sstacze01@arm.com        if (final_tr || smmu.walkCacheNonfinalEnable)
85914039Sstacze01@arm.com            walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr,
86014039Sstacze01@arm.com                            2, level, leaf,
86114039Sstacze01@arm.com                            leaf ? pt_ops->isWritable(pte, level, true) : 0);
86214039Sstacze01@arm.com        if (leaf)
86314039Sstacze01@arm.com            break;
86414039Sstacze01@arm.com    }
86514039Sstacze01@arm.com
86614039Sstacze01@arm.com    TranslResult tr;
86714039Sstacze01@arm.com    tr.fault    = FAULT_NONE;
86814039Sstacze01@arm.com    tr.addrMask = pt_ops->pageMask(pte, level);
86914039Sstacze01@arm.com    tr.addr     = walkPtr + (addr & ~tr.addrMask);
87014039Sstacze01@arm.com    tr.writable = pt_ops->isWritable(pte, level, true);
87114039Sstacze01@arm.com
87214039Sstacze01@arm.com    return tr;
87314039Sstacze01@arm.com}
87414039Sstacze01@arm.com
87514039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
87614039Sstacze01@arm.comSMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
87714039Sstacze01@arm.com{
87814039Sstacze01@arm.com    const PageTableOps *pt_ops =
87914039Sstacze01@arm.com        smmu.getPageTableOps(context.stage1TranslGranule);
88014039Sstacze01@arm.com
88114039Sstacze01@arm.com    const WalkCache::Entry *walk_ep = NULL;
88214039Sstacze01@arm.com    unsigned level;
88314039Sstacze01@arm.com
88414039Sstacze01@arm.com    // Level here is actually (level+1) so we can count down
88514039Sstacze01@arm.com    // to 0 using unsigned int.
88614039Sstacze01@arm.com    for (level = pt_ops->lastLevel() + 1;
88714100Sgiacomo.travaglini@arm.com        level > pt_ops->firstLevel(context.t0sz);
88814039Sstacze01@arm.com        level--)
88914039Sstacze01@arm.com    {
89014039Sstacze01@arm.com        walkCacheLookup(yield, walk_ep, addr,
89114039Sstacze01@arm.com                        context.asid, context.vmid, 1, level-1);
89214039Sstacze01@arm.com
89314039Sstacze01@arm.com        if (walk_ep)
89414039Sstacze01@arm.com            break;
89514039Sstacze01@arm.com    }
89614039Sstacze01@arm.com
89714039Sstacze01@arm.com    // Correct level (see above).
89814039Sstacze01@arm.com    level -= 1;
89914039Sstacze01@arm.com
90014039Sstacze01@arm.com    TranslResult tr;
90114039Sstacze01@arm.com    if (walk_ep) {
90214039Sstacze01@arm.com        if (walk_ep->leaf) {
90314039Sstacze01@arm.com            tr.fault    = FAULT_NONE;
90414039Sstacze01@arm.com            tr.addr     = walk_ep->pa + (addr & ~walk_ep->vaMask);
90514039Sstacze01@arm.com            tr.addrMask = walk_ep->vaMask;
90614039Sstacze01@arm.com            tr.writable = walk_ep->permissions;
90714039Sstacze01@arm.com        } else {
90814039Sstacze01@arm.com            tr = walkStage1And2(yield, addr, pt_ops, level+1, walk_ep->pa);
90914039Sstacze01@arm.com        }
91014039Sstacze01@arm.com    } else {
91114039Sstacze01@arm.com        Addr table_addr = context.ttb0;
91214039Sstacze01@arm.com        if (context.stage2Enable) {
91314039Sstacze01@arm.com            TranslResult s2tr = translateStage2(yield, table_addr, false);
91414039Sstacze01@arm.com            if (s2tr.fault != FAULT_NONE)
91514039Sstacze01@arm.com                return s2tr;
91614039Sstacze01@arm.com
91714039Sstacze01@arm.com            table_addr = s2tr.addr;
91814039Sstacze01@arm.com        }
91914039Sstacze01@arm.com
92014100Sgiacomo.travaglini@arm.com        tr = walkStage1And2(yield, addr, pt_ops,
92114100Sgiacomo.travaglini@arm.com                            pt_ops->firstLevel(context.t0sz),
92214039Sstacze01@arm.com                            table_addr);
92314039Sstacze01@arm.com    }
92414039Sstacze01@arm.com
92514039Sstacze01@arm.com    if (tr.fault == FAULT_NONE)
92614039Sstacze01@arm.com        DPRINTF(SMMUv3, "Translated vaddr %#x to paddr %#x\n", addr, tr.addr);
92714039Sstacze01@arm.com
92814039Sstacze01@arm.com    return tr;
92914039Sstacze01@arm.com}
93014039Sstacze01@arm.com
93114039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
93214039Sstacze01@arm.comSMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
93314039Sstacze01@arm.com{
93414039Sstacze01@arm.com    const PageTableOps *pt_ops =
93514039Sstacze01@arm.com            smmu.getPageTableOps(context.stage2TranslGranule);
93614039Sstacze01@arm.com
93714039Sstacze01@arm.com    const IPACache::Entry *ipa_ep = NULL;
93814039Sstacze01@arm.com    if (smmu.ipaCacheEnable) {
93914039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.ipaSem);
94014039Sstacze01@arm.com        doDelay(yield, smmu.ipaLat);
94114039Sstacze01@arm.com        ipa_ep = smmu.ipaCache.lookup(addr, context.vmid);
94214039Sstacze01@arm.com        doSemaphoreUp(smmu.ipaSem);
94314039Sstacze01@arm.com    }
94414039Sstacze01@arm.com
94514039Sstacze01@arm.com    if (ipa_ep) {
94614039Sstacze01@arm.com        TranslResult tr;
94714039Sstacze01@arm.com        tr.fault    = FAULT_NONE;
94814039Sstacze01@arm.com        tr.addr     = ipa_ep->pa + (addr & ~ipa_ep->ipaMask);
94914039Sstacze01@arm.com        tr.addrMask = ipa_ep->ipaMask;
95014039Sstacze01@arm.com        tr.writable = ipa_ep->permissions;
95114039Sstacze01@arm.com
95214039Sstacze01@arm.com        DPRINTF(SMMUv3, "  IPACache hit  ipa=%#x vmid=%#x pa=%#x\n",
95314039Sstacze01@arm.com            addr, context.vmid, tr.addr);
95414039Sstacze01@arm.com
95514039Sstacze01@arm.com        return tr;
95614039Sstacze01@arm.com    } else if (smmu.ipaCacheEnable) {
95714039Sstacze01@arm.com        DPRINTF(SMMUv3, "  IPACache miss ipa=%#x vmid=%#x\n",
95814039Sstacze01@arm.com                addr, context.vmid);
95914039Sstacze01@arm.com    }
96014039Sstacze01@arm.com
96114039Sstacze01@arm.com    const WalkCache::Entry *walk_ep = NULL;
96214100Sgiacomo.travaglini@arm.com    unsigned level = pt_ops->firstLevel(context.s2t0sz);
96314039Sstacze01@arm.com
96414039Sstacze01@arm.com    if (final_tr || smmu.walkCacheNonfinalEnable) {
96514039Sstacze01@arm.com        // Level here is actually (level+1) so we can count down
96614039Sstacze01@arm.com        // to 0 using unsigned int.
96714039Sstacze01@arm.com        for (level = pt_ops->lastLevel() + 1;
96814100Sgiacomo.travaglini@arm.com            level > pt_ops->firstLevel(context.s2t0sz);
96914039Sstacze01@arm.com            level--)
97014039Sstacze01@arm.com        {
97114039Sstacze01@arm.com            walkCacheLookup(yield, walk_ep, addr,
97214039Sstacze01@arm.com                            0, context.vmid, 2, level-1);
97314039Sstacze01@arm.com
97414039Sstacze01@arm.com            if (walk_ep)
97514039Sstacze01@arm.com                break;
97614039Sstacze01@arm.com        }
97714039Sstacze01@arm.com
97814039Sstacze01@arm.com        // Correct level (see above).
97914039Sstacze01@arm.com        level -= 1;
98014039Sstacze01@arm.com    }
98114039Sstacze01@arm.com
98214039Sstacze01@arm.com    TranslResult tr;
98314039Sstacze01@arm.com    if (walk_ep) {
98414039Sstacze01@arm.com        if (walk_ep->leaf) {
98514039Sstacze01@arm.com            tr.fault    = FAULT_NONE;
98614039Sstacze01@arm.com            tr.addr     = walk_ep->pa + (addr & ~walk_ep->vaMask);
98714039Sstacze01@arm.com            tr.addrMask = walk_ep->vaMask;
98814039Sstacze01@arm.com            tr.writable = walk_ep->permissions;
98914039Sstacze01@arm.com        } else {
99014039Sstacze01@arm.com            tr = walkStage2(yield, addr, final_tr, pt_ops,
99114039Sstacze01@arm.com                            level + 1, walk_ep->pa);
99214039Sstacze01@arm.com        }
99314039Sstacze01@arm.com    } else {
99414100Sgiacomo.travaglini@arm.com        tr = walkStage2(yield, addr, final_tr, pt_ops,
99514100Sgiacomo.travaglini@arm.com                        pt_ops->firstLevel(context.s2t0sz),
99614039Sstacze01@arm.com                        context.httb);
99714039Sstacze01@arm.com    }
99814039Sstacze01@arm.com
99914039Sstacze01@arm.com    if (tr.fault == FAULT_NONE)
100014039Sstacze01@arm.com        DPRINTF(SMMUv3, "  Translated %saddr %#x to paddr %#x\n",
100114039Sstacze01@arm.com            context.stage1Enable ? "ip" : "v", addr, tr.addr);
100214039Sstacze01@arm.com
100314039Sstacze01@arm.com    if (smmu.ipaCacheEnable) {
100414039Sstacze01@arm.com        IPACache::Entry e;
100514039Sstacze01@arm.com        e.valid = true;
100614039Sstacze01@arm.com        e.ipaMask = tr.addrMask;
100714039Sstacze01@arm.com        e.ipa = addr & e.ipaMask;
100814039Sstacze01@arm.com        e.pa = tr.addr & tr.addrMask;
100914039Sstacze01@arm.com        e.permissions = tr.writable;
101014039Sstacze01@arm.com        e.vmid = context.vmid;
101114039Sstacze01@arm.com
101214039Sstacze01@arm.com        doSemaphoreDown(yield, smmu.ipaSem);
101314039Sstacze01@arm.com        smmu.ipaCache.store(e);
101414039Sstacze01@arm.com        doSemaphoreUp(smmu.ipaSem);
101514039Sstacze01@arm.com    }
101614039Sstacze01@arm.com
101714039Sstacze01@arm.com    return tr;
101814039Sstacze01@arm.com}
101914039Sstacze01@arm.com
102014039Sstacze01@arm.comSMMUTranslationProcess::TranslResult
102114039Sstacze01@arm.comSMMUTranslationProcess::combineTranslations(const TranslResult &s1tr,
102214039Sstacze01@arm.com                                            const TranslResult &s2tr) const
102314039Sstacze01@arm.com{
102414039Sstacze01@arm.com    if (s2tr.fault != FAULT_NONE)
102514039Sstacze01@arm.com        return s2tr;
102614039Sstacze01@arm.com
102714039Sstacze01@arm.com    assert(s1tr.fault == FAULT_NONE);
102814039Sstacze01@arm.com
102914039Sstacze01@arm.com    TranslResult tr;
103014039Sstacze01@arm.com    tr.fault    = FAULT_NONE;
103114039Sstacze01@arm.com    tr.addr     = s2tr.addr;
103214039Sstacze01@arm.com    tr.addrMask = s1tr.addrMask | s2tr.addrMask;
103314039Sstacze01@arm.com    tr.writable = s1tr.writable & s2tr.writable;
103414039Sstacze01@arm.com
103514039Sstacze01@arm.com    return tr;
103614039Sstacze01@arm.com}
103714039Sstacze01@arm.com
103814039Sstacze01@arm.combool
103914039Sstacze01@arm.comSMMUTranslationProcess::hazard4kCheck()
104014039Sstacze01@arm.com{
104114039Sstacze01@arm.com    Addr addr4k = request.addr & ~0xfffULL;
104214039Sstacze01@arm.com
104314039Sstacze01@arm.com    for (auto it = ifc.duplicateReqs.begin();
104414039Sstacze01@arm.com         it != ifc.duplicateReqs.end();
104514039Sstacze01@arm.com         ++it)
104614039Sstacze01@arm.com    {
104714039Sstacze01@arm.com        Addr other4k = (*it)->request.addr & ~0xfffULL;
104814039Sstacze01@arm.com        if (addr4k == other4k)
104914039Sstacze01@arm.com            return true;
105014039Sstacze01@arm.com    }
105114039Sstacze01@arm.com
105214039Sstacze01@arm.com    return false;
105314039Sstacze01@arm.com}
105414039Sstacze01@arm.com
105514039Sstacze01@arm.comvoid
105614039Sstacze01@arm.comSMMUTranslationProcess::hazard4kRegister()
105714039Sstacze01@arm.com{
105814039Sstacze01@arm.com    DPRINTF(SMMUv3Hazard, "4kReg:  p=%p a4k=%#x\n",
105914039Sstacze01@arm.com            this, request.addr & ~0xfffULL);
106014039Sstacze01@arm.com
106114039Sstacze01@arm.com    ifc.duplicateReqs.push_back(this);
106214039Sstacze01@arm.com}
106314039Sstacze01@arm.com
106414039Sstacze01@arm.comvoid
106514039Sstacze01@arm.comSMMUTranslationProcess::hazard4kHold(Yield &yield)
106614039Sstacze01@arm.com{
106714039Sstacze01@arm.com    Addr addr4k = request.addr & ~0xfffULL;
106814039Sstacze01@arm.com
106914039Sstacze01@arm.com    bool found_hazard;
107014039Sstacze01@arm.com
107114039Sstacze01@arm.com    do {
107214039Sstacze01@arm.com        found_hazard = false;
107314039Sstacze01@arm.com
107414039Sstacze01@arm.com        for (auto it = ifc.duplicateReqs.begin();
107514039Sstacze01@arm.com             it!=ifc.duplicateReqs.end() && *it!=this;
107614039Sstacze01@arm.com             ++it)
107714039Sstacze01@arm.com        {
107814039Sstacze01@arm.com            Addr other4k = (*it)->request.addr & ~0xfffULL;
107914039Sstacze01@arm.com
108014039Sstacze01@arm.com            DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x Q: p=%p a4k=%#x\n",
108114039Sstacze01@arm.com                    this, addr4k, *it, other4k);
108214039Sstacze01@arm.com
108314039Sstacze01@arm.com            if (addr4k == other4k) {
108414039Sstacze01@arm.com                DPRINTF(SMMUv3Hazard,
108514039Sstacze01@arm.com                        "4kHold: p=%p a4k=%#x WAIT on p=%p a4k=%#x\n",
108614039Sstacze01@arm.com                        this, addr4k, *it, other4k);
108714039Sstacze01@arm.com
108814039Sstacze01@arm.com                doWaitForSignal(yield, ifc.duplicateReqRemoved);
108914039Sstacze01@arm.com
109014039Sstacze01@arm.com                DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x RESUME\n",
109114039Sstacze01@arm.com                        this, addr4k);
109214039Sstacze01@arm.com
109314039Sstacze01@arm.com                // This is to avoid checking *it!=this after doWaitForSignal()
109414039Sstacze01@arm.com                // since it could have been deleted.
109514039Sstacze01@arm.com                found_hazard = true;
109614039Sstacze01@arm.com                break;
109714039Sstacze01@arm.com            }
109814039Sstacze01@arm.com        }
109914039Sstacze01@arm.com    } while (found_hazard);
110014039Sstacze01@arm.com}
110114039Sstacze01@arm.com
110214039Sstacze01@arm.comvoid
110314039Sstacze01@arm.comSMMUTranslationProcess::hazard4kRelease()
110414039Sstacze01@arm.com{
110514039Sstacze01@arm.com    DPRINTF(SMMUv3Hazard, "4kRel:  p=%p a4k=%#x\n",
110614039Sstacze01@arm.com            this, request.addr & ~0xfffULL);
110714039Sstacze01@arm.com
110814039Sstacze01@arm.com    std::list<SMMUTranslationProcess *>::iterator it;
110914039Sstacze01@arm.com
111014039Sstacze01@arm.com    for (it = ifc.duplicateReqs.begin(); it != ifc.duplicateReqs.end(); ++it)
111114039Sstacze01@arm.com        if (*it == this)
111214039Sstacze01@arm.com            break;
111314039Sstacze01@arm.com
111414039Sstacze01@arm.com    if (it == ifc.duplicateReqs.end())
111514039Sstacze01@arm.com        panic("hazard4kRelease: request not found");
111614039Sstacze01@arm.com
111714039Sstacze01@arm.com    ifc.duplicateReqs.erase(it);
111814039Sstacze01@arm.com
111914039Sstacze01@arm.com    doBroadcastSignal(ifc.duplicateReqRemoved);
112014039Sstacze01@arm.com}
112114039Sstacze01@arm.com
112214039Sstacze01@arm.comvoid
112314039Sstacze01@arm.comSMMUTranslationProcess::hazardIdRegister()
112414039Sstacze01@arm.com{
112514039Sstacze01@arm.com    auto orderId = AMBA::orderId(request.pkt);
112614039Sstacze01@arm.com
112714039Sstacze01@arm.com    DPRINTF(SMMUv3Hazard, "IdReg:  p=%p oid=%d\n", this, orderId);
112814039Sstacze01@arm.com
112914039Sstacze01@arm.com    assert(orderId < SMMU_MAX_TRANS_ID);
113014039Sstacze01@arm.com
113114039Sstacze01@arm.com    std::list<SMMUTranslationProcess *> &depReqs =
113214039Sstacze01@arm.com        request.isWrite ?
113314039Sstacze01@arm.com            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
113414039Sstacze01@arm.com    depReqs.push_back(this);
113514039Sstacze01@arm.com}
113614039Sstacze01@arm.com
113714039Sstacze01@arm.comvoid
113814039Sstacze01@arm.comSMMUTranslationProcess::hazardIdHold(Yield &yield)
113914039Sstacze01@arm.com{
114014039Sstacze01@arm.com    auto orderId = AMBA::orderId(request.pkt);
114114039Sstacze01@arm.com
114214039Sstacze01@arm.com    DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d\n", this, orderId);
114314039Sstacze01@arm.com
114414039Sstacze01@arm.com    std::list<SMMUTranslationProcess *> &depReqs =
114514039Sstacze01@arm.com        request.isWrite ?
114614039Sstacze01@arm.com            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
114714039Sstacze01@arm.com    std::list<SMMUTranslationProcess *>::iterator it;
114814039Sstacze01@arm.com
114914039Sstacze01@arm.com    bool found_hazard;
115014039Sstacze01@arm.com
115114039Sstacze01@arm.com    do {
115214039Sstacze01@arm.com        found_hazard = false;
115314039Sstacze01@arm.com
115414039Sstacze01@arm.com        for (auto it = depReqs.begin(); it!=depReqs.end() && *it!=this; ++it) {
115514039Sstacze01@arm.com            DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d Q: %p\n",
115614039Sstacze01@arm.com                    this, orderId, *it);
115714039Sstacze01@arm.com
115814039Sstacze01@arm.com            if (AMBA::orderId((*it)->request.pkt) == orderId) {
115914039Sstacze01@arm.com                DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d WAIT on=%p\n",
116014039Sstacze01@arm.com                        this, orderId, *it);
116114039Sstacze01@arm.com
116214039Sstacze01@arm.com                doWaitForSignal(yield, ifc.dependentReqRemoved);
116314039Sstacze01@arm.com
116414039Sstacze01@arm.com                DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d RESUME\n",
116514039Sstacze01@arm.com                        this, orderId);
116614039Sstacze01@arm.com
116714039Sstacze01@arm.com                // This is to avoid checking *it!=this after doWaitForSignal()
116814039Sstacze01@arm.com                // since it could have been deleted.
116914039Sstacze01@arm.com                found_hazard = true;
117014039Sstacze01@arm.com                break;
117114039Sstacze01@arm.com            }
117214039Sstacze01@arm.com        }
117314039Sstacze01@arm.com    } while (found_hazard);
117414039Sstacze01@arm.com}
117514039Sstacze01@arm.com
117614039Sstacze01@arm.comvoid
117714039Sstacze01@arm.comSMMUTranslationProcess::hazardIdRelease()
117814039Sstacze01@arm.com{
117914039Sstacze01@arm.com    auto orderId = AMBA::orderId(request.pkt);
118014039Sstacze01@arm.com
118114039Sstacze01@arm.com    DPRINTF(SMMUv3Hazard, "IdRel:  p=%p oid=%d\n", this, orderId);
118214039Sstacze01@arm.com
118314039Sstacze01@arm.com    std::list<SMMUTranslationProcess *> &depReqs =
118414039Sstacze01@arm.com        request.isWrite ?
118514039Sstacze01@arm.com            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
118614039Sstacze01@arm.com    std::list<SMMUTranslationProcess *>::iterator it;
118714039Sstacze01@arm.com
118814039Sstacze01@arm.com    for (it = depReqs.begin(); it != depReqs.end(); ++it) {
118914039Sstacze01@arm.com        if (*it == this)
119014039Sstacze01@arm.com            break;
119114039Sstacze01@arm.com    }
119214039Sstacze01@arm.com
119314039Sstacze01@arm.com    if (it == depReqs.end())
119414039Sstacze01@arm.com        panic("hazardIdRelease: request not found");
119514039Sstacze01@arm.com
119614039Sstacze01@arm.com    depReqs.erase(it);
119714039Sstacze01@arm.com
119814039Sstacze01@arm.com    doBroadcastSignal(ifc.dependentReqRemoved);
119914039Sstacze01@arm.com}
120014039Sstacze01@arm.com
120114039Sstacze01@arm.comvoid
120214039Sstacze01@arm.comSMMUTranslationProcess::issuePrefetch(Addr addr)
120314039Sstacze01@arm.com{
120414039Sstacze01@arm.com    if (!smmu.system.isTimingMode())
120514039Sstacze01@arm.com        return;
120614039Sstacze01@arm.com
120714039Sstacze01@arm.com    if (!ifc.prefetchEnable || ifc.xlateSlotsRemaining == 0)
120814039Sstacze01@arm.com        return;
120914039Sstacze01@arm.com
121014039Sstacze01@arm.com    std::string proc_name = csprintf("%sprf", name());
121114039Sstacze01@arm.com    SMMUTranslationProcess *proc =
121214039Sstacze01@arm.com        new SMMUTranslationProcess(proc_name, smmu, ifc);
121314039Sstacze01@arm.com
121414039Sstacze01@arm.com    proc->beginTransaction(
121514039Sstacze01@arm.com            SMMUTranslRequest::prefetch(addr, request.sid, request.ssid));
121614039Sstacze01@arm.com    proc->scheduleWakeup(smmu.clockEdge(Cycles(1)));
121714039Sstacze01@arm.com}
121814039Sstacze01@arm.com
121914039Sstacze01@arm.comvoid
122014039Sstacze01@arm.comSMMUTranslationProcess::completeTransaction(Yield &yield,
122114039Sstacze01@arm.com                                            const TranslResult &tr)
122214039Sstacze01@arm.com{
122314039Sstacze01@arm.com    assert(tr.fault == FAULT_NONE);
122414039Sstacze01@arm.com
122514039Sstacze01@arm.com    unsigned numMasterBeats = request.isWrite ?
122614039Sstacze01@arm.com        (request.size + (smmu.masterPortWidth-1))
122714039Sstacze01@arm.com            / smmu.masterPortWidth :
122814039Sstacze01@arm.com        1;
122914039Sstacze01@arm.com
123014039Sstacze01@arm.com    doSemaphoreDown(yield, smmu.masterPortSem);
123114039Sstacze01@arm.com    doDelay(yield, Cycles(numMasterBeats));
123214039Sstacze01@arm.com    doSemaphoreUp(smmu.masterPortSem);
123314039Sstacze01@arm.com
123414039Sstacze01@arm.com
123514039Sstacze01@arm.com    smmu.translationTimeDist.sample(curTick() - recvTick);
123614039Sstacze01@arm.com    if (!request.isAtsRequest && request.isWrite)
123714039Sstacze01@arm.com        ifc.wrBufSlotsRemaining +=
123814039Sstacze01@arm.com            (request.size + (ifc.portWidth-1)) / ifc.portWidth;
123914039Sstacze01@arm.com
124014039Sstacze01@arm.com    smmu.scheduleSlaveRetries();
124114039Sstacze01@arm.com
124214039Sstacze01@arm.com
124314039Sstacze01@arm.com    SMMUAction a;
124414039Sstacze01@arm.com
124514039Sstacze01@arm.com    if (request.isAtsRequest) {
124614039Sstacze01@arm.com        a.type = ACTION_SEND_RESP_ATS;
124714039Sstacze01@arm.com
124814039Sstacze01@arm.com        if (smmu.system.isAtomicMode()) {
124914039Sstacze01@arm.com            request.pkt->makeAtomicResponse();
125014039Sstacze01@arm.com        } else if (smmu.system.isTimingMode()) {
125114039Sstacze01@arm.com            request.pkt->makeTimingResponse();
125214039Sstacze01@arm.com        } else {
125314039Sstacze01@arm.com            panic("Not in atomic or timing mode");
125414039Sstacze01@arm.com        }
125514039Sstacze01@arm.com    } else {
125614039Sstacze01@arm.com        a.type = ACTION_SEND_REQ_FINAL;
125714039Sstacze01@arm.com        a.ifc = &ifc;
125814039Sstacze01@arm.com    }
125914039Sstacze01@arm.com
126014039Sstacze01@arm.com    a.pkt = request.pkt;
126114039Sstacze01@arm.com    a.delay = 0;
126214039Sstacze01@arm.com
126314039Sstacze01@arm.com    a.pkt->setAddr(tr.addr);
126414039Sstacze01@arm.com    a.pkt->req->setPaddr(tr.addr);
126514039Sstacze01@arm.com
126614039Sstacze01@arm.com    yield(a);
126714039Sstacze01@arm.com
126814039Sstacze01@arm.com    if (!request.isAtsRequest) {
126914039Sstacze01@arm.com        PacketPtr pkt = yield.get();
127014039Sstacze01@arm.com        pkt->setAddr(request.addr);
127114039Sstacze01@arm.com
127214039Sstacze01@arm.com        a.type = ACTION_SEND_RESP;
127314039Sstacze01@arm.com        a.pkt = pkt;
127414039Sstacze01@arm.com        a.ifc = &ifc;
127514039Sstacze01@arm.com        a.delay = 0;
127614039Sstacze01@arm.com        yield(a);
127714039Sstacze01@arm.com    }
127814039Sstacze01@arm.com}
127914039Sstacze01@arm.com
128014039Sstacze01@arm.comvoid
128114039Sstacze01@arm.comSMMUTranslationProcess::completePrefetch(Yield &yield)
128214039Sstacze01@arm.com{
128314039Sstacze01@arm.com    SMMUAction a;
128414039Sstacze01@arm.com    a.type = ACTION_TERMINATE;
128514039Sstacze01@arm.com    a.pkt = NULL;
128614039Sstacze01@arm.com    a.ifc = &ifc;
128714039Sstacze01@arm.com    a.delay = 0;
128814039Sstacze01@arm.com    yield(a);
128914039Sstacze01@arm.com}
129014039Sstacze01@arm.com
129114039Sstacze01@arm.comvoid
129214039Sstacze01@arm.comSMMUTranslationProcess::sendEvent(Yield &yield, const SMMUEvent &ev)
129314039Sstacze01@arm.com{
129414065Sgiacomo.travaglini@arm.com    int sizeMask = mask(smmu.regs.eventq_base & Q_BASE_SIZE_MASK);
129514039Sstacze01@arm.com
129614039Sstacze01@arm.com    if (((smmu.regs.eventq_prod+1) & sizeMask) ==
129714039Sstacze01@arm.com            (smmu.regs.eventq_cons & sizeMask))
129814039Sstacze01@arm.com        panic("Event queue full - aborting\n");
129914039Sstacze01@arm.com
130014039Sstacze01@arm.com    Addr event_addr =
130114039Sstacze01@arm.com        (smmu.regs.eventq_base & Q_BASE_ADDR_MASK) +
130214039Sstacze01@arm.com        (smmu.regs.eventq_prod & sizeMask) * sizeof(ev);
130314039Sstacze01@arm.com
130414039Sstacze01@arm.com    DPRINTF(SMMUv3, "Sending event to addr=%#08x (pos=%d): type=%#x stag=%#x "
130514039Sstacze01@arm.com        "flags=%#x sid=%#x ssid=%#x va=%#08x ipa=%#x\n",
130614039Sstacze01@arm.com        event_addr, smmu.regs.eventq_prod, ev.type, ev.stag,
130714039Sstacze01@arm.com        ev.flags, ev.streamId, ev.substreamId, ev.va, ev.ipa);
130814039Sstacze01@arm.com
130914039Sstacze01@arm.com    // This deliberately resets the overflow field in eventq_prod!
131014039Sstacze01@arm.com    smmu.regs.eventq_prod = (smmu.regs.eventq_prod + 1) & sizeMask;
131114039Sstacze01@arm.com
131214039Sstacze01@arm.com    doWrite(yield, event_addr, &ev, sizeof(ev));
131314039Sstacze01@arm.com
131414039Sstacze01@arm.com    if (!(smmu.regs.eventq_irq_cfg0 & E_BASE_ENABLE_MASK))
131514039Sstacze01@arm.com        panic("eventq msi not enabled\n");
131614039Sstacze01@arm.com
131714039Sstacze01@arm.com    doWrite(yield, smmu.regs.eventq_irq_cfg0 & E_BASE_ADDR_MASK,
131814039Sstacze01@arm.com            &smmu.regs.eventq_irq_cfg1, sizeof(smmu.regs.eventq_irq_cfg1));
131914039Sstacze01@arm.com}
132014039Sstacze01@arm.com
132114039Sstacze01@arm.comvoid
132214039Sstacze01@arm.comSMMUTranslationProcess::doReadSTE(Yield &yield,
132314039Sstacze01@arm.com                                  StreamTableEntry &ste,
132414039Sstacze01@arm.com                                  uint32_t sid)
132514039Sstacze01@arm.com{
132614039Sstacze01@arm.com    unsigned max_sid = 1 << (smmu.regs.strtab_base_cfg & ST_CFG_SIZE_MASK);
132714039Sstacze01@arm.com    if (sid >= max_sid)
132814039Sstacze01@arm.com        panic("SID %#x out of range, max=%#x", sid, max_sid);
132914039Sstacze01@arm.com
133014039Sstacze01@arm.com    Addr ste_addr;
133114039Sstacze01@arm.com
133214039Sstacze01@arm.com    if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_2LEVEL) {
133314039Sstacze01@arm.com        unsigned split =
133414039Sstacze01@arm.com            (smmu.regs.strtab_base_cfg & ST_CFG_SPLIT_MASK) >> ST_CFG_SPLIT_SHIFT;
133514039Sstacze01@arm.com
133614039Sstacze01@arm.com        if (split!= 7 && split!=8 && split!=16)
133714039Sstacze01@arm.com            panic("Invalid stream table split %d", split);
133814039Sstacze01@arm.com
133914039Sstacze01@arm.com        uint64_t l2_ptr;
134014039Sstacze01@arm.com        uint64_t l2_addr =
134114039Sstacze01@arm.com            (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) +
134214039Sstacze01@arm.com            bits(sid, 32, split) * sizeof(l2_ptr);
134314039Sstacze01@arm.com
134414039Sstacze01@arm.com        DPRINTF(SMMUv3, "Read L1STE at %#x\n", l2_addr);
134514039Sstacze01@arm.com
134614039Sstacze01@arm.com        doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, 0);
134714039Sstacze01@arm.com
134814039Sstacze01@arm.com        DPRINTF(SMMUv3, "Got L1STE L1 at %#x: 0x%016x\n", l2_addr, l2_ptr);
134914039Sstacze01@arm.com
135014039Sstacze01@arm.com        unsigned span = l2_ptr & ST_L2_SPAN_MASK;
135114039Sstacze01@arm.com        if (span == 0)
135214039Sstacze01@arm.com            panic("Invalid level 1 stream table descriptor");
135314039Sstacze01@arm.com
135414039Sstacze01@arm.com        unsigned index = bits(sid, split-1, 0);
135514039Sstacze01@arm.com        if (index >= (1 << span))
135614039Sstacze01@arm.com            panic("StreamID %d out of level 1 descriptor range %d",
135714039Sstacze01@arm.com                  sid, 1<<span);
135814039Sstacze01@arm.com
135914039Sstacze01@arm.com        ste_addr = (l2_ptr & ST_L2_ADDR_MASK) + index * sizeof(ste);
136014039Sstacze01@arm.com
136114039Sstacze01@arm.com        smmu.steL1Fetches++;
136214039Sstacze01@arm.com    } else if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_LINEAR) {
136314039Sstacze01@arm.com        ste_addr =
136414039Sstacze01@arm.com            (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + sid * sizeof(ste);
136514039Sstacze01@arm.com    } else {
136614039Sstacze01@arm.com        panic("Invalid stream table format");
136714039Sstacze01@arm.com    }
136814039Sstacze01@arm.com
136914039Sstacze01@arm.com    DPRINTF(SMMUv3, "Read STE at %#x\n", ste_addr);
137014039Sstacze01@arm.com
137114039Sstacze01@arm.com    doReadConfig(yield, ste_addr, &ste, sizeof(ste), sid, 0);
137214039Sstacze01@arm.com
137314039Sstacze01@arm.com    DPRINTF(SMMUv3, "Got STE at %#x [0]: 0x%016x\n", ste_addr, ste.dw0);
137414039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [1]: 0x%016x\n", ste_addr, ste.dw1);
137514039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [2]: 0x%016x\n", ste_addr, ste.dw2);
137614039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [3]: 0x%016x\n", ste_addr, ste.dw3);
137714039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [4]: 0x%016x\n", ste_addr, ste._pad[0]);
137814039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [5]: 0x%016x\n", ste_addr, ste._pad[1]);
137914039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [6]: 0x%016x\n", ste_addr, ste._pad[2]);
138014039Sstacze01@arm.com    DPRINTF(SMMUv3, "    STE at %#x [7]: 0x%016x\n", ste_addr, ste._pad[3]);
138114039Sstacze01@arm.com
138214039Sstacze01@arm.com    if (!ste.dw0.valid)
138314039Sstacze01@arm.com        panic("STE @ %#x not valid\n", ste_addr);
138414039Sstacze01@arm.com
138514039Sstacze01@arm.com    smmu.steFetches++;
138614039Sstacze01@arm.com}
138714039Sstacze01@arm.com
138814039Sstacze01@arm.comvoid
138914039Sstacze01@arm.comSMMUTranslationProcess::doReadCD(Yield &yield,
139014039Sstacze01@arm.com                                 ContextDescriptor &cd,
139114039Sstacze01@arm.com                                 const StreamTableEntry &ste,
139214039Sstacze01@arm.com                                 uint32_t sid, uint32_t ssid)
139314039Sstacze01@arm.com{
139414039Sstacze01@arm.com    Addr cd_addr;
139514039Sstacze01@arm.com
139614039Sstacze01@arm.com    if (ste.dw0.s1cdmax == 0) {
139714039Sstacze01@arm.com        cd_addr = ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT;
139814039Sstacze01@arm.com    } else {
139914039Sstacze01@arm.com        unsigned max_ssid = 1 << ste.dw0.s1cdmax;
140014039Sstacze01@arm.com        if (ssid >= max_ssid)
140114039Sstacze01@arm.com            panic("SSID %#x out of range, max=%#x", ssid, max_ssid);
140214039Sstacze01@arm.com
140314039Sstacze01@arm.com        if (ste.dw0.s1fmt==STAGE1_CFG_2L_4K ||
140414039Sstacze01@arm.com            ste.dw0.s1fmt==STAGE1_CFG_2L_64K)
140514039Sstacze01@arm.com        {
140614039Sstacze01@arm.com            unsigned split = ste.dw0.s1fmt==STAGE1_CFG_2L_4K ? 7 : 11;
140714039Sstacze01@arm.com
140814039Sstacze01@arm.com            uint64_t l2_ptr;
140914039Sstacze01@arm.com            uint64_t l2_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) +
141014039Sstacze01@arm.com                bits(ssid, 24, split) * sizeof(l2_ptr);
141114039Sstacze01@arm.com
141214039Sstacze01@arm.com            if (context.stage2Enable)
141314039Sstacze01@arm.com                l2_addr = translateStage2(yield, l2_addr, false).addr;
141414039Sstacze01@arm.com
141514039Sstacze01@arm.com            DPRINTF(SMMUv3, "Read L1CD at %#x\n", l2_addr);
141614039Sstacze01@arm.com
141714039Sstacze01@arm.com            doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, ssid);
141814039Sstacze01@arm.com
141914039Sstacze01@arm.com            DPRINTF(SMMUv3, "Got L1CD at %#x: 0x%016x\n", l2_addr, l2_ptr);
142014039Sstacze01@arm.com
142114039Sstacze01@arm.com            cd_addr = l2_ptr + bits(ssid, split-1, 0) * sizeof(cd);
142214039Sstacze01@arm.com
142314039Sstacze01@arm.com            smmu.cdL1Fetches++;
142414039Sstacze01@arm.com        } else if (ste.dw0.s1fmt == STAGE1_CFG_1L) {
142514039Sstacze01@arm.com            cd_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + ssid*sizeof(cd);
142614039Sstacze01@arm.com        }
142714039Sstacze01@arm.com    }
142814039Sstacze01@arm.com
142914039Sstacze01@arm.com    if (context.stage2Enable)
143014039Sstacze01@arm.com        cd_addr = translateStage2(yield, cd_addr, false).addr;
143114039Sstacze01@arm.com
143214039Sstacze01@arm.com    DPRINTF(SMMUv3, "Read CD at %#x\n", cd_addr);
143314039Sstacze01@arm.com
143414039Sstacze01@arm.com    doReadConfig(yield, cd_addr, &cd, sizeof(cd), sid, ssid);
143514039Sstacze01@arm.com
143614039Sstacze01@arm.com    DPRINTF(SMMUv3, "Got CD at %#x [0]: 0x%016x\n", cd_addr, cd.dw0);
143714039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [1]: 0x%016x\n", cd_addr, cd.dw1);
143814039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [2]: 0x%016x\n", cd_addr, cd.dw2);
143914039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [3]: 0x%016x\n", cd_addr, cd.mair);
144014039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [4]: 0x%016x\n", cd_addr, cd.amair);
144114039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [5]: 0x%016x\n", cd_addr, cd._pad[0]);
144214039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [6]: 0x%016x\n", cd_addr, cd._pad[1]);
144314039Sstacze01@arm.com    DPRINTF(SMMUv3, "    CD at %#x [7]: 0x%016x\n", cd_addr, cd._pad[2]);
144414039Sstacze01@arm.com
144514039Sstacze01@arm.com
144614039Sstacze01@arm.com    if (!cd.dw0.valid)
144714039Sstacze01@arm.com        panic("CD @ %#x not valid\n", cd_addr);
144814039Sstacze01@arm.com
144914039Sstacze01@arm.com    smmu.cdFetches++;
145014039Sstacze01@arm.com}
145114039Sstacze01@arm.com
145214039Sstacze01@arm.comvoid
145314039Sstacze01@arm.comSMMUTranslationProcess::doReadConfig(Yield &yield, Addr addr,
145414039Sstacze01@arm.com                                     void *ptr, size_t size,
145514039Sstacze01@arm.com                                     uint32_t sid, uint32_t ssid)
145614039Sstacze01@arm.com{
145714039Sstacze01@arm.com    doRead(yield, addr, ptr, size);
145814039Sstacze01@arm.com}
145914039Sstacze01@arm.com
146014039Sstacze01@arm.comvoid
146114039Sstacze01@arm.comSMMUTranslationProcess::doReadPTE(Yield &yield, Addr va, Addr addr,
146214039Sstacze01@arm.com                                  void *ptr, unsigned stage,
146314039Sstacze01@arm.com                                  unsigned level)
146414039Sstacze01@arm.com{
146514039Sstacze01@arm.com    size_t pte_size = sizeof(PageTableOps::pte_t);
146614039Sstacze01@arm.com
146714039Sstacze01@arm.com    Addr mask = pte_size - 1;
146814039Sstacze01@arm.com    Addr base = addr & ~mask;
146914039Sstacze01@arm.com
147014039Sstacze01@arm.com    doRead(yield, base, ptr, pte_size);
147114039Sstacze01@arm.com}
1472