Skip to content

Commit eaf01ee

Browse files
sarah-walker-imgtecmripard
authored andcommitted
drm/imagination: Implement job submission and scheduling
Implement job submission ioctl. Job scheduling is implemented using drm_sched. Jobs are submitted in a stream format. This is intended to allow the UAPI data format to be independent of the actual FWIF structures in use, which vary depending on the GPU in use. The stream formats are documented at: https://gitlab.freedesktop.org/mesa/mesa/-/blob/f8d2b42ae65c2f16f36a43e0ae39d288431e4263/src/imagination/csbgen/rogue_kmd_stream.xml Changes since v8: - Updated for upstreamed DRM scheduler changes - Removed workaround code for the pending_list previously being updated after run_job() returned - Fixed null deref in pvr_queue_cleanup_fw_context() for bad stream ptr given to create_context ioctl - Corrected license identifiers Changes since v7: - Updated for v8 "DRM scheduler changes for XE" patchset Changes since v6: - Fix fence handling in pvr_sync_signal_array_add() - Add handling for SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE flag - Fix missing dma_resv locking in job submit path Changes since v5: - Fix leak in job creation error path Changes since v4: - Use a regular workqueue for job scheduling Changes since v3: - Support partial render jobs - Add job timeout handler - Split sync handling out of job code - Use drm_dev_{enter,exit} Changes since v2: - Use drm_sched for job scheduling Co-developed-by: Boris Brezillon <[email protected]> Signed-off-by: Boris Brezillon <[email protected]> Co-developed-by: Donald Robson <[email protected]> Signed-off-by: Donald Robson <[email protected]> Signed-off-by: Sarah Walker <[email protected]> Link: https://lore.kernel.org/r/c98dab7a5f5fb891fbed7e4990d19b5d13964365.1700668843.git.donald.robson@imgtec.com Signed-off-by: Maxime Ripard <[email protected]>
1 parent d2d79d2 commit eaf01ee

File tree

15 files changed

+3438
-4
lines changed

15 files changed

+3438
-4
lines changed

drivers/gpu/drm/imagination/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ config DRM_POWERVR
66
depends on ARM64
77
depends on DRM
88
depends on PM
9+
select DRM_EXEC
910
select DRM_GEM_SHMEM_HELPER
1011
select DRM_SCHED
1112
select DRM_GPUVM

drivers/gpu/drm/imagination/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ powervr-y := \
1818
pvr_fw_trace.o \
1919
pvr_gem.o \
2020
pvr_hwrt.o \
21+
pvr_job.o \
2122
pvr_mmu.o \
2223
pvr_power.o \
24+
pvr_queue.o \
2325
pvr_stream.o \
2426
pvr_stream_defs.o \
27+
pvr_sync.o \
2528
pvr_vm.o \
2629
pvr_vm_mips.o
2730

drivers/gpu/drm/imagination/pvr_context.c

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
#include "pvr_device.h"
77
#include "pvr_drv.h"
88
#include "pvr_gem.h"
9+
#include "pvr_job.h"
910
#include "pvr_power.h"
1011
#include "pvr_rogue_fwif.h"
1112
#include "pvr_rogue_fwif_common.h"
1213
#include "pvr_rogue_fwif_resetframework.h"
14+
#include "pvr_stream.h"
1315
#include "pvr_stream_defs.h"
1416
#include "pvr_vm.h"
1517

@@ -164,6 +166,116 @@ ctx_fw_data_init(void *cpu_ptr, void *priv)
164166
memcpy(cpu_ptr, ctx->data, ctx->data_size);
165167
}
166168

