Recent patches to the DRM scheduler [1][2] allow for a variable number of run-queues and add support for (shared) workqueues rather than dedicated kthreads per scheduler. This allows us to create a 1:1 relationship between a GPU scheduler and a scheduler entity, in order to properly support firmware schedulers being able to handle an arbitrary amount of dynamically allocated command ring buffers. This perfectly matches Nouveau's needs, hence make use of it. Topology wise we create one scheduler instance per client (handling VM_BIND jobs) and one scheduler instance per channel (handling EXEC jobs). All channel scheduler instances share a workqueue, but every client scheduler instance has a dedicated workqueue. The latter is required to ensure that for VM_BIND job's free_job() work and run_job() work can always run concurrently and hence, free_job() work can never stall run_job() work. For EXEC jobs we don't have this requirement, since EXEC job's free_job() does not require to take any locks which indirectly or directly are held for allocations elsewhere. [1] https://lore.kernel.org/all/8f53f7ef-7621-4f0b-bdef-d8d20bc497ff@redhat.com/T/ [2] https://lore.kernel.org/all/20231031032439.1558703-1-matthew.brost@intel.com/T/ Signed-off-by: Danilo Krummrich <dakr@redhat.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20231114002728.3491-1-dakr@redhat.com
60 lines
1.2 KiB
C
60 lines
1.2 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
|
|
#ifndef __NOUVEAU_EXEC_H__
|
|
#define __NOUVEAU_EXEC_H__
|
|
|
|
#include "nouveau_drv.h"
|
|
#include "nouveau_sched.h"
|
|
|
|
struct nouveau_exec_job_args {
|
|
struct drm_file *file_priv;
|
|
struct nouveau_sched *sched;
|
|
struct nouveau_channel *chan;
|
|
|
|
struct {
|
|
struct drm_nouveau_sync *s;
|
|
u32 count;
|
|
} in_sync;
|
|
|
|
struct {
|
|
struct drm_nouveau_sync *s;
|
|
u32 count;
|
|
} out_sync;
|
|
|
|
struct {
|
|
struct drm_nouveau_exec_push *s;
|
|
u32 count;
|
|
} push;
|
|
};
|
|
|
|
struct nouveau_exec_job {
|
|
struct nouveau_job base;
|
|
struct nouveau_fence *fence;
|
|
struct nouveau_channel *chan;
|
|
|
|
struct {
|
|
struct drm_nouveau_exec_push *s;
|
|
u32 count;
|
|
} push;
|
|
};
|
|
|
|
#define to_nouveau_exec_job(job) \
|
|
container_of((job), struct nouveau_exec_job, base)
|
|
|
|
int nouveau_exec_job_init(struct nouveau_exec_job **job,
|
|
struct nouveau_exec_job_args *args);
|
|
|
|
int nouveau_exec_ioctl_exec(struct drm_device *dev, void *data,
|
|
struct drm_file *file_priv);
|
|
|
|
static inline unsigned int
|
|
nouveau_exec_push_max_from_ib_max(int ib_max)
|
|
{
|
|
/* Limit the number of IBs per job to half the size of the ring in order
|
|
* to avoid the ring running dry between submissions and preserve one
|
|
* more slot for the job's HW fence.
|
|
*/
|
|
return ib_max > 1 ? ib_max / 2 - 1 : 0;
|
|
}
|
|
|
|
#endif
|