401 lines · c
1/*2 * Copyright 2022 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 */23 24#include "amdgpu.h"25#include "amdgpu_psp_ta.h"26 27#if defined(CONFIG_DEBUG_FS)28 29static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf,30 size_t len, loff_t *off);31static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf,32 size_t len, loff_t *off);33static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf,34 size_t len, loff_t *off);35 36static uint32_t get_bin_version(const uint8_t *bin)37{38 const struct common_firmware_header *hdr =39 (const struct common_firmware_header *)bin;40 41 return hdr->ucode_version;42}43 44static int prep_ta_mem_context(struct ta_mem_context *mem_context,45 uint8_t *shared_buf,46 uint32_t shared_buf_len)47{48 if (mem_context->shared_mem_size < shared_buf_len)49 return -EINVAL;50 memset(mem_context->shared_buf, 0, mem_context->shared_mem_size);51 memcpy((void *)mem_context->shared_buf, shared_buf, shared_buf_len);52 53 return 0;54}55 56static bool is_ta_type_valid(enum ta_type_id ta_type)57{58 switch (ta_type) {59 case TA_TYPE_RAS:60 return true;61 default:62 return false;63 }64}65 66static const struct ta_funcs ras_ta_funcs = {67 .fn_ta_initialize = psp_ras_initialize,68 .fn_ta_invoke = psp_ras_invoke,69 .fn_ta_terminate = psp_ras_terminate70};71 72static void set_ta_context_funcs(struct psp_context *psp,73 enum ta_type_id ta_type,74 struct ta_context **pcontext)75{76 switch (ta_type) {77 case TA_TYPE_RAS:78 *pcontext = &psp->ras_context.context;79 psp->ta_funcs = &ras_ta_funcs;80 break;81 default:82 break;83 }84}85 86static const struct file_operations ta_load_debugfs_fops = {87 .write = ta_if_load_debugfs_write,88 .llseek = default_llseek,89 .owner = THIS_MODULE90};91 92static const struct file_operations ta_unload_debugfs_fops = {93 .write = ta_if_unload_debugfs_write,94 .llseek = default_llseek,95 .owner = THIS_MODULE96};97 98static const struct file_operations ta_invoke_debugfs_fops = {99 .write = ta_if_invoke_debugfs_write,100 .llseek = default_llseek,101 .owner = THIS_MODULE102};103 104/*105 * DOC: AMDGPU TA debugfs interfaces106 *107 * Three debugfs interfaces can be opened by a program to108 * load/invoke/unload TA,109 *110 * - /sys/kernel/debug/dri/<N>/ta_if/ta_load111 * - /sys/kernel/debug/dri/<N>/ta_if/ta_invoke112 * - /sys/kernel/debug/dri/<N>/ta_if/ta_unload113 *114 * How to use the interfaces in a program?115 *116 * A program needs to provide transmit buffer to the interfaces117 * and will receive buffer from the interfaces below,118 *119 * - For TA load debugfs interface:120 * Transmit buffer:121 * - TA type (4bytes)122 * - TA bin length (4bytes)123 * - TA bin124 * Receive buffer:125 * - TA ID (4bytes)126 *127 * - For TA invoke debugfs interface:128 * Transmit buffer:129 * - TA type (4bytes)130 * - TA ID (4bytes)131 * - TA CMD ID (4bytes)132 * - TA shard buf length133 * (4bytes, value not beyond TA shared memory size)134 * - TA shared buf135 * Receive buffer:136 * - TA shared buf137 *138 * - For TA unload debugfs interface:139 * Transmit buffer:140 * - TA type (4bytes)141 * - TA ID (4bytes)142 */143 144static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)145{146 uint32_t ta_type = 0;147 uint32_t ta_bin_len = 0;148 uint8_t *ta_bin = NULL;149 uint32_t copy_pos = 0;150 int ret = 0;151 152 struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;153 struct psp_context *psp = &adev->psp;154 struct ta_context *context = NULL;155 156 if (!buf)157 return -EINVAL;158 159 ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));160 if (ret || (!is_ta_type_valid(ta_type)))161 return -EFAULT;162 163 copy_pos += sizeof(uint32_t);164 165 ret = copy_from_user((void *)&ta_bin_len, &buf[copy_pos], sizeof(uint32_t));166 if (ret)167 return -EFAULT;168 169 if (ta_bin_len > PSP_1_MEG)170 return -EINVAL;171 172 copy_pos += sizeof(uint32_t);173 174 ta_bin = kzalloc(ta_bin_len, GFP_KERNEL);175 if (!ta_bin)176 return -ENOMEM;177 if (copy_from_user((void *)ta_bin, &buf[copy_pos], ta_bin_len)) {178 ret = -EFAULT;179 goto err_free_bin;180 }181 182 /* Set TA context and functions */183 set_ta_context_funcs(psp, ta_type, &context);184 185 if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {186 dev_err(adev->dev, "Unsupported function to terminate TA\n");187 ret = -EOPNOTSUPP;188 goto err_free_bin;189 }190 191 /*192 * Allocate TA shared buf in case shared buf was freed193 * due to loading TA failed before.194 */195 if (!context->mem_context.shared_buf) {196 ret = psp_ta_init_shared_buf(psp, &context->mem_context);197 if (ret) {198 ret = -ENOMEM;199 goto err_free_bin;200 }201 }202 203 ret = psp_fn_ta_terminate(psp);204 if (ret || context->resp_status) {205 dev_err(adev->dev,206 "Failed to unload embedded TA (%d) and status (0x%X)\n",207 ret, context->resp_status);208 if (!ret)209 ret = -EINVAL;210 goto err_free_ta_shared_buf;211 }212 213 /* Prepare TA context for TA initialization */214 context->ta_type = ta_type;215 context->bin_desc.fw_version = get_bin_version(ta_bin);216 context->bin_desc.size_bytes = ta_bin_len;217 context->bin_desc.start_addr = ta_bin;218 219 if (!psp->ta_funcs->fn_ta_initialize) {220 dev_err(adev->dev, "Unsupported function to initialize TA\n");221 ret = -EOPNOTSUPP;222 goto err_free_ta_shared_buf;223 }224 225 ret = psp_fn_ta_initialize(psp);226 if (ret || context->resp_status) {227 dev_err(adev->dev, "Failed to load TA via debugfs (%d) and status (0x%X)\n",228 ret, context->resp_status);229 if (!ret)230 ret = -EINVAL;231 goto err_free_ta_shared_buf;232 }233 234 if (copy_to_user((char *)buf, (void *)&context->session_id, sizeof(uint32_t)))235 ret = -EFAULT;236 237err_free_ta_shared_buf:238 /* Only free TA shared buf when returns error code */239 if (ret && context->mem_context.shared_buf)240 psp_ta_free_shared_buf(&context->mem_context);241err_free_bin:242 kfree(ta_bin);243 244 return ret;245}246 247static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)248{249 uint32_t ta_type = 0;250 uint32_t ta_id = 0;251 uint32_t copy_pos = 0;252 int ret = 0;253 254 struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;255 struct psp_context *psp = &adev->psp;256 struct ta_context *context = NULL;257 258 if (!buf)259 return -EINVAL;260 261 ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));262 if (ret || (!is_ta_type_valid(ta_type)))263 return -EFAULT;264 265 copy_pos += sizeof(uint32_t);266 267 ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));268 if (ret)269 return -EFAULT;270 271 set_ta_context_funcs(psp, ta_type, &context);272 context->session_id = ta_id;273 274 if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {275 dev_err(adev->dev, "Unsupported function to terminate TA\n");276 return -EOPNOTSUPP;277 }278 279 ret = psp_fn_ta_terminate(psp);280 if (ret || context->resp_status) {281 dev_err(adev->dev, "Failed to unload TA via debugfs (%d) and status (0x%X)\n",282 ret, context->resp_status);283 if (!ret)284 ret = -EINVAL;285 }286 287 if (context->mem_context.shared_buf)288 psp_ta_free_shared_buf(&context->mem_context);289 290 return ret;291}292 293static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)294{295 uint32_t ta_type = 0;296 uint32_t ta_id = 0;297 uint32_t cmd_id = 0;298 uint32_t shared_buf_len = 0;299 uint8_t *shared_buf = NULL;300 uint32_t copy_pos = 0;301 int ret = 0;302 303 struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private;304 struct psp_context *psp = &adev->psp;305 struct ta_context *context = NULL;306 307 if (!buf)308 return -EINVAL;309 310 ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));311 if (ret)312 return -EFAULT;313 copy_pos += sizeof(uint32_t);314 315 ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));316 if (ret)317 return -EFAULT;318 copy_pos += sizeof(uint32_t);319 320 ret = copy_from_user((void *)&cmd_id, &buf[copy_pos], sizeof(uint32_t));321 if (ret)322 return -EFAULT;323 copy_pos += sizeof(uint32_t);324 325 ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t));326 if (ret)327 return -EFAULT;328 copy_pos += sizeof(uint32_t);329 330 shared_buf = kzalloc(shared_buf_len, GFP_KERNEL);331 if (!shared_buf)332 return -ENOMEM;333 if (copy_from_user((void *)shared_buf, &buf[copy_pos], shared_buf_len)) {334 ret = -EFAULT;335 goto err_free_shared_buf;336 }337 338 set_ta_context_funcs(psp, ta_type, &context);339 340 if (!context || !context->initialized) {341 dev_err(adev->dev, "TA is not initialized\n");342 ret = -EINVAL;343 goto err_free_shared_buf;344 }345 346 if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {347 dev_err(adev->dev, "Unsupported function to invoke TA\n");348 ret = -EOPNOTSUPP;349 goto err_free_shared_buf;350 }351 352 context->session_id = ta_id;353 354 mutex_lock(&psp->ras_context.mutex);355 ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len);356 if (ret)357 goto err_free_shared_buf;358 359 ret = psp_fn_ta_invoke(psp, cmd_id);360 if (ret || context->resp_status) {361 dev_err(adev->dev, "Failed to invoke TA via debugfs (%d) and status (0x%X)\n",362 ret, context->resp_status);363 if (!ret) {364 ret = -EINVAL;365 goto err_free_shared_buf;366 }367 }368 369 if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len))370 ret = -EFAULT;371 372err_free_shared_buf:373 mutex_unlock(&psp->ras_context.mutex);374 kfree(shared_buf);375 376 return ret;377}378 379void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev)380{381 struct drm_minor *minor = adev_to_drm(adev)->primary;382 383 struct dentry *dir = debugfs_create_dir("ta_if", minor->debugfs_root);384 385 debugfs_create_file("ta_load", 0200, dir, adev,386 &ta_load_debugfs_fops);387 388 debugfs_create_file("ta_unload", 0200, dir,389 adev, &ta_unload_debugfs_fops);390 391 debugfs_create_file("ta_invoke", 0200, dir,392 adev, &ta_invoke_debugfs_fops);393}394 395#else396void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev)397{398 399}400#endif401