Reviewed-by: Jacek Lawrynowicz <jacek.lawrynow...@linux.intel.com>

On 1/7/2025 6:32 PM, Maciej Falkowski wrote:
> From: Karol Wachowski <karol.wachow...@intel.com>
> 
> Implement support for explicit command queue management.
> To allow more flexible control over command queues add capabilities
> to create, destroy and submit jobs to specific command queues.
> 
> Signed-off-by: Karol Wachowski <karol.wachow...@intel.com>
> Signed-off-by: Maciej Falkowski <maciej.falkow...@linux.intel.com>
> ---
>  drivers/accel/ivpu/ivpu_drv.c |   6 +
>  drivers/accel/ivpu/ivpu_job.c | 369 +++++++++++++++++++++-------------
>  drivers/accel/ivpu/ivpu_job.h |   5 +-
>  include/uapi/drm/ivpu_accel.h |  84 ++++++++
>  4 files changed, 319 insertions(+), 145 deletions(-)
> 
> diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
> index 1e8ffbe25eee..f4171536640b 100644
> --- a/drivers/accel/ivpu/ivpu_drv.c
> +++ b/drivers/accel/ivpu/ivpu_drv.c
> @@ -137,6 +137,9 @@ static int ivpu_get_capabilities(struct ivpu_device 
> *vdev, struct drm_ivpu_param
>       case DRM_IVPU_CAP_DMA_MEMORY_RANGE:
>               args->value = 1;
>               break;
> +     case DRM_IVPU_CAP_MANAGE_CMDQ:
> +             args->value = 1;
> +             break;
>       default:
>               return -EINVAL;
>       }
> @@ -310,6 +313,9 @@ static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
>       DRM_IOCTL_DEF_DRV(IVPU_METRIC_STREAMER_GET_DATA, 
> ivpu_ms_get_data_ioctl, 0),
>       DRM_IOCTL_DEF_DRV(IVPU_METRIC_STREAMER_STOP, ivpu_ms_stop_ioctl, 0),
>       DRM_IOCTL_DEF_DRV(IVPU_METRIC_STREAMER_GET_INFO, 
> ivpu_ms_get_info_ioctl, 0),
> +     DRM_IOCTL_DEF_DRV(IVPU_CMDQ_CREATE, ivpu_cmdq_create_ioctl, 0),
> +     DRM_IOCTL_DEF_DRV(IVPU_CMDQ_DESTROY, ivpu_cmdq_destroy_ioctl, 0),
> +     DRM_IOCTL_DEF_DRV(IVPU_CMDQ_SUBMIT, ivpu_cmdq_submit_ioctl, 0),
>  };
>  
>  static int ivpu_wait_for_ready(struct ivpu_device *vdev)
> diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
> index 98e53cb38ecd..43507d3aea51 100644
> --- a/drivers/accel/ivpu/ivpu_job.c
> +++ b/drivers/accel/ivpu/ivpu_job.c
> @@ -100,15 +100,43 @@ static struct ivpu_cmdq *ivpu_cmdq_alloc(struct 
> ivpu_file_priv *file_priv)
>  
>  static void ivpu_cmdq_free(struct ivpu_file_priv *file_priv, struct 
> ivpu_cmdq *cmdq)
>  {
> -     if (!cmdq)
> -             return;
> -
>       ivpu_preemption_buffers_free(file_priv->vdev, file_priv, cmdq);
>       ivpu_bo_free(cmdq->mem);
> -     xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
>       kfree(cmdq);
>  }
>  
> +static struct ivpu_cmdq *ivpu_cmdq_create(struct ivpu_file_priv *file_priv, 
> u8 priority,
> +                                       bool is_legacy)
> +{
> +     struct ivpu_device *vdev = file_priv->vdev;
> +     struct ivpu_cmdq *cmdq = NULL;
> +     int ret;
> +
> +     lockdep_assert_held(&file_priv->lock);
> +
> +     cmdq = ivpu_cmdq_alloc(file_priv);
> +     if (!cmdq) {
> +             ivpu_err(vdev, "Failed to allocate command queue\n");
> +             return NULL;
> +     }
> +
> +     cmdq->priority = priority;
> +     cmdq->is_legacy = is_legacy;
> +
> +     ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &cmdq->id, cmdq, 
> file_priv->cmdq_limit,
> +                           &file_priv->cmdq_id_next, GFP_KERNEL);
> +     if (ret < 0) {
> +             ivpu_err(vdev, "Failed to allocate command queue ID: %d\n", 
> ret);
> +             goto err_free_cmdq;
> +     }
> +
> +     return cmdq;
> +
> +err_free_cmdq:
> +     ivpu_cmdq_free(file_priv, cmdq);
> +     return NULL;
> +}
> +
>  static int ivpu_hws_cmdq_init(struct ivpu_file_priv *file_priv, struct 
> ivpu_cmdq *cmdq, u16 engine,
>                             u8 priority)
>  {
> @@ -134,6 +162,13 @@ static int ivpu_register_db(struct ivpu_file_priv 
> *file_priv, struct ivpu_cmdq *
>       struct ivpu_device *vdev = file_priv->vdev;
>       int ret;
>  
> +     ret = xa_alloc_cyclic(&vdev->db_xa, &cmdq->db_id, NULL, vdev->db_limit, 
> &vdev->db_next,
> +                           GFP_KERNEL);
> +     if (ret < 0) {
> +             ivpu_err(vdev, "Failed to allocate doorbell ID: %d\n", ret);
> +             return ret;
> +     }
> +
>       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
>               ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, 
> cmdq->id, cmdq->db_id,
>                                              cmdq->mem->vpu_addr, 
> ivpu_bo_size(cmdq->mem));
> @@ -142,41 +177,52 @@ static int ivpu_register_db(struct ivpu_file_priv 
> *file_priv, struct ivpu_cmdq *
>                                          cmdq->mem->vpu_addr, 
> ivpu_bo_size(cmdq->mem));
>  
>       if (!ret)
> -             ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d\n",
> -                      cmdq->db_id, cmdq->id, file_priv->ctx.id);
> +             ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d 
> priority %d\n",
> +                      cmdq->db_id, cmdq->id, file_priv->ctx.id, 
> cmdq->priority);
> +     else
> +             xa_erase(&vdev->db_xa, cmdq->db_id);
>  
>       return ret;
>  }
>  
> -static int
> -ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u8 
> priority)
> +static void ivpu_cmdq_jobq_init(struct ivpu_device *vdev, struct 
> vpu_job_queue *jobq)
> +{
> +     jobq->header.engine_idx = VPU_ENGINE_COMPUTE;
> +     jobq->header.head = 0;
> +     jobq->header.tail = 0;
> +
> +     if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) {
> +             ivpu_dbg(vdev, JOB, "Turbo mode enabled");
> +             jobq->header.flags = VPU_JOB_QUEUE_FLAGS_TURBO_MODE;
> +     }
> +
> +     wmb(); /* Flush WC buffer for jobq->header */
> +}
> +
> +static inline u32 ivpu_cmdq_get_entry_count(struct ivpu_cmdq *cmdq)
> +{
> +     size_t size = ivpu_bo_size(cmdq->mem) - sizeof(struct 
> vpu_job_queue_header);
> +
> +     return size / sizeof(struct vpu_job_queue_entry);
> +}
> +
> +static int ivpu_cmdq_register(struct ivpu_file_priv *file_priv, struct 
> ivpu_cmdq *cmdq)
>  {
>       struct ivpu_device *vdev = file_priv->vdev;
> -     struct vpu_job_queue_header *jobq_header;
>       int ret;
>  
>       lockdep_assert_held(&file_priv->lock);
>  
> -     if (cmdq->db_registered)
> +     if (cmdq->db_id)
>               return 0;
>  
> -     cmdq->entry_count = (u32)((ivpu_bo_size(cmdq->mem) - sizeof(struct 
> vpu_job_queue_header)) /
> -                               sizeof(struct vpu_job_queue_entry));
> -
> +     cmdq->entry_count = ivpu_cmdq_get_entry_count(cmdq);
>       cmdq->jobq = (struct vpu_job_queue *)ivpu_bo_vaddr(cmdq->mem);
> -     jobq_header = &cmdq->jobq->header;
> -     jobq_header->engine_idx = VPU_ENGINE_COMPUTE;
> -     jobq_header->head = 0;
> -     jobq_header->tail = 0;
> -     if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) {
> -             ivpu_dbg(vdev, JOB, "Turbo mode enabled");
> -             jobq_header->flags = VPU_JOB_QUEUE_FLAGS_TURBO_MODE;
> -     }
>  
> -     wmb(); /* Flush WC buffer for jobq->header */
> +     ivpu_cmdq_jobq_init(vdev, cmdq->jobq);
>  
>       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
> -             ret = ivpu_hws_cmdq_init(file_priv, cmdq, VPU_ENGINE_COMPUTE, 
> priority);
> +             ret = ivpu_hws_cmdq_init(file_priv, cmdq, VPU_ENGINE_COMPUTE, 
> cmdq->priority);
>               if (ret)
>                       return ret;
>       }
> @@ -185,23 +231,19 @@ ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct 
> ivpu_cmdq *cmdq, u8 prio
>       if (ret)
>               return ret;
>  
> -     cmdq->db_registered = true;
> -
>       return 0;
>  }
>  
> -static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq 
> *cmdq)
> +static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct 
> ivpu_cmdq *cmdq)
>  {
>       struct ivpu_device *vdev = file_priv->vdev;
>       int ret;
>  
>       lockdep_assert_held(&file_priv->lock);
>  
> -     if (!cmdq->db_registered)
> +     if (!cmdq->db_id)
>               return 0;
>  
> -     cmdq->db_registered = false;
> -
>       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
>               ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, 
> cmdq->id);
>               if (!ret)
> @@ -212,91 +254,61 @@ static int ivpu_cmdq_fini(struct ivpu_file_priv 
> *file_priv, struct ivpu_cmdq *cm
>       if (!ret)
>               ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id);
>  
> +     xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
> +     cmdq->db_id = 0;
> +
>       return 0;
>  }
>  
> -static int ivpu_db_id_alloc(struct ivpu_device *vdev, u32 *db_id)
> +static inline u8 ivpu_job_to_jsm_priority(u8 priority)
>  {
> -     int ret;
> -     u32 id;
> -
> -     ret = xa_alloc_cyclic(&vdev->db_xa, &id, NULL, vdev->db_limit, 
> &vdev->db_next, GFP_KERNEL);
> -     if (ret < 0)
> -             return ret;
> +     if (priority == DRM_IVPU_JOB_PRIORITY_DEFAULT)
> +             return VPU_JOB_SCHEDULING_PRIORITY_BAND_NORMAL;
>  
> -     *db_id = id;
> -     return 0;
> +     return priority - 1;
>  }
>  
> -static int ivpu_cmdq_id_alloc(struct ivpu_file_priv *file_priv, u32 *cmdq_id)
> +static void ivpu_cmdq_destroy(struct ivpu_file_priv *file_priv, struct 
> ivpu_cmdq *cmdq)
>  {
> -     int ret;
> -     u32 id;
> -
> -     ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &id, NULL, 
> file_priv->cmdq_limit,
> -                           &file_priv->cmdq_id_next, GFP_KERNEL);
> -     if (ret < 0)
> -             return ret;
> -
> -     *cmdq_id = id;
> -     return 0;
> +     ivpu_cmdq_unregister(file_priv, cmdq);
> +     xa_erase(&file_priv->cmdq_xa, cmdq->id);
> +     ivpu_cmdq_free(file_priv, cmdq);
>  }
>  
> -static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, 
> u8 priority)
> +static struct ivpu_cmdq *ivpu_cmdq_acquire_legacy(struct ivpu_file_priv 
> *file_priv, u8 priority)
>  {
> -     struct ivpu_device *vdev = file_priv->vdev;
>       struct ivpu_cmdq *cmdq;
>       unsigned long id;
> -     int ret;
>  
>       lockdep_assert_held(&file_priv->lock);
>  
>       xa_for_each(&file_priv->cmdq_xa, id, cmdq)
> -             if (cmdq->priority == priority)
> +             if (cmdq->is_legacy && cmdq->priority == priority)
>                       break;
>  
>       if (!cmdq) {
> -             cmdq = ivpu_cmdq_alloc(file_priv);
> -             if (!cmdq) {
> -                     ivpu_err(vdev, "Failed to allocate command queue\n");
> +             cmdq = ivpu_cmdq_create(file_priv, priority, true);
> +             if (!cmdq)
>                       return NULL;
> -             }
> +     }
>  
> -             ret = ivpu_db_id_alloc(vdev, &cmdq->db_id);
> -             if (ret) {
> -                     ivpu_err(file_priv->vdev, "Failed to allocate doorbell 
> ID: %d\n", ret);
> -                     goto err_free_cmdq;
> -             }
> +     return cmdq;
> +}
>  
> -             ret = ivpu_cmdq_id_alloc(file_priv, &cmdq->id);
> -             if (ret) {
> -                     ivpu_err(vdev, "Failed to allocate command queue ID: 
> %d\n", ret);
> -                     goto err_erase_db_id;
> -             }
> +static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, 
> u32 cmdq_id)
> +{
> +     struct ivpu_device *vdev = file_priv->vdev;
> +     struct ivpu_cmdq *cmdq;
>  
> -             cmdq->priority = priority;
> -             ret = xa_err(xa_store(&file_priv->cmdq_xa, cmdq->id, cmdq, 
> GFP_KERNEL));
> -             if (ret) {
> -                     ivpu_err(vdev, "Failed to store command queue in 
> cmdq_xa: %d\n", ret);
> -                     goto err_erase_cmdq_id;
> -             }
> -     }
> +     lockdep_assert_held(&file_priv->lock);
>  
> -     ret = ivpu_cmdq_init(file_priv, cmdq, priority);
> -     if (ret) {
> -             ivpu_err(vdev, "Failed to initialize command queue: %d\n", ret);
> -             goto err_free_cmdq;
> +     cmdq = xa_load(&file_priv->cmdq_xa, cmdq_id);
> +     if (!cmdq) {
> +             ivpu_err(vdev, "Failed to find command queue with ID: %u\n", 
> cmdq_id);
> +             return NULL;
>       }
>  
>       return cmdq;
> -
> -err_erase_cmdq_id:
> -     xa_erase(&file_priv->cmdq_xa, cmdq->id);
> -err_erase_db_id:
> -     xa_erase(&vdev->db_xa, cmdq->db_id);
> -err_free_cmdq:
> -     ivpu_cmdq_free(file_priv, cmdq);
> -     return NULL;
>  }
>  
>  void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv)
> @@ -306,11 +318,8 @@ void ivpu_cmdq_release_all_locked(struct ivpu_file_priv 
> *file_priv)
>  
>       lockdep_assert_held(&file_priv->lock);
>  
> -     xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) {
> -             xa_erase(&file_priv->cmdq_xa, cmdq_id);
> -             ivpu_cmdq_fini(file_priv, cmdq);
> -             ivpu_cmdq_free(file_priv, cmdq);
> -     }
> +     xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq)
> +             ivpu_cmdq_destroy(file_priv, cmdq);
>  }
>  
>  /*
> @@ -326,8 +335,10 @@ static void ivpu_cmdq_reset(struct ivpu_file_priv 
> *file_priv)
>  
>       mutex_lock(&file_priv->lock);
>  
> -     xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq)
> -             cmdq->db_registered = false;
> +     xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) {
> +             xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
> +             cmdq->db_id = 0;
> +     }
>  
>       mutex_unlock(&file_priv->lock);
>  }
> @@ -345,13 +356,13 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device 
> *vdev)
>       mutex_unlock(&vdev->context_list_lock);
>  }
>  
> -static void ivpu_cmdq_fini_all(struct ivpu_file_priv *file_priv)
> +static void ivpu_cmdq_unregister_all(struct ivpu_file_priv *file_priv)
>  {
>       struct ivpu_cmdq *cmdq;
>       unsigned long cmdq_id;
>  
>       xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq)
> -             ivpu_cmdq_fini(file_priv, cmdq);
> +             ivpu_cmdq_unregister(file_priv, cmdq);
>  }
>  
>  void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv)
> @@ -360,7 +371,7 @@ void ivpu_context_abort_locked(struct ivpu_file_priv 
> *file_priv)
>  
>       lockdep_assert_held(&file_priv->lock);
>  
> -     ivpu_cmdq_fini_all(file_priv);
> +     ivpu_cmdq_unregister_all(file_priv);
>  
>       if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_OS)
>               ivpu_jsm_context_release(vdev, file_priv->ctx.id);
> @@ -549,7 +560,7 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev)
>               ivpu_job_signal_and_destroy(vdev, id, 
> DRM_IVPU_JOB_STATUS_ABORTED);
>  }
>  
> -static int ivpu_job_submit(struct ivpu_job *job, u8 priority)
> +static int ivpu_job_submit(struct ivpu_job *job, u8 priority, u32 cmdq_id)
>  {
>       struct ivpu_file_priv *file_priv = job->file_priv;
>       struct ivpu_device *vdev = job->vdev;
> @@ -563,14 +574,22 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 
> priority)
>  
>       mutex_lock(&file_priv->lock);
>  
> -     cmdq = ivpu_cmdq_acquire(file_priv, priority);
> +     if (cmdq_id == 0)
> +             cmdq = ivpu_cmdq_acquire_legacy(file_priv, priority);
> +     else
> +             cmdq = ivpu_cmdq_acquire(file_priv, cmdq_id);
>       if (!cmdq) {
> -             ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d 
> engine %d prio %d\n",
> -                                   file_priv->ctx.id, job->engine_idx, 
> priority);
> +             ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx 
> %d\n", file_priv->ctx.id);
>               ret = -EINVAL;
>               goto err_unlock_file_priv;
>       }
>  
> +     ret = ivpu_cmdq_register(file_priv, cmdq);
> +     if (ret) {
> +             ivpu_err(vdev, "Failed to register command queue: %d\n", ret);
> +             goto err_unlock_file_priv;
> +     }
> +
>       xa_lock(&vdev->submitted_jobs_xa);
>       is_first_job = xa_empty(&vdev->submitted_jobs_xa);
>       ret = __xa_alloc_cyclic(&vdev->submitted_jobs_xa, &job->job_id, job, 
> file_priv->job_limit,
> @@ -599,7 +618,7 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 
> priority)
>  
>       trace_job("submit", job);
>       ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d prio %d 
> addr 0x%llx next %d\n",
> -              job->job_id, file_priv->ctx.id, job->engine_idx, priority,
> +              job->job_id, file_priv->ctx.id, job->engine_idx, 
> cmdq->priority,
>                job->cmd_buf_vpu_addr, cmdq->jobq->header.tail);
>  
>       xa_unlock(&vdev->submitted_jobs_xa);
> @@ -625,7 +644,7 @@ static int
>  ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, 
> u32 *buf_handles,
>                               u32 buf_count, u32 commands_offset)
>  {
> -     struct ivpu_file_priv *file_priv = file->driver_priv;
> +     struct ivpu_file_priv *file_priv = job->file_priv;
>       struct ivpu_device *vdev = file_priv->vdev;
>       struct ww_acquire_ctx acquire_ctx;
>       enum dma_resv_usage usage;
> @@ -687,49 +706,20 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, 
> struct ivpu_job *job, u32
>       return ret;
>  }
>  
> -static inline u8 ivpu_job_to_hws_priority(struct ivpu_file_priv *file_priv, 
> u8 priority)
> +static int ivpu_submit(struct drm_file *file, struct ivpu_file_priv 
> *file_priv, u32 cmdq_id,
> +                    u32 buffer_count, u32 engine, void __user *buffers_ptr, 
> u32 cmds_offset,
> +                    u8 priority)
>  {
> -     if (priority == DRM_IVPU_JOB_PRIORITY_DEFAULT)
> -             return DRM_IVPU_JOB_PRIORITY_NORMAL;
> -
> -     return priority - 1;
> -}
> -
> -int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file 
> *file)
> -{
> -     struct ivpu_file_priv *file_priv = file->driver_priv;
>       struct ivpu_device *vdev = file_priv->vdev;
> -     struct drm_ivpu_submit *params = data;
>       struct ivpu_job *job;
>       u32 *buf_handles;
>       int idx, ret;
> -     u8 priority;
> -
> -     if (params->engine != DRM_IVPU_ENGINE_COMPUTE)
> -             return -EINVAL;
> -
> -     if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
> -             return -EINVAL;
> -
> -     if (params->buffer_count == 0 || params->buffer_count > 
> JOB_MAX_BUFFER_COUNT)
> -             return -EINVAL;
> -
> -     if (!IS_ALIGNED(params->commands_offset, 8))
> -             return -EINVAL;
>  
> -     if (!file_priv->ctx.id)
> -             return -EINVAL;
> -
> -     if (file_priv->has_mmu_faults)
> -             return -EBADFD;
> -
> -     buf_handles = kcalloc(params->buffer_count, sizeof(u32), GFP_KERNEL);
> +     buf_handles = kcalloc(buffer_count, sizeof(u32), GFP_KERNEL);
>       if (!buf_handles)
>               return -ENOMEM;
>  
> -     ret = copy_from_user(buf_handles,
> -                          (void __user *)params->buffers_ptr,
> -                          params->buffer_count * sizeof(u32));
> +     ret = copy_from_user(buf_handles, buffers_ptr, buffer_count * 
> sizeof(u32));
>       if (ret) {
>               ret = -EFAULT;
>               goto err_free_handles;
> @@ -740,27 +730,23 @@ int ivpu_submit_ioctl(struct drm_device *dev, void 
> *data, struct drm_file *file)
>               goto err_free_handles;
>       }
>  
> -     ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n",
> -              file_priv->ctx.id, params->buffer_count);
> +     ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n", 
> file_priv->ctx.id, buffer_count);
>  
> -     job = ivpu_job_create(file_priv, params->engine, params->buffer_count);
> +     job = ivpu_job_create(file_priv, engine, buffer_count);
>       if (!job) {
>               ivpu_err(vdev, "Failed to create job\n");
>               ret = -ENOMEM;
>               goto err_exit_dev;
>       }
>  
> -     ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, 
> params->buffer_count,
> -                                           params->commands_offset);
> +     ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, 
> buffer_count, cmds_offset);
>       if (ret) {
>               ivpu_err(vdev, "Failed to prepare job: %d\n", ret);
>               goto err_destroy_job;
>       }
>  
> -     priority = ivpu_job_to_hws_priority(file_priv, params->priority);
> -
>       down_read(&vdev->pm->reset_lock);
> -     ret = ivpu_job_submit(job, priority);
> +     ret = ivpu_job_submit(job, priority, cmdq_id);
>       up_read(&vdev->pm->reset_lock);
>       if (ret)
>               goto err_signal_fence;
> @@ -780,6 +766,101 @@ int ivpu_submit_ioctl(struct drm_device *dev, void 
> *data, struct drm_file *file)
>       return ret;
>  }
>  
> +int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file 
> *file)
> +{
> +     struct ivpu_file_priv *file_priv = file->driver_priv;
> +     struct drm_ivpu_submit *args = data;
> +     u8 priority;
> +
> +     if (args->engine != DRM_IVPU_ENGINE_COMPUTE)
> +             return -EINVAL;
> +
> +     if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
> +             return -EINVAL;
> +
> +     if (args->buffer_count == 0 || args->buffer_count > 
> JOB_MAX_BUFFER_COUNT)
> +             return -EINVAL;
> +
> +     if (!IS_ALIGNED(args->commands_offset, 8))
> +             return -EINVAL;
> +
> +     if (!file_priv->ctx.id)
> +             return -EINVAL;
> +
> +     if (file_priv->has_mmu_faults)
> +             return -EBADFD;
> +
> +     priority = ivpu_job_to_jsm_priority(args->priority);
> +
> +     return ivpu_submit(file, file_priv, 0, args->buffer_count, args->engine,
> +                        (void __user *)args->buffers_ptr, 
> args->commands_offset, priority);
> +}
> +
> +int ivpu_cmdq_submit_ioctl(struct drm_device *dev, void *data, struct 
> drm_file *file)
> +{
> +     struct ivpu_file_priv *file_priv = file->driver_priv;
> +     struct drm_ivpu_cmdq_submit *args = data;
> +
> +     if (args->cmdq_id < IVPU_CMDQ_MIN_ID || args->cmdq_id > 
> IVPU_CMDQ_MAX_ID)
> +             return -EINVAL;
> +
> +     if (args->buffer_count == 0 || args->buffer_count > 
> JOB_MAX_BUFFER_COUNT)
> +             return -EINVAL;
> +
> +     if (!IS_ALIGNED(args->commands_offset, 8))
> +             return -EINVAL;
> +
> +     if (!file_priv->ctx.id)
> +             return -EINVAL;
> +
> +     if (file_priv->has_mmu_faults)
> +             return -EBADFD;
> +
> +     return ivpu_submit(file, file_priv, args->cmdq_id, args->buffer_count, 
> VPU_ENGINE_COMPUTE,
> +                        (void __user *)args->buffers_ptr, 
> args->commands_offset, 0);
> +}
> +
> +int ivpu_cmdq_create_ioctl(struct drm_device *dev, void *data, struct 
> drm_file *file)
> +{
> +     struct ivpu_file_priv *file_priv = file->driver_priv;
> +     struct drm_ivpu_cmdq_create *args = data;
> +     struct ivpu_cmdq *cmdq;
> +
> +     if (args->priority > DRM_IVPU_JOB_PRIORITY_REALTIME)
> +             return -EINVAL;
> +
> +     mutex_lock(&file_priv->lock);
> +
> +     cmdq = ivpu_cmdq_create(file_priv, 
> ivpu_job_to_jsm_priority(args->priority), false);
> +     if (cmdq)
> +             args->cmdq_id = cmdq->id;
> +
> +     mutex_unlock(&file_priv->lock);
> +
> +     return cmdq ? 0 : -ENOMEM;
> +}
> +
> +int ivpu_cmdq_destroy_ioctl(struct drm_device *dev, void *data, struct 
> drm_file *file)
> +{
> +     struct ivpu_file_priv *file_priv = file->driver_priv;
> +     struct drm_ivpu_cmdq_destroy *args = data;
> +     struct ivpu_cmdq *cmdq;
> +     int ret = 0;
> +
> +     mutex_lock(&file_priv->lock);
> +
> +     cmdq = xa_load(&file_priv->cmdq_xa, args->cmdq_id);
> +     if (!cmdq || cmdq->is_legacy) {
> +             ret = -ENOENT;
> +             goto unlock;
> +     }
> +
> +     ivpu_cmdq_destroy(file_priv, cmdq);
> +unlock:
> +     mutex_unlock(&file_priv->lock);
> +     return ret;
> +}
> +
>  static void
>  ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr 
> *ipc_hdr,
>                      struct vpu_jsm_msg *jsm_msg)
> diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h
> index 8b19e3f8b4cf..4d31277bcc41 100644
> --- a/drivers/accel/ivpu/ivpu_job.h
> +++ b/drivers/accel/ivpu/ivpu_job.h
> @@ -30,8 +30,8 @@ struct ivpu_cmdq {
>       u32 entry_count;
>       u32 id;
>       u32 db_id;
> -     bool db_registered;
>       u8 priority;
> +     bool is_legacy;
>  };
>  
>  /**
> @@ -58,6 +58,9 @@ struct ivpu_job {
>  };
>  
>  int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file 
> *file);
> +int ivpu_cmdq_create_ioctl(struct drm_device *dev, void *data, struct 
> drm_file *file);
> +int ivpu_cmdq_destroy_ioctl(struct drm_device *dev, void *data, struct 
> drm_file *file);
> +int ivpu_cmdq_submit_ioctl(struct drm_device *dev, void *data, struct 
> drm_file *file);
>  
>  void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv);
>  
> diff --git a/include/uapi/drm/ivpu_accel.h b/include/uapi/drm/ivpu_accel.h
> index a35b97b097bf..746c43bd3eb6 100644
> --- a/include/uapi/drm/ivpu_accel.h
> +++ b/include/uapi/drm/ivpu_accel.h
> @@ -22,6 +22,9 @@ extern "C" {
>  #define DRM_IVPU_METRIC_STREAMER_STOP          0x08
>  #define DRM_IVPU_METRIC_STREAMER_GET_DATA 0x09
>  #define DRM_IVPU_METRIC_STREAMER_GET_INFO 0x0a
> +#define DRM_IVPU_CMDQ_CREATE              0x0b
> +#define DRM_IVPU_CMDQ_DESTROY             0x0c
> +#define DRM_IVPU_CMDQ_SUBMIT              0x0d
>  
>  #define DRM_IOCTL_IVPU_GET_PARAM                                             
>   \
>       DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_GET_PARAM, struct drm_ivpu_param)
> @@ -57,6 +60,15 @@ extern "C" {
>       DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_METRIC_STREAMER_GET_INFO,         \
>                struct drm_ivpu_metric_streamer_get_data)
>  
> +#define DRM_IOCTL_IVPU_CMDQ_CREATE                                           
>   \
> +     DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_CMDQ_CREATE, struct 
> drm_ivpu_cmdq_create)
> +
> +#define DRM_IOCTL_IVPU_CMDQ_DESTROY                                          
>   \
> +     DRM_IOW(DRM_COMMAND_BASE + DRM_IVPU_CMDQ_DESTROY, struct 
> drm_ivpu_cmdq_destroy)
> +
> +#define DRM_IOCTL_IVPU_CMDQ_SUBMIT                                           
>   \
> +     DRM_IOW(DRM_COMMAND_BASE + DRM_IVPU_CMDQ_SUBMIT, struct 
> drm_ivpu_cmdq_submit)
> +
>  /**
>   * DOC: contexts
>   *
> @@ -107,6 +119,13 @@ extern "C" {
>   * accessible by hardware DMA.
>   */
>  #define DRM_IVPU_CAP_DMA_MEMORY_RANGE        2
> +/**
> + * DRM_IVPU_CAP_MANAGE_CMDQ
> + *
> + * Driver supports explicit command queue operations like command queue 
> create,
> + * command queue destroy and submit job on specific command queue.
> + */
> +#define DRM_IVPU_CAP_MANAGE_CMDQ       3
>  
>  /**
>   * struct drm_ivpu_param - Get/Set VPU parameters
> @@ -316,6 +335,44 @@ struct drm_ivpu_submit {
>       __u32 priority;
>  };
>  
> +/**
> + * struct drm_ivpu_cmdq_submit - Submit commands to the VPU using explicit 
> command queue
> + *
> + * Execute a single command buffer on a given command queue.
> + * Handles to all referenced buffer objects have to be provided in 
> @buffers_ptr.
> + *
> + * User space may wait on job completion using %DRM_IVPU_BO_WAIT ioctl.
> + */
> +struct drm_ivpu_cmdq_submit {
> +     /**
> +      * @buffers_ptr:
> +      *
> +      * A pointer to an u32 array of GEM handles of the BOs required for 
> this job.
> +      * The number of elements in the array must be equal to the value given 
> by @buffer_count.
> +      *
> +      * The first BO is the command buffer. The rest of array has to contain 
> all
> +      * BOs referenced from the command buffer.
> +      */
> +     __u64 buffers_ptr;
> +
> +     /** @buffer_count: Number of elements in the @buffers_ptr */
> +     __u32 buffer_count;
> +
> +     /** @cmdq_id: ID for the command queue where job will be submitted */
> +     __u32 cmdq_id;
> +
> +     /** @flags: Reserved for future use - must be zero */
> +     __u32 flags;
> +
> +     /**
> +      * @commands_offset:
> +      *
> +      * Offset inside the first buffer in @buffers_ptr containing commands
> +      * to be executed. The offset has to be 8-byte aligned.
> +      */
> +     __u32 commands_offset;
> +};
> +
>  /* drm_ivpu_bo_wait job status codes */
>  #define DRM_IVPU_JOB_STATUS_SUCCESS 0
>  #define DRM_IVPU_JOB_STATUS_ABORTED 256
> @@ -388,6 +445,33 @@ struct drm_ivpu_metric_streamer_get_data {
>       __u64 data_size;
>  };
>  
> +/**
> + * struct drm_ivpu_cmdq_create - Create command queue for job submission
> + */
> +struct drm_ivpu_cmdq_create {
> +     /** @cmdq_id: Returned ID of created command queue */
> +     __u32 cmdq_id;
> +     /**
> +      * @priority:
> +      *
> +      * Priority to be set for related job command queue, can be one of the 
> following:
> +      * %DRM_IVPU_JOB_PRIORITY_DEFAULT
> +      * %DRM_IVPU_JOB_PRIORITY_IDLE
> +      * %DRM_IVPU_JOB_PRIORITY_NORMAL
> +      * %DRM_IVPU_JOB_PRIORITY_FOCUS
> +      * %DRM_IVPU_JOB_PRIORITY_REALTIME
> +      */
> +     __u32 priority;
> +};
> +
> +/**
> + * struct drm_ivpu_cmdq_destroy - Destroy a command queue
> + */
> +struct drm_ivpu_cmdq_destroy {
> +     /** @cmdq_id: ID of command queue to destroy */
> +     __u32 cmdq_id;
> +};
> +
>  /**
>   * struct drm_ivpu_metric_streamer_stop - Stop collecting metric data
>   */

Reply via email to