smmu_v3_transl.cc revision 14100
15651Sgblack@eecs.umich.edu/*
25651Sgblack@eecs.umich.edu * Copyright (c) 2013, 2018-2019 ARM Limited
35651Sgblack@eecs.umich.edu * All rights reserved
45651Sgblack@eecs.umich.edu *
55651Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
65651Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
75651Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
85651Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
95651Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
105651Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
115651Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
125651Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
135651Sgblack@eecs.umich.edu *
145651Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
155651Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
165651Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
175651Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
185651Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
195651Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
205651Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
215651Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
225651Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
235651Sgblack@eecs.umich.edu * this software without specific prior written permission.
245651Sgblack@eecs.umich.edu *
255651Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
265651Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
275651Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285651Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
295651Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
305651Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
315651Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
325651Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
335651Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
345651Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
355651Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366216Snate@binkert.org *
375651Sgblack@eecs.umich.edu * Authors: Stan Czerniawski
386046Sgblack@eecs.umich.edu */
395651Sgblack@eecs.umich.edu
405651Sgblack@eecs.umich.edu#include "dev/arm/smmu_v3_transl.hh"
415651Sgblack@eecs.umich.edu
425651Sgblack@eecs.umich.edu#include "debug/SMMUv3.hh"
435651Sgblack@eecs.umich.edu#include "debug/SMMUv3Hazard.hh"
445651Sgblack@eecs.umich.edu#include "dev/arm/amba.hh"
455651Sgblack@eecs.umich.edu#include "dev/arm/smmu_v3.hh"
465651Sgblack@eecs.umich.edu#include "sim/system.hh"
475651Sgblack@eecs.umich.edu
485654Sgblack@eecs.umich.eduSMMUTranslRequest
495654Sgblack@eecs.umich.eduSMMUTranslRequest::fromPacket(PacketPtr pkt, bool ats)
505651Sgblack@eecs.umich.edu{
515651Sgblack@eecs.umich.edu    SMMUTranslRequest req;
525654Sgblack@eecs.umich.edu    req.addr         = pkt->getAddr();
535654Sgblack@eecs.umich.edu    req.size         = pkt->getSize();
545654Sgblack@eecs.umich.edu    req.sid          = pkt->req->streamId();
555654Sgblack@eecs.umich.edu    req.ssid         = pkt->req->hasSubstreamId() ?
565654Sgblack@eecs.umich.edu        pkt->req->substreamId() : 0;
575654Sgblack@eecs.umich.edu    req.isWrite      = pkt->isWrite();
585654Sgblack@eecs.umich.edu    req.isPrefetch   = false;
595654Sgblack@eecs.umich.edu    req.isAtsRequest = ats;
606050Sgblack@eecs.umich.edu    req.pkt          = pkt;
615654Sgblack@eecs.umich.edu
625654Sgblack@eecs.umich.edu    return req;
635654Sgblack@eecs.umich.edu}
645654Sgblack@eecs.umich.edu
655654Sgblack@eecs.umich.eduSMMUTranslRequest
665654Sgblack@eecs.umich.eduSMMUTranslRequest::prefetch(Addr addr, uint32_t sid, uint32_t ssid)
676050Sgblack@eecs.umich.edu{
685654Sgblack@eecs.umich.edu    SMMUTranslRequest req;
695654Sgblack@eecs.umich.edu    req.addr         = addr;
705654Sgblack@eecs.umich.edu    req.size         = 0;
715654Sgblack@eecs.umich.edu    req.sid          = sid;
725654Sgblack@eecs.umich.edu    req.ssid         = ssid;
736050Sgblack@eecs.umich.edu    req.isWrite      = false;
745654Sgblack@eecs.umich.edu    req.isPrefetch   = true;
755654Sgblack@eecs.umich.edu    req.isAtsRequest = false;
765654Sgblack@eecs.umich.edu    req.pkt          = NULL;
775651Sgblack@eecs.umich.edu
785651Sgblack@eecs.umich.edu    return req;
795651Sgblack@eecs.umich.edu}
805651Sgblack@eecs.umich.edu
815651Sgblack@eecs.umich.eduSMMUTranslationProcess::SMMUTranslationProcess(const std::string &name,
8212749Sgiacomo.travaglini@arm.com    SMMUv3 &_smmu, SMMUv3SlaveInterface &_ifc)
8312749Sgiacomo.travaglini@arm.com  :
8412749Sgiacomo.travaglini@arm.com    SMMUProcess(name, _smmu),
8512749Sgiacomo.travaglini@arm.com    ifc(_ifc)
8612749Sgiacomo.travaglini@arm.com{
878949Sandreas.hansson@arm.com    // Decrease number of pending translation slots on the slave interface
885651Sgblack@eecs.umich.edu    assert(ifc.xlateSlotsRemaining > 0);
895651Sgblack@eecs.umich.edu    ifc.xlateSlotsRemaining--;
905651Sgblack@eecs.umich.edu    reinit();
915651Sgblack@eecs.umich.edu}
925651Sgblack@eecs.umich.edu
935651Sgblack@eecs.umich.eduSMMUTranslationProcess::~SMMUTranslationProcess()
945651Sgblack@eecs.umich.edu{
955651Sgblack@eecs.umich.edu    // Increase number of pending translation slots on the slave interface
965651Sgblack@eecs.umich.edu    ifc.xlateSlotsRemaining++;
9713229Sgabeblack@google.com    // If no more SMMU translations are pending (all slots available),
985651Sgblack@eecs.umich.edu    // signal SMMU Slave Interface as drained
995651Sgblack@eecs.umich.edu    if (ifc.xlateSlotsRemaining == ifc.params()->xlate_slots) {
1005651Sgblack@eecs.umich.edu        ifc.signalDrainDone();
1015651Sgblack@eecs.umich.edu    }
1025651Sgblack@eecs.umich.edu}
1035651Sgblack@eecs.umich.edu
1045651Sgblack@eecs.umich.eduvoid
1055651Sgblack@eecs.umich.eduSMMUTranslationProcess::beginTransaction(const SMMUTranslRequest &req)
1065651Sgblack@eecs.umich.edu{
1075651Sgblack@eecs.umich.edu    request = req;
1085651Sgblack@eecs.umich.edu
1095651Sgblack@eecs.umich.edu    reinit();
1105651Sgblack@eecs.umich.edu}
1115651Sgblack@eecs.umich.edu
1125651Sgblack@eecs.umich.eduvoid
1135651Sgblack@eecs.umich.eduSMMUTranslationProcess::resumeTransaction()
1145651Sgblack@eecs.umich.edu{
1155651Sgblack@eecs.umich.edu    assert(smmu.system.isTimingMode());
116
117    assert(!"Stalls are broken");
118
119    Tick resumeTick = curTick();
120
121    (void) resumeTick;
122    DPRINTF(SMMUv3, "Resume at tick = %d. Fault duration = %d (%.3fus)\n",
123        resumeTick, resumeTick-faultTick, (resumeTick-faultTick) / 1e6);
124
125    beginTransaction(request);
126
127    smmu.runProcessTiming(this, request.pkt);
128}
129
130void
131SMMUTranslationProcess::main(Yield &yield)
132{
133    // Hack:
134    // The coroutine starts running as soon as it's created.
135    // But we need to wait for request data esp. in atomic mode.
136    SMMUAction a;
137    a.type = ACTION_INITIAL_NOP;
138    a.pkt = NULL;
139    yield(a);
140
141    const Addr next4k = (request.addr + 0x1000ULL) & ~0xfffULL;
142
143    if ((request.addr + request.size) > next4k)
144        panic("Transaction crosses 4k boundary (addr=%#x size=%#x)!\n",
145                request.addr, request.size);
146
147
148    unsigned numSlaveBeats = request.isWrite ?
149        (request.size + (ifc.portWidth - 1)) / ifc.portWidth : 1;
150
151    doSemaphoreDown(yield, ifc.slavePortSem);
152    doDelay(yield, Cycles(numSlaveBeats));
153    doSemaphoreUp(ifc.slavePortSem);
154
155
156    recvTick = curTick();
157
158
159    if (!(smmu.regs.cr0 & 0x1)) {
160        // SMMU disabled
161        doDelay(yield, Cycles(1));
162        completeTransaction(yield, bypass(request.addr));
163        return;
164    }
165
166    TranslResult tr;
167    bool wasPrefetched = false;
168
169    if (request.isPrefetch) {
170        // Abort prefetch if:
171        //   - there's already a transaction looking up the same 4k page, OR
172        //   - requested address is already in the TLB.
173        if (hazard4kCheck() || ifcTLBLookup(yield, tr, wasPrefetched))
174            completePrefetch(yield); // this never returns
175
176        hazard4kRegister();
177
178        tr = smmuTranslation(yield);
179
180        if (tr.fault == FAULT_NONE)
181            ifcTLBUpdate(yield, tr);
182
183        hazard4kRelease();
184
185        completePrefetch(yield);
186    } else {
187        hazardIdRegister();
188
189        if (!microTLBLookup(yield, tr)) {
190            bool hit = ifcTLBLookup(yield, tr, wasPrefetched);
191            if (!hit) {
192                while (!hit && hazard4kCheck()) {
193                    hazard4kHold(yield);
194                    hit = ifcTLBLookup(yield, tr, wasPrefetched);
195                }
196            }
197
198            // Issue prefetch if:
199            //   - there was a TLB hit and the entry was prefetched, OR
200            //   - TLB miss was successfully serviced
201            if (hit) {
202                if (wasPrefetched)
203                    issuePrefetch(next4k);
204            } else {
205                hazard4kRegister();
206
207                tr = smmuTranslation(yield);
208
209                if (tr.fault == FAULT_NONE) {
210                    ifcTLBUpdate(yield, tr);
211
212                    issuePrefetch(next4k);
213                }
214
215                hazard4kRelease();
216            }
217
218            if (tr.fault == FAULT_NONE)
219                microTLBUpdate(yield, tr);
220        }
221
222        hazardIdHold(yield);
223        hazardIdRelease();
224
225        if (tr.fault != FAULT_NONE)
226            panic("fault\n");
227
228        completeTransaction(yield, tr);
229    }
230}
231
232SMMUTranslationProcess::TranslResult
233SMMUTranslationProcess::bypass(Addr addr) const
234{
235    TranslResult tr;
236    tr.fault = FAULT_NONE;
237    tr.addr = addr;
238    tr.addrMask = 0;
239    tr.writable = 1;
240
241    return tr;
242}
243
244SMMUTranslationProcess::TranslResult
245SMMUTranslationProcess::smmuTranslation(Yield &yield)
246{
247    TranslResult tr;
248
249    // Need SMMU credit to proceed
250    doSemaphoreDown(yield, smmu.transSem);
251
252    // Simulate pipelined IFC->SMMU link
253    doSemaphoreDown(yield, smmu.ifcSmmuSem);
254    doDelay(yield, Cycles(1)); // serialize transactions
255    doSemaphoreUp(smmu.ifcSmmuSem);
256    doDelay(yield, smmu.ifcSmmuLat - Cycles(1)); // remaining pipeline delay
257
258    bool haveConfig = true;
259    if (!configCacheLookup(yield, context)) {
260        if(findConfig(yield, context, tr)) {
261            configCacheUpdate(yield, context);
262        } else {
263            haveConfig = false;
264        }
265    }
266
267    if (haveConfig && !smmuTLBLookup(yield, tr)) {
268        // SMMU main TLB miss
269
270        // Need PTW slot to proceed
271        doSemaphoreDown(yield, smmu.ptwSem);
272
273        // Page table walk
274        Tick ptwStartTick = curTick();
275
276        if (context.stage1Enable) {
277            tr = translateStage1And2(yield, request.addr);
278        } else if (context.stage2Enable) {
279            tr = translateStage2(yield, request.addr, true);
280        } else {
281            tr = bypass(request.addr);
282        }
283
284        if (context.stage1Enable || context.stage2Enable)
285            smmu.ptwTimeDist.sample(curTick() - ptwStartTick);
286
287        // Free PTW slot
288        doSemaphoreUp(smmu.ptwSem);
289
290        if (tr.fault == FAULT_NONE)
291            smmuTLBUpdate(yield, tr);
292    }
293
294    // Simulate pipelined SMMU->SLAVE INTERFACE link
295    doSemaphoreDown(yield, smmu.smmuIfcSem);
296    doDelay(yield, Cycles(1)); // serialize transactions
297    doSemaphoreUp(smmu.smmuIfcSem);
298    doDelay(yield, smmu.smmuIfcLat - Cycles(1)); // remaining pipeline delay
299
300    // return SMMU credit
301    doSemaphoreUp(smmu.transSem);
302
303    return tr;
304}
305
306bool
307SMMUTranslationProcess::microTLBLookup(Yield &yield, TranslResult &tr)
308{
309    if (!ifc.microTLBEnable)
310        return false;
311
312    doSemaphoreDown(yield, ifc.microTLBSem);
313    doDelay(yield, ifc.microTLBLat);
314    const SMMUTLB::Entry *e =
315        ifc.microTLB->lookup(request.sid, request.ssid, request.addr);
316    doSemaphoreUp(ifc.microTLBSem);
317
318    if (!e) {
319        DPRINTF(SMMUv3, "micro TLB miss vaddr=%#x sid=%#x ssid=%#x\n",
320            request.addr, request.sid, request.ssid);
321
322        return false;
323    }
324
325    DPRINTF(SMMUv3,
326        "micro TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x paddr=%#x\n",
327        request.addr, e->vaMask, request.sid, request.ssid, e->pa);
328
329    tr.fault = FAULT_NONE;
330    tr.addr = e->pa + (request.addr & ~e->vaMask);;
331    tr.addrMask = e->vaMask;
332    tr.writable = e->permissions;
333
334    return true;
335}
336
337bool
338SMMUTranslationProcess::ifcTLBLookup(Yield &yield, TranslResult &tr,
339                                     bool &wasPrefetched)
340{
341    if (!ifc.mainTLBEnable)
342        return false;
343
344    doSemaphoreDown(yield, ifc.mainTLBSem);
345    doDelay(yield, ifc.mainTLBLat);
346    const SMMUTLB::Entry *e =
347        ifc.mainTLB->lookup(request.sid, request.ssid, request.addr);
348    doSemaphoreUp(ifc.mainTLBSem);
349
350    if (!e) {
351        DPRINTF(SMMUv3,
352                "SLAVE Interface TLB miss vaddr=%#x sid=%#x ssid=%#x\n",
353                request.addr, request.sid, request.ssid);
354
355        return false;
356    }
357
358    DPRINTF(SMMUv3,
359            "SLAVE Interface TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x "
360            "paddr=%#x\n", request.addr, e->vaMask, request.sid,
361            request.ssid, e->pa);
362
363    tr.fault = FAULT_NONE;
364    tr.addr = e->pa + (request.addr & ~e->vaMask);;
365    tr.addrMask = e->vaMask;
366    tr.writable = e->permissions;
367    wasPrefetched = e->prefetched;
368
369    return true;
370}
371
372bool
373SMMUTranslationProcess::smmuTLBLookup(Yield &yield, TranslResult &tr)
374{
375    if (!smmu.tlbEnable)
376        return false;
377
378    doSemaphoreDown(yield, smmu.tlbSem);
379    doDelay(yield, smmu.tlbLat);
380    const ARMArchTLB::Entry *e =
381        smmu.tlb.lookup(request.addr, context.asid, context.vmid);
382    doSemaphoreUp(smmu.tlbSem);
383
384    if (!e) {
385        DPRINTF(SMMUv3, "SMMU TLB miss vaddr=%#x asid=%#x vmid=%#x\n",
386            request.addr, context.asid, context.vmid);
387
388        return false;
389    }
390
391    DPRINTF(SMMUv3,
392            "SMMU TLB hit vaddr=%#x amask=%#x asid=%#x vmid=%#x paddr=%#x\n",
393            request.addr, e->vaMask, context.asid, context.vmid, e->pa);
394
395    tr.fault = FAULT_NONE;
396    tr.addr = e->pa + (request.addr & ~e->vaMask);;
397    tr.addrMask = e->vaMask;
398    tr.writable = e->permissions;
399
400    return true;
401}
402
403void
404SMMUTranslationProcess::microTLBUpdate(Yield &yield,
405                                       const TranslResult &tr)
406{
407    assert(tr.fault == FAULT_NONE);
408
409    if (!ifc.microTLBEnable)
410        return;
411
412    SMMUTLB::Entry e;
413    e.valid = true;
414    e.prefetched = false;
415    e.sid = request.sid;
416    e.ssid = request.ssid;
417    e.vaMask = tr.addrMask;
418    e.va = request.addr & e.vaMask;
419    e.pa = tr.addr & e.vaMask;
420    e.permissions = tr.writable;
421    e.asid = context.asid;
422    e.vmid = context.vmid;
423
424    doSemaphoreDown(yield, ifc.microTLBSem);
425
426    DPRINTF(SMMUv3,
427        "micro TLB upd vaddr=%#x amask=%#x paddr=%#x sid=%#x ssid=%#x\n",
428        e.va, e.vaMask, e.pa, e.sid, e.ssid);
429
430    ifc.microTLB->store(e, SMMUTLB::ALLOC_ANY_WAY);
431
432    doSemaphoreUp(ifc.microTLBSem);
433}
434
435void
436SMMUTranslationProcess::ifcTLBUpdate(Yield &yield,
437                                     const TranslResult &tr)
438{
439    assert(tr.fault == FAULT_NONE);
440
441    if (!ifc.mainTLBEnable)
442        return;
443
444    SMMUTLB::Entry e;
445    e.valid = true;
446    e.prefetched = request.isPrefetch;
447    e.sid = request.sid;
448    e.ssid = request.ssid;
449    e.vaMask = tr.addrMask;
450    e.va = request.addr & e.vaMask;
451    e.pa = tr.addr & e.vaMask;
452    e.permissions = tr.writable;
453    e.asid = context.asid;
454    e.vmid = context.vmid;
455
456    SMMUTLB::AllocPolicy alloc = SMMUTLB::ALLOC_ANY_WAY;
457    if (ifc.prefetchEnable && ifc.prefetchReserveLastWay)
458        alloc = request.isPrefetch ?
459            SMMUTLB::ALLOC_LAST_WAY : SMMUTLB::ALLOC_ANY_BUT_LAST_WAY;
460
461    doSemaphoreDown(yield, ifc.mainTLBSem);
462
463    DPRINTF(SMMUv3,
464            "SLAVE Interface upd vaddr=%#x amask=%#x paddr=%#x sid=%#x "
465            "ssid=%#x\n", e.va, e.vaMask, e.pa, e.sid, e.ssid);
466
467    ifc.mainTLB->store(e, alloc);
468
469    doSemaphoreUp(ifc.mainTLBSem);
470}
471
472void
473SMMUTranslationProcess::smmuTLBUpdate(Yield &yield,
474                                      const TranslResult &tr)
475{
476    assert(tr.fault == FAULT_NONE);
477
478    if (!smmu.tlbEnable)
479        return;
480
481    ARMArchTLB::Entry e;
482    e.valid = true;
483    e.vaMask = tr.addrMask;
484    e.va = request.addr & e.vaMask;
485    e.asid = context.asid;
486    e.vmid = context.vmid;
487    e.pa = tr.addr & e.vaMask;
488    e.permissions = tr.writable;
489
490    doSemaphoreDown(yield, smmu.tlbSem);
491
492    DPRINTF(SMMUv3,
493            "SMMU TLB upd vaddr=%#x amask=%#x paddr=%#x asid=%#x vmid=%#x\n",
494            e.va, e.vaMask, e.pa, e.asid, e.vmid);
495
496    smmu.tlb.store(e);
497
498    doSemaphoreUp(smmu.tlbSem);
499}
500
501bool
502SMMUTranslationProcess::configCacheLookup(Yield &yield, TranslContext &tc)
503{
504    if (!smmu.configCacheEnable)
505        return false;
506
507    doSemaphoreDown(yield, smmu.configSem);
508    doDelay(yield, smmu.configLat);
509    const ConfigCache::Entry *e =
510        smmu.configCache.lookup(request.sid, request.ssid);
511    doSemaphoreUp(smmu.configSem);
512
513    if (!e) {
514        DPRINTF(SMMUv3, "Config miss sid=%#x ssid=%#x\n",
515                request.sid, request.ssid);
516
517        return false;
518    }
519
520    DPRINTF(SMMUv3, "Config hit sid=%#x ssid=%#x ttb=%#08x asid=%#x\n",
521            request.sid, request.ssid, e->ttb0, e->asid);
522
523    tc.stage1Enable = e->stage1_en;
524    tc.stage2Enable = e->stage2_en;
525
526    tc.ttb0 = e->ttb0;
527    tc.ttb1 = e->ttb1;
528    tc.asid = e->asid;
529    tc.httb = e->httb;
530    tc.vmid = e->vmid;
531
532    tc.stage1TranslGranule = e->stage1_tg;
533    tc.stage2TranslGranule = e->stage2_tg;
534
535    return true;
536}
537
538void
539SMMUTranslationProcess::configCacheUpdate(Yield &yield,
540                                          const TranslContext &tc)
541{
542    if (!smmu.configCacheEnable)
543        return;
544
545    ConfigCache::Entry e;
546    e.valid = true;
547    e.sid = request.sid;
548    e.ssid = request.ssid;
549    e.stage1_en = tc.stage1Enable;
550    e.stage2_en = tc.stage2Enable;
551    e.ttb0 = tc.ttb0;
552    e.ttb1 = tc.ttb1;
553    e.asid = tc.asid;
554    e.httb = tc.httb;
555    e.vmid = tc.vmid;
556    e.stage1_tg = tc.stage1TranslGranule;
557    e.stage2_tg = tc.stage2TranslGranule;
558
559    doSemaphoreDown(yield, smmu.configSem);
560
561    DPRINTF(SMMUv3, "Config upd  sid=%#x ssid=%#x\n", e.sid, e.ssid);
562
563    smmu.configCache.store(e);
564
565    doSemaphoreUp(smmu.configSem);
566}
567
568bool
569SMMUTranslationProcess::findConfig(Yield &yield,
570                                   TranslContext &tc,
571                                   TranslResult &tr)
572{
573    tc.stage1Enable = false;
574    tc.stage2Enable = false;
575
576    StreamTableEntry ste;
577    doReadSTE(yield, ste, request.sid);
578
579    switch (ste.dw0.config) {
580        case STE_CONFIG_BYPASS:
581            break;
582
583        case STE_CONFIG_STAGE1_ONLY:
584            tc.stage1Enable = true;
585            break;
586
587        case STE_CONFIG_STAGE2_ONLY:
588            tc.stage2Enable = true;
589            break;
590
591        case STE_CONFIG_STAGE1_AND_2:
592            tc.stage1Enable = true;
593            tc.stage2Enable = true;
594            break;
595
596        default:
597            panic("Bad or unimplemented STE config %d\n",
598                ste.dw0.config);
599    }
600
601
602    // Establish stage 2 context first since
603    // Context Descriptors can be in IPA space.
604    if (tc.stage2Enable) {
605        tc.httb = ste.dw3.s2ttb << STE_S2TTB_SHIFT;
606        tc.vmid = ste.dw2.s2vmid;
607        tc.stage2TranslGranule = ste.dw2.s2tg;
608        tc.s2t0sz = ste.dw2.s2t0sz;
609    } else {
610        tc.httb = 0xdeadbeef;
611        tc.vmid = 0;
612        tc.stage2TranslGranule = TRANS_GRANULE_INVALID;
613        tc.s2t0sz = 0;
614    }
615
616
617    // Now fetch stage 1 config.
618    if (context.stage1Enable) {
619        ContextDescriptor cd;
620        doReadCD(yield, cd, ste, request.sid, request.ssid);
621
622        tc.ttb0 = cd.dw1.ttb0 << CD_TTB_SHIFT;
623        tc.ttb1 = cd.dw2.ttb1 << CD_TTB_SHIFT;
624        tc.asid = cd.dw0.asid;
625        tc.stage1TranslGranule = cd.dw0.tg0;
626        tc.t0sz = cd.dw0.t0sz;
627    } else {
628        tc.ttb0 = 0xcafebabe;
629        tc.ttb1 = 0xcafed00d;
630        tc.asid = 0;
631        tc.stage1TranslGranule = TRANS_GRANULE_INVALID;
632        tc.t0sz = 0;
633    }
634
635    return true;
636}
637
638void
639SMMUTranslationProcess::walkCacheLookup(
640        Yield &yield,
641        const WalkCache::Entry *&walkEntry,
642        Addr addr, uint16_t asid, uint16_t vmid,
643        unsigned stage, unsigned level)
644{
645    const char *indent = stage==2 ? "  " : "";
646    (void) indent; // this is only used in DPRINTFs
647
648    const PageTableOps *pt_ops =
649        stage == 1 ?
650            smmu.getPageTableOps(context.stage1TranslGranule) :
651            smmu.getPageTableOps(context.stage2TranslGranule);
652
653    unsigned walkCacheLevels =
654        smmu.walkCacheEnable ?
655            (stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels) :
656            0;
657
658    if ((1 << level) & walkCacheLevels) {
659        doSemaphoreDown(yield, smmu.walkSem);
660        doDelay(yield, smmu.walkLat);
661
662        walkEntry = smmu.walkCache.lookup(addr, pt_ops->walkMask(level),
663                                          asid, vmid, stage, level);
664
665        if (walkEntry) {
666            DPRINTF(SMMUv3, "%sWalkCache hit  va=%#x asid=%#x vmid=%#x "
667                            "base=%#x (S%d, L%d)\n",
668                    indent, addr, asid, vmid, walkEntry->pa, stage, level);
669        } else {
670            DPRINTF(SMMUv3, "%sWalkCache miss va=%#x asid=%#x vmid=%#x "
671                            "(S%d, L%d)\n",
672                    indent, addr, asid, vmid, stage, level);
673        }
674
675        doSemaphoreUp(smmu.walkSem);
676    }
677}
678
679void
680SMMUTranslationProcess::walkCacheUpdate(Yield &yield, Addr va,
681                                        Addr vaMask, Addr pa,
682                                        unsigned stage, unsigned level,
683                                        bool leaf, uint8_t permissions)
684{
685    unsigned walkCacheLevels =
686        stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels;
687
688    if (smmu.walkCacheEnable && ((1<<level) & walkCacheLevels)) {
689        WalkCache::Entry e;
690        e.valid = true;
691        e.va = va;
692        e.vaMask = vaMask;
693        e.asid = stage==1 ? context.asid : 0;
694        e.vmid = context.vmid;
695        e.stage = stage;
696        e.level = level;
697        e.leaf = leaf;
698        e.pa = pa;
699        e.permissions = permissions;
700
701        doSemaphoreDown(yield, smmu.walkSem);
702
703        DPRINTF(SMMUv3, "%sWalkCache upd  va=%#x mask=%#x asid=%#x vmid=%#x "
704                        "tpa=%#x leaf=%s (S%d, L%d)\n",
705                e.stage==2 ? "  " : "",
706                e.va, e.vaMask, e.asid, e.vmid,
707                e.pa, e.leaf, e.stage, e.level);
708
709        smmu.walkCache.store(e);
710
711        doSemaphoreUp(smmu.walkSem);
712    }
713}
714
715/*
716 * Please note:
717 * This does not deal with the case where stage 1 page size
718 * is larger than stage 2 page size.
719 */
720SMMUTranslationProcess::TranslResult
721SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr,
722                                       const PageTableOps *pt_ops,
723                                       unsigned level, Addr walkPtr)
724{
725    PageTableOps::pte_t pte = 0;
726
727    doSemaphoreDown(yield, smmu.cycleSem);
728    doDelay(yield, Cycles(1));
729    doSemaphoreUp(smmu.cycleSem);
730
731    for (; level <= pt_ops->lastLevel(); level++) {
732        Addr pte_addr = walkPtr + pt_ops->index(addr, level);
733
734        DPRINTF(SMMUv3, "Fetching S1 L%d PTE from pa=%#08x\n",
735                level, pte_addr);
736
737        doReadPTE(yield, addr, pte_addr, &pte, 1, level);
738
739        DPRINTF(SMMUv3, "Got S1 L%d PTE=%#x from pa=%#08x\n",
740                level, pte, pte_addr);
741
742        doSemaphoreDown(yield, smmu.cycleSem);
743        doDelay(yield, Cycles(1));
744        doSemaphoreUp(smmu.cycleSem);
745
746        bool valid = pt_ops->isValid(pte, level);
747        bool leaf  = pt_ops->isLeaf(pte, level);
748
749        if (!valid) {
750            DPRINTF(SMMUv3, "S1 PTE not valid - fault\n");
751
752            TranslResult tr;
753            tr.fault = FAULT_TRANSLATION;
754            return tr;
755        }
756
757        if (valid && leaf && request.isWrite &&
758            !pt_ops->isWritable(pte, level, false))
759        {
760            DPRINTF(SMMUv3, "S1 page not writable - fault\n");
761
762            TranslResult tr;
763            tr.fault = FAULT_PERMISSION;
764            return tr;
765        }
766
767        walkPtr = pt_ops->nextLevelPointer(pte, level);
768
769        if (leaf)
770            break;
771
772        if (context.stage2Enable) {
773            TranslResult s2tr = translateStage2(yield, walkPtr, false);
774            if (s2tr.fault != FAULT_NONE)
775                return s2tr;
776
777            walkPtr = s2tr.addr;
778        }
779
780        walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr,
781                        1, level, leaf, 0);
782    }
783
784    TranslResult tr;
785    tr.fault    = FAULT_NONE;
786    tr.addrMask = pt_ops->pageMask(pte, level);
787    tr.addr     = walkPtr + (addr & ~tr.addrMask);
788    tr.writable = pt_ops->isWritable(pte, level, false);
789
790    if (context.stage2Enable) {
791        TranslResult s2tr = translateStage2(yield, tr.addr, true);
792        if (s2tr.fault != FAULT_NONE)
793            return s2tr;
794
795        tr = combineTranslations(tr, s2tr);
796    }
797
798    walkCacheUpdate(yield, addr, tr.addrMask, tr.addr,
799                    1, level, true, tr.writable);
800
801    return tr;
802}
803
804SMMUTranslationProcess::TranslResult
805SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr,
806                                   const PageTableOps *pt_ops,
807                                   unsigned level, Addr walkPtr)
808{
809    PageTableOps::pte_t pte;
810
811    doSemaphoreDown(yield, smmu.cycleSem);
812    doDelay(yield, Cycles(1));
813    doSemaphoreUp(smmu.cycleSem);
814
815    for (; level <= pt_ops->lastLevel(); level++) {
816        Addr pte_addr = walkPtr + pt_ops->index(addr, level);
817
818        DPRINTF(SMMUv3, "  Fetching S2 L%d PTE from pa=%#08x\n",
819                level, pte_addr);
820
821        doReadPTE(yield, addr, pte_addr, &pte, 2, level);
822
823        DPRINTF(SMMUv3, "  Got S2 L%d PTE=%#x from pa=%#08x\n",
824                level, pte, pte_addr);
825
826        doSemaphoreDown(yield, smmu.cycleSem);
827        doDelay(yield, Cycles(1));
828        doSemaphoreUp(smmu.cycleSem);
829
830        bool valid = pt_ops->isValid(pte, level);
831        bool leaf  = pt_ops->isLeaf(pte, level);
832
833        if (!valid) {
834            DPRINTF(SMMUv3, "  S2 PTE not valid - fault\n");
835
836            TranslResult tr;
837            tr.fault = FAULT_TRANSLATION;
838            return tr;
839        }
840
841        if (valid && leaf && request.isWrite &&
842            !pt_ops->isWritable(pte, level, true))
843        {
844            DPRINTF(SMMUv3, "  S2 PTE not writable = fault\n");
845
846            TranslResult tr;
847            tr.fault = FAULT_PERMISSION;
848            return tr;
849        }
850
851        walkPtr = pt_ops->nextLevelPointer(pte, level);
852
853        if (final_tr || smmu.walkCacheNonfinalEnable)
854            walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr,
855                            2, level, leaf,
856                            leaf ? pt_ops->isWritable(pte, level, true) : 0);
857        if (leaf)
858            break;
859    }
860
861    TranslResult tr;
862    tr.fault    = FAULT_NONE;
863    tr.addrMask = pt_ops->pageMask(pte, level);
864    tr.addr     = walkPtr + (addr & ~tr.addrMask);
865    tr.writable = pt_ops->isWritable(pte, level, true);
866
867    return tr;
868}
869
870SMMUTranslationProcess::TranslResult
871SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
872{
873    const PageTableOps *pt_ops =
874        smmu.getPageTableOps(context.stage1TranslGranule);
875
876    const WalkCache::Entry *walk_ep = NULL;
877    unsigned level;
878
879    // Level here is actually (level+1) so we can count down
880    // to 0 using unsigned int.
881    for (level = pt_ops->lastLevel() + 1;
882        level > pt_ops->firstLevel(context.t0sz);
883        level--)
884    {
885        walkCacheLookup(yield, walk_ep, addr,
886                        context.asid, context.vmid, 1, level-1);
887
888        if (walk_ep)
889            break;
890    }
891
892    // Correct level (see above).
893    level -= 1;
894
895    TranslResult tr;
896    if (walk_ep) {
897        if (walk_ep->leaf) {
898            tr.fault    = FAULT_NONE;
899            tr.addr     = walk_ep->pa + (addr & ~walk_ep->vaMask);
900            tr.addrMask = walk_ep->vaMask;
901            tr.writable = walk_ep->permissions;
902        } else {
903            tr = walkStage1And2(yield, addr, pt_ops, level+1, walk_ep->pa);
904        }
905    } else {
906        Addr table_addr = context.ttb0;
907        if (context.stage2Enable) {
908            TranslResult s2tr = translateStage2(yield, table_addr, false);
909            if (s2tr.fault != FAULT_NONE)
910                return s2tr;
911
912            table_addr = s2tr.addr;
913        }
914
915        tr = walkStage1And2(yield, addr, pt_ops,
916                            pt_ops->firstLevel(context.t0sz),
917                            table_addr);
918    }
919
920    if (tr.fault == FAULT_NONE)
921        DPRINTF(SMMUv3, "Translated vaddr %#x to paddr %#x\n", addr, tr.addr);
922
923    return tr;
924}
925
926SMMUTranslationProcess::TranslResult
927SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
928{
929    const PageTableOps *pt_ops =
930            smmu.getPageTableOps(context.stage2TranslGranule);
931
932    const IPACache::Entry *ipa_ep = NULL;
933    if (smmu.ipaCacheEnable) {
934        doSemaphoreDown(yield, smmu.ipaSem);
935        doDelay(yield, smmu.ipaLat);
936        ipa_ep = smmu.ipaCache.lookup(addr, context.vmid);
937        doSemaphoreUp(smmu.ipaSem);
938    }
939
940    if (ipa_ep) {
941        TranslResult tr;
942        tr.fault    = FAULT_NONE;
943        tr.addr     = ipa_ep->pa + (addr & ~ipa_ep->ipaMask);
944        tr.addrMask = ipa_ep->ipaMask;
945        tr.writable = ipa_ep->permissions;
946
947        DPRINTF(SMMUv3, "  IPACache hit  ipa=%#x vmid=%#x pa=%#x\n",
948            addr, context.vmid, tr.addr);
949
950        return tr;
951    } else if (smmu.ipaCacheEnable) {
952        DPRINTF(SMMUv3, "  IPACache miss ipa=%#x vmid=%#x\n",
953                addr, context.vmid);
954    }
955
956    const WalkCache::Entry *walk_ep = NULL;
957    unsigned level = pt_ops->firstLevel(context.s2t0sz);
958
959    if (final_tr || smmu.walkCacheNonfinalEnable) {
960        // Level here is actually (level+1) so we can count down
961        // to 0 using unsigned int.
962        for (level = pt_ops->lastLevel() + 1;
963            level > pt_ops->firstLevel(context.s2t0sz);
964            level--)
965        {
966            walkCacheLookup(yield, walk_ep, addr,
967                            0, context.vmid, 2, level-1);
968
969            if (walk_ep)
970                break;
971        }
972
973        // Correct level (see above).
974        level -= 1;
975    }
976
977    TranslResult tr;
978    if (walk_ep) {
979        if (walk_ep->leaf) {
980            tr.fault    = FAULT_NONE;
981            tr.addr     = walk_ep->pa + (addr & ~walk_ep->vaMask);
982            tr.addrMask = walk_ep->vaMask;
983            tr.writable = walk_ep->permissions;
984        } else {
985            tr = walkStage2(yield, addr, final_tr, pt_ops,
986                            level + 1, walk_ep->pa);
987        }
988    } else {
989        tr = walkStage2(yield, addr, final_tr, pt_ops,
990                        pt_ops->firstLevel(context.s2t0sz),
991                        context.httb);
992    }
993
994    if (tr.fault == FAULT_NONE)
995        DPRINTF(SMMUv3, "  Translated %saddr %#x to paddr %#x\n",
996            context.stage1Enable ? "ip" : "v", addr, tr.addr);
997
998    if (smmu.ipaCacheEnable) {
999        IPACache::Entry e;
1000        e.valid = true;
1001        e.ipaMask = tr.addrMask;
1002        e.ipa = addr & e.ipaMask;
1003        e.pa = tr.addr & tr.addrMask;
1004        e.permissions = tr.writable;
1005        e.vmid = context.vmid;
1006
1007        doSemaphoreDown(yield, smmu.ipaSem);
1008        smmu.ipaCache.store(e);
1009        doSemaphoreUp(smmu.ipaSem);
1010    }
1011
1012    return tr;
1013}
1014
1015SMMUTranslationProcess::TranslResult
1016SMMUTranslationProcess::combineTranslations(const TranslResult &s1tr,
1017                                            const TranslResult &s2tr) const
1018{
1019    if (s2tr.fault != FAULT_NONE)
1020        return s2tr;
1021
1022    assert(s1tr.fault == FAULT_NONE);
1023
1024    TranslResult tr;
1025    tr.fault    = FAULT_NONE;
1026    tr.addr     = s2tr.addr;
1027    tr.addrMask = s1tr.addrMask | s2tr.addrMask;
1028    tr.writable = s1tr.writable & s2tr.writable;
1029
1030    return tr;
1031}
1032
1033bool
1034SMMUTranslationProcess::hazard4kCheck()
1035{
1036    Addr addr4k = request.addr & ~0xfffULL;
1037
1038    for (auto it = ifc.duplicateReqs.begin();
1039         it != ifc.duplicateReqs.end();
1040         ++it)
1041    {
1042        Addr other4k = (*it)->request.addr & ~0xfffULL;
1043        if (addr4k == other4k)
1044            return true;
1045    }
1046
1047    return false;
1048}
1049
1050void
1051SMMUTranslationProcess::hazard4kRegister()
1052{
1053    DPRINTF(SMMUv3Hazard, "4kReg:  p=%p a4k=%#x\n",
1054            this, request.addr & ~0xfffULL);
1055
1056    ifc.duplicateReqs.push_back(this);
1057}
1058
1059void
1060SMMUTranslationProcess::hazard4kHold(Yield &yield)
1061{
1062    Addr addr4k = request.addr & ~0xfffULL;
1063
1064    bool found_hazard;
1065
1066    do {
1067        found_hazard = false;
1068
1069        for (auto it = ifc.duplicateReqs.begin();
1070             it!=ifc.duplicateReqs.end() && *it!=this;
1071             ++it)
1072        {
1073            Addr other4k = (*it)->request.addr & ~0xfffULL;
1074
1075            DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x Q: p=%p a4k=%#x\n",
1076                    this, addr4k, *it, other4k);
1077
1078            if (addr4k == other4k) {
1079                DPRINTF(SMMUv3Hazard,
1080                        "4kHold: p=%p a4k=%#x WAIT on p=%p a4k=%#x\n",
1081                        this, addr4k, *it, other4k);
1082
1083                doWaitForSignal(yield, ifc.duplicateReqRemoved);
1084
1085                DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x RESUME\n",
1086                        this, addr4k);
1087
1088                // This is to avoid checking *it!=this after doWaitForSignal()
1089                // since it could have been deleted.
1090                found_hazard = true;
1091                break;
1092            }
1093        }
1094    } while (found_hazard);
1095}
1096
1097void
1098SMMUTranslationProcess::hazard4kRelease()
1099{
1100    DPRINTF(SMMUv3Hazard, "4kRel:  p=%p a4k=%#x\n",
1101            this, request.addr & ~0xfffULL);
1102
1103    std::list<SMMUTranslationProcess *>::iterator it;
1104
1105    for (it = ifc.duplicateReqs.begin(); it != ifc.duplicateReqs.end(); ++it)
1106        if (*it == this)
1107            break;
1108
1109    if (it == ifc.duplicateReqs.end())
1110        panic("hazard4kRelease: request not found");
1111
1112    ifc.duplicateReqs.erase(it);
1113
1114    doBroadcastSignal(ifc.duplicateReqRemoved);
1115}
1116
1117void
1118SMMUTranslationProcess::hazardIdRegister()
1119{
1120    auto orderId = AMBA::orderId(request.pkt);
1121
1122    DPRINTF(SMMUv3Hazard, "IdReg:  p=%p oid=%d\n", this, orderId);
1123
1124    assert(orderId < SMMU_MAX_TRANS_ID);
1125
1126    std::list<SMMUTranslationProcess *> &depReqs =
1127        request.isWrite ?
1128            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
1129    depReqs.push_back(this);
1130}
1131
1132void
1133SMMUTranslationProcess::hazardIdHold(Yield &yield)
1134{
1135    auto orderId = AMBA::orderId(request.pkt);
1136
1137    DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d\n", this, orderId);
1138
1139    std::list<SMMUTranslationProcess *> &depReqs =
1140        request.isWrite ?
1141            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
1142    std::list<SMMUTranslationProcess *>::iterator it;
1143
1144    bool found_hazard;
1145
1146    do {
1147        found_hazard = false;
1148
1149        for (auto it = depReqs.begin(); it!=depReqs.end() && *it!=this; ++it) {
1150            DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d Q: %p\n",
1151                    this, orderId, *it);
1152
1153            if (AMBA::orderId((*it)->request.pkt) == orderId) {
1154                DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d WAIT on=%p\n",
1155                        this, orderId, *it);
1156
1157                doWaitForSignal(yield, ifc.dependentReqRemoved);
1158
1159                DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d RESUME\n",
1160                        this, orderId);
1161
1162                // This is to avoid checking *it!=this after doWaitForSignal()
1163                // since it could have been deleted.
1164                found_hazard = true;
1165                break;
1166            }
1167        }
1168    } while (found_hazard);
1169}
1170
1171void
1172SMMUTranslationProcess::hazardIdRelease()
1173{
1174    auto orderId = AMBA::orderId(request.pkt);
1175
1176    DPRINTF(SMMUv3Hazard, "IdRel:  p=%p oid=%d\n", this, orderId);
1177
1178    std::list<SMMUTranslationProcess *> &depReqs =
1179        request.isWrite ?
1180            ifc.dependentWrites[orderId] : ifc.dependentReads[orderId];
1181    std::list<SMMUTranslationProcess *>::iterator it;
1182
1183    for (it = depReqs.begin(); it != depReqs.end(); ++it) {
1184        if (*it == this)
1185            break;
1186    }
1187
1188    if (it == depReqs.end())
1189        panic("hazardIdRelease: request not found");
1190
1191    depReqs.erase(it);
1192
1193    doBroadcastSignal(ifc.dependentReqRemoved);
1194}
1195
1196void
1197SMMUTranslationProcess::issuePrefetch(Addr addr)
1198{
1199    if (!smmu.system.isTimingMode())
1200        return;
1201
1202    if (!ifc.prefetchEnable || ifc.xlateSlotsRemaining == 0)
1203        return;
1204
1205    std::string proc_name = csprintf("%sprf", name());
1206    SMMUTranslationProcess *proc =
1207        new SMMUTranslationProcess(proc_name, smmu, ifc);
1208
1209    proc->beginTransaction(
1210            SMMUTranslRequest::prefetch(addr, request.sid, request.ssid));
1211    proc->scheduleWakeup(smmu.clockEdge(Cycles(1)));
1212}
1213
1214void
1215SMMUTranslationProcess::completeTransaction(Yield &yield,
1216                                            const TranslResult &tr)
1217{
1218    assert(tr.fault == FAULT_NONE);
1219
1220    unsigned numMasterBeats = request.isWrite ?
1221        (request.size + (smmu.masterPortWidth-1))
1222            / smmu.masterPortWidth :
1223        1;
1224
1225    doSemaphoreDown(yield, smmu.masterPortSem);
1226    doDelay(yield, Cycles(numMasterBeats));
1227    doSemaphoreUp(smmu.masterPortSem);
1228
1229
1230    smmu.translationTimeDist.sample(curTick() - recvTick);
1231    if (!request.isAtsRequest && request.isWrite)
1232        ifc.wrBufSlotsRemaining +=
1233            (request.size + (ifc.portWidth-1)) / ifc.portWidth;
1234
1235    smmu.scheduleSlaveRetries();
1236
1237
1238    SMMUAction a;
1239
1240    if (request.isAtsRequest) {
1241        a.type = ACTION_SEND_RESP_ATS;
1242
1243        if (smmu.system.isAtomicMode()) {
1244            request.pkt->makeAtomicResponse();
1245        } else if (smmu.system.isTimingMode()) {
1246            request.pkt->makeTimingResponse();
1247        } else {
1248            panic("Not in atomic or timing mode");
1249        }
1250    } else {
1251        a.type = ACTION_SEND_REQ_FINAL;
1252        a.ifc = &ifc;
1253    }
1254
1255    a.pkt = request.pkt;
1256    a.delay = 0;
1257
1258    a.pkt->setAddr(tr.addr);
1259    a.pkt->req->setPaddr(tr.addr);
1260
1261    yield(a);
1262
1263    if (!request.isAtsRequest) {
1264        PacketPtr pkt = yield.get();
1265        pkt->setAddr(request.addr);
1266
1267        a.type = ACTION_SEND_RESP;
1268        a.pkt = pkt;
1269        a.ifc = &ifc;
1270        a.delay = 0;
1271        yield(a);
1272    }
1273}
1274
1275void
1276SMMUTranslationProcess::completePrefetch(Yield &yield)
1277{
1278    SMMUAction a;
1279    a.type = ACTION_TERMINATE;
1280    a.pkt = NULL;
1281    a.ifc = &ifc;
1282    a.delay = 0;
1283    yield(a);
1284}
1285
1286void
1287SMMUTranslationProcess::sendEvent(Yield &yield, const SMMUEvent &ev)
1288{
1289    int sizeMask = mask(smmu.regs.eventq_base & Q_BASE_SIZE_MASK);
1290
1291    if (((smmu.regs.eventq_prod+1) & sizeMask) ==
1292            (smmu.regs.eventq_cons & sizeMask))
1293        panic("Event queue full - aborting\n");
1294
1295    Addr event_addr =
1296        (smmu.regs.eventq_base & Q_BASE_ADDR_MASK) +
1297        (smmu.regs.eventq_prod & sizeMask) * sizeof(ev);
1298
1299    DPRINTF(SMMUv3, "Sending event to addr=%#08x (pos=%d): type=%#x stag=%#x "
1300        "flags=%#x sid=%#x ssid=%#x va=%#08x ipa=%#x\n",
1301        event_addr, smmu.regs.eventq_prod, ev.type, ev.stag,
1302        ev.flags, ev.streamId, ev.substreamId, ev.va, ev.ipa);
1303
1304    // This deliberately resets the overflow field in eventq_prod!
1305    smmu.regs.eventq_prod = (smmu.regs.eventq_prod + 1) & sizeMask;
1306
1307    doWrite(yield, event_addr, &ev, sizeof(ev));
1308
1309    if (!(smmu.regs.eventq_irq_cfg0 & E_BASE_ENABLE_MASK))
1310        panic("eventq msi not enabled\n");
1311
1312    doWrite(yield, smmu.regs.eventq_irq_cfg0 & E_BASE_ADDR_MASK,
1313            &smmu.regs.eventq_irq_cfg1, sizeof(smmu.regs.eventq_irq_cfg1));
1314}
1315
1316void
1317SMMUTranslationProcess::doReadSTE(Yield &yield,
1318                                  StreamTableEntry &ste,
1319                                  uint32_t sid)
1320{
1321    unsigned max_sid = 1 << (smmu.regs.strtab_base_cfg & ST_CFG_SIZE_MASK);
1322    if (sid >= max_sid)
1323        panic("SID %#x out of range, max=%#x", sid, max_sid);
1324
1325    Addr ste_addr;
1326
1327    if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_2LEVEL) {
1328        unsigned split =
1329            (smmu.regs.strtab_base_cfg & ST_CFG_SPLIT_MASK) >> ST_CFG_SPLIT_SHIFT;
1330
1331        if (split!= 7 && split!=8 && split!=16)
1332            panic("Invalid stream table split %d", split);
1333
1334        uint64_t l2_ptr;
1335        uint64_t l2_addr =
1336            (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) +
1337            bits(sid, 32, split) * sizeof(l2_ptr);
1338
1339        DPRINTF(SMMUv3, "Read L1STE at %#x\n", l2_addr);
1340
1341        doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, 0);
1342
1343        DPRINTF(SMMUv3, "Got L1STE L1 at %#x: 0x%016x\n", l2_addr, l2_ptr);
1344
1345        unsigned span = l2_ptr & ST_L2_SPAN_MASK;
1346        if (span == 0)
1347            panic("Invalid level 1 stream table descriptor");
1348
1349        unsigned index = bits(sid, split-1, 0);
1350        if (index >= (1 << span))
1351            panic("StreamID %d out of level 1 descriptor range %d",
1352                  sid, 1<<span);
1353
1354        ste_addr = (l2_ptr & ST_L2_ADDR_MASK) + index * sizeof(ste);
1355
1356        smmu.steL1Fetches++;
1357    } else if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_LINEAR) {
1358        ste_addr =
1359            (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + sid * sizeof(ste);
1360    } else {
1361        panic("Invalid stream table format");
1362    }
1363
1364    DPRINTF(SMMUv3, "Read STE at %#x\n", ste_addr);
1365
1366    doReadConfig(yield, ste_addr, &ste, sizeof(ste), sid, 0);
1367
1368    DPRINTF(SMMUv3, "Got STE at %#x [0]: 0x%016x\n", ste_addr, ste.dw0);
1369    DPRINTF(SMMUv3, "    STE at %#x [1]: 0x%016x\n", ste_addr, ste.dw1);
1370    DPRINTF(SMMUv3, "    STE at %#x [2]: 0x%016x\n", ste_addr, ste.dw2);
1371    DPRINTF(SMMUv3, "    STE at %#x [3]: 0x%016x\n", ste_addr, ste.dw3);
1372    DPRINTF(SMMUv3, "    STE at %#x [4]: 0x%016x\n", ste_addr, ste._pad[0]);
1373    DPRINTF(SMMUv3, "    STE at %#x [5]: 0x%016x\n", ste_addr, ste._pad[1]);
1374    DPRINTF(SMMUv3, "    STE at %#x [6]: 0x%016x\n", ste_addr, ste._pad[2]);
1375    DPRINTF(SMMUv3, "    STE at %#x [7]: 0x%016x\n", ste_addr, ste._pad[3]);
1376
1377    if (!ste.dw0.valid)
1378        panic("STE @ %#x not valid\n", ste_addr);
1379
1380    smmu.steFetches++;
1381}
1382
1383void
1384SMMUTranslationProcess::doReadCD(Yield &yield,
1385                                 ContextDescriptor &cd,
1386                                 const StreamTableEntry &ste,
1387                                 uint32_t sid, uint32_t ssid)
1388{
1389    Addr cd_addr;
1390
1391    if (ste.dw0.s1cdmax == 0) {
1392        cd_addr = ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT;
1393    } else {
1394        unsigned max_ssid = 1 << ste.dw0.s1cdmax;
1395        if (ssid >= max_ssid)
1396            panic("SSID %#x out of range, max=%#x", ssid, max_ssid);
1397
1398        if (ste.dw0.s1fmt==STAGE1_CFG_2L_4K ||
1399            ste.dw0.s1fmt==STAGE1_CFG_2L_64K)
1400        {
1401            unsigned split = ste.dw0.s1fmt==STAGE1_CFG_2L_4K ? 7 : 11;
1402
1403            uint64_t l2_ptr;
1404            uint64_t l2_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) +
1405                bits(ssid, 24, split) * sizeof(l2_ptr);
1406
1407            if (context.stage2Enable)
1408                l2_addr = translateStage2(yield, l2_addr, false).addr;
1409
1410            DPRINTF(SMMUv3, "Read L1CD at %#x\n", l2_addr);
1411
1412            doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, ssid);
1413
1414            DPRINTF(SMMUv3, "Got L1CD at %#x: 0x%016x\n", l2_addr, l2_ptr);
1415
1416            cd_addr = l2_ptr + bits(ssid, split-1, 0) * sizeof(cd);
1417
1418            smmu.cdL1Fetches++;
1419        } else if (ste.dw0.s1fmt == STAGE1_CFG_1L) {
1420            cd_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + ssid*sizeof(cd);
1421        }
1422    }
1423
1424    if (context.stage2Enable)
1425        cd_addr = translateStage2(yield, cd_addr, false).addr;
1426
1427    DPRINTF(SMMUv3, "Read CD at %#x\n", cd_addr);
1428
1429    doReadConfig(yield, cd_addr, &cd, sizeof(cd), sid, ssid);
1430
1431    DPRINTF(SMMUv3, "Got CD at %#x [0]: 0x%016x\n", cd_addr, cd.dw0);
1432    DPRINTF(SMMUv3, "    CD at %#x [1]: 0x%016x\n", cd_addr, cd.dw1);
1433    DPRINTF(SMMUv3, "    CD at %#x [2]: 0x%016x\n", cd_addr, cd.dw2);
1434    DPRINTF(SMMUv3, "    CD at %#x [3]: 0x%016x\n", cd_addr, cd.mair);
1435    DPRINTF(SMMUv3, "    CD at %#x [4]: 0x%016x\n", cd_addr, cd.amair);
1436    DPRINTF(SMMUv3, "    CD at %#x [5]: 0x%016x\n", cd_addr, cd._pad[0]);
1437    DPRINTF(SMMUv3, "    CD at %#x [6]: 0x%016x\n", cd_addr, cd._pad[1]);
1438    DPRINTF(SMMUv3, "    CD at %#x [7]: 0x%016x\n", cd_addr, cd._pad[2]);
1439
1440
1441    if (!cd.dw0.valid)
1442        panic("CD @ %#x not valid\n", cd_addr);
1443
1444    smmu.cdFetches++;
1445}
1446
1447void
1448SMMUTranslationProcess::doReadConfig(Yield &yield, Addr addr,
1449                                     void *ptr, size_t size,
1450                                     uint32_t sid, uint32_t ssid)
1451{
1452    doRead(yield, addr, ptr, size);
1453}
1454
1455void
1456SMMUTranslationProcess::doReadPTE(Yield &yield, Addr va, Addr addr,
1457                                  void *ptr, unsigned stage,
1458                                  unsigned level)
1459{
1460    size_t pte_size = sizeof(PageTableOps::pte_t);
1461
1462    Addr mask = pte_size - 1;
1463    Addr base = addr & ~mask;
1464
1465    doRead(yield, base, ptr, pte_size);
1466}
1467