Message ID | 20231124012548.772095-8-mcanal@igalia.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/v3d: Introduce CPU jobs | expand |
El jue, 23-11-2023 a las 21:47 -0300, Maíra Canal escribió: > From: Melissa Wen <mwen@igalia.com> > > Create a new type of job, a CPU job. A CPU job is a type of job that > performs operations that requires CPU intervention. The overall idea > is > to use user extensions to enable different types of CPU job, allowing > the > CPU job to perform different operations according to the type of user > externsion. The user extension ID identify the type of CPU job that s/externsion/extension Iago > must > be dealt. > > Having a CPU job is interesting for synchronization purposes as a CPU > job has a queue like any other V3D job and can be synchoronized by > the > multisync extension. > > Signed-off-by: Melissa Wen <mwen@igalia.com> > Co-developed-by: Maíra Canal <mcanal@igalia.com> > Signed-off-by: Maíra Canal <mcanal@igalia.com> > --- > drivers/gpu/drm/v3d/v3d_drv.c | 4 ++ > drivers/gpu/drm/v3d/v3d_drv.h | 14 +++++- > drivers/gpu/drm/v3d/v3d_sched.c | 57 +++++++++++++++++++++++ > drivers/gpu/drm/v3d/v3d_submit.c | 79 > ++++++++++++++++++++++++++++++++ > include/uapi/drm/v3d_drm.h | 17 +++++++ > 5 files changed, 170 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/v3d/v3d_drv.c > b/drivers/gpu/drm/v3d/v3d_drv.c > index 44a1ca57d6a4..3debf37e7d9b 100644 > --- a/drivers/gpu/drm/v3d/v3d_drv.c > +++ b/drivers/gpu/drm/v3d/v3d_drv.c > @@ -91,6 +91,9 @@ static int v3d_get_param_ioctl(struct drm_device > *dev, void *data, > case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT: > args->value = 1; > return 0; > + case DRM_V3D_PARAM_SUPPORTS_CPU_QUEUE: > + args->value = 1; > + return 0; > default: > DRM_DEBUG("Unknown parameter %d\n", args->param); > return -EINVAL; > @@ -189,6 +192,7 @@ static const struct drm_ioctl_desc > v3d_drm_ioctls[] = { > DRM_IOCTL_DEF_DRV(V3D_PERFMON_CREATE, > v3d_perfmon_create_ioctl, DRM_RENDER_ALLOW), > DRM_IOCTL_DEF_DRV(V3D_PERFMON_DESTROY, > v3d_perfmon_destroy_ioctl, DRM_RENDER_ALLOW), > DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_VALUES, > v3d_perfmon_get_values_ioctl, DRM_RENDER_ALLOW), > + DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CPU, v3d_submit_cpu_ioctl, > DRM_RENDER_ALLOW | DRM_AUTH), > }; > > static const struct drm_driver v3d_drm_driver = { > diff --git a/drivers/gpu/drm/v3d/v3d_drv.h > b/drivers/gpu/drm/v3d/v3d_drv.h > index 4db9ace66024..010b146140ad 100644 > --- a/drivers/gpu/drm/v3d/v3d_drv.h > +++ b/drivers/gpu/drm/v3d/v3d_drv.h > @@ -19,7 +19,7 @@ struct reset_control; > > #define GMP_GRANULARITY (128 * 1024) > > -#define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) > +#define V3D_MAX_QUEUES (V3D_CPU + 1) > > static inline char *v3d_queue_to_string(enum v3d_queue queue) > { > @@ -29,6 +29,7 @@ static inline char *v3d_queue_to_string(enum > v3d_queue queue) > case V3D_TFU: return "tfu"; > case V3D_CSD: return "csd"; > case V3D_CACHE_CLEAN: return "cache_clean"; > + case V3D_CPU: return "cpu"; > } > return "UNKNOWN"; > } > @@ -122,6 +123,7 @@ struct v3d_dev { > struct v3d_render_job *render_job; > struct v3d_tfu_job *tfu_job; > struct v3d_csd_job *csd_job; > + struct v3d_cpu_job *cpu_job; > > struct v3d_queue_state queue[V3D_MAX_QUEUES]; > > @@ -312,6 +314,14 @@ struct v3d_csd_job { > struct drm_v3d_submit_csd args; > }; > > +enum v3d_cpu_job_type {}; > + > +struct v3d_cpu_job { > + struct v3d_job base; > + > + enum v3d_cpu_job_type job_type; > +}; > + > struct v3d_submit_outsync { > struct drm_syncobj *syncobj; > }; > @@ -414,6 +424,8 @@ int v3d_submit_tfu_ioctl(struct drm_device *dev, > void *data, > struct drm_file *file_priv); > int v3d_submit_csd_ioctl(struct drm_device *dev, void *data, > struct drm_file *file_priv); > +int v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, > + struct drm_file *file_priv); > > /* v3d_irq.c */ > int v3d_irq_init(struct v3d_dev *v3d); > diff --git a/drivers/gpu/drm/v3d/v3d_sched.c > b/drivers/gpu/drm/v3d/v3d_sched.c > index fccbea2a5f2e..a32c91b94898 100644 > --- a/drivers/gpu/drm/v3d/v3d_sched.c > +++ b/drivers/gpu/drm/v3d/v3d_sched.c > @@ -55,6 +55,12 @@ to_csd_job(struct drm_sched_job *sched_job) > return container_of(sched_job, struct v3d_csd_job, > base.base); > } > > +static struct v3d_cpu_job * > +to_cpu_job(struct drm_sched_job *sched_job) > +{ > + return container_of(sched_job, struct v3d_cpu_job, > base.base); > +} > + > static void > v3d_sched_job_free(struct drm_sched_job *sched_job) > { > @@ -262,6 +268,42 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) > return fence; > } > > +static struct dma_fence * > +v3d_cpu_job_run(struct drm_sched_job *sched_job) > +{ > + struct v3d_cpu_job *job = to_cpu_job(sched_job); > + struct v3d_dev *v3d = job->base.v3d; > + struct v3d_file_priv *file = job->base.file->driver_priv; > + u64 runtime; > + > + void (*v3d_cpu_job_fn[])(struct v3d_cpu_job *job) = { }; > + > + v3d->cpu_job = job; > + > + if (job->job_type >= ARRAY_SIZE(v3d_cpu_job_fn)) { > + DRM_DEBUG_DRIVER("Unknown CPU job: %d\n", job- > >job_type); > + return NULL; > + } > + > + file->start_ns[V3D_CPU] = local_clock(); > + v3d->queue[V3D_CPU].start_ns = file->start_ns[V3D_CPU]; > + > + v3d_cpu_job_fn[job->job_type](job); > + > + runtime = local_clock() - file->start_ns[V3D_CPU]; > + > + file->enabled_ns[V3D_CPU] += runtime; > + v3d->queue[V3D_CPU].enabled_ns += runtime; > + > + file->jobs_sent[V3D_CPU]++; > + v3d->queue[V3D_CPU].jobs_sent++; > + > + file->start_ns[V3D_CPU] = 0; > + v3d->queue[V3D_CPU].start_ns = 0; > + > + return NULL; > +} > + > static struct dma_fence * > v3d_cache_clean_job_run(struct drm_sched_job *sched_job) > { > @@ -416,6 +458,12 @@ static const struct drm_sched_backend_ops > v3d_cache_clean_sched_ops = { > .free_job = v3d_sched_job_free > }; > > +static const struct drm_sched_backend_ops v3d_cpu_sched_ops = { > + .run_job = v3d_cpu_job_run, > + .timedout_job = v3d_generic_job_timedout, > + .free_job = v3d_sched_job_free > +}; > + > int > v3d_sched_init(struct v3d_dev *v3d) > { > @@ -471,6 +519,15 @@ v3d_sched_init(struct v3d_dev *v3d) > goto fail; > } > > + ret = drm_sched_init(&v3d->queue[V3D_CPU].sched, > + &v3d_cpu_sched_ops, NULL, > + DRM_SCHED_PRIORITY_COUNT, > + 1, job_hang_limit, > + msecs_to_jiffies(hang_limit_ms), NULL, > + NULL, "v3d_cpu", v3d->drm.dev); > + if (ret) > + goto fail; > + > return 0; > > fail: > diff --git a/drivers/gpu/drm/v3d/v3d_submit.c > b/drivers/gpu/drm/v3d/v3d_submit.c > index ed1a310bbd2f..d4b85ab16345 100644 > --- a/drivers/gpu/drm/v3d/v3d_submit.c > +++ b/drivers/gpu/drm/v3d/v3d_submit.c > @@ -761,3 +761,82 @@ v3d_submit_csd_ioctl(struct drm_device *dev, > void *data, > > return ret; > } > + > +/** > + * v3d_submit_cpu_ioctl() - Submits a CPU job to the V3D. > + * @dev: DRM device > + * @data: ioctl argument > + * @file_priv: DRM file for this fd > + * > + * Userspace specifies the CPU job type and data required to perform > its > + * operations through the drm_v3d_extension struct. > + */ > +int > +v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, > + struct drm_file *file_priv) > +{ > + struct v3d_dev *v3d = to_v3d_dev(dev); > + struct drm_v3d_submit_cpu *args = data; > + struct v3d_submit_ext se = {0}; > + struct v3d_cpu_job *cpu_job = NULL; > + struct ww_acquire_ctx acquire_ctx; > + int ret; > + > + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) > { > + DRM_INFO("invalid flags: %d\n", args->flags); > + return -EINVAL; > + } > + > + ret = v3d_job_allocate((void *)&cpu_job, sizeof(*cpu_job)); > + if (ret) > + return ret; > + > + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { > + ret = v3d_get_extensions(file_priv, args->extensions, > &se); > + if (ret) { > + DRM_DEBUG("Failed to get extensions.\n"); > + goto fail; > + } > + } > + > + /* Every CPU job must have a CPU job user extension */ > + if (!cpu_job->job_type) { > + DRM_DEBUG("CPU job must have a CPU job user > extension.\n"); > + goto fail; > + } > + > + ret = v3d_job_init(v3d, file_priv, (void *)&cpu_job, > sizeof(*cpu_job), > + v3d_job_free, 0, &se, V3D_CPU); > + if (ret) > + goto fail; > + > + if (args->bo_handle_count) { > + ret = v3d_lookup_bos(dev, file_priv, &cpu_job->base, > + args->bo_handles, args- > >bo_handle_count); > + if (ret) > + goto fail; > + > + ret = v3d_lock_bo_reservations(&cpu_job->base, > &acquire_ctx); > + if (ret) > + goto fail; > + } > + > + mutex_lock(&v3d->sched_lock); > + v3d_push_job(&cpu_job->base); > + mutex_unlock(&v3d->sched_lock); > + > + v3d_attach_fences_and_unlock_reservation(file_priv, > + &cpu_job->base, > + &acquire_ctx, 0, > + NULL, cpu_job- > >base.done_fence); > + > + v3d_job_put((void *)cpu_job); > + > + return 0; > + > +fail: > + v3d_job_cleanup((void *)cpu_job); > + v3d_put_multisync_post_deps(&se); > + > + return ret; > +} > diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h > index 1a7d7a689de3..00abef9d0db7 100644 > --- a/include/uapi/drm/v3d_drm.h > +++ b/include/uapi/drm/v3d_drm.h > @@ -41,6 +41,7 @@ extern "C" { > #define DRM_V3D_PERFMON_CREATE 0x08 > #define DRM_V3D_PERFMON_DESTROY 0x09 > #define DRM_V3D_PERFMON_GET_VALUES 0x0a > +#define DRM_V3D_SUBMIT_CPU 0x0b > > #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE > + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) > #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE > + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) > @@ -56,6 +57,7 @@ extern "C" { > struct > drm_v3d_perfmon_destroy) > #define DRM_IOCTL_V3D_PERFMON_GET_VALUES DRM_IOWR(DRM_COMMAND_BASE > + DRM_V3D_PERFMON_GET_VALUES, \ > struct > drm_v3d_perfmon_get_values) > +#define DRM_IOCTL_V3D_SUBMIT_CPU DRM_IOW(DRM_COMMAND_BASE + > DRM_V3D_SUBMIT_CPU, struct drm_v3d_submit_cpu) > > #define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01 > #define DRM_V3D_SUBMIT_EXTENSION 0x02 > @@ -93,6 +95,7 @@ enum v3d_queue { > V3D_TFU, > V3D_CSD, > V3D_CACHE_CLEAN, > + V3D_CPU, > }; > > /** > @@ -276,6 +279,7 @@ enum drm_v3d_param { > DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH, > DRM_V3D_PARAM_SUPPORTS_PERFMON, > DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT, > + DRM_V3D_PARAM_SUPPORTS_CPU_QUEUE, > }; > > struct drm_v3d_get_param { > @@ -361,6 +365,19 @@ struct drm_v3d_submit_csd { > __u32 pad; > }; > > +struct drm_v3d_submit_cpu { > + /* Pointer to a u32 array of the BOs that are referenced by > the job. */ > + __u64 bo_handles; > + > + /* Number of BO handles passed in (size is that times 4). */ > + __u32 bo_handle_count; > + > + __u32 flags; > + > + /* Pointer to an array of ioctl extensions*/ > + __u64 extensions; > +}; > + > enum { > V3D_PERFCNT_FEP_VALID_PRIMTS_NO_PIXELS, > V3D_PERFCNT_FEP_VALID_PRIMS,
El jue, 23-11-2023 a las 21:47 -0300, Maíra Canal escribió: > From: Melissa Wen <mwen@igalia.com> > > Create a new type of job, a CPU job. A CPU job is a type of job that > performs operations that requires CPU intervention. The overall idea > is > to use user extensions to enable different types of CPU job, allowing > the > CPU job to perform different operations according to the type of user > externsion. The user extension ID identify the type of CPU job that > must > be dealt. > > Having a CPU job is interesting for synchronization purposes as a CPU > job has a queue like any other V3D job and can be synchoronized by > the > multisync extension. > > Signed-off-by: Melissa Wen <mwen@igalia.com> > Co-developed-by: Maíra Canal <mcanal@igalia.com> > Signed-off-by: Maíra Canal <mcanal@igalia.com> > --- > (...) > diff --git a/drivers/gpu/drm/v3d/v3d_sched.c > b/drivers/gpu/drm/v3d/v3d_sched.c > index fccbea2a5f2e..a32c91b94898 100644 > --- a/drivers/gpu/drm/v3d/v3d_sched.c > +++ b/drivers/gpu/drm/v3d/v3d_sched.c > @@ -55,6 +55,12 @@ to_csd_job(struct drm_sched_job *sched_job) > return container_of(sched_job, struct v3d_csd_job, > base.base); > } > > +static struct v3d_cpu_job * > +to_cpu_job(struct drm_sched_job *sched_job) > +{ > + return container_of(sched_job, struct v3d_cpu_job, > base.base); > +} > + > static void > v3d_sched_job_free(struct drm_sched_job *sched_job) > { > @@ -262,6 +268,42 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) > return fence; > } > > +static struct dma_fence * > +v3d_cpu_job_run(struct drm_sched_job *sched_job) > +{ > + struct v3d_cpu_job *job = to_cpu_job(sched_job); > + struct v3d_dev *v3d = job->base.v3d; > + struct v3d_file_priv *file = job->base.file->driver_priv; > + u64 runtime; > + > + void (*v3d_cpu_job_fn[])(struct v3d_cpu_job *job) = { }; Shouldn't this be a static const? Also, maybe we want declare it outside the function itself? Iago > + > + v3d->cpu_job = job; > + > + if (job->job_type >= ARRAY_SIZE(v3d_cpu_job_fn)) { > + DRM_DEBUG_DRIVER("Unknown CPU job: %d\n", job- > >job_type); > + return NULL; > + } > + > + file->start_ns[V3D_CPU] = local_clock(); > + v3d->queue[V3D_CPU].start_ns = file->start_ns[V3D_CPU]; > + > + v3d_cpu_job_fn[job->job_type](job); > + > + runtime = local_clock() - file->start_ns[V3D_CPU]; > + > + file->enabled_ns[V3D_CPU] += runtime; > + v3d->queue[V3D_CPU].enabled_ns += runtime; > + > + file->jobs_sent[V3D_CPU]++; > + v3d->queue[V3D_CPU].jobs_sent++; > + > + file->start_ns[V3D_CPU] = 0; > + v3d->queue[V3D_CPU].start_ns = 0; > + > + return NULL; > +}
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 44a1ca57d6a4..3debf37e7d9b 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -91,6 +91,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT: args->value = 1; return 0; + case DRM_V3D_PARAM_SUPPORTS_CPU_QUEUE: + args->value = 1; + return 0; default: DRM_DEBUG("Unknown parameter %d\n", args->param); return -EINVAL; @@ -189,6 +192,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(V3D_PERFMON_CREATE, v3d_perfmon_create_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(V3D_PERFMON_DESTROY, v3d_perfmon_destroy_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_VALUES, v3d_perfmon_get_values_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CPU, v3d_submit_cpu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), }; static const struct drm_driver v3d_drm_driver = { diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 4db9ace66024..010b146140ad 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -19,7 +19,7 @@ struct reset_control; #define GMP_GRANULARITY (128 * 1024) -#define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1) +#define V3D_MAX_QUEUES (V3D_CPU + 1) static inline char *v3d_queue_to_string(enum v3d_queue queue) { @@ -29,6 +29,7 @@ static inline char *v3d_queue_to_string(enum v3d_queue queue) case V3D_TFU: return "tfu"; case V3D_CSD: return "csd"; case V3D_CACHE_CLEAN: return "cache_clean"; + case V3D_CPU: return "cpu"; } return "UNKNOWN"; } @@ -122,6 +123,7 @@ struct v3d_dev { struct v3d_render_job *render_job; struct v3d_tfu_job *tfu_job; struct v3d_csd_job *csd_job; + struct v3d_cpu_job *cpu_job; struct v3d_queue_state queue[V3D_MAX_QUEUES]; @@ -312,6 +314,14 @@ struct v3d_csd_job { struct drm_v3d_submit_csd args; }; +enum v3d_cpu_job_type {}; + +struct v3d_cpu_job { + struct v3d_job base; + + enum v3d_cpu_job_type job_type; +}; + struct v3d_submit_outsync { struct drm_syncobj *syncobj; }; @@ -414,6 +424,8 @@ int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_submit_csd_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* v3d_irq.c */ int v3d_irq_init(struct v3d_dev *v3d); diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index fccbea2a5f2e..a32c91b94898 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -55,6 +55,12 @@ to_csd_job(struct drm_sched_job *sched_job) return container_of(sched_job, struct v3d_csd_job, base.base); } +static struct v3d_cpu_job * +to_cpu_job(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct v3d_cpu_job, base.base); +} + static void v3d_sched_job_free(struct drm_sched_job *sched_job) { @@ -262,6 +268,42 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) return fence; } +static struct dma_fence * +v3d_cpu_job_run(struct drm_sched_job *sched_job) +{ + struct v3d_cpu_job *job = to_cpu_job(sched_job); + struct v3d_dev *v3d = job->base.v3d; + struct v3d_file_priv *file = job->base.file->driver_priv; + u64 runtime; + + void (*v3d_cpu_job_fn[])(struct v3d_cpu_job *job) = { }; + + v3d->cpu_job = job; + + if (job->job_type >= ARRAY_SIZE(v3d_cpu_job_fn)) { + DRM_DEBUG_DRIVER("Unknown CPU job: %d\n", job->job_type); + return NULL; + } + + file->start_ns[V3D_CPU] = local_clock(); + v3d->queue[V3D_CPU].start_ns = file->start_ns[V3D_CPU]; + + v3d_cpu_job_fn[job->job_type](job); + + runtime = local_clock() - file->start_ns[V3D_CPU]; + + file->enabled_ns[V3D_CPU] += runtime; + v3d->queue[V3D_CPU].enabled_ns += runtime; + + file->jobs_sent[V3D_CPU]++; + v3d->queue[V3D_CPU].jobs_sent++; + + file->start_ns[V3D_CPU] = 0; + v3d->queue[V3D_CPU].start_ns = 0; + + return NULL; +} + static struct dma_fence * v3d_cache_clean_job_run(struct drm_sched_job *sched_job) { @@ -416,6 +458,12 @@ static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = { .free_job = v3d_sched_job_free }; +static const struct drm_sched_backend_ops v3d_cpu_sched_ops = { + .run_job = v3d_cpu_job_run, + .timedout_job = v3d_generic_job_timedout, + .free_job = v3d_sched_job_free +}; + int v3d_sched_init(struct v3d_dev *v3d) { @@ -471,6 +519,15 @@ v3d_sched_init(struct v3d_dev *v3d) goto fail; } + ret = drm_sched_init(&v3d->queue[V3D_CPU].sched, + &v3d_cpu_sched_ops, NULL, + DRM_SCHED_PRIORITY_COUNT, + 1, job_hang_limit, + msecs_to_jiffies(hang_limit_ms), NULL, + NULL, "v3d_cpu", v3d->drm.dev); + if (ret) + goto fail; + return 0; fail: diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index ed1a310bbd2f..d4b85ab16345 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -761,3 +761,82 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data, return ret; } + +/** + * v3d_submit_cpu_ioctl() - Submits a CPU job to the V3D. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * Userspace specifies the CPU job type and data required to perform its + * operations through the drm_v3d_extension struct. + */ +int +v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct v3d_dev *v3d = to_v3d_dev(dev); + struct drm_v3d_submit_cpu *args = data; + struct v3d_submit_ext se = {0}; + struct v3d_cpu_job *cpu_job = NULL; + struct ww_acquire_ctx acquire_ctx; + int ret; + + if (args->flags && !(args->flags & DRM_V3D_SUBMIT_EXTENSION)) { + DRM_INFO("invalid flags: %d\n", args->flags); + return -EINVAL; + } + + ret = v3d_job_allocate((void *)&cpu_job, sizeof(*cpu_job)); + if (ret) + return ret; + + if (args->flags & DRM_V3D_SUBMIT_EXTENSION) { + ret = v3d_get_extensions(file_priv, args->extensions, &se); + if (ret) { + DRM_DEBUG("Failed to get extensions.\n"); + goto fail; + } + } + + /* Every CPU job must have a CPU job user extension */ + if (!cpu_job->job_type) { + DRM_DEBUG("CPU job must have a CPU job user extension.\n"); + goto fail; + } + + ret = v3d_job_init(v3d, file_priv, (void *)&cpu_job, sizeof(*cpu_job), + v3d_job_free, 0, &se, V3D_CPU); + if (ret) + goto fail; + + if (args->bo_handle_count) { + ret = v3d_lookup_bos(dev, file_priv, &cpu_job->base, + args->bo_handles, args->bo_handle_count); + if (ret) + goto fail; + + ret = v3d_lock_bo_reservations(&cpu_job->base, &acquire_ctx); + if (ret) + goto fail; + } + + mutex_lock(&v3d->sched_lock); + v3d_push_job(&cpu_job->base); + mutex_unlock(&v3d->sched_lock); + + v3d_attach_fences_and_unlock_reservation(file_priv, + &cpu_job->base, + &acquire_ctx, 0, + NULL, cpu_job->base.done_fence); + + v3d_job_put((void *)cpu_job); + + return 0; + +fail: + v3d_job_cleanup((void *)cpu_job); + v3d_put_multisync_post_deps(&se); + + return ret; +} diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 1a7d7a689de3..00abef9d0db7 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -41,6 +41,7 @@ extern "C" { #define DRM_V3D_PERFMON_CREATE 0x08 #define DRM_V3D_PERFMON_DESTROY 0x09 #define DRM_V3D_PERFMON_GET_VALUES 0x0a +#define DRM_V3D_SUBMIT_CPU 0x0b #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) @@ -56,6 +57,7 @@ extern "C" { struct drm_v3d_perfmon_destroy) #define DRM_IOCTL_V3D_PERFMON_GET_VALUES DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_PERFMON_GET_VALUES, \ struct drm_v3d_perfmon_get_values) +#define DRM_IOCTL_V3D_SUBMIT_CPU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CPU, struct drm_v3d_submit_cpu) #define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01 #define DRM_V3D_SUBMIT_EXTENSION 0x02 @@ -93,6 +95,7 @@ enum v3d_queue { V3D_TFU, V3D_CSD, V3D_CACHE_CLEAN, + V3D_CPU, }; /** @@ -276,6 +279,7 @@ enum drm_v3d_param { DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH, DRM_V3D_PARAM_SUPPORTS_PERFMON, DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT, + DRM_V3D_PARAM_SUPPORTS_CPU_QUEUE, }; struct drm_v3d_get_param { @@ -361,6 +365,19 @@ struct drm_v3d_submit_csd { __u32 pad; }; +struct drm_v3d_submit_cpu { + /* Pointer to a u32 array of the BOs that are referenced by the job. */ + __u64 bo_handles; + + /* Number of BO handles passed in (size is that times 4). */ + __u32 bo_handle_count; + + __u32 flags; + + /* Pointer to an array of ioctl extensions*/ + __u64 extensions; +}; + enum { V3D_PERFCNT_FEP_VALID_PRIMTS_NO_PIXELS, V3D_PERFCNT_FEP_VALID_PRIMS,