169+
/**
170+
* pvr_context_destroy_queues() - Destroy all queues attached to a context.
171+
* @ctx: Context to destroy queues on.
172+
*
173+
* Should be called when the last reference to a context object is dropped.
174+
* It releases all resources attached to the queues bound to this context.
175+
*/
176+
static void pvr_context_destroy_queues(struct pvr_context *ctx)
177+
{
178+
switch (ctx->type) {
179+
case DRM_PVR_CTX_TYPE_RENDER:
180+
pvr_queue_destroy(ctx->queues.fragment);
181+
pvr_queue_destroy(ctx->queues.geometry);
182+
break;
183+
case DRM_PVR_CTX_TYPE_COMPUTE:
184+
pvr_queue_destroy(ctx->queues.compute);
185+
break;
186+
case DRM_PVR_CTX_TYPE_TRANSFER_FRAG:
187+
pvr_queue_destroy(ctx->queues.transfer);
188+
break;
189+
}
190+
}
191+
192+
/**
193+
* pvr_context_create_queues() - Create all queues attached to a context.
194+
* @ctx: Context to create queues on.
195+
* @args: Context creation arguments passed by userspace.
196+
* @fw_ctx_map: CPU mapping of the FW context object.
197+
*
198+
* Return:
199+
* * 0 on success, or
200+
* * A negative error code otherwise.
201+
*/
202+
static int pvr_context_create_queues(struct pvr_context *ctx,
203+
struct drm_pvr_ioctl_create_context_args *args,
204+
void *fw_ctx_map)
205+
{
206+
int err;
207+
208+
switch (ctx->type) {
209+
case DRM_PVR_CTX_TYPE_RENDER:
210+
ctx->queues.geometry = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_GEOMETRY,
211+
args, fw_ctx_map);
212+
if (IS_ERR(ctx->queues.geometry)) {
213+
err = PTR_ERR(ctx->queues.geometry);
214+
ctx->queues.geometry = NULL;
215+
goto err_destroy_queues;
216+
}
217+
218+
ctx->queues.fragment = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_FRAGMENT,
219+
args, fw_ctx_map);
220+
if (IS_ERR(ctx->queues.fragment)) {
221+
err = PTR_ERR(ctx->queues.fragment);
222+
ctx->queues.fragment = NULL;
223+
goto err_destroy_queues;
224+
}
225+
return 0;
226+
227+
case DRM_PVR_CTX_TYPE_COMPUTE:
228+
ctx->queues.compute = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_COMPUTE,
229+
args, fw_ctx_map);
230+
if (IS_ERR(ctx->queues.compute)) {
231+
err = PTR_ERR(ctx->queues.compute);
232+
ctx->queues.compute = NULL;
233+
goto err_destroy_queues;
234+
}
235+
return 0;
236+
237+
case DRM_PVR_CTX_TYPE_TRANSFER_FRAG:
238+
ctx->queues.transfer = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_TRANSFER_FRAG,
239+
args, fw_ctx_map);
240+
if (IS_ERR(ctx->queues.transfer)) {
241+
err = PTR_ERR(ctx->queues.transfer);
242+
ctx->queues.transfer = NULL;
243+
goto err_destroy_queues;
244+
}
245+
return 0;
246+
}
247+
248+
return -EINVAL;
249+
250+
err_destroy_queues:
251+
pvr_context_destroy_queues(ctx);
252+
return err;
253+
}
254+
255+
/**
256+
* pvr_context_kill_queues() - Kill queues attached to context.
257+
* @ctx: Context to kill queues on.
258+
*
259+
* Killing the queues implies making them unusable for future jobs, while still
260+
* letting the currently submitted jobs a chance to finish. Queue resources will
261+
* stay around until pvr_context_destroy_queues() is called.
262+
*/
263+
static void pvr_context_kill_queues(struct pvr_context *ctx)
264+
{
265+
switch (ctx->type) {
266+
case DRM_PVR_CTX_TYPE_RENDER:
267+
pvr_queue_kill(ctx->queues.fragment);
268+
pvr_queue_kill(ctx->queues.geometry);
269+
break;
270+
case DRM_PVR_CTX_TYPE_COMPUTE:
271+
pvr_queue_kill(ctx->queues.compute);
272+
break;
273+
case DRM_PVR_CTX_TYPE_TRANSFER_FRAG:
274+
pvr_queue_kill(ctx->queues.transfer);
275+
break;
276+
}
277+
}
278+
167279
/**
168280
* pvr_context_create() - Create a context.
169281
* @pvr_file: File to attach the created context to.
@@ -214,10 +326,14 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co
214326
goto err_put_vm;
215327
}
216328

217-
err = init_fw_objs(ctx, args, ctx->data);
329+
err = pvr_context_create_queues(ctx, args, ctx->data);
218330
if (err)
219331
goto err_free_ctx_data;
220332

333+
err = init_fw_objs(ctx, args, ctx->data);
334+
if (err)
335+
goto err_destroy_queues;
336+
221337
err = pvr_fw_object_create(pvr_dev, ctx_size, PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
222338
ctx_fw_data_init, ctx, &ctx->fw_obj);
223339
if (err)
@@ -243,6 +359,9 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co
243359
err_destroy_fw_obj:
244360
pvr_fw_object_destroy(ctx->fw_obj);
245361

362+
err_destroy_queues:
363+
pvr_context_destroy_queues(ctx);
364+
246365
err_free_ctx_data:
247366
kfree(ctx->data);
248367

@@ -262,6 +381,7 @@ pvr_context_release(struct kref *ref_count)
262381
struct pvr_device *pvr_dev = ctx->pvr_dev;
263382

264383
xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id);
384+
pvr_context_destroy_queues(ctx);
265385
pvr_fw_object_destroy(ctx->fw_obj);
266386
kfree(ctx->data);
267387
pvr_vm_context_put(ctx->vm_ctx);
@@ -299,6 +419,9 @@ pvr_context_destroy(struct pvr_file *pvr_file, u32 handle)
299419
if (!ctx)
300420
return -EINVAL;
301421

422+
/* Make sure nothing can be queued to the queues after that point. */
423+
pvr_context_kill_queues(ctx);
424+
302425
/* Release the reference held by the handle set. */
303426
pvr_context_put(ctx);
304427

