smmu_v3_slaveifc.cc revision 14039
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()) { 8314039Sstacze01@arm.com inform("Slave port is connected to %d\n", 8414039Sstacze01@arm.com slavePort->getMasterPort().name()); 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 { 10214039Sstacze01@arm.com return MemObject::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", 12714039Sstacze01@arm.com slavePort->getMasterPort().name(), 12814039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 12914039Sstacze01@arm.com 13014039Sstacze01@arm.com std::string proc_name = csprintf("%s.port", name()); 13114039Sstacze01@arm.com SMMUTranslationProcess proc(proc_name, *smmu, *this); 13214039Sstacze01@arm.com proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt)); 13314039Sstacze01@arm.com 13414039Sstacze01@arm.com SMMUAction a = smmu->runProcessAtomic(&proc, pkt); 13514039Sstacze01@arm.com assert(a.type == ACTION_SEND_RESP); 13614039Sstacze01@arm.com 13714039Sstacze01@arm.com return a.delay; 13814039Sstacze01@arm.com} 13914039Sstacze01@arm.com 14014039Sstacze01@arm.combool 14114039Sstacze01@arm.comSMMUv3SlaveInterface::recvTimingReq(PacketPtr pkt) 14214039Sstacze01@arm.com{ 14314039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] req from %s addr=%#x size=%#x\n", 14414039Sstacze01@arm.com slavePort->getMasterPort().name(), 14514039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 14614039Sstacze01@arm.com 14714039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 14814039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 14914039Sstacze01@arm.com 15014039Sstacze01@arm.com unsigned nbeats = 15114039Sstacze01@arm.com (pkt->getSize() + (portWidth-1)) / portWidth; 15214039Sstacze01@arm.com 15314039Sstacze01@arm.com if (xlateSlotsRemaining==0 || 15414039Sstacze01@arm.com (pkt->isWrite() && wrBufSlotsRemaining < nbeats)) 15514039Sstacze01@arm.com { 15614039Sstacze01@arm.com deviceNeedsRetry = true; 15714039Sstacze01@arm.com return false; 15814039Sstacze01@arm.com } 15914039Sstacze01@arm.com 16014039Sstacze01@arm.com xlateSlotsRemaining--; 16114039Sstacze01@arm.com if (pkt->isWrite()) 16214039Sstacze01@arm.com wrBufSlotsRemaining -= nbeats; 16314039Sstacze01@arm.com 16414039Sstacze01@arm.com std::string proc_name = csprintf("%s.port", name()); 16514039Sstacze01@arm.com SMMUTranslationProcess *proc = 16614039Sstacze01@arm.com new SMMUTranslationProcess(proc_name, *smmu, *this); 16714039Sstacze01@arm.com proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt)); 16814039Sstacze01@arm.com 16914039Sstacze01@arm.com smmu->runProcessTiming(proc, pkt); 17014039Sstacze01@arm.com 17114039Sstacze01@arm.com return true; 17214039Sstacze01@arm.com} 17314039Sstacze01@arm.com 17414039Sstacze01@arm.comTick 17514039Sstacze01@arm.comSMMUv3SlaveInterface::atsSlaveRecvAtomic(PacketPtr pkt) 17614039Sstacze01@arm.com{ 17714039Sstacze01@arm.com DPRINTF(SMMUv3, "[a] ATS slave req addr=%#x size=%#x\n", 17814039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 17914039Sstacze01@arm.com 18014039Sstacze01@arm.com std::string proc_name = csprintf("%s.atsport", name()); 18114039Sstacze01@arm.com const bool ats_request = true; 18214039Sstacze01@arm.com SMMUTranslationProcess proc( 18314039Sstacze01@arm.com proc_name, *smmu, *this); 18414039Sstacze01@arm.com proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request)); 18514039Sstacze01@arm.com 18614039Sstacze01@arm.com SMMUAction a = smmu->runProcessAtomic(&proc, pkt); 18714039Sstacze01@arm.com assert(a.type == ACTION_SEND_RESP_ATS); 18814039Sstacze01@arm.com 18914039Sstacze01@arm.com return a.delay; 19014039Sstacze01@arm.com} 19114039Sstacze01@arm.com 19214039Sstacze01@arm.combool 19314039Sstacze01@arm.comSMMUv3SlaveInterface::atsSlaveRecvTimingReq(PacketPtr pkt) 19414039Sstacze01@arm.com{ 19514039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] ATS slave req addr=%#x size=%#x\n", 19614039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 19714039Sstacze01@arm.com 19814039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 19914039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 20014039Sstacze01@arm.com 20114039Sstacze01@arm.com if (xlateSlotsRemaining == 0) { 20214039Sstacze01@arm.com deviceNeedsRetry = true; 20314039Sstacze01@arm.com return false; 20414039Sstacze01@arm.com } 20514039Sstacze01@arm.com 20614039Sstacze01@arm.com xlateSlotsRemaining--; 20714039Sstacze01@arm.com 20814039Sstacze01@arm.com std::string proc_name = csprintf("%s.atsport", name()); 20914039Sstacze01@arm.com const bool ats_request = true; 21014039Sstacze01@arm.com SMMUTranslationProcess *proc = 21114039Sstacze01@arm.com new SMMUTranslationProcess(proc_name, *smmu, *this); 21214039Sstacze01@arm.com proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request)); 21314039Sstacze01@arm.com 21414039Sstacze01@arm.com smmu->runProcessTiming(proc, pkt); 21514039Sstacze01@arm.com 21614039Sstacze01@arm.com return true; 21714039Sstacze01@arm.com} 21814039Sstacze01@arm.com 21914039Sstacze01@arm.combool 22014039Sstacze01@arm.comSMMUv3SlaveInterface::atsMasterRecvTimingResp(PacketPtr pkt) 22114039Sstacze01@arm.com{ 22214039Sstacze01@arm.com DPRINTF(SMMUv3, "[t] ATS master resp addr=%#x size=%#x\n", 22314039Sstacze01@arm.com pkt->getAddr(), pkt->getSize()); 22414039Sstacze01@arm.com 22514039Sstacze01@arm.com // @todo: We need to pay for this and not just zero it out 22614039Sstacze01@arm.com pkt->headerDelay = pkt->payloadDelay = 0; 22714039Sstacze01@arm.com 22814039Sstacze01@arm.com SMMUProcess *proc = 22914039Sstacze01@arm.com safe_cast<SMMUProcess *>(pkt->popSenderState()); 23014039Sstacze01@arm.com 23114039Sstacze01@arm.com smmu->runProcessTiming(proc, pkt); 23214039Sstacze01@arm.com 23314039Sstacze01@arm.com return true; 23414039Sstacze01@arm.com} 23514039Sstacze01@arm.com 23614039Sstacze01@arm.comvoid 23714039Sstacze01@arm.comSMMUv3SlaveInterface::sendDeviceRetry() 23814039Sstacze01@arm.com{ 23914039Sstacze01@arm.com slavePort->sendRetryReq(); 24014039Sstacze01@arm.com} 24114039Sstacze01@arm.com 24214039Sstacze01@arm.comvoid 24314039Sstacze01@arm.comSMMUv3SlaveInterface::atsSendDeviceRetry() 24414039Sstacze01@arm.com{ 24514039Sstacze01@arm.com DPRINTF(SMMUv3, "ATS retry\n"); 24614039Sstacze01@arm.com atsSlavePort.sendRetryReq(); 24714039Sstacze01@arm.com} 24814039Sstacze01@arm.com 24914039Sstacze01@arm.comvoid 25014039Sstacze01@arm.comSMMUv3SlaveInterface::scheduleDeviceRetry() 25114039Sstacze01@arm.com{ 25214039Sstacze01@arm.com if (deviceNeedsRetry && !sendDeviceRetryEvent.scheduled()) { 25314039Sstacze01@arm.com DPRINTF(SMMUv3, "sched slave retry\n"); 25414039Sstacze01@arm.com deviceNeedsRetry = false; 25514039Sstacze01@arm.com schedule(sendDeviceRetryEvent, nextCycle()); 25614039Sstacze01@arm.com } 25714039Sstacze01@arm.com} 25814039Sstacze01@arm.com 25914039Sstacze01@arm.comSMMUv3SlaveInterface* 26014039Sstacze01@arm.comSMMUv3SlaveInterfaceParams::create() 26114039Sstacze01@arm.com{ 26214039Sstacze01@arm.com return new SMMUv3SlaveInterface(this); 26314039Sstacze01@arm.com} 264