File Index
Files and directories
Sign in
FILE

amdgpu_psp_ta.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c C
  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#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_terminate
 70};
 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_MODULE
 90};
 91
 92static const struct file_operations ta_unload_debugfs_fops = {
 93	.write  = ta_if_unload_debugfs_write,
 94	.llseek = default_llseek,
 95	.owner  = THIS_MODULE
 96};
 97
 98static const struct file_operations ta_invoke_debugfs_fops = {
 99	.write  = ta_if_invoke_debugfs_write,
100	.llseek = default_llseek,
101	.owner  = THIS_MODULE
102};
103
104/*
105 * DOC: AMDGPU TA debugfs interfaces
106 *
107 * Three debugfs interfaces can be opened by a program to
108 * load/invoke/unload TA,
109 *
110 * - /sys/kernel/debug/dri/<N>/ta_if/ta_load
111 * - /sys/kernel/debug/dri/<N>/ta_if/ta_invoke
112 * - /sys/kernel/debug/dri/<N>/ta_if/ta_unload
113 *
114 * How to use the interfaces in a program?
115 *
116 * A program needs to provide transmit buffer to the interfaces
117 * 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 bin
124 *   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 length
133 *      (4bytes, value not beyond TA shared memory size)
134 *    - TA shared buf
135 *   Receive buffer:
136 *    - TA shared buf
137 *
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 = memdup_user(&buf[copy_pos], ta_bin_len);
175	if (IS_ERR(ta_bin))
176		return PTR_ERR(ta_bin);
177
178	/* Set TA context and functions */
179	set_ta_context_funcs(psp, ta_type, &context);
180
181	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {
182		dev_err(adev->dev, "Unsupported function to terminate TA\n");
183		ret = -EOPNOTSUPP;
184		goto err_free_bin;
185	}
186
187	/*
188	 * Allocate TA shared buf in case shared buf was freed
189	 * due to loading TA failed before.
190	 */
191	if (!context->mem_context.shared_buf) {
192		ret = psp_ta_init_shared_buf(psp, &context->mem_context);
193		if (ret) {
194			ret = -ENOMEM;
195			goto err_free_bin;
196		}
197	}
198
199	ret = psp_fn_ta_terminate(psp);
200	if (ret || context->resp_status) {
201		dev_err(adev->dev,
202			"Failed to unload embedded TA (%d) and status (0x%X)\n",
203			ret, context->resp_status);
204		if (!ret)
205			ret = -EINVAL;
206		goto err_free_ta_shared_buf;
207	}
208
209	/* Prepare TA context for TA initialization */
210	context->ta_type                     = ta_type;
211	context->bin_desc.fw_version         = get_bin_version(ta_bin);
212	context->bin_desc.size_bytes         = ta_bin_len;
213	context->bin_desc.start_addr         = ta_bin;
214
215	if (!psp->ta_funcs->fn_ta_initialize) {
216		dev_err(adev->dev, "Unsupported function to initialize TA\n");
217		ret = -EOPNOTSUPP;
218		goto err_free_ta_shared_buf;
219	}
220
221	ret = psp_fn_ta_initialize(psp);
222	if (ret || context->resp_status) {
223		dev_err(adev->dev, "Failed to load TA via debugfs (%d) and status (0x%X)\n",
224			ret, context->resp_status);
225		if (!ret)
226			ret = -EINVAL;
227		goto err_free_ta_shared_buf;
228	}
229
230	if (copy_to_user((char *)buf, (void *)&context->session_id, sizeof(uint32_t)))
231		ret = -EFAULT;
232
233err_free_ta_shared_buf:
234	/* Only free TA shared buf when returns error code */
235	if (ret && context->mem_context.shared_buf)
236		psp_ta_free_shared_buf(&context->mem_context);
237err_free_bin:
238	kfree(ta_bin);
239
240	return ret;
241}
242
243static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)
244{
245	uint32_t ta_type    = 0;
246	uint32_t ta_id      = 0;
247	uint32_t copy_pos   = 0;
248	int      ret        = 0;
249
250	struct amdgpu_device *adev    = (struct amdgpu_device *)file_inode(fp)->i_private;
251	struct psp_context   *psp     = &adev->psp;
252	struct ta_context    *context = NULL;
253
254	if (!buf)
255		return -EINVAL;
256
257	ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
258	if (ret || (!is_ta_type_valid(ta_type)))
259		return -EFAULT;
260
261	copy_pos += sizeof(uint32_t);
262
263	ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));
264	if (ret)
265		return -EFAULT;
266
267	set_ta_context_funcs(psp, ta_type, &context);
268	context->session_id = ta_id;
269
270	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {
271		dev_err(adev->dev, "Unsupported function to terminate TA\n");
272		return -EOPNOTSUPP;
273	}
274
275	ret = psp_fn_ta_terminate(psp);
276	if (ret || context->resp_status) {
277		dev_err(adev->dev, "Failed to unload TA via debugfs (%d) and status (0x%X)\n",
278			ret, context->resp_status);
279		if (!ret)
280			ret = -EINVAL;
281	}
282
283	if (context->mem_context.shared_buf)
284		psp_ta_free_shared_buf(&context->mem_context);
285
286	return ret;
287}
288
289static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)
290{
291	uint32_t ta_type        = 0;
292	uint32_t ta_id          = 0;
293	uint32_t cmd_id         = 0;
294	uint32_t shared_buf_len = 0;
295	uint8_t *shared_buf     = NULL;
296	uint32_t copy_pos       = 0;
297	int      ret            = 0;
298
299	struct amdgpu_device *adev    = (struct amdgpu_device *)file_inode(fp)->i_private;
300	struct psp_context   *psp     = &adev->psp;
301	struct ta_context    *context = NULL;
302
303	if (!buf)
304		return -EINVAL;
305
306	ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
307	if (ret)
308		return -EFAULT;
309	copy_pos += sizeof(uint32_t);
310
311	ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));
312	if (ret)
313		return -EFAULT;
314	copy_pos += sizeof(uint32_t);
315
316	ret = copy_from_user((void *)&cmd_id, &buf[copy_pos], sizeof(uint32_t));
317	if (ret)
318		return -EFAULT;
319	copy_pos += sizeof(uint32_t);
320
321	ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t));
322	if (ret)
323		return -EFAULT;
324	copy_pos += sizeof(uint32_t);
325
326	shared_buf = memdup_user(&buf[copy_pos], shared_buf_len);
327	if (IS_ERR(shared_buf))
328		return PTR_ERR(shared_buf);
329
330	set_ta_context_funcs(psp, ta_type, &context);
331
332	if (!context || !context->initialized) {
333		dev_err(adev->dev, "TA is not initialized\n");
334		ret = -EINVAL;
335		goto free_shared_buf;
336	}
337
338	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {
339		dev_err(adev->dev, "Unsupported function to invoke TA\n");
340		ret = -EOPNOTSUPP;
341		goto free_shared_buf;
342	}
343
344	context->session_id = ta_id;
345
346	mutex_lock(&psp->ras_context.mutex);
347	ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len);
348	if (ret)
349		goto unlock;
350
351	ret = psp_fn_ta_invoke(psp, cmd_id);
352	if (ret || context->resp_status) {
353		dev_err(adev->dev, "Failed to invoke TA via debugfs (%d) and status (0x%X)\n",
354			ret, context->resp_status);
355		if (!ret) {
356			ret = -EINVAL;
357			goto unlock;
358		}
359	}
360
361	if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len))
362		ret = -EFAULT;
363
364unlock:
365	mutex_unlock(&psp->ras_context.mutex);
366
367free_shared_buf:
368	kfree(shared_buf);
369
370	return ret;
371}
372
373void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev)
374{
375	struct drm_minor *minor = adev_to_drm(adev)->primary;
376
377	struct dentry *dir = debugfs_create_dir("ta_if", minor->debugfs_root);
378
379	debugfs_create_file("ta_load", 0200, dir, adev,
380				     &ta_load_debugfs_fops);
381
382	debugfs_create_file("ta_unload", 0200, dir,
383				     adev, &ta_unload_debugfs_fops);
384
385	debugfs_create_file("ta_invoke", 0200, dir,
386				     adev, &ta_invoke_debugfs_fops);
387}
388
389#else
390void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev)
391{
392
393}
394#endif
~/ Read-only file preview.