drivers/gpu/drm/imagination/pvr_context.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "pvr_cccb.h"
1717
#include "pvr_device.h"
18+
#include "pvr_queue.h"
1819

1920
/* Forward declaration from pvr_gem.h. */
2021
struct pvr_fw_object;
@@ -58,8 +59,51 @@ struct pvr_context {
5859

5960
/** @ctx_id: FW context ID. */
6061
u32 ctx_id;
62+
63+
/**
64+
* @faulty: Set to 1 when the context queues had unfinished job when
65+
* a GPU reset happened.
66+
*
67+
* In that case, the context is in an inconsistent state and can't be
68+
* used anymore.
69+
*/
70+
atomic_t faulty;
71+
72+
/** @queues: Union containing all kind of queues. */
73+
union {
74+
struct {
75+
/** @geometry: Geometry queue. */
76+
struct pvr_queue *geometry;
77+
78+
/** @fragment: Fragment queue. */
79+
struct pvr_queue *fragment;
80+
};
81+
82+
/** @compute: Compute queue. */
83+
struct pvr_queue *compute;
84+
85+
/** @compute: Transfer queue. */
86+
struct pvr_queue *transfer;
87+
} queues;
6188
};
6289

90+
static __always_inline struct pvr_queue *
91+
pvr_context_get_queue_for_job(struct pvr_context *ctx, enum drm_pvr_job_type type)
92+
{
93+
switch (type) {
94+
case DRM_PVR_JOB_TYPE_GEOMETRY:
95+
return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.geometry : NULL;
96+
case DRM_PVR_JOB_TYPE_FRAGMENT:
97+
return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.fragment : NULL;
98+
case DRM_PVR_JOB_TYPE_COMPUTE:
99+
return ctx->type == DRM_PVR_CTX_TYPE_COMPUTE ? ctx->queues.compute : NULL;
100+
case DRM_PVR_JOB_TYPE_TRANSFER_FRAG:
101+
return ctx->type == DRM_PVR_CTX_TYPE_TRANSFER_FRAG ? ctx->queues.transfer : NULL;
102+
}
103+
104+
return NULL;
105+
}
106+
63107
/**
64108
* pvr_context_get() - Take additional reference on context.
65109
* @ctx: Context pointer.

drivers/gpu/drm/imagination/pvr_device.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
#include "pvr_fw.h"
88
#include "pvr_power.h"
9+
#include "pvr_queue.h"
910
#include "pvr_rogue_cr_defs.h"
11+
#include "pvr_stream.h"
1012
#include "pvr_vm.h"
1113

1214
#include <drm/drm_print.h>
@@ -117,6 +119,32 @@ static int pvr_device_clk_init(struct pvr_device *pvr_dev)
117119
return 0;
118120
}
119121

122+
/**
123+
* pvr_device_process_active_queues() - Process all queue related events.
124+
* @pvr_dev: PowerVR device to check
125+
*
126+
* This is called any time we receive a FW event. It iterates over all
127+
* active queues and calls pvr_queue_process() on them.
128+
*/
129+
void pvr_device_process_active_queues(struct pvr_device *pvr_dev)
130+
{
131+
struct pvr_queue *queue, *tmp_queue;
132+
LIST_HEAD(active_queues);
133+
134+
mutex_lock(&pvr_dev->queues.lock);
135+
136+
/* Move all active queues to a temporary list. Queues that remain
137+
* active after we're done processing them are re-inserted to
138+
* the queues.active list by pvr_queue_process().
139+
*/
140+
list_splice_init(&pvr_dev->queues.active, &active_queues);
141+
142+
list_for_each_entry_safe(queue, tmp_queue, &active_queues, node)
143+
pvr_queue_process(queue);
144+
145+
mutex_unlock(&pvr_dev->queues.lock);
146+
}
147+
120148
static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data)
121149
{
122150
struct pvr_device *pvr_dev = data;
@@ -132,6 +160,7 @@ static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data)
132160
if (pvr_dev->fw_dev.booted) {
133161
pvr_fwccb_process(pvr_dev);
134162
pvr_kccb_wake_up_waiters(pvr_dev);
163+
pvr_device_process_active_queues(pvr_dev);
135164
}
136165

