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