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 <fcntl.h>
26 #include <limits.h>
27 #include <stddef.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <vulkan/vulkan.h>
32
33 #include "fw-api/pvr_rogue_fwif.h"
34 #include "fw-api/pvr_rogue_fwif_rf.h"
35 #include "pvr_device_info.h"
36 #include "pvr_private.h"
37 #include "pvr_srv.h"
38 #include "pvr_srv_bridge.h"
39 #include "pvr_srv_job_common.h"
40 #include "pvr_srv_job_compute.h"
41 #include "pvr_srv_sync.h"
42 #include "pvr_winsys.h"
43 #include "util/macros.h"
44 #include "vk_alloc.h"
45 #include "vk_log.h"
46
47 struct pvr_srv_winsys_compute_ctx {
48 struct pvr_winsys_compute_ctx base;
49
50 void *handle;
51
52 int timeline;
53 };
54
55 #define to_pvr_srv_winsys_compute_ctx(ctx) \
56 container_of(ctx, struct pvr_srv_winsys_compute_ctx, base)
57
pvr_srv_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)58 VkResult pvr_srv_winsys_compute_ctx_create(
59 struct pvr_winsys *ws,
60 const struct pvr_winsys_compute_ctx_create_info *create_info,
61 struct pvr_winsys_compute_ctx **const ctx_out)
62 {
63 struct rogue_fwif_static_computecontext_state static_state = {
64 .ctx_switch_regs = {
65 .cdm_context_pds0 = create_info->static_state.cdm_ctx_store_pds0,
66 .cdm_context_pds0_b =
67 create_info->static_state.cdm_ctx_store_pds0_b,
68 .cdm_context_pds1 = create_info->static_state.cdm_ctx_store_pds1,
69
70 .cdm_terminate_pds = create_info->static_state.cdm_ctx_terminate_pds,
71 .cdm_terminate_pds1 =
72 create_info->static_state.cdm_ctx_terminate_pds1,
73
74 .cdm_resume_pds0 = create_info->static_state.cdm_ctx_resume_pds0,
75 .cdm_resume_pds0_b = create_info->static_state.cdm_ctx_resume_pds0_b,
76 },
77 };
78
79 struct rogue_fwif_rf_cmd reset_cmd = { 0 };
80
81 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
82 struct pvr_srv_winsys_compute_ctx *srv_ctx;
83 VkResult result;
84
85 srv_ctx = vk_alloc(ws->alloc,
86 sizeof(*srv_ctx),
87 8U,
88 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
89 if (!srv_ctx)
90 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
91
92 result = pvr_srv_create_timeline(ws->render_fd, &srv_ctx->timeline);
93 if (result != VK_SUCCESS)
94 goto err_free_srv_ctx;
95
96 /* TODO: Add support for reset framework. Currently we subtract
97 * reset_cmd.regs size from reset_cmd size to only pass empty flags field.
98 */
99 result = pvr_srv_rgx_create_compute_context(
100 ws->render_fd,
101 pvr_srv_from_winsys_priority(create_info->priority),
102 sizeof(reset_cmd) - sizeof(reset_cmd.regs),
103 (uint8_t *)&reset_cmd,
104 srv_ws->server_memctx_data,
105 sizeof(static_state),
106 (uint8_t *)&static_state,
107 0U,
108 RGX_CONTEXT_FLAG_DISABLESLR,
109 0U,
110 UINT_MAX,
111 &srv_ctx->handle);
112 if (result != VK_SUCCESS)
113 goto err_close_timeline;
114
115 srv_ctx->base.ws = ws;
116
117 *ctx_out = &srv_ctx->base;
118
119 return VK_SUCCESS;
120
121 err_close_timeline:
122 close(srv_ctx->timeline);
123
124 err_free_srv_ctx:
125 vk_free(ws->alloc, srv_ctx);
126
127 return result;
128 }
129
pvr_srv_winsys_compute_ctx_destroy(struct pvr_winsys_compute_ctx * ctx)130 void pvr_srv_winsys_compute_ctx_destroy(struct pvr_winsys_compute_ctx *ctx)
131 {
132 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
133 struct pvr_srv_winsys_compute_ctx *srv_ctx =
134 to_pvr_srv_winsys_compute_ctx(ctx);
135
136 pvr_srv_rgx_destroy_compute_context(srv_ws->base.render_fd, srv_ctx->handle);
137 close(srv_ctx->timeline);
138 vk_free(srv_ws->base.alloc, srv_ctx);
139 }
140
141 static uint32_t
pvr_srv_compute_cmd_stream_load(struct rogue_fwif_cmd_compute * const cmd,const uint8_t * const stream,const uint32_t stream_len,const struct pvr_device_info * const dev_info)142 pvr_srv_compute_cmd_stream_load(struct rogue_fwif_cmd_compute *const cmd,
143 const uint8_t *const stream,
144 const uint32_t stream_len,
145 const struct pvr_device_info *const dev_info)
146 {
147 const uint32_t *stream_ptr = (const uint32_t *)stream;
148 struct rogue_fwif_cdm_regs *const regs = &cmd->regs;
149 uint32_t main_stream_len =
150 pvr_csb_unpack((uint64_t *)stream_ptr, KMD_STREAM_HDR).length;
151
152 stream_ptr += pvr_cmd_length(KMD_STREAM_HDR);
153
154 regs->tpu_border_colour_table = *(const uint64_t *)stream_ptr;
155 stream_ptr += pvr_cmd_length(CR_TPU_BORDER_COLOUR_TABLE_CDM);
156
157 regs->cdm_ctrl_stream_base = *(const uint64_t *)stream_ptr;
158 stream_ptr += pvr_cmd_length(CR_CDM_CTRL_STREAM_BASE);
159
160 regs->cdm_context_state_base_addr = *(const uint64_t *)stream_ptr;
161 stream_ptr += pvr_cmd_length(CR_CDM_CONTEXT_STATE_BASE);
162
163 regs->cdm_resume_pds1 = *stream_ptr;
164 stream_ptr += pvr_cmd_length(CR_CDM_CONTEXT_PDS1);
165
166 if (PVR_HAS_FEATURE(dev_info, compute_morton_capable)) {
167 regs->cdm_item = *stream_ptr;
168 stream_ptr += pvr_cmd_length(CR_CDM_ITEM);
169 }
170
171 if (PVR_HAS_FEATURE(dev_info, cluster_grouping)) {
172 regs->compute_cluster = *stream_ptr;
173 stream_ptr += pvr_cmd_length(CR_COMPUTE_CLUSTER);
174 }
175
176 if (PVR_HAS_FEATURE(dev_info, gpu_multicore_support)) {
177 cmd->execute_count = *stream_ptr;
178 stream_ptr++;
179 }
180
181 assert((const uint8_t *)stream_ptr - stream <= stream_len);
182 assert((const uint8_t *)stream_ptr - stream == main_stream_len);
183
184 return main_stream_len;
185 }
186
pvr_srv_compute_cmd_ext_stream_load(struct rogue_fwif_cmd_compute * const cmd,const uint8_t * const stream,const uint32_t stream_len,const uint32_t ext_stream_offset,const struct pvr_device_info * const dev_info)187 static void pvr_srv_compute_cmd_ext_stream_load(
188 struct rogue_fwif_cmd_compute *const cmd,
189 const uint8_t *const stream,
190 const uint32_t stream_len,
191 const uint32_t ext_stream_offset,
192 const struct pvr_device_info *const dev_info)
193 {
194 const uint32_t *ext_stream_ptr =
195 (const uint32_t *)((uint8_t *)stream + ext_stream_offset);
196 struct rogue_fwif_cdm_regs *const regs = &cmd->regs;
197
198 struct ROGUE_KMD_STREAM_EXTHDR_COMPUTE0 header0;
199
200 header0 = pvr_csb_unpack(ext_stream_ptr, KMD_STREAM_EXTHDR_COMPUTE0);
201 ext_stream_ptr += pvr_cmd_length(KMD_STREAM_EXTHDR_COMPUTE0);
202
203 assert(PVR_HAS_QUIRK(dev_info, 49927) == header0.has_brn49927);
204 if (header0.has_brn49927) {
205 regs->tpu = *ext_stream_ptr;
206 ext_stream_ptr += pvr_cmd_length(CR_TPU);
207 }
208
209 assert((const uint8_t *)ext_stream_ptr - stream == stream_len);
210 }
211
pvr_srv_compute_cmd_init(const struct pvr_winsys_compute_submit_info * submit_info,struct rogue_fwif_cmd_compute * cmd,const struct pvr_device_info * const dev_info)212 static void pvr_srv_compute_cmd_init(
213 const struct pvr_winsys_compute_submit_info *submit_info,
214 struct rogue_fwif_cmd_compute *cmd,
215 const struct pvr_device_info *const dev_info)
216 {
217 uint32_t ext_stream_offset;
218
219 memset(cmd, 0, sizeof(*cmd));
220
221 cmd->cmn.frame_num = submit_info->frame_num;
222
223 ext_stream_offset =
224 pvr_srv_compute_cmd_stream_load(cmd,
225 submit_info->fw_stream,
226 submit_info->fw_stream_len,
227 dev_info);
228
229 if (ext_stream_offset < submit_info->fw_stream_len) {
230 pvr_srv_compute_cmd_ext_stream_load(cmd,
231 submit_info->fw_stream,
232 submit_info->fw_stream_len,
233 ext_stream_offset,
234 dev_info);
235 }
236
237 if (submit_info->flags.prevent_all_overlap)
238 cmd->flags |= ROGUE_FWIF_COMPUTE_FLAG_PREVENT_ALL_OVERLAP;
239
240 if (submit_info->flags.use_single_core)
241 cmd->flags |= ROGUE_FWIF_COMPUTE_FLAG_SINGLE_CORE;
242 }
243
pvr_srv_winsys_compute_submit(const struct pvr_winsys_compute_ctx * ctx,const struct pvr_winsys_compute_submit_info * submit_info,const struct pvr_device_info * const dev_info,struct vk_sync * signal_sync)244 VkResult pvr_srv_winsys_compute_submit(
245 const struct pvr_winsys_compute_ctx *ctx,
246 const struct pvr_winsys_compute_submit_info *submit_info,
247 const struct pvr_device_info *const dev_info,
248 struct vk_sync *signal_sync)
249 {
250 const struct pvr_srv_winsys_compute_ctx *srv_ctx =
251 to_pvr_srv_winsys_compute_ctx(ctx);
252 const struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
253 struct rogue_fwif_cmd_compute compute_cmd;
254 struct pvr_srv_sync *srv_signal_sync;
255 VkResult result;
256 int in_fd = -1;
257 int fence;
258
259 pvr_srv_compute_cmd_init(submit_info, &compute_cmd, dev_info);
260
261 if (submit_info->wait) {
262 struct pvr_srv_sync *srv_wait_sync = to_srv_sync(submit_info->wait);
263
264 if (srv_wait_sync->fd >= 0) {
265 in_fd = dup(srv_wait_sync->fd);
266 if (in_fd == -1) {
267 return vk_errorf(NULL,
268 VK_ERROR_OUT_OF_HOST_MEMORY,
269 "dup called on wait sync failed, Errno: %s",
270 strerror(errno));
271 }
272 }
273 }
274
275 do {
276 result = pvr_srv_rgx_kick_compute2(srv_ws->base.render_fd,
277 srv_ctx->handle,
278 0U,
279 NULL,
280 NULL,
281 NULL,
282 in_fd,
283 srv_ctx->timeline,
284 sizeof(compute_cmd),
285 (uint8_t *)&compute_cmd,
286 submit_info->job_num,
287 0,
288 NULL,
289 NULL,
290 0U,
291 0U,
292 0U,
293 0U,
294 "COMPUTE",
295 &fence);
296 } while (result == VK_NOT_READY);
297
298 if (result != VK_SUCCESS)
299 goto end_close_in_fd;
300
301 if (signal_sync) {
302 srv_signal_sync = to_srv_sync(signal_sync);
303 pvr_srv_set_sync_payload(srv_signal_sync, fence);
304 } else if (fence != -1) {
305 close(fence);
306 }
307
308 end_close_in_fd:
309 if (in_fd >= 0)
310 close(in_fd);
311
312 return result;
313 }
314