1/* 2 * Copyright (c) 2013, 2018-2019 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Stan Czerniawski 38 */ 39 40#include "dev/arm/smmu_v3_proc.hh" 41 42#include "dev/arm/smmu_v3.hh" 43#include "sim/system.hh" 44 45SMMUProcess::SMMUProcess(const std::string &name, SMMUv3 &_smmu) : 46 coroutine(NULL), 47 myName(name), 48 smmu(_smmu) 49{} 50 51SMMUProcess::~SMMUProcess() 52{ 53 delete coroutine; 54} 55 56void 57SMMUProcess::wakeup() 58{ 59 smmu.runProcess(this, NULL); 60} 61 62void 63SMMUProcess::reinit() 64{ 65 delete coroutine; 66 coroutine = new Coroutine( 67 std::bind(&SMMUProcess::main, this, std::placeholders::_1)); 68} 69 70void 71SMMUProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size) 72{ 73 doSemaphoreDown(yield, smmu.masterPortSem); 74 doDelay(yield, Cycles(1)); // request - assume 1 cycle 75 doSemaphoreUp(smmu.masterPortSem); 76 77 SMMUAction a; 78 a.type = ACTION_SEND_REQ; 79 80 RequestPtr req = std::make_shared<Request>( 81 addr, size, 0, smmu.masterId); 82 83 req->taskId(ContextSwitchTaskId::DMA); 84 85 a.pkt = new Packet(req, MemCmd::ReadReq); 86 a.pkt->dataStatic(ptr); 87 88 a.delay = 0; 89 90 PacketPtr pkt = yield(a).get(); 91 92 assert(pkt); 93 // >= because we may get the whole cache line 94 assert(pkt->getSize() >= size); 95 96 delete pkt; 97} 98 99void 100SMMUProcess::doWrite(Yield &yield, Addr addr, const void *ptr, size_t size) 101{ 102 unsigned nbeats = (size + (smmu.masterPortWidth-1)) / smmu.masterPortWidth; 103 104 doSemaphoreDown(yield, smmu.masterPortSem); 105 doDelay(yield, Cycles(nbeats)); 106 doSemaphoreUp(smmu.masterPortSem); 107 108 109 SMMUAction a; 110 a.type = ACTION_SEND_REQ; 111 112 RequestPtr req = std::make_shared<Request>( 113 addr, size, 0, smmu.masterId); 114 115 req->taskId(ContextSwitchTaskId::DMA); 116 117 a.pkt = new Packet(req, MemCmd::WriteReq); 118 a.pkt->dataStatic(ptr); 119 120 PacketPtr pkt = yield(a).get(); 121 122 delete pkt; 123} 124 125void 126SMMUProcess::doDelay(Yield &yield, Cycles cycles) 127{ 128 if (smmu.system.isTimingMode()) 129 scheduleWakeup(smmu.clockEdge(cycles)); 130 131 SMMUAction a; 132 a.type = ACTION_DELAY; 133 a.delay = cycles * smmu.clockPeriod(); 134 yield(a); 135} 136 137void 138SMMUProcess::doSleep(Yield &yield) 139{ 140 SMMUAction a; 141 a.type = ACTION_SLEEP; 142 yield(a); 143} 144 145void 146SMMUProcess::doSemaphoreDown(Yield &yield, SMMUSemaphore &sem) 147{ 148 while (sem.count == 0) { 149 sem.queue.push(this); 150 doSleep(yield); 151 } 152 153 sem.count--; 154 return; 155} 156 157void 158SMMUProcess::doSemaphoreUp(SMMUSemaphore &sem) 159{ 160 sem.count++; 161 if (!sem.queue.empty()) { 162 SMMUProcess *next_proc = sem.queue.front(); 163 sem.queue.pop(); 164 165 // Schedule event in the current tick instead of 166 // calling the function directly to avoid overflowing 167 // the stack in this coroutine. 168 next_proc->scheduleWakeup(curTick()); 169 } 170} 171 172void 173SMMUProcess::doWaitForSignal(Yield &yield, SMMUSignal &sig) 174{ 175 sig.waiting.push_back(this); 176 doSleep(yield); 177} 178 179void 180SMMUProcess::doBroadcastSignal(SMMUSignal &sig) 181{ 182 if (!sig.waiting.empty()) { 183 for (auto it : sig.waiting) { 184 // Schedule event in the current tick instead of 185 // calling the function directly to avoid overflowing 186 // the stack in this coroutine. 187 it->scheduleWakeup(curTick()); 188 } 189 190 sig.waiting.clear(); 191 } 192} 193 194void 195SMMUProcess::scheduleWakeup(Tick when) 196{ 197 auto *ep = new EventWrapper< 198 SMMUProcess, &SMMUProcess::wakeup> (this, true); 199 200 smmu.schedule(ep, when); 201} 202 203SMMUAction 204SMMUProcess::run(PacketPtr pkt) 205{ 206 assert(coroutine != NULL); 207 assert(*coroutine); 208 return (*coroutine)(pkt).get(); 209} 210