smmu_v3_slaveifc.cc revision 14192
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) : 4914039Sstacze01@arm.com MemObject(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), 7014039Sstacze01@arm.com prefetchEnable(p->prefetch_enable), 7114039Sstacze01@arm.com prefetchReserveLastWay( 7214039Sstacze01@arm.com p->prefetch_reserve_last_way), 7314039Sstacze01@arm.com deviceNeedsRetry(false), 7414039Sstacze01@arm.com atsDeviceNeedsRetry(false), 7514039Sstacze01@arm.com sendDeviceRetryEvent(*this), 7614039Sstacze01@arm.com atsSendDeviceRetryEvent(this) 7714039Sstacze01@arm.com{} 7814039Sstacze01@arm.com 7914039Sstacze01@arm.comvoid 8014039Sstacze01@arm.comSMMUv3SlaveInterface::sendRange() 8114039Sstacze01@arm.com{ 8214039Sstacze01@arm.com if (slavePort->isConnected()) { 8314192Sgabeblack@google.com inform("Slave port is connected to %s\n", slavePort->getPeer()); 8414039Sstacze01@arm.com 8514039Sstacze01@arm.com slavePort->sendRangeChange(); 8614039Sstacze01@arm.com } else { 8714039Sstacze01@arm.com fatal("Slave port is not connected.\n"); 8814039Sstacze01@arm.com } 8914039Sstacze01@arm.com} 9014039Sstacze01@arm.com 9114039Sstacze01@arm.comPort& 9214039Sstacze01@arm.comSMMUv3SlaveInterface::getPort(const std::string &name, PortID id) 9314039Sstacze01@arm.com{ 9414039Sstacze01@arm.com if (name == "ats_master") { 9514039Sstacze01@arm.com return atsMasterPort; 9614039Sstacze01@arm.com } else if (name == "slave") { 9714039Sstacze01@arm.com return *slavePort; 9814039Sstacze01@arm.com } else if (name == "ats_slave") { 9914039Sstacze01@arm.com return atsSlavePort; 10014039Sstacze01@arm.com } else { 10114039Sstacze01@arm.com return MemObject::getPort(name, id); 10214039Sstacze01@arm.com } 10314039Sstacze01@arm.com} 10414039Sstacze01@arm.com 10514039Sstacze01@arm.comvoid 10614039Sstacze01@arm.comSMMUv3SlaveInterface::schedTimingResp(PacketPtr pkt) 10714039Sstacze01@arm.com{ 10814039Sstacze01@arm.com slavePort->schedTimingResp(pkt, nextCycle()); 10914039Sstacze01@arm.com} 11014039Sstacze01@arm.com 11114039Sstacze01@arm.comvoid 11214039Sstacze01@arm.comSMMUv3SlaveInterface::schedAtsTimingResp(PacketPtr pkt) 11314039Sstacze01@arm.com{ 11414039Sstacze01@arm.com atsSlavePort.schedTimingResp(pkt, nextCycle()); 11514039Sstacze01@arm.com 11614039Sstacze01@arm.com if (atsDeviceNeedsRetry) { 11714039Sstacze01@arm.com atsDeviceNeedsRetry = false; 11814039Sstacze01@arm.com schedule(atsSendDeviceRetryEvent, nextCycle()); 11914039Sstacze01@arm.com } 12014039Sstacze01@arm.com} 12114039Sstacze01@arm.com 12214039Sstacze01@arm.comTick 12314039Sstacze01@arm.comSMMUv3SlaveInterface::recvAtomic(PacketPtr pkt) 12414039Sstacze01@arm.com{ 12514039Sstacze01@arm.com DPRINTF(SMMUv3, "[a] req from %s addr=%#x size=%#x\n", 12614192Sgabeblack@google.com slavePort->getPeer(), pkt->getAddr(), pkt->getSize()); 12714039Sstacze01@arm.com 12814039Sstacze01@arm.com std::string proc_name = csprintf("%s.port", name()); 12914039Sstacze01@arm.com SMMUTranslationProcess proc(proc_name, *smmu, *this); 13014039Sstacze01@arm.com proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt)); 13114039Sstacze01@arm.com 13214039Sstacze01@arm.com SMMUAction a = smmu->runProcessAtomic(&proc, pkt); 13314039Sstacze01@arm.com assert(a.type == ACTION_SEND_RESP); 13414039Sstacze01@arm.com 13514039Sstacze01@arm.com return a.delay; 13614039Sstacze01@arm.com} 13714039Sstacze01@arm.com 13814039Sstacze01@arm.combool 13914039Sstacze01@arm.comSMMUv3SlaveInterface::recvTimingReq(PacketPtr pkt) 14014039Sstacze01@arm.com{ 14114039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] req from %s addr=%#x size=%#x\n", 14214192Sgabeblack@google.com slavePort->getPeer(), pkt->getAddr(), pkt->getSize()); 14314039Sstacze01@arm.com 14414039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 14514039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 14614039Sstacze01@arm.com 14714039Sstacze01@arm.com unsigned nbeats = 14814039Sstacze01@arm.com (pkt->getSize() + (portWidth-1)) / portWidth; 14914039Sstacze01@arm.com 15014039Sstacze01@arm.com if (xlateSlotsRemaining==0 || 15114039Sstacze01@arm.com (pkt->isWrite() && wrBufSlotsRemaining < nbeats)) 15214039Sstacze01@arm.com { 15314039Sstacze01@arm.com deviceNeedsRetry = true; 15414039Sstacze01@arm.com return false; 15514039Sstacze01@arm.com } 15614039Sstacze01@arm.com 15714039Sstacze01@arm.com if (pkt->isWrite()) 15814039Sstacze01@arm.com wrBufSlotsRemaining -= nbeats; 15914039Sstacze01@arm.com 16014039Sstacze01@arm.com std::string proc_name = csprintf("%s.port", name()); 16114039Sstacze01@arm.com SMMUTranslationProcess *proc = 16214039Sstacze01@arm.com new SMMUTranslationProcess(proc_name, *smmu, *this); 16314039Sstacze01@arm.com proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt)); 16414039Sstacze01@arm.com 16514039Sstacze01@arm.com smmu->runProcessTiming(proc, pkt); 16614039Sstacze01@arm.com 16714039Sstacze01@arm.com return true; 16814039Sstacze01@arm.com} 16914039Sstacze01@arm.com 17014039Sstacze01@arm.comTick 17114039Sstacze01@arm.comSMMUv3SlaveInterface::atsSlaveRecvAtomic(PacketPtr pkt) 17214039Sstacze01@arm.com{ 17314039Sstacze01@arm.com DPRINTF(SMMUv3, "[a] ATS slave req addr=%#x size=%#x\n", 17414039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 17514039Sstacze01@arm.com 17614039Sstacze01@arm.com std::string proc_name = csprintf("%s.atsport", name()); 17714039Sstacze01@arm.com const bool ats_request = true; 17814039Sstacze01@arm.com SMMUTranslationProcess proc( 17914039Sstacze01@arm.com proc_name, *smmu, *this); 18014039Sstacze01@arm.com proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request)); 18114039Sstacze01@arm.com 18214039Sstacze01@arm.com SMMUAction a = smmu->runProcessAtomic(&proc, pkt); 18314039Sstacze01@arm.com assert(a.type == ACTION_SEND_RESP_ATS); 18414039Sstacze01@arm.com 18514039Sstacze01@arm.com return a.delay; 18614039Sstacze01@arm.com} 18714039Sstacze01@arm.com 18814039Sstacze01@arm.combool 18914039Sstacze01@arm.comSMMUv3SlaveInterface::atsSlaveRecvTimingReq(PacketPtr pkt) 19014039Sstacze01@arm.com{ 19114039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] ATS slave req addr=%#x size=%#x\n", 19214039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 19314039Sstacze01@arm.com 19414039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 19514039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 19614039Sstacze01@arm.com 19714039Sstacze01@arm.com if (xlateSlotsRemaining == 0) { 19814039Sstacze01@arm.com deviceNeedsRetry = true; 19914039Sstacze01@arm.com return false; 20014039Sstacze01@arm.com } 20114039Sstacze01@arm.com 20214039Sstacze01@arm.com std::string proc_name = csprintf("%s.atsport", name()); 20314039Sstacze01@arm.com const bool ats_request = true; 20414039Sstacze01@arm.com SMMUTranslationProcess *proc = 20514039Sstacze01@arm.com new SMMUTranslationProcess(proc_name, *smmu, *this); 20614039Sstacze01@arm.com proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request)); 20714039Sstacze01@arm.com 20814039Sstacze01@arm.com smmu->runProcessTiming(proc, pkt); 20914039Sstacze01@arm.com 21014039Sstacze01@arm.com return true; 21114039Sstacze01@arm.com} 21214039Sstacze01@arm.com 21314039Sstacze01@arm.combool 21414039Sstacze01@arm.comSMMUv3SlaveInterface::atsMasterRecvTimingResp(PacketPtr pkt) 21514039Sstacze01@arm.com{ 21614039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] ATS master resp addr=%#x size=%#x\n", 21714039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 21814039Sstacze01@arm.com 21914039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 22014039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 22114039Sstacze01@arm.com 22214039Sstacze01@arm.com SMMUProcess *proc = 22314039Sstacze01@arm.com safe_cast<SMMUProcess *>(pkt->popSenderState()); 22414039Sstacze01@arm.com 22514039Sstacze01@arm.com smmu->runProcessTiming(proc, pkt); 22614039Sstacze01@arm.com 22714039Sstacze01@arm.com return true; 22814039Sstacze01@arm.com} 22914039Sstacze01@arm.com 23014039Sstacze01@arm.comvoid 23114039Sstacze01@arm.comSMMUv3SlaveInterface::sendDeviceRetry() 23214039Sstacze01@arm.com{ 23314039Sstacze01@arm.com slavePort->sendRetryReq(); 23414039Sstacze01@arm.com} 23514039Sstacze01@arm.com 23614039Sstacze01@arm.comvoid 23714039Sstacze01@arm.comSMMUv3SlaveInterface::atsSendDeviceRetry() 23814039Sstacze01@arm.com{ 23914039Sstacze01@arm.com DPRINTF(SMMUv3, "ATS retry\n"); 24014039Sstacze01@arm.com atsSlavePort.sendRetryReq(); 24114039Sstacze01@arm.com} 24214039Sstacze01@arm.com 24314039Sstacze01@arm.comvoid 24414039Sstacze01@arm.comSMMUv3SlaveInterface::scheduleDeviceRetry() 24514039Sstacze01@arm.com{ 24614039Sstacze01@arm.com if (deviceNeedsRetry && !sendDeviceRetryEvent.scheduled()) { 24714039Sstacze01@arm.com DPRINTF(SMMUv3, "sched slave retry\n"); 24814039Sstacze01@arm.com deviceNeedsRetry = false; 24914039Sstacze01@arm.com schedule(sendDeviceRetryEvent, nextCycle()); 25014039Sstacze01@arm.com } 25114039Sstacze01@arm.com} 25214039Sstacze01@arm.com 25314064Sadrian.herrera@arm.comDrainState 25414064Sadrian.herrera@arm.comSMMUv3SlaveInterface::drain() 25514064Sadrian.herrera@arm.com{ 25614064Sadrian.herrera@arm.com // Wait until all SMMU translations are completed 25714064Sadrian.herrera@arm.com if (xlateSlotsRemaining < params()->xlate_slots) { 25814064Sadrian.herrera@arm.com return DrainState::Draining; 25914064Sadrian.herrera@arm.com } 26014064Sadrian.herrera@arm.com return DrainState::Drained; 26114064Sadrian.herrera@arm.com} 26214064Sadrian.herrera@arm.com 26314039Sstacze01@arm.comSMMUv3SlaveInterface* 26414039Sstacze01@arm.comSMMUv3SlaveInterfaceParams::create() 26514039Sstacze01@arm.com{ 26614039Sstacze01@arm.com return new SMMUv3SlaveInterface(this); 26714039Sstacze01@arm.com} 268