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