smmu_v3_transl.cc revision 14063:fc05dc40f6d1
16019Shines@cs.fsu.edu/*
214028Sgiacomo.gabrielli@arm.com * Copyright (c) 2013, 2018-2019 ARM Limited
37091Sgblack@eecs.umich.edu * All rights reserved
47091Sgblack@eecs.umich.edu *
57091Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
67091Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
77091Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
87091Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
97091Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
107091Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
117091Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
127091Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
137091Sgblack@eecs.umich.edu *
146019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without
156019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are
166019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright
176019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer;
186019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright
196019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the
206019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution;
216019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its
226019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from
236019Shines@cs.fsu.edu * this software without specific prior written permission.
246019Shines@cs.fsu.edu *
256019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
276019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
296019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
306019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
316019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
326019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
336019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
346019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
356019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366019Shines@cs.fsu.edu *
376019Shines@cs.fsu.edu * Authors: Stan Czerniawski
386019Shines@cs.fsu.edu */
396019Shines@cs.fsu.edu
406019Shines@cs.fsu.edu#include "dev/arm/smmu_v3_transl.hh"
416019Shines@cs.fsu.edu
426019Shines@cs.fsu.edu#include "debug/SMMUv3.hh"
438449Sgblack@eecs.umich.edu#include "debug/SMMUv3Hazard.hh"
448449Sgblack@eecs.umich.edu#include "dev/arm/amba.hh"
458449Sgblack@eecs.umich.edu#include "dev/arm/smmu_v3.hh"
468449Sgblack@eecs.umich.edu#include "sim/system.hh"
478449Sgblack@eecs.umich.edu
488449Sgblack@eecs.umich.eduSMMUTranslRequest
4913759Sgiacomo.gabrielli@arm.comSMMUTranslRequest::fromPacket(PacketPtr pkt, bool ats)
508449Sgblack@eecs.umich.edu{
5112386Sgabeblack@google.com    SMMUTranslRequest req;
528449Sgblack@eecs.umich.edu    req.addr         = pkt->getAddr();
5312110SRekai.GonzalezAlberquilla@arm.com    req.size         = pkt->getSize();
5413915Sgabeblack@google.com    req.sid          = pkt->req->streamId();
5512110SRekai.GonzalezAlberquilla@arm.com    req.ssid         = pkt->req->hasSubstreamId() ?
5612110SRekai.GonzalezAlberquilla@arm.com        pkt->req->substreamId() : 0;
5713759Sgiacomo.gabrielli@arm.com    req.isWrite      = pkt->isWrite();
5813759Sgiacomo.gabrielli@arm.com    req.isPrefetch   = false;
5913915Sgabeblack@google.com    req.isAtsRequest = ats;
6013759Sgiacomo.gabrielli@arm.com    req.pkt          = pkt;
616019Shines@cs.fsu.edu
626019Shines@cs.fsu.edu    return req;
636312Sgblack@eecs.umich.edu}
646312Sgblack@eecs.umich.edu
657720Sgblack@eecs.umich.eduSMMUTranslRequest
666312Sgblack@eecs.umich.eduSMMUTranslRequest::prefetch(Addr addr, uint32_t sid, uint32_t ssid)
677186Sgblack@eecs.umich.edu{
687720Sgblack@eecs.umich.edu    SMMUTranslRequest req;
697186Sgblack@eecs.umich.edu    req.addr         = addr;
707186Sgblack@eecs.umich.edu    req.size         = 0;
716312Sgblack@eecs.umich.edu    req.sid          = sid;
727093Sgblack@eecs.umich.edu    req.ssid         = ssid;
736312Sgblack@eecs.umich.edu    req.isWrite      = false;
746312Sgblack@eecs.umich.edu    req.isPrefetch   = true;
757148Sgblack@eecs.umich.edu    req.isAtsRequest = false;
767148Sgblack@eecs.umich.edu    req.pkt          = NULL;
777148Sgblack@eecs.umich.edu
787148Sgblack@eecs.umich.edu    return req;
797184Sgblack@eecs.umich.edu}
807184Sgblack@eecs.umich.edu
817289Sgblack@eecs.umich.eduSMMUTranslationProcess::SMMUTranslationProcess(const std::string &name,
827289Sgblack@eecs.umich.edu    SMMUv3 &_smmu, SMMUv3SlaveInterface &_ifc)
837289Sgblack@eecs.umich.edu  :
847289Sgblack@eecs.umich.edu    SMMUProcess(name, _smmu),
857184Sgblack@eecs.umich.edu    ifc(_ifc)
867184Sgblack@eecs.umich.edu{
877184Sgblack@eecs.umich.edu    // Decrease number of pending translation slots on the slave interface
887184Sgblack@eecs.umich.edu    assert(ifc.xlateSlotsRemaining > 0);
897184Sgblack@eecs.umich.edu    ifc.xlateSlotsRemaining--;
907184Sgblack@eecs.umich.edu    reinit();
9110037SARM gem5 Developers}
9210037SARM gem5 Developers
9310037SARM gem5 DevelopersSMMUTranslationProcess::~SMMUTranslationProcess()
9410037SARM gem5 Developers{
9510037SARM gem5 Developers    // Increase number of pending translation slots on the slave interface
9610037SARM gem5 Developers    ifc.xlateSlotsRemaining++;
9710037SARM gem5 Developers}
9810037SARM gem5 Developers
9910037SARM gem5 Developersvoid
10010037SARM gem5 DevelopersSMMUTranslationProcess::beginTransaction(const SMMUTranslRequest &req)
10110037SARM gem5 Developers{
10210037SARM gem5 Developers    request = req;
10310037SARM gem5 Developers
10410037SARM gem5 Developers    reinit();
10510037SARM gem5 Developers}
10610037SARM gem5 Developers
10710037SARM gem5 Developersvoid
10810037SARM gem5 DevelopersSMMUTranslationProcess::resumeTransaction()
10910037SARM gem5 Developers{
11012499Sgiacomo.travaglini@arm.com    assert(smmu.system.isTimingMode());
11110037SARM gem5 Developers
11210037SARM gem5 Developers    assert(!"Stalls are broken");
11310037SARM gem5 Developers
11412499Sgiacomo.travaglini@arm.com    Tick resumeTick = curTick();
11510037SARM gem5 Developers
1167797Sgblack@eecs.umich.edu    (void) resumeTick;
1177797Sgblack@eecs.umich.edu    DPRINTF(SMMUv3, "Resume at tick = %d. Fault duration = %d (%.3fus)\n",
1187797Sgblack@eecs.umich.edu        resumeTick, resumeTick-faultTick, (resumeTick-faultTick) / 1e6);
1197797Sgblack@eecs.umich.edu
1207797Sgblack@eecs.umich.edu    beginTransaction(request);
1217797Sgblack@eecs.umich.edu
1227797Sgblack@eecs.umich.edu    smmu.runProcessTiming(this, request.pkt);
1237797Sgblack@eecs.umich.edu}
1247797Sgblack@eecs.umich.edu
1257797Sgblack@eecs.umich.eduvoid
1267797Sgblack@eecs.umich.eduSMMUTranslationProcess::main(Yield &yield)
1277797Sgblack@eecs.umich.edu{
12812110SRekai.GonzalezAlberquilla@arm.com    // Hack:
12912110SRekai.GonzalezAlberquilla@arm.com    // The coroutine starts running as soon as it's created.
13012110SRekai.GonzalezAlberquilla@arm.com    // But we need to wait for request data esp. in atomic mode.
13112110SRekai.GonzalezAlberquilla@arm.com    SMMUAction a;
13212110SRekai.GonzalezAlberquilla@arm.com    a.type = ACTION_INITIAL_NOP;
13312110SRekai.GonzalezAlberquilla@arm.com    a.pkt = NULL;
13412110SRekai.GonzalezAlberquilla@arm.com    yield(a);
13512110SRekai.GonzalezAlberquilla@arm.com
13612110SRekai.GonzalezAlberquilla@arm.com    const Addr next4k = (request.addr + 0x1000ULL) & ~0xfffULL;
13713759Sgiacomo.gabrielli@arm.com
13813759Sgiacomo.gabrielli@arm.com    if ((request.addr + request.size) > next4k)
13913759Sgiacomo.gabrielli@arm.com        panic("Transaction crosses 4k boundary (addr=%#x size=%#x)!\n",
1407797Sgblack@eecs.umich.edu                request.addr, request.size);
1417797Sgblack@eecs.umich.edu
1427797Sgblack@eecs.umich.edu
1437797Sgblack@eecs.umich.edu    unsigned numSlaveBeats = request.isWrite ?
14410037SARM gem5 Developers        (request.size + (ifc.portWidth - 1)) / ifc.portWidth : 1;
14510037SARM gem5 Developers
14610037SARM gem5 Developers    doSemaphoreDown(yield, ifc.slavePortSem);
14710037SARM gem5 Developers    doDelay(yield, Cycles(numSlaveBeats));
14810037SARM gem5 Developers    doSemaphoreUp(ifc.slavePortSem);
14910037SARM gem5 Developers
15010037SARM gem5 Developers
15110037SARM gem5 Developers    recvTick = curTick();
15210037SARM gem5 Developers
15310037SARM gem5 Developers
15410037SARM gem5 Developers    if (!(smmu.regs.cr0 & 0x1)) {
15510037SARM gem5 Developers        // SMMU disabled
1567797Sgblack@eecs.umich.edu        doDelay(yield, Cycles(1));
1577797Sgblack@eecs.umich.edu        completeTransaction(yield, bypass(request.addr));
1587797Sgblack@eecs.umich.edu        return;
1597797Sgblack@eecs.umich.edu    }
1607797Sgblack@eecs.umich.edu
1617797Sgblack@eecs.umich.edu    TranslResult tr;
1627797Sgblack@eecs.umich.edu    bool wasPrefetched = false;
1637797Sgblack@eecs.umich.edu
1647797Sgblack@eecs.umich.edu    if (request.isPrefetch) {
1657797Sgblack@eecs.umich.edu        // Abort prefetch if:
1667797Sgblack@eecs.umich.edu        //   - there's already a transaction looking up the same 4k page, OR
1677797Sgblack@eecs.umich.edu        //   - requested address is already in the TLB.
1687797Sgblack@eecs.umich.edu        if (hazard4kCheck() || ifcTLBLookup(yield, tr, wasPrefetched))
1697797Sgblack@eecs.umich.edu            completePrefetch(yield); // this never returns
1707797Sgblack@eecs.umich.edu
17110338SCurtis.Dunham@arm.com        hazard4kRegister();
17210338SCurtis.Dunham@arm.com
1737797Sgblack@eecs.umich.edu        tr = smmuTranslation(yield);
1747797Sgblack@eecs.umich.edu
1759251Snathanael.premillieu@irisa.fr        if (tr.fault == FAULT_NONE)
1767797Sgblack@eecs.umich.edu            ifcTLBUpdate(yield, tr);
17710037SARM gem5 Developers
17810037SARM gem5 Developers        hazard4kRelease();
17910037SARM gem5 Developers
18010037SARM gem5 Developers        completePrefetch(yield);
18110037SARM gem5 Developers    } else {
18210037SARM gem5 Developers        hazardIdRegister();
1837797Sgblack@eecs.umich.edu
1847797Sgblack@eecs.umich.edu        if (!microTLBLookup(yield, tr)) {
1857797Sgblack@eecs.umich.edu            bool hit = ifcTLBLookup(yield, tr, wasPrefetched);
1867797Sgblack@eecs.umich.edu            if (!hit) {
18710037SARM gem5 Developers                while (!hit && hazard4kCheck()) {
1886312Sgblack@eecs.umich.edu                    hazard4kHold(yield);
1896312Sgblack@eecs.umich.edu                    hit = ifcTLBLookup(yield, tr, wasPrefetched);
1906019Shines@cs.fsu.edu                }
1917119Sgblack@eecs.umich.edu            }
1927797Sgblack@eecs.umich.edu
19310037SARM gem5 Developers            // Issue prefetch if:
19410037SARM gem5 Developers            //   - there was a TLB hit and the entry was prefetched, OR
19510037SARM gem5 Developers            //   - TLB miss was successfully serviced
1967797Sgblack@eecs.umich.edu            if (hit) {
1977797Sgblack@eecs.umich.edu                if (wasPrefetched)
1987797Sgblack@eecs.umich.edu                    issuePrefetch(next4k);
19910037SARM gem5 Developers            } else {
20012134Sgedare@rtems.org                hazard4kRegister();
2017797Sgblack@eecs.umich.edu
20210037SARM gem5 Developers                tr = smmuTranslation(yield);
20310037SARM gem5 Developers
2047797Sgblack@eecs.umich.edu                if (tr.fault == FAULT_NONE) {
20510037SARM gem5 Developers                    ifcTLBUpdate(yield, tr);
2067797Sgblack@eecs.umich.edu
2077797Sgblack@eecs.umich.edu                    issuePrefetch(next4k);
2087797Sgblack@eecs.umich.edu                }
2097797Sgblack@eecs.umich.edu
2107797Sgblack@eecs.umich.edu                hazard4kRelease();
21110037SARM gem5 Developers            }
21210037SARM gem5 Developers
21310037SARM gem5 Developers            if (tr.fault == FAULT_NONE)
21410037SARM gem5 Developers                microTLBUpdate(yield, tr);
21510037SARM gem5 Developers        }
21610037SARM gem5 Developers
21710037SARM gem5 Developers        hazardIdHold(yield);
21810037SARM gem5 Developers        hazardIdRelease();
21910037SARM gem5 Developers
2207797Sgblack@eecs.umich.edu        if (tr.fault != FAULT_NONE)
2217797Sgblack@eecs.umich.edu            panic("fault\n");
2227797Sgblack@eecs.umich.edu
2237797Sgblack@eecs.umich.edu        completeTransaction(yield, tr);
2246019Shines@cs.fsu.edu    }
2257797Sgblack@eecs.umich.edu}
2267797Sgblack@eecs.umich.edu
22710037SARM gem5 DevelopersSMMUTranslationProcess::TranslResult
2287797Sgblack@eecs.umich.eduSMMUTranslationProcess::bypass(Addr addr) const
22910037SARM gem5 Developers{
2307797Sgblack@eecs.umich.edu    TranslResult tr;
2318204SAli.Saidi@ARM.com    tr.fault = FAULT_NONE;
2327797Sgblack@eecs.umich.edu    tr.addr = addr;
2338204SAli.Saidi@ARM.com    tr.addrMask = 0;
2348204SAli.Saidi@ARM.com    tr.writable = 1;
2358204SAli.Saidi@ARM.com
23610037SARM gem5 Developers    return tr;
23710037SARM gem5 Developers}
23810037SARM gem5 Developers
23910037SARM gem5 DevelopersSMMUTranslationProcess::TranslResult
2407797Sgblack@eecs.umich.eduSMMUTranslationProcess::smmuTranslation(Yield &yield)
24110338SCurtis.Dunham@arm.com{
24210338SCurtis.Dunham@arm.com    TranslResult tr;
24310338SCurtis.Dunham@arm.com
24410338SCurtis.Dunham@arm.com    // Need SMMU credit to proceed
24510338SCurtis.Dunham@arm.com    doSemaphoreDown(yield, smmu.transSem);
24610338SCurtis.Dunham@arm.com
24710338SCurtis.Dunham@arm.com    // Simulate pipelined IFC->SMMU link
24810338SCurtis.Dunham@arm.com    doSemaphoreDown(yield, smmu.ifcSmmuSem);
24910338SCurtis.Dunham@arm.com    doDelay(yield, Cycles(1)); // serialize transactions
25010338SCurtis.Dunham@arm.com    doSemaphoreUp(smmu.ifcSmmuSem);
25110338SCurtis.Dunham@arm.com    doDelay(yield, smmu.ifcSmmuLat - Cycles(1)); // remaining pipeline delay
25210338SCurtis.Dunham@arm.com
2538303SAli.Saidi@ARM.com    bool haveConfig = true;
25410338SCurtis.Dunham@arm.com    if (!configCacheLookup(yield, context)) {
25510338SCurtis.Dunham@arm.com        if(findConfig(yield, context, tr)) {
25610338SCurtis.Dunham@arm.com            configCacheUpdate(yield, context);
25710338SCurtis.Dunham@arm.com        } else {
25810338SCurtis.Dunham@arm.com            haveConfig = false;
25910338SCurtis.Dunham@arm.com        }
26010338SCurtis.Dunham@arm.com    }
26110338SCurtis.Dunham@arm.com
26210338SCurtis.Dunham@arm.com    if (haveConfig && !smmuTLBLookup(yield, tr)) {
26310338SCurtis.Dunham@arm.com        // SMMU main TLB miss
26410338SCurtis.Dunham@arm.com
26510338SCurtis.Dunham@arm.com        // Need PTW slot to proceed
2667797Sgblack@eecs.umich.edu        doSemaphoreDown(yield, smmu.ptwSem);
2677797Sgblack@eecs.umich.edu
26813603Sgiacomo.travaglini@arm.com        // Page table walk
26913815Sgiacomo.travaglini@arm.com        Tick ptwStartTick = curTick();
27013815Sgiacomo.travaglini@arm.com
27113815Sgiacomo.travaglini@arm.com        if (context.stage1Enable) {
27213815Sgiacomo.travaglini@arm.com            tr = translateStage1And2(yield, request.addr);
27313815Sgiacomo.travaglini@arm.com        } else if (context.stage2Enable) {
27413815Sgiacomo.travaglini@arm.com            tr = translateStage2(yield, request.addr, true);
27513815Sgiacomo.travaglini@arm.com        } else {
27613815Sgiacomo.travaglini@arm.com            tr = bypass(request.addr);
2777797Sgblack@eecs.umich.edu        }
27813603Sgiacomo.travaglini@arm.com
27913603Sgiacomo.travaglini@arm.com        if (context.stage1Enable || context.stage2Enable)
28013603Sgiacomo.travaglini@arm.com            smmu.ptwTimeDist.sample(curTick() - ptwStartTick);
28113603Sgiacomo.travaglini@arm.com
28213603Sgiacomo.travaglini@arm.com        // Free PTW slot
28313603Sgiacomo.travaglini@arm.com        doSemaphoreUp(smmu.ptwSem);
28413603Sgiacomo.travaglini@arm.com
28513603Sgiacomo.travaglini@arm.com        if (tr.fault == FAULT_NONE)
28613603Sgiacomo.travaglini@arm.com            smmuTLBUpdate(yield, tr);
28713603Sgiacomo.travaglini@arm.com    }
28813603Sgiacomo.travaglini@arm.com
28913603Sgiacomo.travaglini@arm.com    // Simulate pipelined SMMU->SLAVE INTERFACE link
29013603Sgiacomo.travaglini@arm.com    doSemaphoreDown(yield, smmu.smmuIfcSem);
29113603Sgiacomo.travaglini@arm.com    doDelay(yield, Cycles(1)); // serialize transactions
29213603Sgiacomo.travaglini@arm.com    doSemaphoreUp(smmu.smmuIfcSem);
29313603Sgiacomo.travaglini@arm.com    doDelay(yield, smmu.smmuIfcLat - Cycles(1)); // remaining pipeline delay
2947797Sgblack@eecs.umich.edu
29513603Sgiacomo.travaglini@arm.com    // return SMMU credit
29613815Sgiacomo.travaglini@arm.com    doSemaphoreUp(smmu.transSem);
29713815Sgiacomo.travaglini@arm.com
29813815Sgiacomo.travaglini@arm.com    return tr;
29913815Sgiacomo.travaglini@arm.com}
3007797Sgblack@eecs.umich.edu
30113603Sgiacomo.travaglini@arm.combool
30213815Sgiacomo.travaglini@arm.comSMMUTranslationProcess::microTLBLookup(Yield &yield, TranslResult &tr)
30313815Sgiacomo.travaglini@arm.com{
30413815Sgiacomo.travaglini@arm.com    if (!ifc.microTLBEnable)
30513815Sgiacomo.travaglini@arm.com        return false;
30613815Sgiacomo.travaglini@arm.com
30713815Sgiacomo.travaglini@arm.com    doSemaphoreDown(yield, ifc.microTLBSem);
30813815Sgiacomo.travaglini@arm.com    doDelay(yield, ifc.microTLBLat);
30913815Sgiacomo.travaglini@arm.com    const SMMUTLB::Entry *e =
31013603Sgiacomo.travaglini@arm.com        ifc.microTLB->lookup(request.sid, request.ssid, request.addr);
31113603Sgiacomo.travaglini@arm.com    doSemaphoreUp(ifc.microTLBSem);
31213603Sgiacomo.travaglini@arm.com
31313603Sgiacomo.travaglini@arm.com    if (!e) {
31413603Sgiacomo.travaglini@arm.com        DPRINTF(SMMUv3, "micro TLB miss vaddr=%#x sid=%#x ssid=%#x\n",
31513603Sgiacomo.travaglini@arm.com            request.addr, request.sid, request.ssid);
31613603Sgiacomo.travaglini@arm.com
31713603Sgiacomo.travaglini@arm.com        return false;
31813603Sgiacomo.travaglini@arm.com    }
31913603Sgiacomo.travaglini@arm.com
32013603Sgiacomo.travaglini@arm.com    DPRINTF(SMMUv3,
32113603Sgiacomo.travaglini@arm.com        "micro TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x paddr=%#x\n",
32213603Sgiacomo.travaglini@arm.com        request.addr, e->vaMask, request.sid, request.ssid, e->pa);
32313603Sgiacomo.travaglini@arm.com
32413603Sgiacomo.travaglini@arm.com    tr.fault = FAULT_NONE;
32513603Sgiacomo.travaglini@arm.com    tr.addr = e->pa + (request.addr & ~e->vaMask);;
32613603Sgiacomo.travaglini@arm.com    tr.addrMask = e->vaMask;
32713603Sgiacomo.travaglini@arm.com    tr.writable = e->permissions;
32813603Sgiacomo.travaglini@arm.com
32913815Sgiacomo.travaglini@arm.com    return true;
33013815Sgiacomo.travaglini@arm.com}
33113815Sgiacomo.travaglini@arm.com
33213815Sgiacomo.travaglini@arm.combool
3337797Sgblack@eecs.umich.eduSMMUTranslationProcess::ifcTLBLookup(Yield &yield, TranslResult &tr,
33410037SARM gem5 Developers                                     bool &wasPrefetched)
33512110SRekai.GonzalezAlberquilla@arm.com{
33612110SRekai.GonzalezAlberquilla@arm.com    if (!ifc.mainTLBEnable)
33712110SRekai.GonzalezAlberquilla@arm.com        return false;
33812110SRekai.GonzalezAlberquilla@arm.com
33912110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreDown(yield, ifc.mainTLBSem);
34012110SRekai.GonzalezAlberquilla@arm.com    doDelay(yield, ifc.mainTLBLat);
34112110SRekai.GonzalezAlberquilla@arm.com    const SMMUTLB::Entry *e =
34212110SRekai.GonzalezAlberquilla@arm.com        ifc.mainTLB->lookup(request.sid, request.ssid, request.addr);
34312110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreUp(ifc.mainTLBSem);
34412110SRekai.GonzalezAlberquilla@arm.com
34510037SARM gem5 Developers    if (!e) {
34612110SRekai.GonzalezAlberquilla@arm.com        DPRINTF(SMMUv3,
34712110SRekai.GonzalezAlberquilla@arm.com                "SLAVE Interface TLB miss vaddr=%#x sid=%#x ssid=%#x\n",
34812110SRekai.GonzalezAlberquilla@arm.com                request.addr, request.sid, request.ssid);
34912110SRekai.GonzalezAlberquilla@arm.com
35012110SRekai.GonzalezAlberquilla@arm.com        return false;
35112110SRekai.GonzalezAlberquilla@arm.com    }
35212110SRekai.GonzalezAlberquilla@arm.com
35312110SRekai.GonzalezAlberquilla@arm.com    DPRINTF(SMMUv3,
35412110SRekai.GonzalezAlberquilla@arm.com            "SLAVE Interface TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x "
35512110SRekai.GonzalezAlberquilla@arm.com            "paddr=%#x\n", request.addr, e->vaMask, request.sid,
35610037SARM gem5 Developers            request.ssid, e->pa);
35712110SRekai.GonzalezAlberquilla@arm.com
35812110SRekai.GonzalezAlberquilla@arm.com    tr.fault = FAULT_NONE;
35912110SRekai.GonzalezAlberquilla@arm.com    tr.addr = e->pa + (request.addr & ~e->vaMask);;
36012110SRekai.GonzalezAlberquilla@arm.com    tr.addrMask = e->vaMask;
36112110SRekai.GonzalezAlberquilla@arm.com    tr.writable = e->permissions;
36212110SRekai.GonzalezAlberquilla@arm.com    wasPrefetched = e->prefetched;
36312110SRekai.GonzalezAlberquilla@arm.com
36412110SRekai.GonzalezAlberquilla@arm.com    return true;
36512110SRekai.GonzalezAlberquilla@arm.com}
36612110SRekai.GonzalezAlberquilla@arm.com
36710037SARM gem5 Developersbool
36812110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::smmuTLBLookup(Yield &yield, TranslResult &tr)
36912110SRekai.GonzalezAlberquilla@arm.com{
37012110SRekai.GonzalezAlberquilla@arm.com    if (!smmu.tlbEnable)
37112110SRekai.GonzalezAlberquilla@arm.com        return false;
37212110SRekai.GonzalezAlberquilla@arm.com
37312110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreDown(yield, smmu.tlbSem);
37412110SRekai.GonzalezAlberquilla@arm.com    doDelay(yield, smmu.tlbLat);
37512110SRekai.GonzalezAlberquilla@arm.com    const ARMArchTLB::Entry *e =
37612110SRekai.GonzalezAlberquilla@arm.com        smmu.tlb.lookup(request.addr, context.asid, context.vmid);
37712110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreUp(smmu.tlbSem);
37810037SARM gem5 Developers
37912110SRekai.GonzalezAlberquilla@arm.com    if (!e) {
38012110SRekai.GonzalezAlberquilla@arm.com        DPRINTF(SMMUv3, "SMMU TLB miss vaddr=%#x asid=%#x vmid=%#x\n",
38112110SRekai.GonzalezAlberquilla@arm.com            request.addr, context.asid, context.vmid);
38212110SRekai.GonzalezAlberquilla@arm.com
38312110SRekai.GonzalezAlberquilla@arm.com        return false;
38412110SRekai.GonzalezAlberquilla@arm.com    }
38512110SRekai.GonzalezAlberquilla@arm.com
38612110SRekai.GonzalezAlberquilla@arm.com    DPRINTF(SMMUv3,
38712110SRekai.GonzalezAlberquilla@arm.com            "SMMU TLB hit vaddr=%#x amask=%#x asid=%#x vmid=%#x paddr=%#x\n",
38812110SRekai.GonzalezAlberquilla@arm.com            request.addr, e->vaMask, context.asid, context.vmid, e->pa);
38910037SARM gem5 Developers
39012110SRekai.GonzalezAlberquilla@arm.com    tr.fault = FAULT_NONE;
39112110SRekai.GonzalezAlberquilla@arm.com    tr.addr = e->pa + (request.addr & ~e->vaMask);;
39212110SRekai.GonzalezAlberquilla@arm.com    tr.addrMask = e->vaMask;
39312110SRekai.GonzalezAlberquilla@arm.com    tr.writable = e->permissions;
39412110SRekai.GonzalezAlberquilla@arm.com
39512110SRekai.GonzalezAlberquilla@arm.com    return true;
39612110SRekai.GonzalezAlberquilla@arm.com}
39712110SRekai.GonzalezAlberquilla@arm.com
39812110SRekai.GonzalezAlberquilla@arm.comvoid
39912110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::microTLBUpdate(Yield &yield,
40010037SARM gem5 Developers                                       const TranslResult &tr)
40112110SRekai.GonzalezAlberquilla@arm.com{
40212110SRekai.GonzalezAlberquilla@arm.com    assert(tr.fault == FAULT_NONE);
40312110SRekai.GonzalezAlberquilla@arm.com
40412110SRekai.GonzalezAlberquilla@arm.com    if (!ifc.microTLBEnable)
40512110SRekai.GonzalezAlberquilla@arm.com        return;
40612110SRekai.GonzalezAlberquilla@arm.com
40712110SRekai.GonzalezAlberquilla@arm.com    SMMUTLB::Entry e;
40812110SRekai.GonzalezAlberquilla@arm.com    e.valid = true;
40912110SRekai.GonzalezAlberquilla@arm.com    e.prefetched = false;
41012110SRekai.GonzalezAlberquilla@arm.com    e.sid = request.sid;
41110037SARM gem5 Developers    e.ssid = request.ssid;
41212110SRekai.GonzalezAlberquilla@arm.com    e.vaMask = tr.addrMask;
41312110SRekai.GonzalezAlberquilla@arm.com    e.va = request.addr & e.vaMask;
41412110SRekai.GonzalezAlberquilla@arm.com    e.pa = tr.addr & e.vaMask;
41512110SRekai.GonzalezAlberquilla@arm.com    e.permissions = tr.writable;
41612110SRekai.GonzalezAlberquilla@arm.com    e.asid = context.asid;
41712110SRekai.GonzalezAlberquilla@arm.com    e.vmid = context.vmid;
41812110SRekai.GonzalezAlberquilla@arm.com
41912110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreDown(yield, ifc.microTLBSem);
42012110SRekai.GonzalezAlberquilla@arm.com
42112110SRekai.GonzalezAlberquilla@arm.com    DPRINTF(SMMUv3,
42210037SARM gem5 Developers        "micro TLB upd vaddr=%#x amask=%#x paddr=%#x sid=%#x ssid=%#x\n",
42312110SRekai.GonzalezAlberquilla@arm.com        e.va, e.vaMask, e.pa, e.sid, e.ssid);
42412110SRekai.GonzalezAlberquilla@arm.com
42512110SRekai.GonzalezAlberquilla@arm.com    ifc.microTLB->store(e, SMMUTLB::ALLOC_ANY_WAY);
42612110SRekai.GonzalezAlberquilla@arm.com
42712110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreUp(ifc.microTLBSem);
42812110SRekai.GonzalezAlberquilla@arm.com}
42912110SRekai.GonzalezAlberquilla@arm.com
43012110SRekai.GonzalezAlberquilla@arm.comvoid
43112110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::ifcTLBUpdate(Yield &yield,
43212110SRekai.GonzalezAlberquilla@arm.com                                     const TranslResult &tr)
43310037SARM gem5 Developers{
43412110SRekai.GonzalezAlberquilla@arm.com    assert(tr.fault == FAULT_NONE);
43512110SRekai.GonzalezAlberquilla@arm.com
43612110SRekai.GonzalezAlberquilla@arm.com    if (!ifc.mainTLBEnable)
43712110SRekai.GonzalezAlberquilla@arm.com        return;
43812110SRekai.GonzalezAlberquilla@arm.com
43912110SRekai.GonzalezAlberquilla@arm.com    SMMUTLB::Entry e;
44012110SRekai.GonzalezAlberquilla@arm.com    e.valid = true;
44112110SRekai.GonzalezAlberquilla@arm.com    e.prefetched = request.isPrefetch;
44212110SRekai.GonzalezAlberquilla@arm.com    e.sid = request.sid;
44312110SRekai.GonzalezAlberquilla@arm.com    e.ssid = request.ssid;
44410037SARM gem5 Developers    e.vaMask = tr.addrMask;
44512110SRekai.GonzalezAlberquilla@arm.com    e.va = request.addr & e.vaMask;
44612110SRekai.GonzalezAlberquilla@arm.com    e.pa = tr.addr & e.vaMask;
44712110SRekai.GonzalezAlberquilla@arm.com    e.permissions = tr.writable;
44812110SRekai.GonzalezAlberquilla@arm.com    e.asid = context.asid;
44912110SRekai.GonzalezAlberquilla@arm.com    e.vmid = context.vmid;
45012110SRekai.GonzalezAlberquilla@arm.com
45112110SRekai.GonzalezAlberquilla@arm.com    SMMUTLB::AllocPolicy alloc = SMMUTLB::ALLOC_ANY_WAY;
45212110SRekai.GonzalezAlberquilla@arm.com    if (ifc.prefetchEnable && ifc.prefetchReserveLastWay)
45312110SRekai.GonzalezAlberquilla@arm.com        alloc = request.isPrefetch ?
45412110SRekai.GonzalezAlberquilla@arm.com            SMMUTLB::ALLOC_LAST_WAY : SMMUTLB::ALLOC_ANY_BUT_LAST_WAY;
45510037SARM gem5 Developers
45612110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreDown(yield, ifc.mainTLBSem);
45712110SRekai.GonzalezAlberquilla@arm.com
45812110SRekai.GonzalezAlberquilla@arm.com    DPRINTF(SMMUv3,
45912110SRekai.GonzalezAlberquilla@arm.com            "SLAVE Interface upd vaddr=%#x amask=%#x paddr=%#x sid=%#x "
46012110SRekai.GonzalezAlberquilla@arm.com            "ssid=%#x\n", e.va, e.vaMask, e.pa, e.sid, e.ssid);
46112110SRekai.GonzalezAlberquilla@arm.com
46212110SRekai.GonzalezAlberquilla@arm.com    ifc.mainTLB->store(e, alloc);
46312110SRekai.GonzalezAlberquilla@arm.com
46412110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreUp(ifc.mainTLBSem);
46512110SRekai.GonzalezAlberquilla@arm.com}
46610037SARM gem5 Developers
46712110SRekai.GonzalezAlberquilla@arm.comvoid
46812110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::smmuTLBUpdate(Yield &yield,
46912110SRekai.GonzalezAlberquilla@arm.com                                      const TranslResult &tr)
47012110SRekai.GonzalezAlberquilla@arm.com{
47112110SRekai.GonzalezAlberquilla@arm.com    assert(tr.fault == FAULT_NONE);
47212110SRekai.GonzalezAlberquilla@arm.com
47312110SRekai.GonzalezAlberquilla@arm.com    if (!smmu.tlbEnable)
47412110SRekai.GonzalezAlberquilla@arm.com        return;
47512110SRekai.GonzalezAlberquilla@arm.com
47612110SRekai.GonzalezAlberquilla@arm.com    ARMArchTLB::Entry e;
47712110SRekai.GonzalezAlberquilla@arm.com    e.valid = true;
47812110SRekai.GonzalezAlberquilla@arm.com    e.vaMask = tr.addrMask;
47912110SRekai.GonzalezAlberquilla@arm.com    e.va = request.addr & e.vaMask;
48012110SRekai.GonzalezAlberquilla@arm.com    e.asid = context.asid;
48112110SRekai.GonzalezAlberquilla@arm.com    e.vmid = context.vmid;
48212110SRekai.GonzalezAlberquilla@arm.com    e.pa = tr.addr & e.vaMask;
48312110SRekai.GonzalezAlberquilla@arm.com    e.permissions = tr.writable;
48412110SRekai.GonzalezAlberquilla@arm.com
48512110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreDown(yield, smmu.tlbSem);
48612110SRekai.GonzalezAlberquilla@arm.com
48712110SRekai.GonzalezAlberquilla@arm.com    DPRINTF(SMMUv3,
48812110SRekai.GonzalezAlberquilla@arm.com            "SMMU TLB upd vaddr=%#x amask=%#x paddr=%#x asid=%#x vmid=%#x\n",
48912110SRekai.GonzalezAlberquilla@arm.com            e.va, e.vaMask, e.pa, e.asid, e.vmid);
49012110SRekai.GonzalezAlberquilla@arm.com
49112110SRekai.GonzalezAlberquilla@arm.com    smmu.tlb.store(e);
49212110SRekai.GonzalezAlberquilla@arm.com
49312110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreUp(smmu.tlbSem);
49412110SRekai.GonzalezAlberquilla@arm.com}
49512110SRekai.GonzalezAlberquilla@arm.com
49612110SRekai.GonzalezAlberquilla@arm.combool
49712110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::configCacheLookup(Yield &yield, TranslContext &tc)
49812110SRekai.GonzalezAlberquilla@arm.com{
49912110SRekai.GonzalezAlberquilla@arm.com    if (!smmu.configCacheEnable)
50012110SRekai.GonzalezAlberquilla@arm.com        return false;
50112110SRekai.GonzalezAlberquilla@arm.com
50212110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreDown(yield, smmu.configSem);
50312110SRekai.GonzalezAlberquilla@arm.com    doDelay(yield, smmu.configLat);
50412110SRekai.GonzalezAlberquilla@arm.com    const ConfigCache::Entry *e =
50512110SRekai.GonzalezAlberquilla@arm.com        smmu.configCache.lookup(request.sid, request.ssid);
50612110SRekai.GonzalezAlberquilla@arm.com    doSemaphoreUp(smmu.configSem);
50712110SRekai.GonzalezAlberquilla@arm.com
50812110SRekai.GonzalezAlberquilla@arm.com    if (!e) {
50912110SRekai.GonzalezAlberquilla@arm.com        DPRINTF(SMMUv3, "Config miss sid=%#x ssid=%#x\n",
51012110SRekai.GonzalezAlberquilla@arm.com                request.sid, request.ssid);
51112110SRekai.GonzalezAlberquilla@arm.com
51212110SRekai.GonzalezAlberquilla@arm.com        return false;
51312110SRekai.GonzalezAlberquilla@arm.com    }
51412110SRekai.GonzalezAlberquilla@arm.com
51512110SRekai.GonzalezAlberquilla@arm.com    DPRINTF(SMMUv3, "Config hit sid=%#x ssid=%#x ttb=%#08x asid=%#x\n",
51612110SRekai.GonzalezAlberquilla@arm.com            request.sid, request.ssid, e->ttb0, e->asid);
51712110SRekai.GonzalezAlberquilla@arm.com
51812110SRekai.GonzalezAlberquilla@arm.com    tc.stage1Enable = e->stage1_en;
51912110SRekai.GonzalezAlberquilla@arm.com    tc.stage2Enable = e->stage2_en;
52012110SRekai.GonzalezAlberquilla@arm.com
52112110SRekai.GonzalezAlberquilla@arm.com    tc.ttb0 = e->ttb0;
52212110SRekai.GonzalezAlberquilla@arm.com    tc.ttb1 = e->ttb1;
52312110SRekai.GonzalezAlberquilla@arm.com    tc.asid = e->asid;
52412110SRekai.GonzalezAlberquilla@arm.com    tc.httb = e->httb;
52512110SRekai.GonzalezAlberquilla@arm.com    tc.vmid = e->vmid;
52612110SRekai.GonzalezAlberquilla@arm.com
52712110SRekai.GonzalezAlberquilla@arm.com    tc.stage1TranslGranule = e->stage1_tg;
52812110SRekai.GonzalezAlberquilla@arm.com    tc.stage2TranslGranule = e->stage2_tg;
52912110SRekai.GonzalezAlberquilla@arm.com
53012110SRekai.GonzalezAlberquilla@arm.com    return true;
53112110SRekai.GonzalezAlberquilla@arm.com}
53210037SARM gem5 Developers
53314106Sjavier.setoain@arm.comvoid
53414106Sjavier.setoain@arm.comSMMUTranslationProcess::configCacheUpdate(Yield &yield,
53514106Sjavier.setoain@arm.com                                          const TranslContext &tc)
53614106Sjavier.setoain@arm.com{
53714106Sjavier.setoain@arm.com    if (!smmu.configCacheEnable)
53814106Sjavier.setoain@arm.com        return;
53914106Sjavier.setoain@arm.com
54014106Sjavier.setoain@arm.com    ConfigCache::Entry e;
54114106Sjavier.setoain@arm.com    e.valid = true;
54214106Sjavier.setoain@arm.com    e.sid = request.sid;
54314106Sjavier.setoain@arm.com    e.ssid = request.ssid;
54414106Sjavier.setoain@arm.com    e.stage1_en = tc.stage1Enable;
54514106Sjavier.setoain@arm.com    e.stage2_en = tc.stage2Enable;
54614106Sjavier.setoain@arm.com    e.ttb0 = tc.ttb0;
54714106Sjavier.setoain@arm.com    e.ttb1 = tc.ttb1;
54814106Sjavier.setoain@arm.com    e.asid = tc.asid;
54914106Sjavier.setoain@arm.com    e.httb = tc.httb;
55014106Sjavier.setoain@arm.com    e.vmid = tc.vmid;
55114106Sjavier.setoain@arm.com    e.stage1_tg = tc.stage1TranslGranule;
55214106Sjavier.setoain@arm.com    e.stage2_tg = tc.stage2TranslGranule;
55314106Sjavier.setoain@arm.com
55414106Sjavier.setoain@arm.com    doSemaphoreDown(yield, smmu.configSem);
55514106Sjavier.setoain@arm.com
55614106Sjavier.setoain@arm.com    DPRINTF(SMMUv3, "Config upd  sid=%#x ssid=%#x\n", e.sid, e.ssid);
55714106Sjavier.setoain@arm.com
55814106Sjavier.setoain@arm.com    smmu.configCache.store(e);
55914106Sjavier.setoain@arm.com
56014106Sjavier.setoain@arm.com    doSemaphoreUp(smmu.configSem);
56114106Sjavier.setoain@arm.com}
56214106Sjavier.setoain@arm.com
56314106Sjavier.setoain@arm.combool
56414106Sjavier.setoain@arm.comSMMUTranslationProcess::findConfig(Yield &yield,
56514106Sjavier.setoain@arm.com                                   TranslContext &tc,
56614106Sjavier.setoain@arm.com                                   TranslResult &tr)
56714106Sjavier.setoain@arm.com{
56814106Sjavier.setoain@arm.com    tc.stage1Enable = false;
56914106Sjavier.setoain@arm.com    tc.stage2Enable = false;
57014106Sjavier.setoain@arm.com
57114106Sjavier.setoain@arm.com    StreamTableEntry ste;
57214106Sjavier.setoain@arm.com    doReadSTE(yield, ste, request.sid);
57314106Sjavier.setoain@arm.com
57414106Sjavier.setoain@arm.com    switch (ste.dw0.config) {
57514106Sjavier.setoain@arm.com        case STE_CONFIG_BYPASS:
57614106Sjavier.setoain@arm.com            break;
57714106Sjavier.setoain@arm.com
57813759Sgiacomo.gabrielli@arm.com        case STE_CONFIG_STAGE1_ONLY:
57913759Sgiacomo.gabrielli@arm.com            tc.stage1Enable = true;
58013759Sgiacomo.gabrielli@arm.com            break;
58113759Sgiacomo.gabrielli@arm.com
58213759Sgiacomo.gabrielli@arm.com        case STE_CONFIG_STAGE2_ONLY:
58313759Sgiacomo.gabrielli@arm.com            tc.stage2Enable = true;
58413759Sgiacomo.gabrielli@arm.com            break;
58513759Sgiacomo.gabrielli@arm.com
58613759Sgiacomo.gabrielli@arm.com        case STE_CONFIG_STAGE1_AND_2:
58713759Sgiacomo.gabrielli@arm.com            tc.stage1Enable = true;
58813759Sgiacomo.gabrielli@arm.com            tc.stage2Enable = true;
58914028Sgiacomo.gabrielli@arm.com            break;
59014028Sgiacomo.gabrielli@arm.com
59114028Sgiacomo.gabrielli@arm.com        default:
59214028Sgiacomo.gabrielli@arm.com            panic("Bad or unimplemented STE config %d\n",
59314028Sgiacomo.gabrielli@arm.com                ste.dw0.config);
59414028Sgiacomo.gabrielli@arm.com    }
59514028Sgiacomo.gabrielli@arm.com
59614028Sgiacomo.gabrielli@arm.com
59714028Sgiacomo.gabrielli@arm.com    // Establish stage 2 context first since
59814028Sgiacomo.gabrielli@arm.com    // Context Descriptors can be in IPA space.
59914028Sgiacomo.gabrielli@arm.com    if (tc.stage2Enable) {
60014028Sgiacomo.gabrielli@arm.com        tc.httb = ste.dw3.s2ttb << STE_S2TTB_SHIFT;
60114028Sgiacomo.gabrielli@arm.com        tc.vmid = ste.dw2.s2vmid;
60214028Sgiacomo.gabrielli@arm.com        tc.stage2TranslGranule = ste.dw2.s2tg;
60314028Sgiacomo.gabrielli@arm.com    } else {
60414028Sgiacomo.gabrielli@arm.com        tc.httb = 0xdeadbeef;
60514028Sgiacomo.gabrielli@arm.com        tc.vmid = 0;
60614028Sgiacomo.gabrielli@arm.com        tc.stage2TranslGranule = TRANS_GRANULE_INVALID;
60714028Sgiacomo.gabrielli@arm.com    }
60814028Sgiacomo.gabrielli@arm.com
60914028Sgiacomo.gabrielli@arm.com
61014028Sgiacomo.gabrielli@arm.com    // Now fetch stage 1 config.
61114028Sgiacomo.gabrielli@arm.com    if (context.stage1Enable) {
61214028Sgiacomo.gabrielli@arm.com        ContextDescriptor cd;
61314028Sgiacomo.gabrielli@arm.com        doReadCD(yield, cd, ste, request.sid, request.ssid);
61414028Sgiacomo.gabrielli@arm.com
61514028Sgiacomo.gabrielli@arm.com        tc.ttb0 = cd.dw1.ttb0 << CD_TTB_SHIFT;
61614028Sgiacomo.gabrielli@arm.com        tc.ttb1 = cd.dw2.ttb1 << CD_TTB_SHIFT;
61714028Sgiacomo.gabrielli@arm.com        tc.asid = cd.dw0.asid;
61814028Sgiacomo.gabrielli@arm.com        tc.stage1TranslGranule = cd.dw0.tg0;
61914028Sgiacomo.gabrielli@arm.com    } else {
62014028Sgiacomo.gabrielli@arm.com        tc.ttb0 = 0xcafebabe;
62114028Sgiacomo.gabrielli@arm.com        tc.ttb1 = 0xcafed00d;
62213759Sgiacomo.gabrielli@arm.com        tc.asid = 0;
62313759Sgiacomo.gabrielli@arm.com        tc.stage1TranslGranule = TRANS_GRANULE_INVALID;
62413759Sgiacomo.gabrielli@arm.com    }
62513759Sgiacomo.gabrielli@arm.com
62613759Sgiacomo.gabrielli@arm.com    return true;
62713759Sgiacomo.gabrielli@arm.com}
62813759Sgiacomo.gabrielli@arm.com
62914091Sgabor.dozsa@arm.comvoid
63014091Sgabor.dozsa@arm.comSMMUTranslationProcess::walkCacheLookup(
63113759Sgiacomo.gabrielli@arm.com        Yield &yield,
6327797Sgblack@eecs.umich.edu        const WalkCache::Entry *&walkEntry,
6337797Sgblack@eecs.umich.edu        Addr addr, uint16_t asid, uint16_t vmid,
6347797Sgblack@eecs.umich.edu        unsigned stage, unsigned level)
63510037SARM gem5 Developers{
63610037SARM gem5 Developers    const char *indent = stage==2 ? "  " : "";
63710037SARM gem5 Developers    (void) indent; // this is only used in DPRINTFs
63810037SARM gem5 Developers
6397797Sgblack@eecs.umich.edu    const PageTableOps *pt_ops =
6407797Sgblack@eecs.umich.edu        stage == 1 ?
6417797Sgblack@eecs.umich.edu            smmu.getPageTableOps(context.stage1TranslGranule) :
6428302SAli.Saidi@ARM.com            smmu.getPageTableOps(context.stage2TranslGranule);
6437797Sgblack@eecs.umich.edu
6447797Sgblack@eecs.umich.edu    unsigned walkCacheLevels =
6457797Sgblack@eecs.umich.edu        smmu.walkCacheEnable ?
6467797Sgblack@eecs.umich.edu            (stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels) :
6477797Sgblack@eecs.umich.edu            0;
6487797Sgblack@eecs.umich.edu
6497797Sgblack@eecs.umich.edu    if ((1 << level) & walkCacheLevels) {
65010037SARM gem5 Developers        doSemaphoreDown(yield, smmu.walkSem);
6517797Sgblack@eecs.umich.edu        doDelay(yield, smmu.walkLat);
65210037SARM gem5 Developers
65310037SARM gem5 Developers        walkEntry = smmu.walkCache.lookup(addr, pt_ops->walkMask(level),
65410037SARM gem5 Developers                                          asid, vmid, stage, level);
65510037SARM gem5 Developers
65610037SARM gem5 Developers        if (walkEntry) {
65710037SARM gem5 Developers            DPRINTF(SMMUv3, "%sWalkCache hit  va=%#x asid=%#x vmid=%#x "
65810037SARM gem5 Developers                            "base=%#x (S%d, L%d)\n",
65910037SARM gem5 Developers                    indent, addr, asid, vmid, walkEntry->pa, stage, level);
66010037SARM gem5 Developers        } else {
66110037SARM gem5 Developers            DPRINTF(SMMUv3, "%sWalkCache miss va=%#x asid=%#x vmid=%#x "
66210037SARM gem5 Developers                            "(S%d, L%d)\n",
6637797Sgblack@eecs.umich.edu                    indent, addr, asid, vmid, stage, level);
6647797Sgblack@eecs.umich.edu        }
6658209SAli.Saidi@ARM.com
66610037SARM gem5 Developers        doSemaphoreUp(smmu.walkSem);
6676019Shines@cs.fsu.edu    }
6686308Sgblack@eecs.umich.edu}
6698139SMatt.Horsnell@arm.com
67010037SARM gem5 Developersvoid
67110037SARM gem5 DevelopersSMMUTranslationProcess::walkCacheUpdate(Yield &yield, Addr va,
6727797Sgblack@eecs.umich.edu                                        Addr vaMask, Addr pa,
67313603Sgiacomo.travaglini@arm.com                                        unsigned stage, unsigned level,
6748139SMatt.Horsnell@arm.com                                        bool leaf, uint8_t permissions)
67510037SARM gem5 Developers{
6768139SMatt.Horsnell@arm.com    unsigned walkCacheLevels =
67710037SARM gem5 Developers        stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels;
6786308Sgblack@eecs.umich.edu
6796019Shines@cs.fsu.edu    if (smmu.walkCacheEnable && ((1<<level) & walkCacheLevels)) {
6807797Sgblack@eecs.umich.edu        WalkCache::Entry e;
6816019Shines@cs.fsu.edu        e.valid = true;
6827797Sgblack@eecs.umich.edu        e.va = va;
68310037SARM gem5 Developers        e.vaMask = vaMask;
6847797Sgblack@eecs.umich.edu        e.asid = stage==1 ? context.asid : 0;
6857797Sgblack@eecs.umich.edu        e.vmid = context.vmid;
6867797Sgblack@eecs.umich.edu        e.stage = stage;
6877797Sgblack@eecs.umich.edu        e.level = level;
6887797Sgblack@eecs.umich.edu        e.leaf = leaf;
6897797Sgblack@eecs.umich.edu        e.pa = pa;
6907797Sgblack@eecs.umich.edu        e.permissions = permissions;
6918205SAli.Saidi@ARM.com
6928205SAli.Saidi@ARM.com        doSemaphoreDown(yield, smmu.walkSem);
69311514Sandreas.sandberg@arm.com
6947797Sgblack@eecs.umich.edu        DPRINTF(SMMUv3, "%sWalkCache upd  va=%#x mask=%#x asid=%#x vmid=%#x "
6957797Sgblack@eecs.umich.edu                        "tpa=%#x leaf=%s (S%d, L%d)\n",
6967797Sgblack@eecs.umich.edu                e.stage==2 ? "  " : "",
6977797Sgblack@eecs.umich.edu                e.va, e.vaMask, e.asid, e.vmid,
6987797Sgblack@eecs.umich.edu                e.pa, e.leaf, e.stage, e.level);
6997797Sgblack@eecs.umich.edu
7007797Sgblack@eecs.umich.edu        smmu.walkCache.store(e);
7017797Sgblack@eecs.umich.edu
7027797Sgblack@eecs.umich.edu        doSemaphoreUp(smmu.walkSem);
7036019Shines@cs.fsu.edu    }
704}
705
706/*
707 * Please note:
708 * This does not deal with the case where stage 1 page size
709 * is larger than stage 2 page size.
710 */
711SMMUTranslationProcess::TranslResult
712SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr,
713                                       const PageTableOps *pt_ops,
714                                       unsigned level, Addr walkPtr)
715{
716    PageTableOps::pte_t pte = 0;
717
718    doSemaphoreDown(yield, smmu.cycleSem);
719    doDelay(yield, Cycles(1));
720    doSemaphoreUp(smmu.cycleSem);
721
722    for (; level <= pt_ops->lastLevel(); level++) {
723        Addr pte_addr = walkPtr + pt_ops->index(addr, level);
724
725        DPRINTF(SMMUv3, "Fetching S1 L%d PTE from pa=%#08x\n",
726                level, pte_addr);
727
728        doReadPTE(yield, addr, pte_addr, &pte, 1, level);
729
730        DPRINTF(SMMUv3, "Got S1 L%d PTE=%#x from pa=%#08x\n",
731                level, pte, pte_addr);
732
733        doSemaphoreDown(yield, smmu.cycleSem);
734        doDelay(yield, Cycles(1));
735        doSemaphoreUp(smmu.cycleSem);
736
737        bool valid = pt_ops->isValid(pte, level);
738        bool leaf  = pt_ops->isLeaf(pte, level);
739
740        if (!valid) {
741            DPRINTF(SMMUv3, "S1 PTE not valid - fault\n");
742
743            TranslResult tr;
744            tr.fault = FAULT_TRANSLATION;
745            return tr;
746        }
747
748        if (valid && leaf && request.isWrite &&
749            !pt_ops->isWritable(pte, level, false))
750        {
751            DPRINTF(SMMUv3, "S1 page not writable - fault\n");
752
753            TranslResult tr;
754            tr.fault = FAULT_PERMISSION;
755            return tr;
756        }
757
758        walkPtr = pt_ops->nextLevelPointer(pte, level);
759
760        if (leaf)
761            break;
762
763        if (context.stage2Enable) {
764            TranslResult s2tr = translateStage2(yield, walkPtr, false);
765            if (s2tr.fault != FAULT_NONE)
766                return s2tr;
767
768            walkPtr = s2tr.addr;
769        }
770
771        walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr,
772                        1, level, leaf, 0);
773    }
774
775    TranslResult tr;
776    tr.fault    = FAULT_NONE;
777    tr.addrMask = pt_ops->pageMask(pte, level);
778    tr.addr     = walkPtr + (addr & ~tr.addrMask);
779    tr.writable = pt_ops->isWritable(pte, level, false);
780
781    if (context.stage2Enable) {
782        TranslResult s2tr = translateStage2(yield, tr.addr, true);
783        if (s2tr.fault != FAULT_NONE)
784            return s2tr;
785
786        tr = combineTranslations(tr, s2tr);
787    }
788
789    walkCacheUpdate(yield, addr, tr.addrMask, tr.addr,
790                    1, level, true, tr.writable);
791
792    return tr;
793}
794
795SMMUTranslationProcess::TranslResult
796SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr,
797                                   const PageTableOps *pt_ops,
798                                   unsigned level, Addr walkPtr)
799{
800    PageTableOps::pte_t pte;
801
802    doSemaphoreDown(yield, smmu.cycleSem);
803    doDelay(yield, Cycles(1));
804    doSemaphoreUp(smmu.cycleSem);
805
806    for (; level <= pt_ops->lastLevel(); level++) {
807        Addr pte_addr = walkPtr + pt_ops->index(addr, level);
808
809        DPRINTF(SMMUv3, "  Fetching S2 L%d PTE from pa=%#08x\n",
810                level, pte_addr);
811
812        doReadPTE(yield, addr, pte_addr, &pte, 2, level);
813
814        DPRINTF(SMMUv3, "  Got S2 L%d PTE=%#x from pa=%#08x\n",
815                level, pte, pte_addr);
816
817        doSemaphoreDown(yield, smmu.cycleSem);
818        doDelay(yield, Cycles(1));
819        doSemaphoreUp(smmu.cycleSem);
820
821        bool valid = pt_ops->isValid(pte, level);
822        bool leaf  = pt_ops->isLeaf(pte, level);
823
824        if (!valid) {
825            DPRINTF(SMMUv3, "  S2 PTE not valid - fault\n");
826
827            TranslResult tr;
828            tr.fault = FAULT_TRANSLATION;
829            return tr;
830        }
831
832        if (valid && leaf && request.isWrite &&
833            !pt_ops->isWritable(pte, level, true))
834        {
835            DPRINTF(SMMUv3, "  S2 PTE not writable = fault\n");
836
837            TranslResult tr;
838            tr.fault = FAULT_PERMISSION;
839            return tr;
840        }
841
842        walkPtr = pt_ops->nextLevelPointer(pte, level);
843
844        if (final_tr || smmu.walkCacheNonfinalEnable)
845            walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr,
846                            2, level, leaf,
847                            leaf ? pt_ops->isWritable(pte, level, true) : 0);
848        if (leaf)
849            break;
850    }
851
852    TranslResult tr;
853    tr.fault    = FAULT_NONE;
854    tr.addrMask = pt_ops->pageMask(pte, level);
855    tr.addr     = walkPtr + (addr & ~tr.addrMask);
856    tr.writable = pt_ops->isWritable(pte, level, true);
857
858    return tr;
859}
860
861SMMUTranslationProcess::TranslResult
862SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
863{
864    const PageTableOps *pt_ops =
865        smmu.getPageTableOps(context.stage1TranslGranule);
866
867    const WalkCache::Entry *walk_ep = NULL;
868    unsigned level;
869
870    // Level here is actually (level+1) so we can count down
871    // to 0 using unsigned int.
872    for (level = pt_ops->lastLevel() + 1;
873        level > pt_ops->firstLevel();
874        level--)
875    {
876        walkCacheLookup(yield, walk_ep, addr,
877                        context.asid, context.vmid, 1, level-1);
878
879        if (walk_ep)
880            break;
881    }
882
883    // Correct level (see above).
884    level -= 1;
885
886    TranslResult tr;
887    if (walk_ep) {
888        if (walk_ep->leaf) {
889            tr.fault    = FAULT_NONE;
890            tr.addr     = walk_ep->pa + (addr & ~walk_ep->vaMask);
891            tr.addrMask = walk_ep->vaMask;
892            tr.writable = walk_ep->permissions;
893        } else {
894            tr = walkStage1And2(yield, addr, pt_ops, level+1, walk_ep->pa);
895        }
896    } else {
897        Addr table_addr = context.ttb0;
898        if (context.stage2Enable) {
899            TranslResult s2tr = translateStage2(yield, table_addr, false);
900            if (s2tr.fault != FAULT_NONE)
901                return s2tr;
902
903            table_addr = s2tr.addr;
904        }
905
906        tr = walkStage1And2(yield, addr, pt_ops, pt_ops->firstLevel(),
907                            table_addr);
908    }
909
910    if (tr.fault == FAULT_NONE)
911        DPRINTF(SMMUv3, "Translated vaddr %#x to paddr %#x\n", addr, tr.addr);
912
913    return tr;
914}
915
916SMMUTranslationProcess::TranslResult
917SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
918{
919    const PageTableOps *pt_ops =
920            smmu.getPageTableOps(context.stage2TranslGranule);
921
922    const IPACache::Entry *ipa_ep = NULL;
923    if (smmu.ipaCacheEnable) {
924        doSemaphoreDown(yield, smmu.ipaSem);
925        doDelay(yield, smmu.ipaLat);
926        ipa_ep = smmu.ipaCache.lookup(addr, context.vmid);
927        doSemaphoreUp(smmu.ipaSem);
928    }
929
930    if (ipa_ep) {
931        TranslResult tr;
932        tr.fault    = FAULT_NONE;
933        tr.addr     = ipa_ep->pa + (addr & ~ipa_ep->ipaMask);
934        tr.addrMask = ipa_ep->ipaMask;
935        tr.writable = ipa_ep->permissions;
936
937        DPRINTF(SMMUv3, "  IPACache hit  ipa=%#x vmid=%#x pa=%#x\n",
938            addr, context.vmid, tr.addr);
939
940        return tr;
941    } else if (smmu.ipaCacheEnable) {
942        DPRINTF(SMMUv3, "  IPACache miss ipa=%#x vmid=%#x\n",
943                addr, context.vmid);
944    }
945
946    const WalkCache::Entry *walk_ep = NULL;
947    unsigned level = pt_ops->firstLevel();
948
949    if (final_tr || smmu.walkCacheNonfinalEnable) {
950        // Level here is actually (level+1) so we can count down
951        // to 0 using unsigned int.
952        for (level = pt_ops->lastLevel() + 1;
953            level > pt_ops->firstLevel();
954            level--)
955        {
956            walkCacheLookup(yield, walk_ep, addr,
957                            0, context.vmid, 2, level-1);
958
959            if (walk_ep)
960                break;
961        }
962
963        // Correct level (see above).
964        level -= 1;
965    }
966
967    TranslResult tr;
968    if (walk_ep) {
969        if (walk_ep->leaf) {
970            tr.fault    = FAULT_NONE;
971            tr.addr     = walk_ep->pa + (addr & ~walk_ep->vaMask);
972            tr.addrMask = walk_ep->vaMask;
973            tr.writable = walk_ep->permissions;
974        } else {
975            tr = walkStage2(yield, addr, final_tr, pt_ops,
976                            level + 1, walk_ep->pa);
977        }
978    } else {
979        tr = walkStage2(yield, addr, final_tr, pt_ops, pt_ops->firstLevel(),
980                        context.httb);
981    }
982
983    if (tr.fault == FAULT_NONE)
984        DPRINTF(SMMUv3, "  Translated %saddr %#x to paddr %#x\n",
985            context.stage1Enable ? "ip" : "v", addr, tr.addr);
986
987    if (smmu.ipaCacheEnable) {
988        IPACache::Entry e;
989        e.valid = true;
990        e.ipaMask = tr.addrMask;
991        e.ipa = addr & e.ipaMask;
992        e.pa = tr.addr & tr.addrMask;
993        e.permissions = tr.writable;
994        e.vmid = context.vmid;
995
996        doSemaphoreDown(yield, smmu.ipaSem);
997        smmu.ipaCache.store(e);
998        doSemaphoreUp(smmu.ipaSem);
999    }
1000
1001    return tr;
1002}
1003
1004SMMUTranslationProcess::TranslResult
1005SMMUTranslationProcess::combineTranslations(const TranslResult &s1tr,
1006                                            const TranslResult &s2tr) const
1007{
1008    if (s2tr.fault != FAULT_NONE)
1009        return s2tr;
1010
1011    assert(s1tr.fault == FAULT_NONE);
1012
1013    TranslResult tr;
1014    tr.fault    = FAULT_NONE;
1015    tr.addr     = s2tr.addr;
1016    tr.addrMask = s1tr.addrMask | s2tr.addrMask;
1017    tr.writable = s1tr.writable & s2tr.writable;
1018
1019    return tr;
1020}
1021
1022bool
1023SMMUTranslationProcess::hazard4kCheck()
1024{
1025    Addr addr4k = request.addr & ~0xfffULL;
1026
1027    for (auto it = ifc.duplicateReqs.begin();
1028         it != ifc.duplicateReqs.end();
1029         ++it)
1030    {
1031        Addr other4k = (*it)->request.addr & ~0xfffULL;
1032        if (addr4k == other4k)
1033            return true;
1034    }
1035
1036    return false;
1037}
1038
1039void
1040SMMUTranslationProcess::hazard4kRegister()
1041{
1042    DPRINTF(SMMUv3Hazard, "4kReg:  p=%p a4k=%#x\n",
1043            this, request.addr & ~0xfffULL);
1044
1045    ifc.duplicateReqs.push_back(this);
1046}
1047
1048void
1049SMMUTranslationProcess::hazard4kHold(Yield &yield)
1050{
1051    Addr addr4k = request.addr & ~0xfffULL;
1052
1053    bool found_hazard;
1054
1055    do {
1056        found_hazard = false;
1057
1058        for (auto it = ifc.duplicateReqs.begin();
1059             it!=ifc.duplicateReqs.end() && *it!=this;
1060             ++it)
1061        {
1062            Addr other4k = (*it)->request.addr & ~0xfffULL;
1063
1064            DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x Q: p=%p a4k=%#x\n",
1065                    this, addr4k, *it, other4k);
1066
1067            if (addr4k == other4k) {
1068                DPRINTF(SMMUv3Hazard,
1069                        "4kHold: p=%p a4k=%#x WAIT on p=%p a4k=%#x\n",
1070                        this, addr4k, *it, other4k);
1071
1072                doWaitForSignal(yield, ifc.duplicateReqRemoved);
1073
1074                DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x RESUME\n",
1075                        this, addr4k);
1076
1077                // This is to avoid checking *it!=this after doWaitForSignal()
1078                // since it could have been deleted.
1079                found_hazard = true;
1080                break;
1081            }
1082        }
1083    } while (found_hazard);
1084}
1085
1086void
1087SMMUTranslationProcess::hazard4kRelease()
1088{
1089    DPRINTF(SMMUv3Hazard, "4kRel:  p=%p a4k=%#x\n",
1090            this, request.addr & ~0xfffULL);
1091
1092    std::list<SMMUTranslationProcess *>::iterator it;
1093
1094    for (it = ifc.duplicateReqs.begin(); it != ifc.duplicateReqs.end(); ++it)
1095        if (*it == this)
1096            break;
1097
1098    if (it == ifc.duplicateReqs.end())
1099        panic("hazard4kRelease: request not found");
1100
1101    ifc.duplicateReqs.erase(it);
1102
1103    doBroadcastSignal(ifc.duplicateReqRemoved);
1104}
1105
1106void
1107SMMUTranslationProcess::hazardIdRegister()
1108{
1109    auto orderId = AMBA::orderId(request.pkt);
1110
1111    DPRINTF(SMMUv3Hazard, "IdReg:  p=%p oid=%d\n", this, orderId);
1112
1113    assert(orderId < SMMU_MAX_TRANS_ID);
1114
1115    std::list<SMMUTranslationProcess *> &depReqs =
1116        request.isWrite ?
1117            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
1118    depReqs.push_back(this);
1119}
1120
1121void
1122SMMUTranslationProcess::hazardIdHold(Yield &yield)
1123{
1124    auto orderId = AMBA::orderId(request.pkt);
1125
1126    DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d\n", this, orderId);
1127
1128    std::list<SMMUTranslationProcess *> &depReqs =
1129        request.isWrite ?
1130            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
1131    std::list<SMMUTranslationProcess *>::iterator it;
1132
1133    bool found_hazard;
1134
1135    do {
1136        found_hazard = false;
1137
1138        for (auto it = depReqs.begin(); it!=depReqs.end() && *it!=this; ++it) {
1139            DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d Q: %p\n",
1140                    this, orderId, *it);
1141
1142            if (AMBA::orderId((*it)->request.pkt) == orderId) {
1143                DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d WAIT on=%p\n",
1144                        this, orderId, *it);
1145
1146                doWaitForSignal(yield, ifc.dependentReqRemoved);
1147
1148                DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d RESUME\n",
1149                        this, orderId);
1150
1151                // This is to avoid checking *it!=this after doWaitForSignal()
1152                // since it could have been deleted.
1153                found_hazard = true;
1154                break;
1155            }
1156        }
1157    } while (found_hazard);
1158}
1159
1160void
1161SMMUTranslationProcess::hazardIdRelease()
1162{
1163    auto orderId = AMBA::orderId(request.pkt);
1164
1165    DPRINTF(SMMUv3Hazard, "IdRel:  p=%p oid=%d\n", this, orderId);
1166
1167    std::list<SMMUTranslationProcess *> &depReqs =
1168        request.isWrite ?
1169            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
1170    std::list<SMMUTranslationProcess *>::iterator it;
1171
1172    for (it = depReqs.begin(); it != depReqs.end(); ++it) {
1173        if (*it == this)
1174            break;
1175    }
1176
1177    if (it == depReqs.end())
1178        panic("hazardIdRelease: request not found");
1179
1180    depReqs.erase(it);
1181
1182    doBroadcastSignal(ifc.dependentReqRemoved);
1183}
1184
1185void
1186SMMUTranslationProcess::issuePrefetch(Addr addr)
1187{
1188    if (!smmu.system.isTimingMode())
1189        return;
1190
1191    if (!ifc.prefetchEnable || ifc.xlateSlotsRemaining == 0)
1192        return;
1193
1194    std::string proc_name = csprintf("%sprf", name());
1195    SMMUTranslationProcess *proc =
1196        new SMMUTranslationProcess(proc_name, smmu, ifc);
1197
1198    proc->beginTransaction(
1199            SMMUTranslRequest::prefetch(addr, request.sid, request.ssid));
1200    proc->scheduleWakeup(smmu.clockEdge(Cycles(1)));
1201}
1202
1203void
1204SMMUTranslationProcess::completeTransaction(Yield &yield,
1205                                            const TranslResult &tr)
1206{
1207    assert(tr.fault == FAULT_NONE);
1208
1209    unsigned numMasterBeats = request.isWrite ?
1210        (request.size + (smmu.masterPortWidth-1))
1211            / smmu.masterPortWidth :
1212        1;
1213
1214    doSemaphoreDown(yield, smmu.masterPortSem);
1215    doDelay(yield, Cycles(numMasterBeats));
1216    doSemaphoreUp(smmu.masterPortSem);
1217
1218
1219    smmu.translationTimeDist.sample(curTick() - recvTick);
1220    if (!request.isAtsRequest && request.isWrite)
1221        ifc.wrBufSlotsRemaining +=
1222            (request.size + (ifc.portWidth-1)) / ifc.portWidth;
1223
1224    smmu.scheduleSlaveRetries();
1225
1226
1227    SMMUAction a;
1228
1229    if (request.isAtsRequest) {
1230        a.type = ACTION_SEND_RESP_ATS;
1231
1232        if (smmu.system.isAtomicMode()) {
1233            request.pkt->makeAtomicResponse();
1234        } else if (smmu.system.isTimingMode()) {
1235            request.pkt->makeTimingResponse();
1236        } else {
1237            panic("Not in atomic or timing mode");
1238        }
1239    } else {
1240        a.type = ACTION_SEND_REQ_FINAL;
1241        a.ifc = &ifc;
1242    }
1243
1244    a.pkt = request.pkt;
1245    a.delay = 0;
1246
1247    a.pkt->setAddr(tr.addr);
1248    a.pkt->req->setPaddr(tr.addr);
1249
1250    yield(a);
1251
1252    if (!request.isAtsRequest) {
1253        PacketPtr pkt = yield.get();
1254        pkt->setAddr(request.addr);
1255
1256        a.type = ACTION_SEND_RESP;
1257        a.pkt = pkt;
1258        a.ifc = &ifc;
1259        a.delay = 0;
1260        yield(a);
1261    }
1262}
1263
1264void
1265SMMUTranslationProcess::completePrefetch(Yield &yield)
1266{
1267    SMMUAction a;
1268    a.type = ACTION_TERMINATE;
1269    a.pkt = NULL;
1270    a.ifc = &ifc;
1271    a.delay = 0;
1272    yield(a);
1273}
1274
1275void
1276SMMUTranslationProcess::sendEvent(Yield &yield, const SMMUEvent &ev)
1277{
1278    int sizeMask = mask(smmu.regs.eventq_base & Q_BASE_SIZE_MASK) &
1279            Q_CONS_PROD_MASK;
1280
1281    if (((smmu.regs.eventq_prod+1) & sizeMask) ==
1282            (smmu.regs.eventq_cons & sizeMask))
1283        panic("Event queue full - aborting\n");
1284
1285    Addr event_addr =
1286        (smmu.regs.eventq_base & Q_BASE_ADDR_MASK) +
1287        (smmu.regs.eventq_prod & sizeMask) * sizeof(ev);
1288
1289    DPRINTF(SMMUv3, "Sending event to addr=%#08x (pos=%d): type=%#x stag=%#x "
1290        "flags=%#x sid=%#x ssid=%#x va=%#08x ipa=%#x\n",
1291        event_addr, smmu.regs.eventq_prod, ev.type, ev.stag,
1292        ev.flags, ev.streamId, ev.substreamId, ev.va, ev.ipa);
1293
1294    // This deliberately resets the overflow field in eventq_prod!
1295    smmu.regs.eventq_prod = (smmu.regs.eventq_prod + 1) & sizeMask;
1296
1297    doWrite(yield, event_addr, &ev, sizeof(ev));
1298
1299    if (!(smmu.regs.eventq_irq_cfg0 & E_BASE_ENABLE_MASK))
1300        panic("eventq msi not enabled\n");
1301
1302    doWrite(yield, smmu.regs.eventq_irq_cfg0 & E_BASE_ADDR_MASK,
1303            &smmu.regs.eventq_irq_cfg1, sizeof(smmu.regs.eventq_irq_cfg1));
1304}
1305
1306void
1307SMMUTranslationProcess::doReadSTE(Yield &yield,
1308                                  StreamTableEntry &ste,
1309                                  uint32_t sid)
1310{
1311    unsigned max_sid = 1 << (smmu.regs.strtab_base_cfg & ST_CFG_SIZE_MASK);
1312    if (sid >= max_sid)
1313        panic("SID %#x out of range, max=%#x", sid, max_sid);
1314
1315    Addr ste_addr;
1316
1317    if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_2LEVEL) {
1318        unsigned split =
1319            (smmu.regs.strtab_base_cfg & ST_CFG_SPLIT_MASK) >> ST_CFG_SPLIT_SHIFT;
1320
1321        if (split!= 7 && split!=8 && split!=16)
1322            panic("Invalid stream table split %d", split);
1323
1324        uint64_t l2_ptr;
1325        uint64_t l2_addr =
1326            (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) +
1327            bits(sid, 32, split) * sizeof(l2_ptr);
1328
1329        DPRINTF(SMMUv3, "Read L1STE at %#x\n", l2_addr);
1330
1331        doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, 0);
1332
1333        DPRINTF(SMMUv3, "Got L1STE L1 at %#x: 0x%016x\n", l2_addr, l2_ptr);
1334
1335        unsigned span = l2_ptr & ST_L2_SPAN_MASK;
1336        if (span == 0)
1337            panic("Invalid level 1 stream table descriptor");
1338
1339        unsigned index = bits(sid, split-1, 0);
1340        if (index >= (1 << span))
1341            panic("StreamID %d out of level 1 descriptor range %d",
1342                  sid, 1<<span);
1343
1344        ste_addr = (l2_ptr & ST_L2_ADDR_MASK) + index * sizeof(ste);
1345
1346        smmu.steL1Fetches++;
1347    } else if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_LINEAR) {
1348        ste_addr =
1349            (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + sid * sizeof(ste);
1350    } else {
1351        panic("Invalid stream table format");
1352    }
1353
1354    DPRINTF(SMMUv3, "Read STE at %#x\n", ste_addr);
1355
1356    doReadConfig(yield, ste_addr, &ste, sizeof(ste), sid, 0);
1357
1358    DPRINTF(SMMUv3, "Got STE at %#x [0]: 0x%016x\n", ste_addr, ste.dw0);
1359    DPRINTF(SMMUv3, "    STE at %#x [1]: 0x%016x\n", ste_addr, ste.dw1);
1360    DPRINTF(SMMUv3, "    STE at %#x [2]: 0x%016x\n", ste_addr, ste.dw2);
1361    DPRINTF(SMMUv3, "    STE at %#x [3]: 0x%016x\n", ste_addr, ste.dw3);
1362    DPRINTF(SMMUv3, "    STE at %#x [4]: 0x%016x\n", ste_addr, ste._pad[0]);
1363    DPRINTF(SMMUv3, "    STE at %#x [5]: 0x%016x\n", ste_addr, ste._pad[1]);
1364    DPRINTF(SMMUv3, "    STE at %#x [6]: 0x%016x\n", ste_addr, ste._pad[2]);
1365    DPRINTF(SMMUv3, "    STE at %#x [7]: 0x%016x\n", ste_addr, ste._pad[3]);
1366
1367    if (!ste.dw0.valid)
1368        panic("STE @ %#x not valid\n", ste_addr);
1369
1370    smmu.steFetches++;
1371}
1372
1373void
1374SMMUTranslationProcess::doReadCD(Yield &yield,
1375                                 ContextDescriptor &cd,
1376                                 const StreamTableEntry &ste,
1377                                 uint32_t sid, uint32_t ssid)
1378{
1379    Addr cd_addr;
1380
1381    if (ste.dw0.s1cdmax == 0) {
1382        cd_addr = ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT;
1383    } else {
1384        unsigned max_ssid = 1 << ste.dw0.s1cdmax;
1385        if (ssid >= max_ssid)
1386            panic("SSID %#x out of range, max=%#x", ssid, max_ssid);
1387
1388        if (ste.dw0.s1fmt==STAGE1_CFG_2L_4K ||
1389            ste.dw0.s1fmt==STAGE1_CFG_2L_64K)
1390        {
1391            unsigned split = ste.dw0.s1fmt==STAGE1_CFG_2L_4K ? 7 : 11;
1392
1393            uint64_t l2_ptr;
1394            uint64_t l2_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) +
1395                bits(ssid, 24, split) * sizeof(l2_ptr);
1396
1397            if (context.stage2Enable)
1398                l2_addr = translateStage2(yield, l2_addr, false).addr;
1399
1400            DPRINTF(SMMUv3, "Read L1CD at %#x\n", l2_addr);
1401
1402            doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, ssid);
1403
1404            DPRINTF(SMMUv3, "Got L1CD at %#x: 0x%016x\n", l2_addr, l2_ptr);
1405
1406            cd_addr = l2_ptr + bits(ssid, split-1, 0) * sizeof(cd);
1407
1408            smmu.cdL1Fetches++;
1409        } else if (ste.dw0.s1fmt == STAGE1_CFG_1L) {
1410            cd_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + ssid*sizeof(cd);
1411        }
1412    }
1413
1414    if (context.stage2Enable)
1415        cd_addr = translateStage2(yield, cd_addr, false).addr;
1416
1417    DPRINTF(SMMUv3, "Read CD at %#x\n", cd_addr);
1418
1419    doReadConfig(yield, cd_addr, &cd, sizeof(cd), sid, ssid);
1420
1421    DPRINTF(SMMUv3, "Got CD at %#x [0]: 0x%016x\n", cd_addr, cd.dw0);
1422    DPRINTF(SMMUv3, "    CD at %#x [1]: 0x%016x\n", cd_addr, cd.dw1);
1423    DPRINTF(SMMUv3, "    CD at %#x [2]: 0x%016x\n", cd_addr, cd.dw2);
1424    DPRINTF(SMMUv3, "    CD at %#x [3]: 0x%016x\n", cd_addr, cd.mair);
1425    DPRINTF(SMMUv3, "    CD at %#x [4]: 0x%016x\n", cd_addr, cd.amair);
1426    DPRINTF(SMMUv3, "    CD at %#x [5]: 0x%016x\n", cd_addr, cd._pad[0]);
1427    DPRINTF(SMMUv3, "    CD at %#x [6]: 0x%016x\n", cd_addr, cd._pad[1]);
1428    DPRINTF(SMMUv3, "    CD at %#x [7]: 0x%016x\n", cd_addr, cd._pad[2]);
1429
1430
1431    if (!cd.dw0.valid)
1432        panic("CD @ %#x not valid\n", cd_addr);
1433
1434    smmu.cdFetches++;
1435}
1436
1437void
1438SMMUTranslationProcess::doReadConfig(Yield &yield, Addr addr,
1439                                     void *ptr, size_t size,
1440                                     uint32_t sid, uint32_t ssid)
1441{
1442    doRead(yield, addr, ptr, size);
1443}
1444
1445void
1446SMMUTranslationProcess::doReadPTE(Yield &yield, Addr va, Addr addr,
1447                                  void *ptr, unsigned stage,
1448                                  unsigned level)
1449{
1450    size_t pte_size = sizeof(PageTableOps::pte_t);
1451
1452    Addr mask = pte_size - 1;
1453    Addr base = addr & ~mask;
1454
1455    doRead(yield, base, ptr, pte_size);
1456}
1457