On 9/16/2025 5:29 PM, Lizhi Hou wrote:
>
> On 9/16/25 01:25, Karol Wachowski wrote:
>> On 9/15/2025 10:33 PM, Lizhi Hou wrote:
>>> On 9/15/25 03:34, Karol Wachowski wrote:
>>>> From: Andrzej Kacprowski <[email protected]>
>>>>
>>>> Allow user mode drivers to manage preemption buffers, enabling
>>>> memory savings by sharing a single buffer across multiple
>>>> command queues within the same memory context.
>>>>
>>>> Introduce DRM_IVPU_PARAM_PREEMPT_BUFFER_SIZE to report the required
>>>> preemption buffer size as specified by the firmware.
>>>>
>>>> The preemption buffer is now passed from user space as an entry
>>>> in the BO list of DRM_IVPU_CMDQ_SUBMIT. The buffer must be
>>>> non-mappable and large enough to hold preemption data.
>>>>
>>>> For backward compatibility, the kernel will allocate an internal
>>>> preemption buffer if user space does not provide one.
>>>>
>>>> User space can only provide a single preemption buffer,
>>>> simplifying the ioctl interface and parameter validation.
>>>> A separate secondary preemption buffer is only needed
>>>> to save below 4GB address space on 37xx and only if preemption
>>>> buffers are not shared.
>>>>
>>>> Signed-off-by: Andrzej Kacprowski <[email protected]>
>>>> Signed-off-by: Karol Wachowski <[email protected]>
>>>> ---
>>>>    drivers/accel/ivpu/ivpu_drv.c |  3 ++
>>>>    drivers/accel/ivpu/ivpu_fw.c  | 57 +++++++++++++++++----
>>>>    drivers/accel/ivpu/ivpu_fw.h  |  7 ++-
>>>>    drivers/accel/ivpu/ivpu_gem.h |  7 ++-
>>>>    drivers/accel/ivpu/ivpu_job.c | 96
>>>> ++++++++++++++++++++++++-----------
>>>>    drivers/accel/ivpu/ivpu_job.h |  4 +-
>>>>    include/uapi/drm/ivpu_accel.h | 11 ++++
>>>>    7 files changed, 141 insertions(+), 44 deletions(-)
>>>>
>>>> diff --git a/drivers/accel/ivpu/ivpu_drv.c
>>>> b/drivers/accel/ivpu/ivpu_drv.c
>>>> index 3d6d52492536..61c4f627c7c7 100644
>>>> --- a/drivers/accel/ivpu/ivpu_drv.c
>>>> +++ b/drivers/accel/ivpu/ivpu_drv.c
>>>> @@ -200,6 +200,9 @@ static int ivpu_get_param_ioctl(struct drm_device
>>>> *dev, void *data, struct drm_f
>>>>        case DRM_IVPU_PARAM_CAPABILITIES:
>>>>            args->value = ivpu_is_capable(vdev, args->index);
>>>>            break;
>>>> +    case DRM_IVPU_PARAM_PREEMPT_BUFFER_SIZE:
>>>> +        args->value = ivpu_fw_preempt_buf_size(vdev);
>>>> +        break;
>>>>        default:
>>>>            ret = -EINVAL;
>>>>            break;
>>>> diff --git a/drivers/accel/ivpu/ivpu_fw.c
>>>> b/drivers/accel/ivpu/ivpu_fw.c
>>>> index 9db741695401..6e0941d324a8 100644
>>>> --- a/drivers/accel/ivpu/ivpu_fw.c
>>>> +++ b/drivers/accel/ivpu/ivpu_fw.c
>>>> @@ -26,6 +26,8 @@
>>>>    #define FW_RUNTIME_MIN_ADDR    (FW_GLOBAL_MEM_START)
>>>>    #define FW_RUNTIME_MAX_ADDR    (FW_GLOBAL_MEM_END -
>>>> FW_SHARED_MEM_SIZE)
>>>>    #define FW_FILE_IMAGE_OFFSET    (VPU_FW_HEADER_SIZE +
>>>> FW_VERSION_HEADER_SIZE)
>>>> +#define FW_PREEMPT_BUF_MIN_SIZE SZ_4K
>>>> +#define FW_PREEMPT_BUF_MAX_SIZE SZ_32M
>>>>      #define WATCHDOG_MSS_REDIRECT    32
>>>>    #define WATCHDOG_NCE_REDIRECT    33
>>>> @@ -151,6 +153,47 @@ ivpu_fw_sched_mode_select(struct ivpu_device
>>>> *vdev, const struct vpu_firmware_he
>>>>        return VPU_SCHEDULING_MODE_HW;
>>>>    }
>>>>    +static void
>>>> +ivpu_preemption_config_parse(struct ivpu_device *vdev, const struct
>>>> vpu_firmware_header *fw_hdr)
>>>> +{
>>>> +    struct ivpu_fw_info *fw = vdev->fw;
>>>> +    u32 primary_preempt_buf_size, secondary_preempt_buf_size;
>>>> +
>>>> +    if (fw_hdr->preemption_buffer_1_max_size)
>>>> +        primary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_1_max_size;
>>>> +    else
>>>> +        primary_preempt_buf_size = fw_hdr->preemption_buffer_1_size;
>>>> +
>>>> +    if (fw_hdr->preemption_buffer_2_max_size)
>>>> +        secondary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_2_max_size;
>>>> +    else
>>>> +        secondary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_2_size;
>>>> +
>>>> +    ivpu_dbg(vdev, FW_BOOT, "Preemption buffer size, primary: %u,
>>>> secondary: %u\n",
>>>> +         primary_preempt_buf_size, secondary_preempt_buf_size);
>>>> +
>>>> +    if (primary_preempt_buf_size < FW_PREEMPT_BUF_MIN_SIZE ||
>>>> +        secondary_preempt_buf_size < FW_PREEMPT_BUF_MIN_SIZE) {
>>>> +        ivpu_warn(vdev, "Preemption buffers size too small\n");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    if (primary_preempt_buf_size > FW_PREEMPT_BUF_MAX_SIZE ||
>>>> +        secondary_preempt_buf_size > FW_PREEMPT_BUF_MAX_SIZE) {
>>>> +        ivpu_warn(vdev, "Preemption buffers size too big\n");
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    if (fw->sched_mode != VPU_SCHEDULING_MODE_HW)
>>>> +        return;
>>>> +
>>>> +    if (ivpu_test_mode & IVPU_TEST_MODE_MIP_DISABLE)
>>>> +        return;
>>>> +
>>>> +    vdev->fw->primary_preempt_buf_size =
>>>> ALIGN(primary_preempt_buf_size, PAGE_SIZE);
>>>> +    vdev->fw->secondary_preempt_buf_size =
>>>> ALIGN(secondary_preempt_buf_size, PAGE_SIZE);
>>>> +}
>>>> +
>>>>    static int ivpu_fw_parse(struct ivpu_device *vdev)
>>>>    {
>>>>        struct ivpu_fw_info *fw = vdev->fw;
>>>> @@ -235,17 +278,9 @@ static int ivpu_fw_parse(struct ivpu_device
>>>> *vdev)
>>>>        fw->sched_mode = ivpu_fw_sched_mode_select(vdev, fw_hdr);
>>>>        ivpu_info(vdev, "Scheduler mode: %s\n", fw->sched_mode ? "HW" :
>>>> "OS");
>>>>    -    if (fw_hdr->preemption_buffer_1_max_size)
>>>> -        fw->primary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_1_max_size;
>>>> -    else
>>>> -        fw->primary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_1_size;
>>>> -
>>>> -    if (fw_hdr->preemption_buffer_2_max_size)
>>>> -        fw->secondary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_2_max_size;
>>>> -    else
>>>> -        fw->secondary_preempt_buf_size =
>>>> fw_hdr->preemption_buffer_2_size;
>>>> -    ivpu_dbg(vdev, FW_BOOT, "Preemption buffer sizes: primary %u,
>>>> secondary %u\n",
>>>> -         fw->primary_preempt_buf_size,
>>>> fw->secondary_preempt_buf_size);
>>>> +    ivpu_preemption_config_parse(vdev, fw_hdr);
>>>> +    ivpu_dbg(vdev, FW_BOOT, "Mid-inference preemption %s
>>>> supported\n",
>>>> +         ivpu_fw_preempt_buf_size(vdev) ? "is" : "is not");
>>>>          if (fw_hdr->ro_section_start_address &&
>>>> !is_within_range(fw_hdr->ro_section_start_address,
>>>>                                     fw_hdr->ro_section_size,
>>>> diff --git a/drivers/accel/ivpu/ivpu_fw.h
>>>> b/drivers/accel/ivpu/ivpu_fw.h
>>>> index 7081913fb0dd..6fe2917abda6 100644
>>>> --- a/drivers/accel/ivpu/ivpu_fw.h
>>>> +++ b/drivers/accel/ivpu/ivpu_fw.h
>>>> @@ -1,6 +1,6 @@
>>>>    /* SPDX-License-Identifier: GPL-2.0-only */
>>>>    /*
>>>> - * Copyright (C) 2020-2024 Intel Corporation
>>>> + * Copyright (C) 2020-2025 Intel Corporation
>>>>     */
>>>>      #ifndef __IVPU_FW_H__
>>>> @@ -52,4 +52,9 @@ static inline bool ivpu_fw_is_cold_boot(struct
>>>> ivpu_device *vdev)
>>>>        return vdev->fw->entry_point ==
>>>> vdev->fw->cold_boot_entry_point;
>>>>    }
>>>>    +static inline u32 ivpu_fw_preempt_buf_size(struct ivpu_device
>>>> *vdev)
>>>> +{
>>>> +    return vdev->fw->primary_preempt_buf_size +
>>>> vdev->fw->secondary_preempt_buf_size;
>>>> +}
>>>> +
>>>>    #endif /* __IVPU_FW_H__ */
>>>> diff --git a/drivers/accel/ivpu/ivpu_gem.h
>>>> b/drivers/accel/ivpu/ivpu_gem.h
>>>> index aa8ff14f7aae..3ee996d503b2 100644
>>>> --- a/drivers/accel/ivpu/ivpu_gem.h
>>>> +++ b/drivers/accel/ivpu/ivpu_gem.h
>>>> @@ -1,6 +1,6 @@
>>>>    /* SPDX-License-Identifier: GPL-2.0-only */
>>>>    /*
>>>> - * Copyright (C) 2020-2023 Intel Corporation
>>>> + * Copyright (C) 2020-2025 Intel Corporation
>>>>     */
>>>>    #ifndef __IVPU_GEM_H__
>>>>    #define __IVPU_GEM_H__
>>>> @@ -96,4 +96,9 @@ static inline u32 cpu_to_vpu_addr(struct ivpu_bo
>>>> *bo, void *cpu_addr)
>>>>        return bo->vpu_addr + (cpu_addr - ivpu_bo_vaddr(bo));
>>>>    }
>>>>    +static inline bool ivpu_bo_is_mappable(struct ivpu_bo *bo)
>>>> +{
>>>> +    return bo->flags & DRM_IVPU_BO_MAPPABLE;
>>>> +}
>>>> +
>>>>    #endif /* __IVPU_GEM_H__ */
>>>> diff --git a/drivers/accel/ivpu/ivpu_job.c
>>>> b/drivers/accel/ivpu/ivpu_job.c
>>>> index fa1720fa06a4..521b7ac6e35e 100644
>>>> --- a/drivers/accel/ivpu/ivpu_job.c
>>>> +++ b/drivers/accel/ivpu/ivpu_job.c
>>>> @@ -34,22 +34,20 @@ static void ivpu_cmdq_ring_db(struct ivpu_device
>>>> *vdev, struct ivpu_cmdq *cmdq)
>>>>    static int ivpu_preemption_buffers_create(struct ivpu_device *vdev,
>>>>                          struct ivpu_file_priv *file_priv, struct
>>>> ivpu_cmdq *cmdq)
>>>>    {
>>>> -    u64 primary_size = ALIGN(vdev->fw->primary_preempt_buf_size,
>>>> PAGE_SIZE);
>>>> -    u64 secondary_size = ALIGN(vdev->fw->secondary_preempt_buf_size,
>>>> PAGE_SIZE);
>>>> -
>>>> -    if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW ||
>>>> -        ivpu_test_mode & IVPU_TEST_MODE_MIP_DISABLE)
>>>> +    if (ivpu_fw_preempt_buf_size(vdev) == 0)
>>>>            return 0;
>>>>          cmdq->primary_preempt_buf = ivpu_bo_create(vdev,
>>>> &file_priv->ctx, &vdev->hw->ranges.user,
>>>> -                           primary_size, DRM_IVPU_BO_WC);
>>>> +                           vdev->fw->primary_preempt_buf_size,
>>>> +                           DRM_IVPU_BO_WC);
>>> Could vdev->fw->primary_preempt_buf_size be zero?
>> This can be zero and zero is intended to indicate that preemption
>> buffers are disabled and should not be allocated by the driver.
>>> ivpu_fw_preempt_buf_size(vdev) make sure primary+secondary is not zero.
>> Either of them or both can be zero. In case of both of them being zero
>> function returns early not allocating any of the buffers.
>
> ivpu_bo_create will generate a warning stack if size is zero. So just
> checking if both are zero is not good enough. 
Thank you for your feedback. I apologize for my earlier inaccurate
statement regarding the possibility of zeroing the buffers separately.
To clarify, the driver ensures that both preemption buffer sizes are
either non-zero or both zero. This is already handled during the
firmware header parsing, 
specifically in the ivpu_preemption_config_parse() function. 
That function guarantees that both preemption buffer sizes are set to
non-zero values together, or both are explicitly set to zero.
Therefore, whenever ivpu_preemption_buffers_create() is invoked, both
buffers are either allocated with non-zero sizes or not allocated at all. 
Adding individual checks within this function would reduce readability,
as we only ever allocate both buffers together or neither.

Thanks,
Karol
>
> Lizhi
>
>>
>> Best regards,
>>
>> Karol
>>
>>> Lizhi
>>>
>>>>        if (!cmdq->primary_preempt_buf) {
>>>>            ivpu_err(vdev, "Failed to create primary preemption
>>>> buffer\n");
>>>>            return -ENOMEM;
>>>>        }
>>>>          cmdq->secondary_preempt_buf = ivpu_bo_create(vdev,
>>>> &file_priv->ctx, &vdev->hw->ranges.dma,
>>>> -                             secondary_size, DRM_IVPU_BO_WC);
>>>> +                             vdev->fw->secondary_preempt_buf_size,
>>>> +                             DRM_IVPU_BO_WC);
>>>>        if (!cmdq->secondary_preempt_buf) {
>>>>            ivpu_err(vdev, "Failed to create secondary preemption
>>>> buffer\n");
>>>>            goto err_free_primary;
>>>> @@ -66,20 +64,39 @@ static int ivpu_preemption_buffers_create(struct
>>>> ivpu_device *vdev,
>>>>    static void ivpu_preemption_buffers_free(struct ivpu_device *vdev,
>>>>                         struct ivpu_file_priv *file_priv, struct
>>>> ivpu_cmdq *cmdq)
>>>>    {
>>>> -    if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW)
>>>> -        return;
>>>> -
>>>>        if (cmdq->primary_preempt_buf)
>>>>            ivpu_bo_free(cmdq->primary_preempt_buf);
>>>>        if (cmdq->secondary_preempt_buf)
>>>>            ivpu_bo_free(cmdq->secondary_preempt_buf);
>>>>    }
>>>>    +static int ivpu_preemption_job_init(struct ivpu_device *vdev,
>>>> struct ivpu_file_priv *file_priv,
>>>> +                    struct ivpu_cmdq *cmdq, struct ivpu_job *job)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    /* Use preemption buffer provided by the user space */
>>>> +    if (job->primary_preempt_buf)
>>>> +        return 0;
>>>> +
>>>> +    if (!cmdq->primary_preempt_buf) {
>>>> +        /* Allocate per command queue preemption buffers */
>>>> +        ret = ivpu_preemption_buffers_create(vdev, file_priv, cmdq);
>>>> +        if (ret)
>>>> +            return ret;
>>>> +    }
>>>> +
>>>> +    /* Use preemption buffers allocated by the kernel */
>>>> +    job->primary_preempt_buf = cmdq->primary_preempt_buf;
>>>> +    job->secondary_preempt_buf = cmdq->secondary_preempt_buf;
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>>    static struct ivpu_cmdq *ivpu_cmdq_alloc(struct ivpu_file_priv
>>>> *file_priv)
>>>>    {
>>>>        struct ivpu_device *vdev = file_priv->vdev;
>>>>        struct ivpu_cmdq *cmdq;
>>>> -    int ret;
>>>>          cmdq = kzalloc(sizeof(*cmdq), GFP_KERNEL);
>>>>        if (!cmdq)
>>>> @@ -89,10 +106,6 @@ static struct ivpu_cmdq *ivpu_cmdq_alloc(struct
>>>> ivpu_file_priv *file_priv)
>>>>        if (!cmdq->mem)
>>>>            goto err_free_cmdq;
>>>>    -    ret = ivpu_preemption_buffers_create(vdev, file_priv, cmdq);
>>>> -    if (ret)
>>>> -        ivpu_warn(vdev, "Failed to allocate preemption buffers,
>>>> preemption limited\n");
>>>> -
>>>>        return cmdq;
>>>>      err_free_cmdq:
>>>> @@ -429,17 +442,14 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq
>>>> *cmdq, struct ivpu_job *job)
>>>>        if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION))
>>>>            entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK;
>>>>    -    if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
>>>> -        if (cmdq->primary_preempt_buf) {
>>>> -            entry->primary_preempt_buf_addr =
>>>> cmdq->primary_preempt_buf->vpu_addr;
>>>> -            entry->primary_preempt_buf_size =
>>>> ivpu_bo_size(cmdq->primary_preempt_buf);
>>>> -        }
>>>> +    if (job->primary_preempt_buf) {
>>>> +        entry->primary_preempt_buf_addr =
>>>> job->primary_preempt_buf->vpu_addr;
>>>> +        entry->primary_preempt_buf_size =
>>>> ivpu_bo_size(job->primary_preempt_buf);
>>>> +    }
>>>>    -        if (cmdq->secondary_preempt_buf) {
>>>> -            entry->secondary_preempt_buf_addr =
>>>> cmdq->secondary_preempt_buf->vpu_addr;
>>>> -            entry->secondary_preempt_buf_size =
>>>> -                ivpu_bo_size(cmdq->secondary_preempt_buf);
>>>> -        }
>>>> +    if (job->secondary_preempt_buf) {
>>>> +        entry->secondary_preempt_buf_addr =
>>>> job->secondary_preempt_buf->vpu_addr;
>>>> +        entry->secondary_preempt_buf_size =
>>>> ivpu_bo_size(job->secondary_preempt_buf);
>>>>        }
>>>>          wmb(); /* Ensure that tail is updated after filling entry */
>>>> @@ -663,6 +673,13 @@ static int ivpu_job_submit(struct ivpu_job *job,
>>>> u8 priority, u32 cmdq_id)
>>>>            goto err_unlock;
>>>>        }
>>>>    +    ret = ivpu_preemption_job_init(vdev, file_priv, cmdq, job);
>>>> +    if (ret) {
>>>> +        ivpu_err(vdev, "Failed to initialize preemption buffers for
>>>> job %d: %d\n",
>>>> +             job->job_id, ret);
>>>> +        goto err_unlock;
>>>> +    }
>>>> +
>>>>        job->cmdq_id = cmdq->id;
>>>>          is_first_job = xa_empty(&vdev->submitted_jobs_xa);
>>>> @@ -716,7 +733,7 @@ static int ivpu_job_submit(struct ivpu_job *job,
>>>> u8 priority, u32 cmdq_id)
>>>>      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)
>>>> +                u32 buf_count, u32 commands_offset, u32
>>>> preempt_buffer_index)
>>>>    {
>>>>        struct ivpu_file_priv *file_priv = job->file_priv;
>>>>        struct ivpu_device *vdev = file_priv->vdev;
>>>> @@ -752,6 +769,20 @@ ivpu_job_prepare_bos_for_submit(struct drm_file
>>>> *file, struct ivpu_job *job, u32
>>>>          job->cmd_buf_vpu_addr = bo->vpu_addr + commands_offset;
>>>>    +    if (preempt_buffer_index) {
>>>> +        struct ivpu_bo *preempt_bo = job->bos[preempt_buffer_index];
>>>> +
>>>> +        if (ivpu_bo_size(preempt_bo) <
>>>> ivpu_fw_preempt_buf_size(vdev)) {
>>>> +            ivpu_warn(vdev, "Preemption buffer is too small\n");
>>>> +            return -EINVAL;
>>>> +        }
>>>> +        if (ivpu_bo_is_mappable(preempt_bo)) {
>>>> +            ivpu_warn(vdev, "Preemption buffer cannot be
>>>> mappable\n");
>>>> +            return -EINVAL;
>>>> +        }
>>>> +        job->primary_preempt_buf = preempt_bo;
>>>> +    }
>>>> +
>>>>        ret = drm_gem_lock_reservations((struct drm_gem_object
>>>> **)job->bos, buf_count,
>>>>                        &acquire_ctx);
>>>>        if (ret) {
>>>> @@ -782,7 +813,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file
>>>> *file, struct ivpu_job *job, u32
>>>>      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)
>>>> +               u32 preempt_buffer_index, u8 priority)
>>>>    {
>>>>        struct ivpu_device *vdev = file_priv->vdev;
>>>>        struct ivpu_job *job;
>>>> @@ -814,7 +845,8 @@ static int ivpu_submit(struct drm_file *file,
>>>> struct ivpu_file_priv *file_priv,
>>>>            goto err_exit_dev;
>>>>        }
>>>>    -    ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles,
>>>> buffer_count, cmds_offset);
>>>> +    ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles,
>>>> buffer_count, cmds_offset,
>>>> +                          preempt_buffer_index);
>>>>        if (ret) {
>>>>            ivpu_err(vdev, "Failed to prepare job: %d\n", ret);
>>>>            goto err_destroy_job;
>>>> @@ -868,7 +900,7 @@ int ivpu_submit_ioctl(struct drm_device *dev,
>>>> void *data, struct drm_file *file)
>>>>        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);
>>>> +               (void __user *)args->buffers_ptr,
>>>> args->commands_offset, 0, priority);
>>>>    }
>>>>      int ivpu_cmdq_submit_ioctl(struct drm_device *dev, void *data,
>>>> struct drm_file *file)
>>>> @@ -885,6 +917,9 @@ int ivpu_cmdq_submit_ioctl(struct drm_device
>>>> *dev, void *data, struct drm_file *
>>>>        if (args->buffer_count == 0 || args->buffer_count >
>>>> JOB_MAX_BUFFER_COUNT)
>>>>            return -EINVAL;
>>>>    +    if (args->preempt_buffer_index >= args->buffer_count)
>>>> +        return -EINVAL;
>>>> +
>>>>        if (!IS_ALIGNED(args->commands_offset, 8))
>>>>            return -EINVAL;
>>>>    @@ -895,7 +930,8 @@ int ivpu_cmdq_submit_ioctl(struct drm_device
>>>> *dev, void *data, struct drm_file *
>>>>            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);
>>>> +               (void __user *)args->buffers_ptr,
>>>> args->commands_offset,
>>>> +               args->preempt_buffer_index, 0);
>>>>    }
>>>>      int ivpu_cmdq_create_ioctl(struct drm_device *dev, void *data,
>>>> struct drm_file *file)
>>>> diff --git a/drivers/accel/ivpu/ivpu_job.h
>>>> b/drivers/accel/ivpu/ivpu_job.h
>>>> index 2e301c2eea7b..6c8b9c739b51 100644
>>>> --- a/drivers/accel/ivpu/ivpu_job.h
>>>> +++ b/drivers/accel/ivpu/ivpu_job.h
>>>> @@ -1,6 +1,6 @@
>>>>    /* SPDX-License-Identifier: GPL-2.0-only */
>>>>    /*
>>>> - * Copyright (C) 2020-2024 Intel Corporation
>>>> + * Copyright (C) 2020-2025 Intel Corporation
>>>>     */
>>>>      #ifndef __IVPU_JOB_H__
>>>> @@ -55,6 +55,8 @@ struct ivpu_job {
>>>>        u32 job_id;
>>>>        u32 engine_idx;
>>>>        size_t bo_count;
>>>> +    struct ivpu_bo *primary_preempt_buf;
>>>> +    struct ivpu_bo *secondary_preempt_buf;
>>>>        struct ivpu_bo *bos[] __counted_by(bo_count);
>>>>    };
>>>>    diff --git a/include/uapi/drm/ivpu_accel.h
>>>> b/include/uapi/drm/ivpu_accel.h
>>>> index 160ee1411d4a..e470b0221e02 100644
>>>> --- a/include/uapi/drm/ivpu_accel.h
>>>> +++ b/include/uapi/drm/ivpu_accel.h
>>>> @@ -90,6 +90,7 @@ extern "C" {
>>>>    #define DRM_IVPU_PARAM_TILE_CONFIG        11
>>>>    #define DRM_IVPU_PARAM_SKU            12
>>>>    #define DRM_IVPU_PARAM_CAPABILITIES        13
>>>> +#define DRM_IVPU_PARAM_PREEMPT_BUFFER_SIZE  14
>>>>      #define DRM_IVPU_PLATFORM_TYPE_SILICON        0
>>>>    @@ -176,6 +177,9 @@ struct drm_ivpu_param {
>>>>         *
>>>>         * %DRM_IVPU_PARAM_CAPABILITIES:
>>>>         * Supported capabilities (read-only)
>>>> +     *
>>>> +     * %DRM_IVPU_PARAM_PREEMPT_BUFFER_SIZE:
>>>> +     * Size of the preemption buffer (read-only)
>>>>         */
>>>>        __u32 param;
>>>>    @@ -371,6 +375,13 @@ struct drm_ivpu_cmdq_submit {
>>>>         * to be executed. The offset has to be 8-byte aligned.
>>>>         */
>>>>        __u32 commands_offset;
>>>> +    /**
>>>> +     * @preempt_buffer_index:
>>>> +     *
>>>> +     * Index of the preemption buffer in the buffers_ptr array.
>>>> +     */
>>>> +    __u32 preempt_buffer_index;
>>>> +    __u32 reserved;
>>>>    };
>>>>      /* drm_ivpu_bo_wait job status codes */

Reply via email to