1 /* 2 * Copyright 2022 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * 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 OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24 #include "amdgpu.h" 25 #include "amdgpu_psp_ta.h" 26 27 static const char *TA_IF_FS_NAME = "ta_if"; 28 29 struct dentry *dir; 30 static struct dentry *ta_load_debugfs_dentry; 31 static struct dentry *ta_unload_debugfs_dentry; 32 static struct dentry *ta_invoke_debugfs_dentry; 33 34 static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, 35 size_t len, loff_t *off); 36 static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, 37 size_t len, loff_t *off); 38 static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, 39 size_t len, loff_t *off); 40 41 42 static uint32_t get_bin_version(const uint8_t *bin) 43 { 44 const struct common_firmware_header *hdr = 45 (const struct common_firmware_header *)bin; 46 47 return hdr->ucode_version; 48 } 49 50 static void prep_ta_mem_context(struct psp_context *psp, 51 struct ta_context *context, 52 uint8_t *shared_buf, 53 uint32_t shared_buf_len) 54 { 55 context->mem_context.shared_mem_size = PAGE_ALIGN(shared_buf_len); 56 psp_ta_init_shared_buf(psp, &context->mem_context); 57 58 memcpy((void *)context->mem_context.shared_buf, shared_buf, shared_buf_len); 59 } 60 61 static bool is_ta_type_valid(enum ta_type_id ta_type) 62 { 63 bool ret = false; 64 65 switch (ta_type) { 66 case TA_TYPE_RAS: 67 ret = true; 68 break; 69 default: 70 break; 71 } 72 73 return ret; 74 } 75 76 static const struct file_operations ta_load_debugfs_fops = { 77 .write = ta_if_load_debugfs_write, 78 .llseek = default_llseek, 79 .owner = THIS_MODULE 80 }; 81 82 static const struct file_operations ta_unload_debugfs_fops = { 83 .write = ta_if_unload_debugfs_write, 84 .llseek = default_llseek, 85 .owner = THIS_MODULE 86 }; 87 88 static const struct file_operations ta_invoke_debugfs_fops = { 89 .write = ta_if_invoke_debugfs_write, 90 .llseek = default_llseek, 91 .owner = THIS_MODULE 92 }; 93 94 95 /** 96 * DOC: AMDGPU TA debugfs interfaces 97 * 98 * Three debugfs interfaces can be opened by a program to 99 * load/invoke/unload TA, 100 * 101 * - /sys/kernel/debug/dri/<N>/ta_if/ta_load 102 * - /sys/kernel/debug/dri/<N>/ta_if/ta_invoke 103 * - /sys/kernel/debug/dri/<N>/ta_if/ta_unload 104 * 105 * How to use the interfaces in a program? 106 * 107 * A program needs to provide transmit buffer to the interfaces 108 * and will receive buffer from the interfaces below, 109 * 110 * - For TA load debugfs interface: 111 * Transmit buffer: 112 * - TA type (4bytes) 113 * - TA bin length (4bytes) 114 * - TA bin 115 * Receive buffer: 116 * - TA ID (4bytes) 117 * 118 * - For TA invoke debugfs interface: 119 * Transmit buffer: 120 * - TA ID (4bytes) 121 * - TA CMD ID (4bytes) 122 * - TA shard buf length (4bytes) 123 * - TA shared buf 124 * Receive buffer: 125 * - TA shared buf 126 * 127 * - For TA unload debugfs interface: 128 * Transmit buffer: 129 * - TA ID (4bytes) 130 */ 131 132 static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off) 133 { 134 uint32_t ta_type = 0; 135 uint32_t ta_bin_len = 0; 136 uint8_t *ta_bin = NULL; 137 uint32_t copy_pos = 0; 138 int ret = 0; 139 140 struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; 141 struct psp_context *psp = &adev->psp; 142 struct ta_context context = {0}; 143 144 if (!buf) 145 return -EINVAL; 146 147 ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t)); 148 if (ret || (!is_ta_type_valid(ta_type))) 149 return -EINVAL; 150 151 copy_pos += sizeof(uint32_t); 152 153 ret = copy_from_user((void *)&ta_bin_len, &buf[copy_pos], sizeof(uint32_t)); 154 if (ret) 155 return -EINVAL; 156 157 copy_pos += sizeof(uint32_t); 158 159 ta_bin = kzalloc(ta_bin_len, GFP_KERNEL); 160 if (!ta_bin) 161 ret = -ENOMEM; 162 ret = copy_from_user((void *)ta_bin, &buf[copy_pos], ta_bin_len); 163 if (ret) 164 goto err_free_bin; 165 166 ret = psp_ras_terminate(psp); 167 if (ret) { 168 dev_err(adev->dev, "Failed to unload embedded RAS TA\n"); 169 goto err_free_bin; 170 } 171 172 context.ta_type = ta_type; 173 context.ta_load_type = GFX_CMD_ID_LOAD_TA; 174 context.bin_desc.fw_version = get_bin_version(ta_bin); 175 context.bin_desc.size_bytes = ta_bin_len; 176 context.bin_desc.start_addr = ta_bin; 177 178 ret = psp_ta_load(psp, &context); 179 180 if (ret || context.resp_status) { 181 dev_err(adev->dev, "TA load via debugfs failed (%d) status %d\n", 182 ret, context.resp_status); 183 goto err_free_bin; 184 } 185 186 context.initialized = true; 187 ret = copy_to_user((char *)buf, (void *)&context.session_id, sizeof(uint32_t)); 188 189 err_free_bin: 190 kfree(ta_bin); 191 192 return ret; 193 } 194 195 static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off) 196 { 197 uint32_t ta_id = 0; 198 int ret = 0; 199 200 struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; 201 struct psp_context *psp = &adev->psp; 202 struct ta_context context = {0}; 203 204 if (!buf) 205 return -EINVAL; 206 207 ret = copy_from_user((void *)&ta_id, buf, sizeof(uint32_t)); 208 if (ret) 209 return -EINVAL; 210 211 context.session_id = ta_id; 212 213 ret = psp_ta_unload(psp, &context); 214 if (!ret) 215 context.initialized = false; 216 217 return ret; 218 } 219 220 static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off) 221 { 222 uint32_t ta_id = 0; 223 uint32_t cmd_id = 0; 224 uint32_t shared_buf_len = 0; 225 uint8_t *shared_buf = NULL; 226 uint32_t copy_pos = 0; 227 int ret = 0; 228 229 struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; 230 struct psp_context *psp = &adev->psp; 231 struct ta_context context = {0}; 232 233 if (!buf) 234 return -EINVAL; 235 236 ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t)); 237 if (ret) 238 return -EINVAL; 239 copy_pos += sizeof(uint32_t); 240 241 ret = copy_from_user((void *)&cmd_id, &buf[copy_pos], sizeof(uint32_t)); 242 if (ret) 243 return -EINVAL; 244 copy_pos += sizeof(uint32_t); 245 246 ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t)); 247 if (ret) 248 return -EINVAL; 249 copy_pos += sizeof(uint32_t); 250 251 shared_buf = kzalloc(shared_buf_len, GFP_KERNEL); 252 if (!shared_buf) 253 ret = -ENOMEM; 254 ret = copy_from_user((void *)shared_buf, &buf[copy_pos], shared_buf_len); 255 if (ret) 256 goto err_free_shared_buf; 257 258 context.session_id = ta_id; 259 260 prep_ta_mem_context(psp, &context, shared_buf, shared_buf_len); 261 262 ret = psp_ta_invoke_indirect(psp, cmd_id, &context); 263 264 if (ret || context.resp_status) { 265 dev_err(adev->dev, "TA invoke via debugfs failed (%d) status %d\n", 266 ret, context.resp_status); 267 goto err_free_ta_shared_buf; 268 } 269 270 ret = copy_to_user((char *)buf, context.mem_context.shared_buf, shared_buf_len); 271 272 err_free_ta_shared_buf: 273 psp_ta_free_shared_buf(&context.mem_context); 274 275 err_free_shared_buf: 276 kfree(shared_buf); 277 278 return ret; 279 } 280 281 static struct dentry *amdgpu_ta_if_debugfs_create(struct amdgpu_device *adev) 282 { 283 struct drm_minor *minor = adev_to_drm(adev)->primary; 284 285 dir = debugfs_create_dir(TA_IF_FS_NAME, minor->debugfs_root); 286 287 ta_load_debugfs_dentry = debugfs_create_file("ta_load", 0200, dir, adev, 288 &ta_load_debugfs_fops); 289 290 ta_unload_debugfs_dentry = debugfs_create_file("ta_unload", 0200, dir, 291 adev, &ta_unload_debugfs_fops); 292 293 ta_invoke_debugfs_dentry = debugfs_create_file("ta_invoke", 0200, dir, 294 adev, &ta_invoke_debugfs_fops); 295 return dir; 296 } 297 298 void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev) 299 { 300 #if defined(CONFIG_DEBUG_FS) 301 dir = amdgpu_ta_if_debugfs_create(adev); 302 #endif 303 } 304 305 void amdgpu_ta_if_debugfs_remove(void) 306 { 307 debugfs_remove_recursive(dir); 308 } 309