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	copy_pos += sizeof(uint32_t);
170
171	ta_bin = kzalloc(ta_bin_len, GFP_KERNEL);
172	if (!ta_bin)
173		return -ENOMEM;
174	if (copy_from_user((void *)ta_bin, &buf[copy_pos], ta_bin_len)) {
175		ret = -EFAULT;
176		goto err_free_bin;
177	}
178
179	/* Set TA context and functions */
180	set_ta_context_funcs(psp, ta_type, &context);
181
182	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {
183		dev_err(adev->dev, "Unsupported function to terminate TA\n");
184		ret = -EOPNOTSUPP;
185		goto err_free_bin;
186	}
187
188	/*
189	 * Allocate TA shared buf in case shared buf was freed
190	 * due to loading TA failed before.
191	 */
192	if (!context->mem_context.shared_buf) {
193		ret = psp_ta_init_shared_buf(psp, &context->mem_context);
194		if (ret) {
195			ret = -ENOMEM;
196			goto err_free_bin;
197		}
198	}
199
200	ret = psp_fn_ta_terminate(psp);
201	if (ret || context->resp_status) {
202		dev_err(adev->dev,
203			"Failed to unload embedded TA (%d) and status (0x%X)\n",
204			ret, context->resp_status);
205		if (!ret)
206			ret = -EINVAL;
207		goto err_free_ta_shared_buf;
208	}
209
210	/* Prepare TA context for TA initialization */
211	context->ta_type                     = ta_type;
212	context->bin_desc.fw_version         = get_bin_version(ta_bin);
213	context->bin_desc.size_bytes         = ta_bin_len;
214	context->bin_desc.start_addr         = ta_bin;
215
216	if (!psp->ta_funcs->fn_ta_initialize) {
217		dev_err(adev->dev, "Unsupported function to initialize TA\n");
218		ret = -EOPNOTSUPP;
219		goto err_free_ta_shared_buf;
220	}
221
222	ret = psp_fn_ta_initialize(psp);
223	if (ret || context->resp_status) {
224		dev_err(adev->dev, "Failed to load TA via debugfs (%d) and status (0x%X)\n",
225			ret, context->resp_status);
226		if (!ret)
227			ret = -EINVAL;
228		goto err_free_ta_shared_buf;
229	}
230
231	if (copy_to_user((char *)buf, (void *)&context->session_id, sizeof(uint32_t)))
232		ret = -EFAULT;
233
234err_free_ta_shared_buf:
235	/* Only free TA shared buf when returns error code */
236	if (ret && context->mem_context.shared_buf)
237		psp_ta_free_shared_buf(&context->mem_context);
238err_free_bin:
239	kfree(ta_bin);
240
241	return ret;
242}
243
244static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)
245{
246	uint32_t ta_type    = 0;
247	uint32_t ta_id      = 0;
248	uint32_t copy_pos   = 0;
249	int      ret        = 0;
250
251	struct amdgpu_device *adev    = (struct amdgpu_device *)file_inode(fp)->i_private;
252	struct psp_context   *psp     = &adev->psp;
253	struct ta_context    *context = NULL;
254
255	if (!buf)
256		return -EINVAL;
257
258	ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
259	if (ret || (!is_ta_type_valid(ta_type)))
260		return -EFAULT;
261
262	copy_pos += sizeof(uint32_t);
263
264	ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));
265	if (ret)
266		return -EFAULT;
267
268	set_ta_context_funcs(psp, ta_type, &context);
269	context->session_id = ta_id;
270
271	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) {
272		dev_err(adev->dev, "Unsupported function to terminate TA\n");
273		return -EOPNOTSUPP;
274	}
275
276	ret = psp_fn_ta_terminate(psp);
277	if (ret || context->resp_status) {
278		dev_err(adev->dev, "Failed to unload TA via debugfs (%d) and status (0x%X)\n",
279			ret, context->resp_status);
280		if (!ret)
281			ret = -EINVAL;
282	}
283
284	if (context->mem_context.shared_buf)
285		psp_ta_free_shared_buf(&context->mem_context);
286
287	return ret;
288}
289
290static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off)
291{
292	uint32_t ta_type        = 0;
293	uint32_t ta_id          = 0;
294	uint32_t cmd_id         = 0;
295	uint32_t shared_buf_len = 0;
296	uint8_t *shared_buf     = NULL;
297	uint32_t copy_pos       = 0;
298	int      ret            = 0;
299
300	struct amdgpu_device *adev    = (struct amdgpu_device *)file_inode(fp)->i_private;
301	struct psp_context   *psp     = &adev->psp;
302	struct ta_context    *context = NULL;
303
304	if (!buf)
305		return -EINVAL;
306
307	ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t));
308	if (ret)
309		return -EFAULT;
310	copy_pos += sizeof(uint32_t);
311
312	ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t));
313	if (ret)
314		return -EFAULT;
315	copy_pos += sizeof(uint32_t);
316
317	ret = copy_from_user((void *)&cmd_id, &buf[copy_pos], sizeof(uint32_t));
318	if (ret)
319		return -EFAULT;
320	copy_pos += sizeof(uint32_t);
321
322	ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t));
323	if (ret)
324		return -EFAULT;
325	copy_pos += sizeof(uint32_t);
326
327	shared_buf = kzalloc(shared_buf_len, GFP_KERNEL);
328	if (!shared_buf)
329		return -ENOMEM;
330	if (copy_from_user((void *)shared_buf, &buf[copy_pos], shared_buf_len)) {
331		ret = -EFAULT;
332		goto err_free_shared_buf;
333	}
334
335	set_ta_context_funcs(psp, ta_type, &context);
336
337	if (!context->initialized) {
338		dev_err(adev->dev, "TA is not initialized\n");
339		ret = -EINVAL;
340		goto err_free_shared_buf;
341	}
342
343	if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {
344		dev_err(adev->dev, "Unsupported function to invoke TA\n");
345		ret = -EOPNOTSUPP;
346		goto err_free_shared_buf;
347	}
348
349	context->session_id = ta_id;
350
351	ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len);
352	if (ret)
353		goto err_free_shared_buf;
354
355	ret = psp_fn_ta_invoke(psp, cmd_id);
356	if (ret || context->resp_status) {
357		dev_err(adev->dev, "Failed to invoke TA via debugfs (%d) and status (0x%X)\n",
358			ret, context->resp_status);
359		if (!ret) {
360			ret = -EINVAL;
361			goto err_free_shared_buf;
362		}
363	}
364
365	if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len))
366		ret = -EFAULT;
367
368err_free_shared_buf:
369	kfree(shared_buf);
370
371	return ret;
372}
373
374void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev)
375{
376	struct drm_minor *minor = adev_to_drm(adev)->primary;
377
378	struct dentry *dir = debugfs_create_dir("ta_if", minor->debugfs_root);
379
380	debugfs_create_file("ta_load", 0200, dir, adev,
381				     &ta_load_debugfs_fops);
382
383	debugfs_create_file("ta_unload", 0200, dir,
384				     adev, &ta_unload_debugfs_fops);
385
386	debugfs_create_file("ta_invoke", 0200, dir,
387				     adev, &ta_invoke_debugfs_fops);
388}
389
390#else
391void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev)
392{
393
394}
395#endif
396