1/* 2 * Copyright (c) 2014-2016 ARM Limited 3 * All rights reserved 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * Authors: Andreas Sandberg 18 */ 19 20#include "jobslot.hh" 21 22#include <cassert> 23#include <cstdlib> 24 25#include "jobcontrol.hh" 26#include "gpu.hh" 27#include "regutils.hh" 28 29namespace NoMali { 30 31static const Status STATUS_IDLE(Status::CLASS_NOFAULT, 0, 0); 32static const Status STATUS_DONE(Status::CLASS_NOFAULT, 0, 1); 33static const Status STATUS_ACTIVE(Status::CLASS_NOFAULT, 1, 0); 34 35const std::vector<JobSlot::cmd_t> JobSlot::cmds { 36 &JobSlot::cmdNop, // JSn_COMMAND_NOP 37 &JobSlot::cmdStart, // JSn_COMMAND_START 38 &JobSlot::cmdSoftStop, // JSn_COMMAND_SOFT_STOP 39 &JobSlot::cmdHardStop, // JSn_COMMAND_HARD_STOP 40 &JobSlot::cmdSoftStop0, // JSn_COMMAND_SOFT_STOP_0 41 &JobSlot::cmdHardStop0, // JSn_COMMAND_HARD_STOP_0 42 &JobSlot::cmdSoftStop1, // JSn_COMMAND_SOFT_STOP_1 43 &JobSlot::cmdHardStop1, // JSn_COMMAND_HARD_STOP_1 44}; 45 46JobSlot::JobSlot(GPU &_gpu, JobControl &_jc, uint8_t _id) 47 : GPUBlock(_gpu, JSn_NO_REGS), 48 id(_id), 49 jc(_jc) 50{ 51} 52 53JobSlot::JobSlot(JobSlot &&rhs) 54 : GPUBlock(std::move(rhs)), 55 id(std::move(rhs.id)), 56 jc(rhs.jc) 57{ 58} 59 60JobSlot::~JobSlot() 61{ 62} 63 64void 65JobSlot::writeReg(RegAddr addr, uint32_t value) 66{ 67 switch (addr.value) { 68 case JSn_COMMAND: 69 jobCommand(value); 70 break; 71 72 case JSn_COMMAND_NEXT: 73 regs[addr] = value; 74 tryStart(); 75 break; 76 77 case JSn_HEAD_NEXT_LO: 78 case JSn_HEAD_NEXT_HI: 79 case JSn_AFFINITY_NEXT_LO: 80 case JSn_AFFINITY_NEXT_HI: 81 case JSn_CONFIG_NEXT: 82 GPUBlock::writeReg(addr, value); 83 break; 84 85 default: 86 // Ignore writes by default 87 break; 88 }; 89} 90 91bool 92JobSlot::active() const 93{ 94 return false; 95} 96 97bool 98JobSlot::activeNext() const 99{ 100 return regs[RegAddr(JSn_COMMAND_NEXT)] == JSn_COMMAND_START; 101} 102 103void 104JobSlot::tryStart() 105{ 106 // Only actually start something if the next command is start 107 if (regs[RegAddr(JSn_COMMAND_NEXT)] != JSn_COMMAND_START ) 108 return; 109 110 // Reset the status register 111 regs[RegAddr(JSn_STATUS)] = STATUS_ACTIVE.value; 112 113 // Transfer the next job configuration to the active job 114 // configuration 115 regs.set64(RegAddr(JSn_HEAD_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO))); 116 regs.set64(RegAddr(JSn_TAIL_LO), regs.get64(RegAddr(JSn_HEAD_NEXT_LO))); 117 regs.set64(RegAddr(JSn_AFFINITY_LO), 118 regs.get64(RegAddr(JSn_AFFINITY_NEXT_LO))); 119 regs[RegAddr(JSn_CONFIG)] = regs[RegAddr(JSn_CONFIG_NEXT)]; 120 121 // Reset the next job configuration 122 regs.set64(RegAddr(JSn_HEAD_NEXT_LO), 0); 123 regs[RegAddr(JSn_COMMAND_NEXT)] = 0; 124 125 runJob(); 126} 127 128void 129JobSlot::runJob() 130{ 131 exitJob(STATUS_DONE, 132 0); // Time stamp counter value 133} 134 135void 136JobSlot::exitJob(Status status, uint64_t fault_address) 137{ 138 assert(status.statusClass() == Status::CLASS_NOFAULT || 139 status.statusClass() == Status::CLASS_JOB); 140 141 regs[RegAddr(JSn_STATUS)] = status.value; 142 143 if (status.statusClass() == Status::CLASS_NOFAULT) { 144 jc.jobDone(id); 145 } else { 146 jc.jobFailed(id); 147 } 148} 149 150void 151JobSlot::jobCommand(uint32_t cmd) 152{ 153 if (cmd < cmds.size()) 154 (this->*cmds[cmd])(cmd); 155} 156 157void 158JobSlot::cmdNop(uint32_t cmd) 159{ 160 assert(cmd == JSn_COMMAND_NOP); 161} 162 163void 164JobSlot::cmdStart(uint32_t cmd) 165{ 166 assert(cmd == JSn_COMMAND_START); 167 // The JSn_COMMAND_START should never be issued through the 168 // JSn_COMMAND register. It should use the JSn_COMMAND_NEXT 169 // register instead. 170 abort(); 171} 172 173void 174JobSlot::cmdSoftStop(uint32_t cmd) 175{ 176 assert(cmd == JSn_COMMAND_SOFT_STOP || 177 cmd == JSn_COMMAND_SOFT_STOP_0 || 178 cmd == JSn_COMMAND_SOFT_STOP_1); 179} 180 181void 182JobSlot::cmdHardStop(uint32_t cmd) 183{ 184 assert(cmd == JSn_COMMAND_HARD_STOP || 185 cmd == JSn_COMMAND_HARD_STOP_0 || 186 cmd == JSn_COMMAND_HARD_STOP_1); 187} 188 189void 190JobSlot::cmdSoftStop0(uint32_t cmd) 191{ 192 if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)) 193 cmdSoftStop(cmd); 194} 195 196void 197JobSlot::cmdHardStop0(uint32_t cmd) 198{ 199 if (!(regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG)) 200 cmdHardStop(cmd); 201} 202 203void 204JobSlot::cmdSoftStop1(uint32_t cmd) 205{ 206 if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG) 207 cmdSoftStop(cmd); 208} 209 210void 211JobSlot::cmdHardStop1(uint32_t cmd) 212{ 213 if (regs[RegAddr(JSn_CONFIG)] & JSn_CONFIG_JOB_CHAIN_FLAG) 214 cmdHardStop(cmd); 215} 216 217} 218