114039Sstacze01@arm.com/*
214039Sstacze01@arm.com * Copyright (c) 2019 ARM Limited
314039Sstacze01@arm.com * All rights reserved
414039Sstacze01@arm.com *
514039Sstacze01@arm.com * The license below extends only to copyright in the software and shall
614039Sstacze01@arm.com * not be construed as granting a license to any other intellectual
714039Sstacze01@arm.com * property including but not limited to intellectual property relating
814039Sstacze01@arm.com * to a hardware implementation of the functionality of the software
914039Sstacze01@arm.com * licensed hereunder.  You may use the software subject to the license
1014039Sstacze01@arm.com * terms below provided that you ensure that this notice is replicated
1114039Sstacze01@arm.com * unmodified and in its entirety in all distributions of the software,
1214039Sstacze01@arm.com * modified or unmodified, in source code or in binary form.
1314039Sstacze01@arm.com *
1414039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without
1514039Sstacze01@arm.com * modification, are permitted provided that the following conditions are
1614039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright
1714039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer;
1814039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright
1914039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the
2014039Sstacze01@arm.com * documentation and/or other materials provided with the distribution;
2114039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its
2214039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from
2314039Sstacze01@arm.com * this software without specific prior written permission.
2414039Sstacze01@arm.com *
2514039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2614039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2714039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2814039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2914039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3014039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3114039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3214039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3314039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3414039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3514039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3614039Sstacze01@arm.com *
3714039Sstacze01@arm.com * Authors: Stan Czerniawski
3814039Sstacze01@arm.com *          Giacomo Travaglini
3914039Sstacze01@arm.com */
4014039Sstacze01@arm.com
4114039Sstacze01@arm.com#include "dev/arm/smmu_v3_slaveifc.hh"
4214039Sstacze01@arm.com
4314039Sstacze01@arm.com#include "debug/SMMUv3.hh"
4414039Sstacze01@arm.com#include "dev/arm/smmu_v3.hh"
4514039Sstacze01@arm.com#include "dev/arm/smmu_v3_transl.hh"
4614039Sstacze01@arm.com
4714039Sstacze01@arm.comSMMUv3SlaveInterface::SMMUv3SlaveInterface(
4814039Sstacze01@arm.com    const SMMUv3SlaveInterfaceParams *p) :
4914252Sgabeblack@google.com    ClockedObject(p),
5014039Sstacze01@arm.com    smmu(nullptr),
5114039Sstacze01@arm.com    microTLB(new SMMUTLB(p->utlb_entries,
5214039Sstacze01@arm.com                         p->utlb_assoc,
5314039Sstacze01@arm.com                         p->utlb_policy)),
5414039Sstacze01@arm.com    mainTLB(new SMMUTLB(p->tlb_entries,
5514039Sstacze01@arm.com                        p->tlb_assoc,
5614039Sstacze01@arm.com                        p->tlb_policy)),
5714039Sstacze01@arm.com    microTLBEnable(p->utlb_enable),
5814039Sstacze01@arm.com    mainTLBEnable(p->tlb_enable),
5914039Sstacze01@arm.com    slavePortSem(1),
6014039Sstacze01@arm.com    microTLBSem(p->utlb_slots),
6114039Sstacze01@arm.com    mainTLBSem(p->tlb_slots),
6214039Sstacze01@arm.com    microTLBLat(p->utlb_lat),
6314039Sstacze01@arm.com    mainTLBLat(p->tlb_lat),
6414039Sstacze01@arm.com    slavePort(new SMMUSlavePort(csprintf("%s.slave", name()), *this)),
6514039Sstacze01@arm.com    atsSlavePort(name() + ".atsSlave", *this),
6614039Sstacze01@arm.com    atsMasterPort(name() + ".atsMaster", *this),
6714039Sstacze01@arm.com    portWidth(p->port_width),
6814039Sstacze01@arm.com    wrBufSlotsRemaining(p->wrbuf_slots),
6914039Sstacze01@arm.com    xlateSlotsRemaining(p->xlate_slots),
7014223Sgiacomo.travaglini@arm.com    pendingMemAccesses(0),
7114039Sstacze01@arm.com    prefetchEnable(p->prefetch_enable),
7214039Sstacze01@arm.com    prefetchReserveLastWay(
7314039Sstacze01@arm.com        p->prefetch_reserve_last_way),
7414039Sstacze01@arm.com    deviceNeedsRetry(false),
7514039Sstacze01@arm.com    atsDeviceNeedsRetry(false),
7614039Sstacze01@arm.com    sendDeviceRetryEvent(*this),
7714039Sstacze01@arm.com    atsSendDeviceRetryEvent(this)
7814039Sstacze01@arm.com{}
7914039Sstacze01@arm.com
8014039Sstacze01@arm.comvoid
8114039Sstacze01@arm.comSMMUv3SlaveInterface::sendRange()
8214039Sstacze01@arm.com{
8314039Sstacze01@arm.com    if (slavePort->isConnected()) {
8414192Sgabeblack@google.com        inform("Slave port is connected to %s\n", slavePort->getPeer());
8514039Sstacze01@arm.com
8614039Sstacze01@arm.com        slavePort->sendRangeChange();
8714039Sstacze01@arm.com    } else {
8814039Sstacze01@arm.com        fatal("Slave port is not connected.\n");
8914039Sstacze01@arm.com    }
9014039Sstacze01@arm.com}
9114039Sstacze01@arm.com
9214039Sstacze01@arm.comPort&
9314039Sstacze01@arm.comSMMUv3SlaveInterface::getPort(const std::string &name, PortID id)
9414039Sstacze01@arm.com{
9514039Sstacze01@arm.com    if (name == "ats_master") {
9614039Sstacze01@arm.com        return atsMasterPort;
9714039Sstacze01@arm.com    } else if (name == "slave") {
9814039Sstacze01@arm.com        return *slavePort;
9914039Sstacze01@arm.com    } else if (name == "ats_slave") {
10014039Sstacze01@arm.com        return atsSlavePort;
10114039Sstacze01@arm.com    } else {
10214252Sgabeblack@google.com        return ClockedObject::getPort(name, id);
10314039Sstacze01@arm.com    }
10414039Sstacze01@arm.com}
10514039Sstacze01@arm.com
10614039Sstacze01@arm.comvoid
10714039Sstacze01@arm.comSMMUv3SlaveInterface::schedTimingResp(PacketPtr pkt)
10814039Sstacze01@arm.com{
10914039Sstacze01@arm.com    slavePort->schedTimingResp(pkt, nextCycle());
11014039Sstacze01@arm.com}
11114039Sstacze01@arm.com
11214039Sstacze01@arm.comvoid
11314039Sstacze01@arm.comSMMUv3SlaveInterface::schedAtsTimingResp(PacketPtr pkt)
11414039Sstacze01@arm.com{
11514039Sstacze01@arm.com    atsSlavePort.schedTimingResp(pkt, nextCycle());
11614039Sstacze01@arm.com
11714039Sstacze01@arm.com    if (atsDeviceNeedsRetry) {
11814039Sstacze01@arm.com        atsDeviceNeedsRetry = false;
11914039Sstacze01@arm.com        schedule(atsSendDeviceRetryEvent, nextCycle());
12014039Sstacze01@arm.com    }
12114039Sstacze01@arm.com}
12214039Sstacze01@arm.com
12314039Sstacze01@arm.comTick
12414039Sstacze01@arm.comSMMUv3SlaveInterface::recvAtomic(PacketPtr pkt)
12514039Sstacze01@arm.com{
12614039Sstacze01@arm.com    DPRINTF(SMMUv3, "[a] req from %s addr=%#x size=%#x\n",
12714192Sgabeblack@google.com            slavePort->getPeer(), pkt->getAddr(), pkt->getSize());
12814039Sstacze01@arm.com
12914039Sstacze01@arm.com    std::string proc_name = csprintf("%s.port", name());
13014039Sstacze01@arm.com    SMMUTranslationProcess proc(proc_name, *smmu, *this);
13114039Sstacze01@arm.com    proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt));
13214039Sstacze01@arm.com
13314039Sstacze01@arm.com    SMMUAction a = smmu->runProcessAtomic(&proc, pkt);
13414039Sstacze01@arm.com    assert(a.type == ACTION_SEND_RESP);
13514039Sstacze01@arm.com
13614039Sstacze01@arm.com    return a.delay;
13714039Sstacze01@arm.com}
13814039Sstacze01@arm.com
13914039Sstacze01@arm.combool
14014039Sstacze01@arm.comSMMUv3SlaveInterface::recvTimingReq(PacketPtr pkt)
14114039Sstacze01@arm.com{
14214039Sstacze01@arm.com    DPRINTF(SMMUv3, "[t] req from %s addr=%#x size=%#x\n",
14314192Sgabeblack@google.com            slavePort->getPeer(), pkt->getAddr(), pkt->getSize());
14414039Sstacze01@arm.com
14514039Sstacze01@arm.com    // @todo: We need to pay for this and not just zero it out
14614039Sstacze01@arm.com    pkt->headerDelay = pkt->payloadDelay = 0;
14714039Sstacze01@arm.com
14814039Sstacze01@arm.com    unsigned nbeats =
14914039Sstacze01@arm.com        (pkt->getSize() + (portWidth-1)) / portWidth;
15014039Sstacze01@arm.com
15114039Sstacze01@arm.com    if (xlateSlotsRemaining==0 ||
15214039Sstacze01@arm.com        (pkt->isWrite() && wrBufSlotsRemaining < nbeats))
15314039Sstacze01@arm.com    {
15414039Sstacze01@arm.com        deviceNeedsRetry = true;
15514039Sstacze01@arm.com        return false;
15614039Sstacze01@arm.com    }
15714039Sstacze01@arm.com
15814039Sstacze01@arm.com    if (pkt->isWrite())
15914039Sstacze01@arm.com        wrBufSlotsRemaining -= nbeats;
16014039Sstacze01@arm.com
16114039Sstacze01@arm.com    std::string proc_name = csprintf("%s.port", name());
16214039Sstacze01@arm.com    SMMUTranslationProcess *proc =
16314039Sstacze01@arm.com        new SMMUTranslationProcess(proc_name, *smmu, *this);
16414039Sstacze01@arm.com    proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt));
16514039Sstacze01@arm.com
16614039Sstacze01@arm.com    smmu->runProcessTiming(proc, pkt);
16714039Sstacze01@arm.com
16814039Sstacze01@arm.com    return true;
16914039Sstacze01@arm.com}
17014039Sstacze01@arm.com
17114039Sstacze01@arm.comTick
17214039Sstacze01@arm.comSMMUv3SlaveInterface::atsSlaveRecvAtomic(PacketPtr pkt)
17314039Sstacze01@arm.com{
17414039Sstacze01@arm.com    DPRINTF(SMMUv3, "[a] ATS slave  req  addr=%#x size=%#x\n",
17514039Sstacze01@arm.com            pkt->getAddr(), pkt->getSize());
17614039Sstacze01@arm.com
17714039Sstacze01@arm.com    std::string proc_name = csprintf("%s.atsport", name());
17814039Sstacze01@arm.com    const bool ats_request = true;
17914039Sstacze01@arm.com    SMMUTranslationProcess proc(
18014039Sstacze01@arm.com        proc_name, *smmu, *this);
18114039Sstacze01@arm.com    proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request));
18214039Sstacze01@arm.com
18314039Sstacze01@arm.com    SMMUAction a = smmu->runProcessAtomic(&proc, pkt);
18414039Sstacze01@arm.com    assert(a.type == ACTION_SEND_RESP_ATS);
18514039Sstacze01@arm.com
18614039Sstacze01@arm.com    return a.delay;
18714039Sstacze01@arm.com}
18814039Sstacze01@arm.com
18914039Sstacze01@arm.combool
19014039Sstacze01@arm.comSMMUv3SlaveInterface::atsSlaveRecvTimingReq(PacketPtr pkt)
19114039Sstacze01@arm.com{
19214039Sstacze01@arm.com    DPRINTF(SMMUv3, "[t] ATS slave  req  addr=%#x size=%#x\n",
19314039Sstacze01@arm.com            pkt->getAddr(), pkt->getSize());
19414039Sstacze01@arm.com
19514039Sstacze01@arm.com    // @todo: We need to pay for this and not just zero it out
19614039Sstacze01@arm.com    pkt->headerDelay = pkt->payloadDelay = 0;
19714039Sstacze01@arm.com
19814039Sstacze01@arm.com    if (xlateSlotsRemaining == 0) {
19914039Sstacze01@arm.com        deviceNeedsRetry = true;
20014039Sstacze01@arm.com        return false;
20114039Sstacze01@arm.com    }
20214039Sstacze01@arm.com
20314039Sstacze01@arm.com    std::string proc_name = csprintf("%s.atsport", name());
20414039Sstacze01@arm.com    const bool ats_request = true;
20514039Sstacze01@arm.com    SMMUTranslationProcess *proc =
20614039Sstacze01@arm.com        new SMMUTranslationProcess(proc_name, *smmu, *this);
20714039Sstacze01@arm.com    proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request));
20814039Sstacze01@arm.com
20914039Sstacze01@arm.com    smmu->runProcessTiming(proc, pkt);
21014039Sstacze01@arm.com
21114039Sstacze01@arm.com    return true;
21214039Sstacze01@arm.com}
21314039Sstacze01@arm.com
21414039Sstacze01@arm.combool
21514039Sstacze01@arm.comSMMUv3SlaveInterface::atsMasterRecvTimingResp(PacketPtr pkt)
21614039Sstacze01@arm.com{
21714039Sstacze01@arm.com    DPRINTF(SMMUv3, "[t] ATS master resp addr=%#x size=%#x\n",
21814039Sstacze01@arm.com            pkt->getAddr(), pkt->getSize());
21914039Sstacze01@arm.com
22014039Sstacze01@arm.com    // @todo: We need to pay for this and not just zero it out
22114039Sstacze01@arm.com    pkt->headerDelay = pkt->payloadDelay = 0;
22214039Sstacze01@arm.com
22314039Sstacze01@arm.com    SMMUProcess *proc =
22414039Sstacze01@arm.com        safe_cast<SMMUProcess *>(pkt->popSenderState());
22514039Sstacze01@arm.com
22614039Sstacze01@arm.com    smmu->runProcessTiming(proc, pkt);
22714039Sstacze01@arm.com
22814039Sstacze01@arm.com    return true;
22914039Sstacze01@arm.com}
23014039Sstacze01@arm.com
23114039Sstacze01@arm.comvoid
23214039Sstacze01@arm.comSMMUv3SlaveInterface::sendDeviceRetry()
23314039Sstacze01@arm.com{
23414039Sstacze01@arm.com    slavePort->sendRetryReq();
23514039Sstacze01@arm.com}
23614039Sstacze01@arm.com
23714039Sstacze01@arm.comvoid
23814039Sstacze01@arm.comSMMUv3SlaveInterface::atsSendDeviceRetry()
23914039Sstacze01@arm.com{
24014039Sstacze01@arm.com    DPRINTF(SMMUv3, "ATS retry\n");
24114039Sstacze01@arm.com    atsSlavePort.sendRetryReq();
24214039Sstacze01@arm.com}
24314039Sstacze01@arm.com
24414039Sstacze01@arm.comvoid
24514039Sstacze01@arm.comSMMUv3SlaveInterface::scheduleDeviceRetry()
24614039Sstacze01@arm.com{
24714039Sstacze01@arm.com    if (deviceNeedsRetry && !sendDeviceRetryEvent.scheduled()) {
24814039Sstacze01@arm.com        DPRINTF(SMMUv3, "sched slave retry\n");
24914039Sstacze01@arm.com        deviceNeedsRetry = false;
25014039Sstacze01@arm.com        schedule(sendDeviceRetryEvent, nextCycle());
25114039Sstacze01@arm.com    }
25214039Sstacze01@arm.com}
25314039Sstacze01@arm.com
25414064Sadrian.herrera@arm.comDrainState
25514064Sadrian.herrera@arm.comSMMUv3SlaveInterface::drain()
25614064Sadrian.herrera@arm.com{
25714064Sadrian.herrera@arm.com    // Wait until all SMMU translations are completed
25814064Sadrian.herrera@arm.com    if (xlateSlotsRemaining < params()->xlate_slots) {
25914064Sadrian.herrera@arm.com        return DrainState::Draining;
26014064Sadrian.herrera@arm.com    }
26114064Sadrian.herrera@arm.com    return DrainState::Drained;
26214064Sadrian.herrera@arm.com}
26314064Sadrian.herrera@arm.com
26414039Sstacze01@arm.comSMMUv3SlaveInterface*
26514039Sstacze01@arm.comSMMUv3SlaveInterfaceParams::create()
26614039Sstacze01@arm.com{
26714039Sstacze01@arm.com    return new SMMUv3SlaveInterface(this);
26814039Sstacze01@arm.com}
269