xref: /linux/drivers/gpu/drm/xe/xe_pxp_submit.c (revision dcdd6b84d9acaa0794c29de7024cfdb20cfd7b92)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright(c) 2024 Intel Corporation.
4  */
5 
6 #include "xe_pxp_submit.h"
7 
8 #include <uapi/drm/xe_drm.h>
9 
10 #include "xe_device_types.h"
11 #include "xe_bo.h"
12 #include "xe_exec_queue.h"
13 #include "xe_gsc_submit.h"
14 #include "xe_gt.h"
15 #include "xe_pxp_types.h"
16 #include "xe_vm.h"
17 
18 /*
19  * The VCS is used for kernel-owned GGTT submissions to issue key termination.
20  * Terminations are serialized, so we only need a single queue and a single
21  * batch.
22  */
23 static int allocate_vcs_execution_resources(struct xe_pxp *pxp)
24 {
25 	struct xe_gt *gt = pxp->gt;
26 	struct xe_device *xe = pxp->xe;
27 	struct xe_tile *tile = gt_to_tile(gt);
28 	struct xe_hw_engine *hwe;
29 	struct xe_exec_queue *q;
30 	struct xe_bo *bo;
31 	int err;
32 
33 	hwe = xe_gt_hw_engine(gt, XE_ENGINE_CLASS_VIDEO_DECODE, 0, true);
34 	if (!hwe)
35 		return -ENODEV;
36 
37 	q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), 1, hwe,
38 				 EXEC_QUEUE_FLAG_KERNEL | EXEC_QUEUE_FLAG_PERMANENT, 0);
39 	if (IS_ERR(q))
40 		return PTR_ERR(q);
41 
42 	/*
43 	 * Each termination is 16 DWORDS, so 4K is enough to contain a
44 	 * termination for each sessions.
45 	 */
46 	bo = xe_bo_create_pin_map(xe, tile, 0, SZ_4K, ttm_bo_type_kernel,
47 				  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_GGTT);
48 	if (IS_ERR(bo)) {
49 		err = PTR_ERR(bo);
50 		goto out_queue;
51 	}
52 
53 	pxp->vcs_exec.q = q;
54 	pxp->vcs_exec.bo = bo;
55 
56 	return 0;
57 
58 out_queue:
59 	xe_exec_queue_put(q);
60 	return err;
61 }
62 
63 static void destroy_vcs_execution_resources(struct xe_pxp *pxp)
64 {
65 	if (pxp->vcs_exec.bo)
66 		xe_bo_unpin_map_no_vm(pxp->vcs_exec.bo);
67 
68 	if (pxp->vcs_exec.q)
69 		xe_exec_queue_put(pxp->vcs_exec.q);
70 }
71 
72 #define PXP_BB_SIZE		XE_PAGE_SIZE
73 static int allocate_gsc_client_resources(struct xe_gt *gt,
74 					 struct xe_pxp_gsc_client_resources *gsc_res,
75 					 size_t inout_size)
76 {
77 	struct xe_tile *tile = gt_to_tile(gt);
78 	struct xe_device *xe = tile_to_xe(tile);
79 	struct xe_hw_engine *hwe;
80 	struct xe_vm *vm;
81 	struct xe_bo *bo;
82 	struct xe_exec_queue *q;
83 	struct dma_fence *fence;
84 	long timeout;
85 	int err = 0;
86 
87 	hwe = xe_gt_hw_engine(gt, XE_ENGINE_CLASS_OTHER, 0, true);
88 
89 	/* we shouldn't reach here if the GSC engine is not available */
90 	xe_assert(xe, hwe);
91 
92 	/* PXP instructions must be issued from PPGTT */
93 	vm = xe_vm_create(xe, XE_VM_FLAG_GSC);
94 	if (IS_ERR(vm))
95 		return PTR_ERR(vm);
96 
97 	/* We allocate a single object for the batch and the in/out memory */
98 	xe_vm_lock(vm, false);
99 	bo = xe_bo_create_pin_map(xe, tile, vm, PXP_BB_SIZE + inout_size * 2,
100 				  ttm_bo_type_kernel,
101 				  XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_NEEDS_UC);
102 	xe_vm_unlock(vm);
103 	if (IS_ERR(bo)) {
104 		err = PTR_ERR(bo);
105 		goto vm_out;
106 	}
107 
108 	fence = xe_vm_bind_kernel_bo(vm, bo, NULL, 0, XE_CACHE_WB);
109 	if (IS_ERR(fence)) {
110 		err = PTR_ERR(fence);
111 		goto bo_out;
112 	}
113 
114 	timeout = dma_fence_wait_timeout(fence, false, HZ);
115 	dma_fence_put(fence);
116 	if (timeout <= 0) {
117 		err = timeout ?: -ETIME;
118 		goto bo_out;
119 	}
120 
121 	q = xe_exec_queue_create(xe, vm, BIT(hwe->logical_instance), 1, hwe,
122 				 EXEC_QUEUE_FLAG_KERNEL |
123 				 EXEC_QUEUE_FLAG_PERMANENT, 0);
124 	if (IS_ERR(q)) {
125 		err = PTR_ERR(q);
126 		goto bo_out;
127 	}
128 
129 	gsc_res->vm = vm;
130 	gsc_res->bo = bo;
131 	gsc_res->inout_size = inout_size;
132 	gsc_res->batch = IOSYS_MAP_INIT_OFFSET(&bo->vmap, 0);
133 	gsc_res->msg_in = IOSYS_MAP_INIT_OFFSET(&bo->vmap, PXP_BB_SIZE);
134 	gsc_res->msg_out = IOSYS_MAP_INIT_OFFSET(&bo->vmap, PXP_BB_SIZE + inout_size);
135 	gsc_res->q = q;
136 
137 	/* initialize host-session-handle (for all Xe-to-gsc-firmware PXP cmds) */
138 	gsc_res->host_session_handle = xe_gsc_create_host_session_id();
139 
140 	return 0;
141 
142 bo_out:
143 	xe_bo_unpin_map_no_vm(bo);
144 vm_out:
145 	xe_vm_close_and_put(vm);
146 
147 	return err;
148 }
149 
150 static void destroy_gsc_client_resources(struct xe_pxp_gsc_client_resources *gsc_res)
151 {
152 	if (!gsc_res->q)
153 		return;
154 
155 	xe_exec_queue_put(gsc_res->q);
156 	xe_bo_unpin_map_no_vm(gsc_res->bo);
157 	xe_vm_close_and_put(gsc_res->vm);
158 }
159 
160 /**
161  * xe_pxp_allocate_execution_resources - Allocate PXP submission objects
162  * @pxp: the xe_pxp structure
163  *
164  * Allocates exec_queues objects for VCS and GSCCS submission. The GSCCS
165  * submissions are done via PPGTT, so this function allocates a VM for it and
166  * maps the object into it.
167  *
168  * Returns 0 if the allocation and mapping is successful, an errno value
169  * otherwise.
170  */
171 int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp)
172 {
173 	int err;
174 
175 	err = allocate_vcs_execution_resources(pxp);
176 	if (err)
177 		return err;
178 
179 	/*
180 	 * PXP commands can require a lot of BO space (see PXP_MAX_PACKET_SIZE),
181 	 * but we currently only support a subset of commands that are small
182 	 * (< 20 dwords), so a single page is enough for now.
183 	 */
184 	err = allocate_gsc_client_resources(pxp->gt, &pxp->gsc_res, XE_PAGE_SIZE);
185 	if (err)
186 		goto destroy_vcs_context;
187 
188 	return 0;
189 
190 destroy_vcs_context:
191 	destroy_vcs_execution_resources(pxp);
192 	return err;
193 }
194 
195 void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp)
196 {
197 	destroy_gsc_client_resources(&pxp->gsc_res);
198 	destroy_vcs_execution_resources(pxp);
199 }
200