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 <stddef.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <vulkan/vulkan.h>
31
32 #include "fw-api/pvr_rogue_fwif.h"
33 #include "fw-api/pvr_rogue_fwif_rf.h"
34 #include "pvr_device_info.h"
35 #include "pvr_private.h"
36 #include "pvr_srv.h"
37 #include "pvr_srv_bridge.h"
38 #include "pvr_srv_job_common.h"
39 #include "pvr_srv_job_transfer.h"
40 #include "pvr_srv_sync.h"
41 #include "pvr_winsys.h"
42 #include "util/macros.h"
43 #include "vk_alloc.h"
44 #include "vk_log.h"
45 #include "vk_util.h"
46
47 #define PVR_SRV_TRANSFER_CONTEXT_INITIAL_CCB_SIZE_LOG2 16U
48 #define PVR_SRV_TRANSFER_CONTEXT_MAX_CCB_SIZE_LOG2 0U
49
50 struct pvr_srv_winsys_transfer_ctx {
51 struct pvr_winsys_transfer_ctx base;
52
53 void *handle;
54
55 int timeline_3d;
56 };
57
58 #define to_pvr_srv_winsys_transfer_ctx(ctx) \
59 container_of(ctx, struct pvr_srv_winsys_transfer_ctx, base)
60
pvr_srv_winsys_transfer_ctx_create(struct pvr_winsys * ws,const struct pvr_winsys_transfer_ctx_create_info * create_info,struct pvr_winsys_transfer_ctx ** const ctx_out)61 VkResult pvr_srv_winsys_transfer_ctx_create(
62 struct pvr_winsys *ws,
63 const struct pvr_winsys_transfer_ctx_create_info *create_info,
64 struct pvr_winsys_transfer_ctx **const ctx_out)
65 {
66 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
67 struct pvr_srv_winsys_transfer_ctx *srv_ctx;
68 struct rogue_fwif_rf_cmd reset_cmd = { 0 };
69 VkResult result;
70
71 /* First 2 U8s are 2d work load related, and the last 2 are 3d workload
72 * related.
73 */
74 const uint32_t packed_ccb_size =
75 PVR_U8888_TO_U32(PVR_SRV_TRANSFER_CONTEXT_INITIAL_CCB_SIZE_LOG2,
76 PVR_SRV_TRANSFER_CONTEXT_MAX_CCB_SIZE_LOG2,
77 PVR_SRV_TRANSFER_CONTEXT_INITIAL_CCB_SIZE_LOG2,
78 PVR_SRV_TRANSFER_CONTEXT_MAX_CCB_SIZE_LOG2);
79
80 srv_ctx = vk_alloc(ws->alloc,
81 sizeof(*srv_ctx),
82 8U,
83 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
84 if (!srv_ctx)
85 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
86
87 result = pvr_srv_create_timeline(ws->render_fd, &srv_ctx->timeline_3d);
88 if (result != VK_SUCCESS)
89 goto err_free_srv_ctx;
90
91 /* TODO: Add support for reset framework. Currently we subtract
92 * reset_cmd.regs size from reset_cmd size to only pass empty flags field.
93 */
94 result = pvr_srv_rgx_create_transfer_context(
95 ws->render_fd,
96 pvr_srv_from_winsys_priority(create_info->priority),
97 sizeof(reset_cmd) - sizeof(reset_cmd.regs),
98 (uint8_t *)&reset_cmd,
99 srv_ws->server_memctx_data,
100 packed_ccb_size,
101 RGX_CONTEXT_FLAG_DISABLESLR,
102 0U,
103 NULL,
104 NULL,
105 &srv_ctx->handle);
106 if (result != VK_SUCCESS)
107 goto err_close_timeline;
108
109 srv_ctx->base.ws = ws;
110 *ctx_out = &srv_ctx->base;
111
112 return VK_SUCCESS;
113
114 err_close_timeline:
115 close(srv_ctx->timeline_3d);
116
117 err_free_srv_ctx:
118 vk_free(ws->alloc, srv_ctx);
119
120 return result;
121 }
122
pvr_srv_winsys_transfer_ctx_destroy(struct pvr_winsys_transfer_ctx * ctx)123 void pvr_srv_winsys_transfer_ctx_destroy(struct pvr_winsys_transfer_ctx *ctx)
124 {
125 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
126 struct pvr_srv_winsys_transfer_ctx *srv_ctx =
127 to_pvr_srv_winsys_transfer_ctx(ctx);
128
129 pvr_srv_rgx_destroy_transfer_context(srv_ws->base.render_fd,
130 srv_ctx->handle);
131 close(srv_ctx->timeline_3d);
132 vk_free(srv_ws->base.alloc, srv_ctx);
133 }
134
135 static void
pvr_srv_transfer_cmd_stream_load(struct rogue_fwif_cmd_transfer * const cmd,const uint8_t * const stream,const uint32_t stream_len,const struct pvr_device_info * const dev_info)136 pvr_srv_transfer_cmd_stream_load(struct rogue_fwif_cmd_transfer *const cmd,
137 const uint8_t *const stream,
138 const uint32_t stream_len,
139 const struct pvr_device_info *const dev_info)
140 {
141 const uint32_t *stream_ptr = (const uint32_t *)stream;
142 struct rogue_fwif_transfer_regs *const regs = &cmd->regs;
143 uint32_t main_stream_len =
144 pvr_csb_unpack((uint64_t *)stream_ptr, KMD_STREAM_HDR).length;
145
146 stream_ptr += pvr_cmd_length(KMD_STREAM_HDR);
147
148 regs->pds_bgnd0_base = *(uint64_t *)stream_ptr;
149 stream_ptr += pvr_cmd_length(CR_PDS_BGRND0_BASE);
150
151 regs->pds_bgnd1_base = *(uint64_t *)stream_ptr;
152 stream_ptr += pvr_cmd_length(CR_PDS_BGRND1_BASE);
153
154 regs->pds_bgnd3_sizeinfo = *(uint64_t *)stream_ptr;
155 stream_ptr += pvr_cmd_length(CR_PDS_BGRND3_SIZEINFO);
156
157 regs->isp_mtile_base = *(uint64_t *)stream_ptr;
158 stream_ptr += pvr_cmd_length(CR_ISP_MTILE_BASE);
159
160 STATIC_ASSERT(ARRAY_SIZE(regs->pbe_wordx_mrty) == 9U);
161 STATIC_ASSERT(sizeof(regs->pbe_wordx_mrty[0]) == sizeof(uint64_t));
162 memcpy(regs->pbe_wordx_mrty, stream_ptr, sizeof(regs->pbe_wordx_mrty));
163 stream_ptr += 9U * 2U;
164
165 regs->isp_bgobjvals = *stream_ptr;
166 stream_ptr += pvr_cmd_length(CR_ISP_BGOBJVALS);
167
168 regs->usc_pixel_output_ctrl = *stream_ptr;
169 stream_ptr += pvr_cmd_length(CR_USC_PIXEL_OUTPUT_CTRL);
170
171 regs->usc_clear_register0 = *stream_ptr;
172 stream_ptr += pvr_cmd_length(CR_USC_CLEAR_REGISTER);
173
174 regs->usc_clear_register1 = *stream_ptr;
175 stream_ptr += pvr_cmd_length(CR_USC_CLEAR_REGISTER);
176
177 regs->usc_clear_register2 = *stream_ptr;
178 stream_ptr += pvr_cmd_length(CR_USC_CLEAR_REGISTER);
179
180 regs->usc_clear_register3 = *stream_ptr;
181 stream_ptr += pvr_cmd_length(CR_USC_CLEAR_REGISTER);
182
183 regs->isp_mtile_size = *stream_ptr;
184 stream_ptr += pvr_cmd_length(CR_ISP_MTILE_SIZE);
185
186 regs->isp_render_origin = *stream_ptr;
187 stream_ptr += pvr_cmd_length(CR_ISP_RENDER_ORIGIN);
188
189 regs->isp_ctl = *stream_ptr;
190 stream_ptr += pvr_cmd_length(CR_ISP_CTL);
191
192 regs->isp_aa = *stream_ptr;
193 stream_ptr += pvr_cmd_length(CR_ISP_AA);
194
195 regs->event_pixel_pds_info = *stream_ptr;
196 stream_ptr += pvr_cmd_length(CR_EVENT_PIXEL_PDS_INFO);
197
198 regs->event_pixel_pds_code = *stream_ptr;
199 stream_ptr += pvr_cmd_length(CR_EVENT_PIXEL_PDS_CODE);
200
201 regs->event_pixel_pds_data = *stream_ptr;
202 stream_ptr += pvr_cmd_length(CR_EVENT_PIXEL_PDS_DATA);
203
204 regs->isp_render = *stream_ptr;
205 stream_ptr += pvr_cmd_length(CR_ISP_RENDER);
206
207 regs->isp_rgn = *stream_ptr;
208 stream_ptr++;
209
210 if (PVR_HAS_FEATURE(dev_info, gpu_multicore_support)) {
211 regs->frag_screen = *stream_ptr;
212 stream_ptr++;
213 }
214
215 assert((const uint8_t *)stream_ptr - stream == stream_len);
216 assert((const uint8_t *)stream_ptr - stream == main_stream_len);
217 }
218
pvr_srv_transfer_cmds_init(const struct pvr_winsys_transfer_submit_info * submit_info,struct rogue_fwif_cmd_transfer * cmds,uint32_t cmd_count,const struct pvr_device_info * const dev_info)219 static void pvr_srv_transfer_cmds_init(
220 const struct pvr_winsys_transfer_submit_info *submit_info,
221 struct rogue_fwif_cmd_transfer *cmds,
222 uint32_t cmd_count,
223 const struct pvr_device_info *const dev_info)
224 {
225 memset(cmds, 0, sizeof(*cmds) * submit_info->cmd_count);
226
227 for (uint32_t i = 0; i < cmd_count; i++) {
228 const struct pvr_winsys_transfer_cmd *submit_cmd = &submit_info->cmds[i];
229 struct rogue_fwif_cmd_transfer *cmd = &cmds[i];
230
231 cmd->cmn.frame_num = submit_info->frame_num;
232
233 pvr_srv_transfer_cmd_stream_load(cmd,
234 submit_cmd->fw_stream,
235 submit_cmd->fw_stream_len,
236 dev_info);
237
238 if (submit_info->cmds[i].flags.use_single_core)
239 cmd->flags |= ROGUE_FWIF_CMDTRANSFER_SINGLE_CORE;
240 }
241 }
242
pvr_srv_winsys_transfer_submit(const struct pvr_winsys_transfer_ctx * ctx,const struct pvr_winsys_transfer_submit_info * submit_info,const struct pvr_device_info * const dev_info,struct vk_sync * signal_sync)243 VkResult pvr_srv_winsys_transfer_submit(
244 const struct pvr_winsys_transfer_ctx *ctx,
245 const struct pvr_winsys_transfer_submit_info *submit_info,
246 const struct pvr_device_info *const dev_info,
247 struct vk_sync *signal_sync)
248 {
249 const struct pvr_srv_winsys_transfer_ctx *srv_ctx =
250 to_pvr_srv_winsys_transfer_ctx(ctx);
251 const struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
252
253 struct rogue_fwif_cmd_transfer
254 *cmds_ptr_arr[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT];
255 uint32_t *update_sync_offsets[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT] = { 0 };
256 uint32_t client_update_count[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT] = { 0 };
257 void **update_ufo_syc_prims[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT] = { 0 };
258 uint32_t *update_values[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT] = { 0 };
259 uint32_t cmd_flags[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT] = { 0 };
260 uint32_t cmd_sizes[PVR_TRANSFER_MAX_PREPARES_PER_SUBMIT];
261
262 struct pvr_srv_sync *srv_signal_sync;
263 uint32_t job_num;
264 VkResult result;
265 int in_fd = -1;
266 int fence;
267
268 STACK_ARRAY(struct rogue_fwif_cmd_transfer,
269 transfer_cmds,
270 submit_info->cmd_count);
271 if (!transfer_cmds)
272 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
273
274 pvr_srv_transfer_cmds_init(submit_info,
275 transfer_cmds,
276 submit_info->cmd_count,
277 dev_info);
278
279 for (uint32_t i = 0U; i < submit_info->cmd_count; i++) {
280 cmd_sizes[i] = sizeof(**cmds_ptr_arr);
281 cmds_ptr_arr[i] = &transfer_cmds[i];
282 }
283
284 if (submit_info->wait) {
285 struct pvr_srv_sync *srv_wait_sync = to_srv_sync(submit_info->wait);
286
287 if (srv_wait_sync->fd >= 0) {
288 in_fd = dup(srv_wait_sync->fd);
289 if (in_fd == -1) {
290 return vk_errorf(NULL,
291 VK_ERROR_OUT_OF_HOST_MEMORY,
292 "dup called on wait sync failed, Errno: %s",
293 strerror(errno));
294 }
295 }
296 }
297
298 job_num = submit_info->job_num;
299
300 do {
301 result = pvr_srv_rgx_submit_transfer2(srv_ws->base.render_fd,
302 srv_ctx->handle,
303 submit_info->cmd_count,
304 client_update_count,
305 update_ufo_syc_prims,
306 update_sync_offsets,
307 update_values,
308 in_fd,
309 -1,
310 srv_ctx->timeline_3d,
311 "TRANSFER",
312 cmd_sizes,
313 (uint8_t **)cmds_ptr_arr,
314 cmd_flags,
315 job_num,
316 0U,
317 NULL,
318 NULL,
319 NULL,
320 &fence);
321 } while (result == VK_NOT_READY);
322
323 if (result != VK_SUCCESS)
324 goto end_close_in_fd;
325
326 if (signal_sync) {
327 srv_signal_sync = to_srv_sync(signal_sync);
328 pvr_srv_set_sync_payload(srv_signal_sync, fence);
329 } else if (fence != -1) {
330 close(fence);
331 }
332
333 end_close_in_fd:
334 if (in_fd >= 0)
335 close(in_fd);
336
337 STACK_ARRAY_FINISH(transfer_cmds);
338
339 return result;
340 }
341