Message ID | 20231124012548.772095-14-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ó: (...) > +static void > +v3d_timestamp_query(struct v3d_cpu_job *job) > +{ > + struct v3d_timestamp_query_info *timestamp_query = &job- > >timestamp_query; > + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); I presume there is an implicit expectation here that a timestamp query job only has one BO where we are writing query results, right? Maybe we should document this more explicitly in the uAPI and also check that we have at least that one BO before trying to map it and write to it? Also, is there a reason why we take the job reference from job- >base.bo[0] instead of job->bo[0]? Iago > + u8 *value_addr; > + > + v3d_get_bo_vaddr(bo); > + > + for (int i = 0; i < timestamp_query->count; i++) { > + value_addr = ((u8 *) bo->vaddr) + timestamp_query- > >queries[i].offset; > + *((u64 *) value_addr) = i == 0 ? ktime_get_ns() : > 0ull; > + > + drm_syncobj_replace_fence(timestamp_query- > >queries[i].syncobj, > + job->base.done_fence); > + } > + > + v3d_put_bo_vaddr(bo); > +} > + > static struct dma_fence * > v3d_cpu_job_run(struct drm_sched_job *sched_job) > { > @@ -315,6 +352,7 @@ v3d_cpu_job_run(struct drm_sched_job *sched_job) > > void (*v3d_cpu_job_fn[])(struct v3d_cpu_job *job) = { > [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = > v3d_rewrite_csd_job_wg_counts_from_indirect, > + [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = > v3d_timestamp_query, > }; > > v3d->cpu_job = job; > @@ -504,7 +542,7 @@ static const struct drm_sched_backend_ops > v3d_cache_clean_sched_ops = { > 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 > + .free_job = v3d_cpu_job_free > }; > > int > diff --git a/drivers/gpu/drm/v3d/v3d_submit.c > b/drivers/gpu/drm/v3d/v3d_submit.c > index b6707ef42706..2f03c8bca593 100644 > --- a/drivers/gpu/drm/v3d/v3d_submit.c > +++ b/drivers/gpu/drm/v3d/v3d_submit.c > @@ -438,6 +438,64 @@ v3d_get_cpu_indirect_csd_params(struct drm_file > *file_priv, > NULL, &info->acquire_ctx); > } > > +/* Get data for the query timestamp job submission. */ > +static int > +v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv, > + struct drm_v3d_extension __user > *ext, > + struct v3d_cpu_job *job) > +{ > + u32 __user *offsets, *syncs; > + struct drm_v3d_timestamp_query timestamp; > + > + if (!job) { > + DRM_DEBUG("CPU job extension was attached to a GPU > job.\n"); > + return -EINVAL; > + } > + > + if (job->job_type) { > + DRM_DEBUG("Two CPU job extensions were added to the > same CPU job.\n"); > + return -EINVAL; > + } > + > + if (copy_from_user(×tamp, ext, sizeof(timestamp))) > + return -EFAULT; > + > + if (timestamp.pad) > + return -EINVAL; > + > + job->job_type = V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY; > + > + job->timestamp_query.queries = > kvmalloc_array(timestamp.count, > + sizeof(struct > v3d_timestamp_query), > + GFP_KERNEL); > + if (!job->timestamp_query.queries) > + return -ENOMEM; > + > + offsets = u64_to_user_ptr(timestamp.offsets); > + syncs = u64_to_user_ptr(timestamp.syncs); > + > + for (int i = 0; i < timestamp.count; i++) { > + u32 offset, sync; > + > + if (copy_from_user(&offset, offsets++, > sizeof(offset))) { > + kvfree(job->timestamp_query.queries); > + return -EFAULT; > + } > + > + job->timestamp_query.queries[i].offset = offset; > + > + if (copy_from_user(&sync, syncs++, sizeof(sync))) { > + kvfree(job->timestamp_query.queries); > + return -EFAULT; > + } > + > + job->timestamp_query.queries[i].syncobj = > drm_syncobj_find(file_priv, sync); > + } > + job->timestamp_query.count = timestamp.count; > + > + return 0; > +} > + > /* Whenever userspace sets ioctl extensions, v3d_get_extensions > parses data > * according to the extension id (name). > */ > @@ -466,6 +524,9 @@ v3d_get_extensions(struct drm_file *file_priv, > case DRM_V3D_EXT_ID_CPU_INDIRECT_CSD: > ret = > v3d_get_cpu_indirect_csd_params(file_priv, user_ext, job); > break; > + case DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY: > + ret = > v3d_get_cpu_timestamp_query_params(file_priv, user_ext, job); > + break; > default: > DRM_DEBUG_DRIVER("Unknown extension id: > %d\n", ext.id); > return -EINVAL; > @@ -954,6 +1015,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, > void *data, > v3d_job_cleanup((void *)csd_job); > v3d_job_cleanup(clean_job); > v3d_put_multisync_post_deps(&se); > + kvfree(cpu_job->timestamp_query.queries); > > return ret; > } > diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h > index 059b84984fb0..65d5de076366 100644 > --- a/include/uapi/drm/v3d_drm.h > +++ b/include/uapi/drm/v3d_drm.h > @@ -73,6 +73,7 @@ struct drm_v3d_extension { > __u32 id; > #define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 > #define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 > +#define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 > __u32 flags; /* mbz */ > }; > > @@ -400,6 +401,32 @@ struct drm_v3d_indirect_csd { > __u32 wg_uniform_offsets[3]; > }; > > +/** > + * struct drm_v3d_timestamp_query - ioctl extension for the CPU job > to calculate > + * a timestamp query > + * > + * When an extension DRM_V3D_EXT_ID_TIMESTAMP_QUERY is defined, it > points to > + * this extension to define a timestamp query submission. This CPU > job will > + * calculate the timestamp query and update the query value within > the > + * timestamp BO. Moreover, it will signal the timestamp syncobj to > indicate > + * query availability. > + */ > +struct drm_v3d_timestamp_query { > + struct drm_v3d_extension base; > + > + /* Array of queries' offsets within the timestamp BO for > their value */ > + __u64 offsets; > + > + /* Array of timestamp's syncobjs to indicate its availability > */ > + __u64 syncs; > + > + /* Number of queries */ > + __u32 count; > + > + /* mbz */ > + __u32 pad; > +}; > + > struct drm_v3d_submit_cpu { > /* Pointer to a u32 array of the BOs that are referenced by > the job. */ > __u64 bo_handles;
Hi Iago, On 11/27/23 06:16, Iago Toral wrote: > El jue, 23-11-2023 a las 21:47 -0300, Maíra Canal escribió: > > (...) >> +static void >> +v3d_timestamp_query(struct v3d_cpu_job *job) >> +{ >> + struct v3d_timestamp_query_info *timestamp_query = &job- >>> timestamp_query; >> + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); > > I presume there is an implicit expectation here that a timestamp query > job only has one BO where we are writing query results, right? Maybe we > should document this more explicitly in the uAPI and also check that we > have at least that one BO before trying to map it and write to it? I'll do it. > > Also, is there a reason why we take the job reference from job- >> base.bo[0] instead of job->bo[0]? job is a struct v3d_cpu_job, which has a struct v3d_job as base. The BOs are stored on struct v3d_job, as this is a common functionality of all job types. Best Regards, - Maíra > > Iago > >> + u8 *value_addr; >> + >> + v3d_get_bo_vaddr(bo); >> + >> + for (int i = 0; i < timestamp_query->count; i++) { >> + value_addr = ((u8 *) bo->vaddr) + timestamp_query- >>> queries[i].offset; >> + *((u64 *) value_addr) = i == 0 ? ktime_get_ns() : >> 0ull; >> + >> + drm_syncobj_replace_fence(timestamp_query- >>> queries[i].syncobj, >> + job->base.done_fence); >> + } >> + >> + v3d_put_bo_vaddr(bo); >> +} >> + >> static struct dma_fence * >> v3d_cpu_job_run(struct drm_sched_job *sched_job) >> { >> @@ -315,6 +352,7 @@ v3d_cpu_job_run(struct drm_sched_job *sched_job) >> >> void (*v3d_cpu_job_fn[])(struct v3d_cpu_job *job) = { >> [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = >> v3d_rewrite_csd_job_wg_counts_from_indirect, >> + [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = >> v3d_timestamp_query, >> }; >> >> v3d->cpu_job = job; >> @@ -504,7 +542,7 @@ static const struct drm_sched_backend_ops >> v3d_cache_clean_sched_ops = { >> 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 >> + .free_job = v3d_cpu_job_free >> }; >> >> int >> diff --git a/drivers/gpu/drm/v3d/v3d_submit.c >> b/drivers/gpu/drm/v3d/v3d_submit.c >> index b6707ef42706..2f03c8bca593 100644 >> --- a/drivers/gpu/drm/v3d/v3d_submit.c >> +++ b/drivers/gpu/drm/v3d/v3d_submit.c >> @@ -438,6 +438,64 @@ v3d_get_cpu_indirect_csd_params(struct drm_file >> *file_priv, >> NULL, &info->acquire_ctx); >> } >> >> +/* Get data for the query timestamp job submission. */ >> +static int >> +v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv, >> + struct drm_v3d_extension __user >> *ext, >> + struct v3d_cpu_job *job) >> +{ >> + u32 __user *offsets, *syncs; >> + struct drm_v3d_timestamp_query timestamp; >> + >> + if (!job) { >> + DRM_DEBUG("CPU job extension was attached to a GPU >> job.\n"); >> + return -EINVAL; >> + } >> + >> + if (job->job_type) { >> + DRM_DEBUG("Two CPU job extensions were added to the >> same CPU job.\n"); >> + return -EINVAL; >> + } >> + >> + if (copy_from_user(×tamp, ext, sizeof(timestamp))) >> + return -EFAULT; >> + >> + if (timestamp.pad) >> + return -EINVAL; >> + >> + job->job_type = V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY; >> + >> + job->timestamp_query.queries = >> kvmalloc_array(timestamp.count, >> + sizeof(struct >> v3d_timestamp_query), >> + GFP_KERNEL); >> + if (!job->timestamp_query.queries) >> + return -ENOMEM; >> + >> + offsets = u64_to_user_ptr(timestamp.offsets); >> + syncs = u64_to_user_ptr(timestamp.syncs); >> + >> + for (int i = 0; i < timestamp.count; i++) { >> + u32 offset, sync; >> + >> + if (copy_from_user(&offset, offsets++, >> sizeof(offset))) { >> + kvfree(job->timestamp_query.queries); >> + return -EFAULT; >> + } >> + >> + job->timestamp_query.queries[i].offset = offset; >> + >> + if (copy_from_user(&sync, syncs++, sizeof(sync))) { >> + kvfree(job->timestamp_query.queries); >> + return -EFAULT; >> + } >> + >> + job->timestamp_query.queries[i].syncobj = >> drm_syncobj_find(file_priv, sync); >> + } >> + job->timestamp_query.count = timestamp.count; >> + >> + return 0; >> +} >> + >> /* Whenever userspace sets ioctl extensions, v3d_get_extensions >> parses data >> * according to the extension id (name). >> */ >> @@ -466,6 +524,9 @@ v3d_get_extensions(struct drm_file *file_priv, >> case DRM_V3D_EXT_ID_CPU_INDIRECT_CSD: >> ret = >> v3d_get_cpu_indirect_csd_params(file_priv, user_ext, job); >> break; >> + case DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY: >> + ret = >> v3d_get_cpu_timestamp_query_params(file_priv, user_ext, job); >> + break; >> default: >> DRM_DEBUG_DRIVER("Unknown extension id: >> %d\n", ext.id); >> return -EINVAL; >> @@ -954,6 +1015,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, >> void *data, >> v3d_job_cleanup((void *)csd_job); >> v3d_job_cleanup(clean_job); >> v3d_put_multisync_post_deps(&se); >> + kvfree(cpu_job->timestamp_query.queries); >> >> return ret; >> } >> diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h >> index 059b84984fb0..65d5de076366 100644 >> --- a/include/uapi/drm/v3d_drm.h >> +++ b/include/uapi/drm/v3d_drm.h >> @@ -73,6 +73,7 @@ struct drm_v3d_extension { >> __u32 id; >> #define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 >> #define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 >> +#define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 >> __u32 flags; /* mbz */ >> }; >> >> @@ -400,6 +401,32 @@ struct drm_v3d_indirect_csd { >> __u32 wg_uniform_offsets[3]; >> }; >> >> +/** >> + * struct drm_v3d_timestamp_query - ioctl extension for the CPU job >> to calculate >> + * a timestamp query >> + * >> + * When an extension DRM_V3D_EXT_ID_TIMESTAMP_QUERY is defined, it >> points to >> + * this extension to define a timestamp query submission. This CPU >> job will >> + * calculate the timestamp query and update the query value within >> the >> + * timestamp BO. Moreover, it will signal the timestamp syncobj to >> indicate >> + * query availability. >> + */ >> +struct drm_v3d_timestamp_query { >> + struct drm_v3d_extension base; >> + >> + /* Array of queries' offsets within the timestamp BO for >> their value */ >> + __u64 offsets; >> + >> + /* Array of timestamp's syncobjs to indicate its availability >> */ >> + __u64 syncs; >> + >> + /* Number of queries */ >> + __u32 count; >> + >> + /* mbz */ >> + __u32 pad; >> +}; >> + >> struct drm_v3d_submit_cpu { >> /* Pointer to a u32 array of the BOs that are referenced by >> the job. */ >> __u64 bo_handles; >
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index f665f3f5b65b..524e4e952bae 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -318,6 +318,15 @@ struct v3d_csd_job { enum v3d_cpu_job_type { V3D_CPU_JOB_TYPE_INDIRECT_CSD = 1, + V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY, +}; + +struct v3d_timestamp_query { + /* Offset of this query in the timestamp BO for its value. */ + u32 offset; + + /* Syncobj that indicates the timestamp availability */ + struct drm_syncobj *syncobj; }; struct v3d_indirect_csd_info { @@ -345,12 +354,20 @@ struct v3d_indirect_csd_info { struct ww_acquire_ctx acquire_ctx; }; +struct v3d_timestamp_query_info { + struct v3d_timestamp_query *queries; + + u32 count; +}; + struct v3d_cpu_job { struct v3d_job base; enum v3d_cpu_job_type job_type; struct v3d_indirect_csd_info indirect_csd; + + struct v3d_timestamp_query_info timestamp_query; }; struct v3d_submit_outsync { diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index a8ac46f70cee..828c4fc14dcd 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -21,6 +21,8 @@ #include <linux/sched/clock.h> #include <linux/kthread.h> +#include <drm/drm_syncobj.h> + #include "v3d_drv.h" #include "v3d_regs.h" #include "v3d_trace.h" @@ -71,6 +73,21 @@ v3d_sched_job_free(struct drm_sched_job *sched_job) v3d_job_cleanup(job); } +static void +v3d_cpu_job_free(struct drm_sched_job *sched_job) +{ + struct v3d_cpu_job *job = to_cpu_job(sched_job); + struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + + if (timestamp_query->queries) { + for (int i = 0; i < timestamp_query->count; i++) + drm_syncobj_put(timestamp_query->queries[i].syncobj); + kvfree(timestamp_query->queries); + } + + v3d_job_cleanup(&job->base); +} + static void v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job) { @@ -305,6 +322,26 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job) v3d_put_bo_vaddr(bo); } +static void +v3d_timestamp_query(struct v3d_cpu_job *job) +{ + struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; + struct v3d_bo *bo = to_v3d_bo(job->base.bo[0]); + u8 *value_addr; + + v3d_get_bo_vaddr(bo); + + for (int i = 0; i < timestamp_query->count; i++) { + value_addr = ((u8 *) bo->vaddr) + timestamp_query->queries[i].offset; + *((u64 *) value_addr) = i == 0 ? ktime_get_ns() : 0ull; + + drm_syncobj_replace_fence(timestamp_query->queries[i].syncobj, + job->base.done_fence); + } + + v3d_put_bo_vaddr(bo); +} + static struct dma_fence * v3d_cpu_job_run(struct drm_sched_job *sched_job) { @@ -315,6 +352,7 @@ v3d_cpu_job_run(struct drm_sched_job *sched_job) void (*v3d_cpu_job_fn[])(struct v3d_cpu_job *job) = { [V3D_CPU_JOB_TYPE_INDIRECT_CSD] = v3d_rewrite_csd_job_wg_counts_from_indirect, + [V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY] = v3d_timestamp_query, }; v3d->cpu_job = job; @@ -504,7 +542,7 @@ static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = { 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 + .free_job = v3d_cpu_job_free }; int diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index b6707ef42706..2f03c8bca593 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -438,6 +438,64 @@ v3d_get_cpu_indirect_csd_params(struct drm_file *file_priv, NULL, &info->acquire_ctx); } +/* Get data for the query timestamp job submission. */ +static int +v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv, + struct drm_v3d_extension __user *ext, + struct v3d_cpu_job *job) +{ + u32 __user *offsets, *syncs; + struct drm_v3d_timestamp_query timestamp; + + if (!job) { + DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); + return -EINVAL; + } + + if (job->job_type) { + DRM_DEBUG("Two CPU job extensions were added to the same CPU job.\n"); + return -EINVAL; + } + + if (copy_from_user(×tamp, ext, sizeof(timestamp))) + return -EFAULT; + + if (timestamp.pad) + return -EINVAL; + + job->job_type = V3D_CPU_JOB_TYPE_TIMESTAMP_QUERY; + + job->timestamp_query.queries = kvmalloc_array(timestamp.count, + sizeof(struct v3d_timestamp_query), + GFP_KERNEL); + if (!job->timestamp_query.queries) + return -ENOMEM; + + offsets = u64_to_user_ptr(timestamp.offsets); + syncs = u64_to_user_ptr(timestamp.syncs); + + for (int i = 0; i < timestamp.count; i++) { + u32 offset, sync; + + if (copy_from_user(&offset, offsets++, sizeof(offset))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].offset = offset; + + if (copy_from_user(&sync, syncs++, sizeof(sync))) { + kvfree(job->timestamp_query.queries); + return -EFAULT; + } + + job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); + } + job->timestamp_query.count = timestamp.count; + + return 0; +} + /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data * according to the extension id (name). */ @@ -466,6 +524,9 @@ v3d_get_extensions(struct drm_file *file_priv, case DRM_V3D_EXT_ID_CPU_INDIRECT_CSD: ret = v3d_get_cpu_indirect_csd_params(file_priv, user_ext, job); break; + case DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY: + ret = v3d_get_cpu_timestamp_query_params(file_priv, user_ext, job); + break; default: DRM_DEBUG_DRIVER("Unknown extension id: %d\n", ext.id); return -EINVAL; @@ -954,6 +1015,7 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data, v3d_job_cleanup((void *)csd_job); v3d_job_cleanup(clean_job); v3d_put_multisync_post_deps(&se); + kvfree(cpu_job->timestamp_query.queries); return ret; } diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index 059b84984fb0..65d5de076366 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -73,6 +73,7 @@ struct drm_v3d_extension { __u32 id; #define DRM_V3D_EXT_ID_MULTI_SYNC 0x01 #define DRM_V3D_EXT_ID_CPU_INDIRECT_CSD 0x02 +#define DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY 0x03 __u32 flags; /* mbz */ }; @@ -400,6 +401,32 @@ struct drm_v3d_indirect_csd { __u32 wg_uniform_offsets[3]; }; +/** + * struct drm_v3d_timestamp_query - ioctl extension for the CPU job to calculate + * a timestamp query + * + * When an extension DRM_V3D_EXT_ID_TIMESTAMP_QUERY is defined, it points to + * this extension to define a timestamp query submission. This CPU job will + * calculate the timestamp query and update the query value within the + * timestamp BO. Moreover, it will signal the timestamp syncobj to indicate + * query availability. + */ +struct drm_v3d_timestamp_query { + struct drm_v3d_extension base; + + /* Array of queries' offsets within the timestamp BO for their value */ + __u64 offsets; + + /* Array of timestamp's syncobjs to indicate its availability */ + __u64 syncs; + + /* Number of queries */ + __u32 count; + + /* mbz */ + __u32 pad; +}; + struct drm_v3d_submit_cpu { /* Pointer to a u32 array of the BOs that are referenced by the job. */ __u64 bo_handles;
A CPU job is a type of job that performs operations that requires CPU intervention. A timestamp query job is a job that calculates the query timestamp and updates the query availability by signaling a syncobj. As V3D doesn't provide any mechanism to obtain a timestamp from the GPU, it is a job that needs CPU intervention. So, create a user extension for the CPU job that enables the creation of a timestamp query job. This user extension will allow the creation of a CPU job that performs the timestamp query calculation and updates the timestamp BO with the proper value. Signed-off-by: Maíra Canal <mcanal@igalia.com> --- drivers/gpu/drm/v3d/v3d_drv.h | 17 +++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 40 ++++++++++++++++++++- drivers/gpu/drm/v3d/v3d_submit.c | 62 ++++++++++++++++++++++++++++++++ include/uapi/drm/v3d_drm.h | 27 ++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-)