xref: /aosp_15_r20/external/mesa3d/src/imagination/vulkan/winsys/powervr/pvr_drm_job_compute.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2022 Imagination Technologies Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <vulkan/vulkan.h>
30 #include <xf86drm.h>
31 
32 #include "drm-uapi/pvr_drm.h"
33 #include "pvr_drm.h"
34 #include "pvr_drm_job_common.h"
35 #include "pvr_drm_job_compute.h"
36 #include "pvr_private.h"
37 #include "pvr_winsys.h"
38 #include "pvr_winsys_helper.h"
39 #include "util/macros.h"
40 #include "vk_alloc.h"
41 #include "vk_drm_syncobj.h"
42 #include "vk_log.h"
43 
44 struct pvr_drm_winsys_compute_ctx {
45    struct pvr_winsys_compute_ctx base;
46 
47    /* Handle to kernel context. */
48    uint32_t handle;
49 };
50 
51 #define to_pvr_drm_winsys_compute_ctx(ctx) \
52    container_of(ctx, struct pvr_drm_winsys_compute_ctx, base)
53 
pvr_drm_compute_ctx_static_state_init(const struct pvr_winsys_compute_ctx_create_info * create_info,uint8_t * stream_ptr_start,uint32_t * stream_len_ptr)54 static void pvr_drm_compute_ctx_static_state_init(
55    const struct pvr_winsys_compute_ctx_create_info *create_info,
56    uint8_t *stream_ptr_start,
57    uint32_t *stream_len_ptr)
58 {
59    const struct pvr_winsys_compute_ctx_static_state *ws_static_state =
60       &create_info->static_state;
61    uint64_t *stream_ptr = (uint64_t *)stream_ptr_start;
62 
63    /* Leave space for stream header. */
64    stream_ptr += pvr_cmd_length(KMD_STREAM_HDR) / 2;
65 
66    *stream_ptr++ = ws_static_state->cdm_ctx_store_pds0;
67    *stream_ptr++ = ws_static_state->cdm_ctx_store_pds1;
68    *stream_ptr++ = ws_static_state->cdm_ctx_terminate_pds;
69    *stream_ptr++ = ws_static_state->cdm_ctx_terminate_pds1;
70    *stream_ptr++ = ws_static_state->cdm_ctx_resume_pds0;
71    *stream_ptr++ = ws_static_state->cdm_ctx_store_pds0_b;
72    *stream_ptr++ = ws_static_state->cdm_ctx_resume_pds0_b;
73 
74    *stream_len_ptr = ((uint8_t *)stream_ptr - stream_ptr_start);
75 
76    pvr_csb_pack ((uint64_t *)stream_ptr_start, KMD_STREAM_HDR, value) {
77       value.length = *stream_len_ptr;
78    }
79 }
80 
pvr_drm_winsys_compute_ctx_create(struct pvr_winsys * ws,const struct pvr_winsys_compute_ctx_create_info * create_info,struct pvr_winsys_compute_ctx ** const ctx_out)81 VkResult pvr_drm_winsys_compute_ctx_create(
82    struct pvr_winsys *ws,
83    const struct pvr_winsys_compute_ctx_create_info *create_info,
84    struct pvr_winsys_compute_ctx **const ctx_out)
85 {
86    uint8_t static_ctx_state_fw_stream[64];
87    struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ws);
88    struct drm_pvr_ioctl_create_context_args ctx_args = {
89       .type = DRM_PVR_CTX_TYPE_COMPUTE,
90       .priority = pvr_drm_from_winsys_priority(create_info->priority),
91       .static_context_state = (__u64)static_ctx_state_fw_stream,
92       .static_context_state_len = (__u32)sizeof(static_ctx_state_fw_stream),
93       .vm_context_handle = drm_ws->vm_context,
94    };
95 
96    struct pvr_drm_winsys_compute_ctx *drm_ctx;
97    VkResult result;
98 
99    drm_ctx = vk_alloc(ws->alloc,
100                       sizeof(*drm_ctx),
101                       8,
102                       VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
103    if (!drm_ctx) {
104       result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
105       goto err_out;
106    }
107 
108    pvr_drm_compute_ctx_static_state_init(create_info,
109                                          static_ctx_state_fw_stream,
110                                          &ctx_args.static_context_state_len);
111 
112    result = pvr_ioctlf(ws->render_fd,
113                        DRM_IOCTL_PVR_CREATE_CONTEXT,
114                        &ctx_args,
115                        VK_ERROR_INITIALIZATION_FAILED,
116                        "Failed to create compute context");
117    if (result != VK_SUCCESS)
118       goto err_free_ctx;
119 
120    drm_ctx->base.ws = ws;
121    drm_ctx->handle = ctx_args.handle;
122 
123    *ctx_out = &drm_ctx->base;
124 
125    return VK_SUCCESS;
126 
127 err_free_ctx:
128    vk_free(ws->alloc, drm_ctx);
129 
130 err_out:
131    return result;
132 }
133 
pvr_drm_winsys_compute_ctx_destroy(struct pvr_winsys_compute_ctx * ctx)134 void pvr_drm_winsys_compute_ctx_destroy(struct pvr_winsys_compute_ctx *ctx)
135 {
136    struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ctx->ws);
137    struct pvr_drm_winsys_compute_ctx *drm_ctx =
138       to_pvr_drm_winsys_compute_ctx(ctx);
139    struct drm_pvr_ioctl_destroy_context_args args = {
140       .handle = drm_ctx->handle,
141    };
142 
143    pvr_ioctlf(drm_ws->base.render_fd,
144               DRM_IOCTL_PVR_DESTROY_CONTEXT,
145               &args,
146               VK_ERROR_UNKNOWN,
147               "Error destroying compute context");
148 
149    vk_free(drm_ws->base.alloc, drm_ctx);
150 }
151 
pvr_winsys_compute_flags_to_drm(const struct pvr_winsys_compute_submit_flags * const ws_flags)152 static uint32_t pvr_winsys_compute_flags_to_drm(
153    const struct pvr_winsys_compute_submit_flags *const ws_flags)
154 {
155    uint32_t flags = 0U;
156 
157    if (ws_flags->prevent_all_overlap)
158       flags |= DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP;
159 
160    if (ws_flags->use_single_core)
161       flags |= DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE;
162 
163    return flags;
164 }
165 
pvr_drm_winsys_compute_submit(const struct pvr_winsys_compute_ctx * ctx,const struct pvr_winsys_compute_submit_info * submit_info,UNUSED const struct pvr_device_info * dev_info,struct vk_sync * signal_sync)166 VkResult pvr_drm_winsys_compute_submit(
167    const struct pvr_winsys_compute_ctx *ctx,
168    const struct pvr_winsys_compute_submit_info *submit_info,
169    UNUSED const struct pvr_device_info *dev_info,
170    struct vk_sync *signal_sync)
171 {
172    const struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ctx->ws);
173    const struct pvr_drm_winsys_compute_ctx *drm_ctx =
174       to_pvr_drm_winsys_compute_ctx(ctx);
175 
176    struct drm_pvr_sync_op sync_ops[2];
177    struct drm_pvr_job job_args = {
178       .type = DRM_PVR_JOB_TYPE_COMPUTE,
179       .context_handle = drm_ctx->handle,
180       .cmd_stream = (__u64)&submit_info->fw_stream[0],
181       .cmd_stream_len = submit_info->fw_stream_len,
182       /* bo_handles is unused and zeroed. */
183       /* num_bo_handles is unused and zeroed. */
184       .flags = pvr_winsys_compute_flags_to_drm(&submit_info->flags),
185       .sync_ops = DRM_PVR_OBJ_ARRAY(0, sync_ops),
186    };
187 
188    struct drm_pvr_ioctl_submit_jobs_args args = {
189       .jobs = DRM_PVR_OBJ_ARRAY(1, &job_args),
190    };
191 
192    if (submit_info->wait) {
193       struct vk_sync *sync = submit_info->wait;
194 
195       assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
196       sync_ops[job_args.sync_ops.count++] = (struct drm_pvr_sync_op){
197          .handle = vk_sync_as_drm_syncobj(sync)->syncobj,
198          .flags = DRM_PVR_SYNC_OP_FLAG_WAIT |
199                   DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
200          .value = 0,
201       };
202    }
203 
204    if (signal_sync) {
205       assert(!(signal_sync->flags & VK_SYNC_IS_TIMELINE));
206       sync_ops[job_args.sync_ops.count++] = (struct drm_pvr_sync_op){
207          .handle = vk_sync_as_drm_syncobj(signal_sync)->syncobj,
208          .flags = DRM_PVR_SYNC_OP_FLAG_SIGNAL |
209                   DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
210          .value = 0,
211       };
212    }
213 
214    /* Returns VK_ERROR_OUT_OF_DEVICE_MEMORY to match pvrsrv. */
215    return pvr_ioctlf(drm_ws->base.render_fd,
216                      DRM_IOCTL_PVR_SUBMIT_JOBS,
217                      &args,
218                      VK_ERROR_OUT_OF_DEVICE_MEMORY,
219                      "Failed to submit compute job");
220 }
221