Applied to drm-misc-next
On 9/17/2025 5:21 PM, Lizhi Hou wrote: > > On 9/17/25 00:24, Karol Wachowski wrote: >> 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. > > Reviewed-by: Lizhi Hou <[email protected]> > > Adding some comment might be good. :) > >> >> 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 */