137166
pm_runtime_mark_last_busy(from_pvr_device(pvr_dev)->dev);
@@ -398,6 +427,8 @@ pvr_device_gpu_init(struct pvr_device *pvr_dev)
398427
else
399428
return -EINVAL;
400429

430+
pvr_stream_create_musthave_masks(pvr_dev);
431+
401432
err = pvr_set_dma_info(pvr_dev);
402433
if (err)
403434
return err;

drivers/gpu/drm/imagination/pvr_device.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,26 @@ struct pvr_device {
173173
*/
174174
struct xarray free_list_ids;
175175

176+
/**
177+
* @job_ids: Array of jobs belonging to this device. Array members
178+
* are of type "struct pvr_job *".
179+
*/
180+
struct xarray job_ids;
181+
182+
/**
183+
* @queues: Queue-related fields.
184+
*/
185+
struct {
186+
/** @active: Active queue list. */
187+
struct list_head active;
188+
189+
/** @idle: Idle queue list. */
190+
struct list_head idle;
191+
192+
/** @lock: Lock protecting access to the active/idle lists. */
193+
struct mutex lock;
194+
} queues;
195+
176196
struct {
177197
/** @work: Work item for watchdog callback. */
178198
struct delayed_work work;
@@ -442,6 +462,7 @@ packed_bvnc_to_pvr_gpu_id(u64 bvnc, struct pvr_gpu_id *gpu_id)
442462

443463
int pvr_device_init(struct pvr_device *pvr_dev);
444464
void pvr_device_fini(struct pvr_device *pvr_dev);
465+
void pvr_device_reset(struct pvr_device *pvr_dev);
445466

446467
bool
447468
pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk);

0 commit comments

Comments
 (0)