Re: [PATCH] drm/debugfs: fix memory leak in drm_debugfs_remove_files()
On Thu, Dec 28, 2023 at 04:07:40PM +0800, Yaxiong Tian wrote: > From: Yaxiong Tian > > The dentry returned by debugfs_lookup() needs to be released by calling > dput() which is missing in drm_debugfs_remove_files(). Fix this by adding > dput(). > > Signed-off-by: Yaxiong Tian Reviewed-by: Stanislaw Gruszka > --- > drivers/gpu/drm/drm_debugfs.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c > index f4715a67e340..4d299152c302 100644 > --- a/drivers/gpu/drm/drm_debugfs.c > +++ b/drivers/gpu/drm/drm_debugfs.c > @@ -277,6 +277,7 @@ int drm_debugfs_remove_files(const struct drm_info_list > *files, int count, > > drmm_kfree(minor->dev, d_inode(dent)->i_private); > debugfs_remove(dent); > + dput(dent); > } > return 0; > } > -- > 2.25.1 >
Re: [PATCH 3/8] accel/ivpu: Stop job_done_thread on suspend
Hi On Mon, Nov 13, 2023 at 08:39:42AM +0100, Daniel Vetter wrote: > This conflicts with the kthread change in 6.7-rc1 6309727ef271 > ("kthread: add kthread_stop_put") > > Please double-check that the conflict resolution I've done in drm-tip > is correct and then ask drm-misc/accel maintainers to backmerge -rc2 > to bake this in properly. Adding them as fyi. Can not rebuild drm-tip due to core-to-CI merge problem. However resolution in drm-rerere commit fa53f5a2888265d883eedb83a943613a410b9fc9 is correct. Thomas please do the backmarge. Regards Stanislaw > On Sat, 28 Oct 2023 at 18:00, Stanislaw Gruszka > wrote: > > > > Stop job_done thread when going to suspend. Use kthread_park() instead > > of kthread_stop() to avoid memory allocation and potential failure > > on resume. > > > > Use separate function as thread wake up condition. Use spin lock to assure > > rx_msg_list is properly protected against concurrent access. > > > > Reviewed-by: Karol Wachowski > > Signed-off-by: Stanislaw Gruszka > > --- > > drivers/accel/ivpu/ivpu_drv.c | 2 ++ > > drivers/accel/ivpu/ivpu_ipc.c | 17 +++-- > > drivers/accel/ivpu/ivpu_job.c | 20 > > drivers/accel/ivpu/ivpu_job.h | 2 ++ > > 4 files changed, 35 insertions(+), 6 deletions(-) > > > > diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c > > index 064cabef41bb..60277ff6af69 100644 > > --- a/drivers/accel/ivpu/ivpu_drv.c > > +++ b/drivers/accel/ivpu/ivpu_drv.c > > @@ -378,6 +378,7 @@ int ivpu_boot(struct ivpu_device *vdev) > > enable_irq(vdev->irq); > > ivpu_hw_irq_enable(vdev); > > ivpu_ipc_enable(vdev); > > + ivpu_job_done_thread_enable(vdev); > > return 0; > > } > > > > @@ -389,6 +390,7 @@ int ivpu_shutdown(struct ivpu_device *vdev) > > disable_irq(vdev->irq); > > ivpu_ipc_disable(vdev); > > ivpu_mmu_disable(vdev); > > + ivpu_job_done_thread_disable(vdev); > > > > ret = ivpu_hw_power_down(vdev); > > if (ret) > > diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c > > index d069d1e1f91d..270caef789bf 100644 > > --- a/drivers/accel/ivpu/ivpu_ipc.c > > +++ b/drivers/accel/ivpu/ivpu_ipc.c > > @@ -202,6 +202,20 @@ ivpu_ipc_send(struct ivpu_device *vdev, struct > > ivpu_ipc_consumer *cons, struct v > > return ret; > > } > > > > +static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) > > +{ > > + int ret = 0; > > + > > + if (IS_KTHREAD()) > > + ret |= (kthread_should_stop() || kthread_should_park()); > > + > > + spin_lock_irq(&cons->rx_msg_lock); > > + ret |= !list_empty(&cons->rx_msg_list); > > + spin_unlock_irq(&cons->rx_msg_lock); > > + > > + return ret; > > +} > > + > > int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer > > *cons, > > struct ivpu_ipc_hdr *ipc_buf, > > struct vpu_jsm_msg *ipc_payload, unsigned long > > timeout_ms) > > @@ -211,8 +225,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct > > ivpu_ipc_consumer *cons, > > int wait_ret, ret = 0; > > > > wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq, > > - (IS_KTHREAD() && > > kthread_should_stop()) || > > - > > !list_empty(&cons->rx_msg_list), > > + > > ivpu_ipc_rx_need_wakeup(cons), > > > > msecs_to_jiffies(timeout_ms)); > > > > if (IS_KTHREAD() && kthread_should_stop()) > > diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c > > index 6e96c921547d..a245b2d44db7 100644 > > --- a/drivers/accel/ivpu/ivpu_job.c > > +++ b/drivers/accel/ivpu/ivpu_job.c > > @@ -590,6 +590,11 @@ static int ivpu_job_done_thread(void *arg) > > ivpu_pm_schedule_recovery(vdev); > > } > > } > > + if (kthread_should_park()) { > > + ivpu_dbg(vdev, JOB, "Parked %s\n", __func__); > > + kthread_parkme(); > > + ivpu_dbg(vdev, JOB, "Unparked %s\n", __
Re: [PATCH 0/8] accel/ivpu: Update for -next 2023-10-28
On Sat, Oct 28, 2023 at 05:59:28PM +0200, Stanislaw Gruszka wrote: > Various driver updates: > - MMU page tables handling optimizations > - Rebrand to NPU > - FW profiling frequency knob > - job done thread suspend handling > > This is based on top of previous update: > https://lore.kernel.org/dri-devel/20231028133415.1169975-1-stanislaw.grus...@linux.intel.com/ Applied to drm-misc-next Regards Stanislaw
[PATCH 4/4] accel/ivpu: Use GEM shmem helper for all buffers
From: Jacek Lawrynowicz Use struct drm_gem_shmem_object as a base for struct ivpu_bo. This cuts by 50% the buffer management code. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/Kconfig| 2 +- drivers/accel/ivpu/ivpu_drv.c | 6 +- drivers/accel/ivpu/ivpu_gem.c | 518 -- drivers/accel/ivpu/ivpu_gem.h | 70 + drivers/accel/ivpu/ivpu_job.c | 8 +- 5 files changed, 144 insertions(+), 460 deletions(-) diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig index 82749e0da524..682c53245286 100644 --- a/drivers/accel/ivpu/Kconfig +++ b/drivers/accel/ivpu/Kconfig @@ -6,7 +6,7 @@ config DRM_ACCEL_IVPU depends on X86_64 && !UML depends on PCI && PCI_MSI select FW_LOADER - select SHMEM + select DRM_GEM_SHMEM_HELPER select GENERIC_ALLOCATOR help Choose this option if you have a system with an 14th generation diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index cc6a4dca2aaa..51fa60b6254c 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -360,7 +360,7 @@ int ivpu_boot(struct ivpu_device *vdev) int ret; /* Update boot params located at first 4KB of FW memory */ - ivpu_fw_boot_params_setup(vdev, vdev->fw->mem->kvaddr); + ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem)); ret = ivpu_hw_boot_fw(vdev); if (ret) { @@ -409,7 +409,9 @@ static const struct drm_driver driver = { .open = ivpu_open, .postclose = ivpu_postclose, - .gem_prime_import = ivpu_gem_prime_import, + + .gem_create_object = ivpu_gem_create_object, + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, .ioctls = ivpu_drm_ioctls, .num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls), diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 2a91eb1e3627..1dda4f38ea25 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -20,224 +20,18 @@ #include "ivpu_mmu.h" #include "ivpu_mmu_context.h" -MODULE_IMPORT_NS(DMA_BUF); - static const struct drm_gem_object_funcs ivpu_gem_funcs; -static struct lock_class_key prime_bo_lock_class_key; - static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) { if (bo->ctx) ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n", -action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle, -bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); +action, ivpu_bo_size(bo), (bool)bo->base.pages, (bool)bo->base.sgt, +bo->handle, bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); else ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n", -action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle); -} - -static int __must_check prime_alloc_pages_locked(struct ivpu_bo *bo) -{ - /* Pages are managed by the underlying dma-buf */ - return 0; -} - -static void prime_free_pages_locked(struct ivpu_bo *bo) -{ - /* Pages are managed by the underlying dma-buf */ -} - -static int prime_map_pages_locked(struct ivpu_bo *bo) -{ - struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); - struct sg_table *sgt; - - sgt = dma_buf_map_attachment_unlocked(bo->base.import_attach, DMA_BIDIRECTIONAL); - if (IS_ERR(sgt)) { - ivpu_err(vdev, "Failed to map attachment: %ld\n", PTR_ERR(sgt)); - return PTR_ERR(sgt); - } - - bo->sgt = sgt; - return 0; -} - -static void prime_unmap_pages_locked(struct ivpu_bo *bo) -{ - dma_buf_unmap_attachment_unlocked(bo->base.import_attach, bo->sgt, DMA_BIDIRECTIONAL); - bo->sgt = NULL; -} - -static const struct ivpu_bo_ops prime_ops = { - .type = IVPU_BO_TYPE_PRIME, - .name = "prime", - .alloc_pages = prime_alloc_pages_locked, - .free_pages = prime_free_pages_locked, - .map_pages = prime_map_pages_locked, - .unmap_pages = prime_unmap_pages_locked, -}; - -static int __must_check shmem_alloc_pages_locked(struct ivpu_bo *bo) -{ - int npages = ivpu_bo_size(bo) >> PAGE_SHIFT; - struct page **pages; - - pages = drm_gem_get_pages(&bo->base); - if (IS_ERR(pages)) - return PTR_ERR(pages); - - if (bo->flags & DRM_IVPU_BO_WC) - set_pages_array_wc(pages, npages); - - bo->pages = pages; - return 0; -} - -stat
[PATCH 3/4] accel/ivpu: Remove support for uncached buffers
From: Jacek Lawrynowicz Usages of DRM_IVPU_BO_UNCACHED should be replaced by DRM_IVPU_BO_WC. There is no functional benefit from DRM_IVPU_BO_UNCACHED if these buffers are never mapped to host VM. This allows to cut the buffer handling code in the kernel driver by half. Usage of DRM_IVPU_BO_UNCACHED buffers was removed from user-space driver and will not be part of first UMD release. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_fw.c | 2 +- drivers/accel/ivpu/ivpu_gem.c | 3 --- include/uapi/drm/ivpu_accel.h | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 3fd74cd4205f..3d0c18d68f6c 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -286,7 +286,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (fw->shave_nn_size) { fw->mem_shave_nn = ivpu_bo_alloc_internal(vdev, vdev->hw->ranges.shave.start, - fw->shave_nn_size, DRM_IVPU_BO_UNCACHED); + fw->shave_nn_size, DRM_IVPU_BO_WC); if (!fw->mem_shave_nn) { ivpu_err(vdev, "Failed to allocate shavenn buffer\n"); ret = -ENOMEM; diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 915c53d7bb97..2a91eb1e3627 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -89,8 +89,6 @@ static int __must_check shmem_alloc_pages_locked(struct ivpu_bo *bo) if (bo->flags & DRM_IVPU_BO_WC) set_pages_array_wc(pages, npages); - else if (bo->flags & DRM_IVPU_BO_UNCACHED) - set_pages_array_uc(pages, npages); bo->pages = pages; return 0; @@ -366,7 +364,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_b switch (flags & DRM_IVPU_BO_CACHE_MASK) { case DRM_IVPU_BO_CACHED: - case DRM_IVPU_BO_UNCACHED: case DRM_IVPU_BO_WC: break; default: diff --git a/include/uapi/drm/ivpu_accel.h b/include/uapi/drm/ivpu_accel.h index 262db0c3beee..de1944e42c65 100644 --- a/include/uapi/drm/ivpu_accel.h +++ b/include/uapi/drm/ivpu_accel.h @@ -196,7 +196,7 @@ struct drm_ivpu_bo_create { * * %DRM_IVPU_BO_UNCACHED: * -* Allocated BO will not be cached on host side nor snooped on the VPU side. +* Not supported. Use DRM_IVPU_BO_WC instead. * * %DRM_IVPU_BO_WC: * -- 2.25.1
[PATCH 2/4] accel/ivpu: Fix locking in ivpu_bo_remove_all_bos_from_context()
From: Jacek Lawrynowicz ivpu_bo_remove_all_bos_from_context() could race with ivpu_bo_free() when prime buffer was closed after vpu device was closed. Move the bo_list from context to vdev and use a dedicated lock to sync it. This list is not modified when BO is added/removed from a context. Also rename ivpu_bo_free_vpu_addr() to ivpu_bo_unbind() because this function does more then just free vpu_addr. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 7 +- drivers/accel/ivpu/ivpu_drv.h | 3 + drivers/accel/ivpu/ivpu_gem.c | 131 +- drivers/accel/ivpu/ivpu_gem.h | 6 +- drivers/accel/ivpu/ivpu_mmu.c | 5 +- drivers/accel/ivpu/ivpu_mmu_context.c | 36 --- drivers/accel/ivpu/ivpu_mmu_context.h | 11 +-- 7 files changed, 109 insertions(+), 90 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 60277ff6af69..cc6a4dca2aaa 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -91,8 +91,8 @@ static void file_priv_release(struct kref *ref) ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id); ivpu_cmdq_release_all(file_priv); - ivpu_bo_remove_all_bos_from_context(&file_priv->ctx); ivpu_jsm_context_release(vdev, file_priv->ctx.id); + ivpu_bo_remove_all_bos_from_context(vdev, &file_priv->ctx); ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv); mutex_destroy(&file_priv->lock); @@ -528,6 +528,11 @@ static int ivpu_dev_init(struct ivpu_device *vdev) xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC); xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1); lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); + INIT_LIST_HEAD(&vdev->bo_list); + + ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock); + if (ret) + goto err_xa_destroy; ret = ivpu_pci_init(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 79b193ffbc26..e0517ec4133d 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -115,6 +115,9 @@ struct ivpu_device { struct xarray context_xa; struct xa_limit context_xa_limit; + struct mutex bo_list_lock; /* Protects bo_list */ + struct list_head bo_list; + struct xarray submitted_jobs_xa; struct task_struct *job_done_thread; diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index d1077cf90b65..915c53d7bb97 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -26,6 +26,17 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs; static struct lock_class_key prime_bo_lock_class_key; +static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) +{ + if (bo->ctx) + ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u ctx %d vpu_addr 0x%llx mmu_mapped %d\n", +action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle, +bo->ctx->id, bo->vpu_addr, bo->mmu_mapped); + else + ivpu_dbg(vdev, BO, "%6s: size %zu has_pages %d dma_mapped %d handle %u (not added to context)\n", +action, bo->base.size, (bool)bo->pages, (bool)bo->sgt, bo->handle); +} + static int __must_check prime_alloc_pages_locked(struct ivpu_bo *bo) { /* Pages are managed by the underlying dma-buf */ @@ -245,9 +256,8 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) mutex_lock(&bo->lock); - if (!bo->vpu_addr) { - ivpu_err(vdev, "vpu_addr not set for BO ctx_id: %d handle: %d\n", -bo->ctx->id, bo->handle); + if (!bo->ctx) { + ivpu_err(vdev, "vpu_addr not allocated for BO %d\n", bo->handle); ret = -EINVAL; goto unlock; } @@ -281,53 +291,68 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); int ret; - mutex_lock(&ctx->lock); - ret = ivpu_mmu_context_insert_node_locked(ctx, range, ivpu_bo_size(bo), &bo->mm_node); + mutex_lock(&bo->lock); + + ret = ivpu_mmu_context_insert_node(ctx, range, bo->base.size, &bo->mm_node); if (!ret) { bo->ctx = ctx; bo->vpu_addr = bo->mm_node.s
[PATCH 1/4] accel/ivpu: Allocate vpu_addr in gem->open() callback
From: Jacek Lawrynowicz Use gem->open() callback to simplify the code and prepare for gem_shmem conversion. It is called during handle creation for a gem object, during prime import and in BO_CREATE ioctl. Hence can be used for vpu_addr allocation. On the way remove unused bo->user_ptr field. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_gem.c | 66 --- drivers/accel/ivpu/ivpu_gem.h | 1 - drivers/accel/ivpu/ivpu_mmu_context.c | 2 + 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index c91852f2edc8..d1077cf90b65 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -281,15 +281,6 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, struct ivpu_device *vdev = ivpu_bo_to_vdev(bo); int ret; - if (!range) { - if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) - range = &vdev->hw->ranges.shave; - else if (bo->flags & DRM_IVPU_BO_DMA_MEM) - range = &vdev->hw->ranges.dma; - else - range = &vdev->hw->ranges.user; - } - mutex_lock(&ctx->lock); ret = ivpu_mmu_context_insert_node_locked(ctx, range, ivpu_bo_size(bo), &bo->mm_node); if (!ret) { @@ -299,6 +290,9 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx, } mutex_unlock(&ctx->lock); + if (ret) + ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); + return ret; } @@ -337,9 +331,7 @@ void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx) } static struct ivpu_bo * -ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, - u64 size, u32 flags, const struct ivpu_bo_ops *ops, - const struct ivpu_addr_range *range, u64 user_ptr) +ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, const struct ivpu_bo_ops *ops) { struct ivpu_bo *bo; int ret = 0; @@ -364,7 +356,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, bo->base.funcs = &ivpu_gem_funcs; bo->flags = flags; bo->ops = ops; - bo->user_ptr = user_ptr; if (ops->type == IVPU_BO_TYPE_SHMEM) ret = drm_gem_object_init(&vdev->drm, &bo->base, size); @@ -384,14 +375,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, } } - if (mmu_context) { - ret = ivpu_bo_alloc_vpu_addr(bo, mmu_context, range); - if (ret) { - ivpu_err(vdev, "Failed to add BO to context: %d\n", ret); - goto err_release; - } - } - return bo; err_release: @@ -401,6 +384,23 @@ ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context, return ERR_PTR(ret); } +static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) +{ + struct ivpu_file_priv *file_priv = file->driver_priv; + struct ivpu_device *vdev = file_priv->vdev; + struct ivpu_bo *bo = to_ivpu_bo(obj); + struct ivpu_addr_range *range; + + if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) + range = &vdev->hw->ranges.shave; + else if (bo->flags & DRM_IVPU_BO_DMA_MEM) + range = &vdev->hw->ranges.dma; + else + range = &vdev->hw->ranges.user; + + return ivpu_bo_alloc_vpu_addr(bo, &file_priv->ctx, range); +} + static void ivpu_bo_free(struct drm_gem_object *obj) { struct ivpu_bo *bo = to_ivpu_bo(obj); @@ -516,6 +516,7 @@ static const struct vm_operations_struct ivpu_vm_ops = { static const struct drm_gem_object_funcs ivpu_gem_funcs = { .free = ivpu_bo_free, + .open = ivpu_bo_open, .mmap = ivpu_bo_mmap, .vm_ops = &ivpu_vm_ops, .get_sg_table = ivpu_bo_get_sg_table, @@ -537,7 +538,7 @@ ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (size == 0) return -EINVAL; - bo = ivpu_bo_alloc(vdev, &file_priv->ctx, size, args->flags, &shmem_ops, NULL, 0); + bo = ivpu_bo_alloc(vdev, size, args->flags, &shmem_ops); if (IS_ERR(bo)) { ivpu_err(vdev, "Failed to create BO: %pe (ctx %u size %llu flags 0x%x)", bo, file_priv->ctx.id, args->size, args->flags); @@ -578,13 +579,17 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla
[PATCH 0/4] accel/ivpu: Use GEM shmem
Use GEM shmem for buffer management code; Previously sent as RFC: https://lore.kernel.org/dri-devel/20230901164842.178654-1-stanislaw.grus...@linux.intel.com/ Compared to RFC only changelog's were improved. Jacek Lawrynowicz (4): accel/ivpu: Allocate vpu_addr in gem->open() callback accel/ivpu: Fix locking in ivpu_bo_remove_all_bos_from_context() accel/ivpu: Remove support for uncached buffers accel/ivpu: Use GEM shmem helper for all buffers drivers/accel/ivpu/Kconfig| 2 +- drivers/accel/ivpu/ivpu_drv.c | 13 +- drivers/accel/ivpu/ivpu_drv.h | 3 + drivers/accel/ivpu/ivpu_fw.c | 2 +- drivers/accel/ivpu/ivpu_gem.c | 678 -- drivers/accel/ivpu/ivpu_gem.h | 75 +-- drivers/accel/ivpu/ivpu_job.c | 8 +- drivers/accel/ivpu/ivpu_mmu.c | 5 +- drivers/accel/ivpu/ivpu_mmu_context.c | 38 +- drivers/accel/ivpu/ivpu_mmu_context.h | 11 +- include/uapi/drm/ivpu_accel.h | 2 +- 11 files changed, 266 insertions(+), 571 deletions(-) -- 2.25.1
Re: [PATCH 06/11] accel/ivpu: Change test_mode module param to bitmask
On Mon, Oct 30, 2023 at 08:05:28AM -0600, Jeffrey Hugo wrote: > On 10/28/2023 2:18 AM, Stanislaw Gruszka wrote: > > On Fri, Oct 27, 2023 at 08:47:11AM -0600, Jeffrey Hugo wrote: > > > On 10/25/2023 3:43 AM, Stanislaw Gruszka wrote: > > > > From: Karol Wachowski > > > > > > > > Change meaning of test_mode module parameter from integer value > > > > to bitmask allowing setting different test features with corresponding > > > > bits. > > > > > > > > Signed-off-by: Karol Wachowski > > > > Reviewed-by: Stanislaw Gruszka > > > > Signed-off-by: Stanislaw Gruszka > > > > > > Seems like this changes the uAPI. You still haven't made a release of the > > > userspace, correct? > > > > Yes the user space is not yet released. However I think module parameter > > is not considered part of the linux kernel uAPI and there are no guaranties > > regarding not changing or removing or change the semantics. > > Patch 3 of [1] seems to suggest otherwise (module parameters are part of the > uAPI) I hope it will not be applied :-) Will be quite burden to maintain module parameters compatibility. Regards Stanislaw
Re: [PATCH v2 00/11] accel/ivpu: Update for -next 2023-10-25
On Sat, Oct 28, 2023 at 03:34:04PM +0200, Stanislaw Gruszka wrote: > Various driver updates: > > - FW api update > - suspend/resume optimizations > - dynamic valtage and frequency mode knob > - new test modes > > v2: > - fix spelling mistakes pointed Jeffrey > - move patch 7, add note where new function will be used > - change patches 8 and 9 ordering > - separate print warn change from patch 10 into separate patch > - squash patch 10 and 11 > - rebase to latest drm-misc-next Applied to drm-misc-next Regards Stanislaw
Re: [PATCH] accel/qaic: Support for 0 resize slice execution in BO
On Fri, Oct 27, 2023 at 10:43:30AM -0600, Jeffrey Hugo wrote: > From: Pranjal Ramajor Asha Kanojiya > > Add support to partially execute a slice which is resized to zero. > Executing a zero size slice in a BO should mean that there is no DMA > transfers involved but you should still configure doorbell and semaphores. > > For example consider a BO of size 18K and it is sliced into 3 6K slices > and user calls partial execute ioctl with resize as 10K. > slice 0 - size is 6k and offset is 0, so resize of 10K will not cut short > this slice hence we send the entire slice for execution. > slice 1 - size is 6k and offset is 6k, so resize of 10K will cut short this > slice and only the first 4k should be DMA along with configuring > doorbell and semaphores. > slice 2 - size is 6k and offset is 12k, so resize of 10k will cut short > this slice and no DMA transfer would be involved but we should > would configure doorbell and semaphores. > > This change begs to change the behavior of 0 resize. Currently, 0 resize > partial execute ioctl behaves exactly like execute ioctl i.e. no resize. > After this patch all the slice in BO should behave exactly like slice 2 in > above example. > > Refactor copy_partial_exec_reqs() to make it more readable and less > complex. > > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka
Re: [PATCH] accel/qaic: Quiet array bounds check on DMA abort message
On Fri, Oct 27, 2023 at 12:08:10PM -0600, Jeffrey Hugo wrote: > From: Carl Vanderlip > > Current wrapper is right-sized to the message being transferred; > however, this is smaller than the structure defining message wrappers > since the trailing element is a union of message/transfer headers of > various sizes (8 and 32 bytes on 32-bit system where issue was > reported). Using the smaller header with a small message > (wire_trans_dma_xfer is 24 bytes including header) ends up being smaller > than a wrapper with the larger header. There are no accesses outside of > the defined size, however they are possible if the larger union member > is referenced. > > Abort messages are outside of hot-path and changing the wrapper struct > would require a larger rewrite, so having the memory allocated to the > message be 8 bytes too big is acceptable. > > Reported-by: kernel test robot > Closes: > https://lore.kernel.org/oe-kbuild-all/202310182253.bcb9jcyj-...@intel.com/ > Signed-off-by: Carl Vanderlip > Reviewed-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka
Re: [PATCH] accel/ivpu: avoid build failure with CONFIG_PM=n
On Fri, Oct 27, 2023 at 05:26:23PM +0200, Arnd Bergmann wrote: > From: Arnd Bergmann > > The usage count of struct dev_pm_info is an implementation detail that > is only available if CONFIG_PM is enabled, so printing it in a debug message > causes a build failure in configurations without PM: > > In file included from include/linux/device.h:15, > from include/linux/pci.h:37, > from drivers/accel/ivpu/ivpu_pm.c:8: > drivers/accel/ivpu/ivpu_pm.c: In function 'ivpu_rpm_get_if_active': > drivers/accel/ivpu/ivpu_pm.c:254:51: error: 'struct dev_pm_info' has no > member named 'usage_count' > 254 | atomic_read(&vdev->drm.dev->power.usage_count)); > | ^ > include/linux/dev_printk.h:129:48: note: in definition of macro 'dev_printk' > 129 | _dev_printk(level, dev, fmt, ##__VA_ARGS__); > \ > |^~~ > drivers/accel/ivpu/ivpu_drv.h:75:17: note: in expansion of macro 'dev_dbg' >75 | dev_dbg((vdev)->drm.dev, "[%s] " fmt, #type, ##args); > \ > | ^~~ > drivers/accel/ivpu/ivpu_pm.c:253:9: note: in expansion of macro 'ivpu_dbg' > 253 | ivpu_dbg(vdev, RPM, "rpm_get_if_active count %d\n", > | ^~~~ > > The print message does not seem essential, so the easiest workaround is > to just remove it. > > Fixes: c39dc15191c4 ("accel/ivpu: Read clock rate only if device is up") > Signed-off-by: Arnd Bergmann Applied to drm-misc-next Thanks Stanislaw
[PATCH 8/8] accel/ivpu: Rename VPU to NPU in product strings
From: Jacek Lawrynowicz VPU was rebranded as NPU (Neural Processing Unit) so user facing strings have to be updated but the code remains as is and the module is still called intel_vpu.ko. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/Kconfig| 9 + drivers/accel/ivpu/ivpu_drv.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig index 1a4c4ed9d113..82749e0da524 100644 --- a/drivers/accel/ivpu/Kconfig +++ b/drivers/accel/ivpu/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_ACCEL_IVPU - tristate "Intel VPU for Meteor Lake and newer" + tristate "Intel NPU (Neural Processing Unit)" depends on DRM_ACCEL depends on X86_64 && !UML depends on PCI && PCI_MSI @@ -9,8 +9,9 @@ config DRM_ACCEL_IVPU select SHMEM select GENERIC_ALLOCATOR help - Choose this option if you have a system that has an 14th generation Intel CPU - or newer. VPU stands for Versatile Processing Unit and it's a CPU-integrated - inference accelerator for Computer Vision and Deep Learning applications. + Choose this option if you have a system with an 14th generation + Intel CPU (Meteor Lake) or newer. Intel NPU (formerly called Intel VPU) + is a CPU-integrated inference accelerator for Computer Vision + and Deep Learning applications. If "M" is selected, the module will be called intel_vpu. diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 1b482d1d66d9..79b193ffbc26 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -19,7 +19,7 @@ #include "ivpu_mmu_context.h" #define DRIVER_NAME "intel_vpu" -#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)" +#define DRIVER_DESC "Driver for Intel NPU (Neural Processing Unit)" #define DRIVER_DATE "20230117" #define PCI_DEVICE_ID_MTL 0x7d1d -- 2.25.1
[PATCH 5/8] accel/ivpu: Print CMDQ errors after consumer timeout
From: Karol Wachowski Add checking of error reason bits in IVPU_MMU_CMDQ_CONS register when waiting for consumer timeout occurred. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_mmu.c | 34 +++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index 2538c78fbebe..b15cf9cc9c43 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -230,7 +230,12 @@ (REG_FLD(IVPU_MMU_REG_GERROR, MSI_PRIQ_ABT)) | \ (REG_FLD(IVPU_MMU_REG_GERROR, MSI_ABT))) -static char *ivpu_mmu_event_to_str(u32 cmd) +#define IVPU_MMU_CERROR_NONE 0x0 +#define IVPU_MMU_CERROR_ILL 0x1 +#define IVPU_MMU_CERROR_ABT 0x2 +#define IVPU_MMU_CERROR_ATC_INV_SYNC 0x3 + +static const char *ivpu_mmu_event_to_str(u32 cmd) { switch (cmd) { case IVPU_MMU_EVT_F_UUT: @@ -276,6 +281,22 @@ static char *ivpu_mmu_event_to_str(u32 cmd) } } +static const char *ivpu_mmu_cmdq_err_to_str(u32 err) +{ + switch (err) { + case IVPU_MMU_CERROR_NONE: + return "No CMDQ Error"; + case IVPU_MMU_CERROR_ILL: + return "Illegal command"; + case IVPU_MMU_CERROR_ABT: + return "External abort on CMDQ read"; + case IVPU_MMU_CERROR_ATC_INV_SYNC: + return "Sync failed to complete ATS invalidation"; + default: + return "Unknown CMDQ Error"; + } +} + static void ivpu_mmu_config_check(struct ivpu_device *vdev) { u32 val_ref; @@ -492,8 +513,15 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) REGV_WR32(IVPU_MMU_REG_CMDQ_PROD, q->prod); ret = ivpu_mmu_cmdq_wait_for_cons(vdev); - if (ret) - ivpu_err(vdev, "Timed out waiting for consumer: %d\n", ret); + if (ret) { + u32 err; + + val = REGV_RD32(IVPU_MMU_REG_CMDQ_CONS); + err = REG_GET_FLD(IVPU_MMU_REG_CMDQ_CONS, ERR, val); + + ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret, +ivpu_mmu_cmdq_err_to_str(err)); + } return ret; } -- 2.25.1
[PATCH 7/8] accel/ivpu: Simplify MMU SYNC command
From: Jacek Lawrynowicz CMD_SYNC does not need any args as we poll for completion anyway. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_mmu.c | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index b15cf9cc9c43..b46f3743c0e7 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -500,10 +500,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) u64 val; int ret; - val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_SYNC) | - FIELD_PREP(IVPU_MMU_CMD_SYNC_0_CS, 0x2) | - FIELD_PREP(IVPU_MMU_CMD_SYNC_0_MSH, 0x3) | - FIELD_PREP(IVPU_MMU_CMD_SYNC_0_MSI_ATTR, 0xf); + val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_SYNC); ret = ivpu_mmu_cmdq_cmd_write(vdev, "SYNC", val, 0); if (ret) -- 2.25.1
[PATCH 6/8] accel/ivpu: Make DMA allocations for MMU600 write combined
From: Karol Wachowski Previously using dma_alloc_wc() API we created cache coherent (mapped as write-back) mappings. Because we disable MMU600 snooping it was required to do costly page walk and cache flushes after each page table modification. With write-combined buffers it's possible to do a single write memory barrier to flush write-combined buffer to memory which simplifies the driver and significantly reduce time of map/unmap operations. Mapping time of 255 MB is reduced from 2.5 ms to 500 us. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_mmu_context.c | 115 ++ 1 file changed, 63 insertions(+), 52 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index 0c8c65351919..7d8005bc78d2 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -5,6 +5,9 @@ #include #include +#include + +#include #include "ivpu_drv.h" #include "ivpu_hw.h" @@ -38,12 +41,57 @@ #define IVPU_MMU_ENTRY_MAPPED (IVPU_MMU_ENTRY_FLAG_AF | IVPU_MMU_ENTRY_FLAG_USER | \ IVPU_MMU_ENTRY_FLAG_NG | IVPU_MMU_ENTRY_VALID) +static void *ivpu_pgtable_alloc_page(struct ivpu_device *vdev, dma_addr_t *dma) +{ + dma_addr_t dma_addr; + struct page *page; + void *cpu; + + page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (!page) + return NULL; + + set_pages_array_wc(&page, 1); + + dma_addr = dma_map_page(vdev->drm.dev, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(vdev->drm.dev, dma_addr)) + goto err_free_page; + + cpu = vmap(&page, 1, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + if (!cpu) + goto err_dma_unmap_page; + + + *dma = dma_addr; + return cpu; + +err_dma_unmap_page: + dma_unmap_page(vdev->drm.dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + +err_free_page: + put_page(page); + return NULL; +} + +static void ivpu_pgtable_free_page(struct ivpu_device *vdev, u64 *cpu_addr, dma_addr_t dma_addr) +{ + struct page *page; + + if (cpu_addr) { + page = vmalloc_to_page(cpu_addr); + vunmap(cpu_addr); + dma_unmap_page(vdev->drm.dev, dma_addr & ~IVPU_MMU_ENTRY_FLAGS_MASK, PAGE_SIZE, + DMA_BIDIRECTIONAL); + set_pages_array_wb(&page, 1); + put_page(page); + } +} + static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { dma_addr_t pgd_dma; - pgtable->pgd_dma_ptr = dma_alloc_coherent(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pgd_dma, - GFP_KERNEL); + pgtable->pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); if (!pgtable->pgd_dma_ptr) return -ENOMEM; @@ -52,13 +100,6 @@ static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtab return 0; } -static void ivpu_mmu_pgtable_free(struct ivpu_device *vdev, u64 *cpu_addr, dma_addr_t dma_addr) -{ - if (cpu_addr) - dma_free_coherent(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, cpu_addr, - dma_addr & ~IVPU_MMU_ENTRY_FLAGS_MASK); -} - static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { int pgd_idx, pud_idx, pmd_idx; @@ -83,19 +124,19 @@ static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgt pte_dma_ptr = pgtable->pte_ptrs[pgd_idx][pud_idx][pmd_idx]; pte_dma = pgtable->pmd_ptrs[pgd_idx][pud_idx][pmd_idx]; - ivpu_mmu_pgtable_free(vdev, pte_dma_ptr, pte_dma); + ivpu_pgtable_free_page(vdev, pte_dma_ptr, pte_dma); } kfree(pgtable->pte_ptrs[pgd_idx][pud_idx]); - ivpu_mmu_pgtable_free(vdev, pmd_dma_ptr, pmd_dma); + ivpu_pgtable_free_page(vdev, pmd_dma_ptr, pmd_dma); } kfree(pgtable->pmd_ptrs[pgd_idx]); kfree(pgtable->pte_ptrs[pgd_idx]); - ivpu_mmu_pgtable_free(vdev, pud_dma_ptr, pud_dma); + ivpu_pgtable_free_page(vdev, pud_dma_ptr, pud_dma); } - ivpu_mmu_pgtable_free(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); + ivpu_pgtable_free_page(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); } static u64* @@ -107,7 +148,7 @@ ivpu_mmu_ensure_pud(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pud_dma_ptr) return pud_dma_ptr; - p
[PATCH 4/8] accel/ivpu: Abort pending rx ipc on reset
Waking up process, which wait for particular condition, will go to sleep again on wake_up() if the condition is not met. Add abort flag to wake up IPC receivers, which will finish with -ECANCELED error. This is only needed for reset, run time power management prevent to suspend VPU when there is pending IPC processing or pending job. Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_ipc.c | 20 +--- drivers/accel/ivpu/ivpu_ipc.h | 3 ++- drivers/accel/ivpu/ivpu_job.c | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 270caef789bf..255f2b8b0b5e 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -148,6 +148,7 @@ ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, cons->channel = channel; cons->tx_vpu_addr = 0; cons->request_id = 0; + cons->aborted = false; spin_lock_init(&cons->rx_msg_lock); INIT_LIST_HEAD(&cons->rx_msg_list); init_waitqueue_head(&cons->rx_msg_wq); @@ -169,7 +170,8 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c spin_lock_irq(&cons->rx_msg_lock); list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) { list_del(&rx_msg->link); - ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); + if (!cons->aborted) + ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); atomic_dec(&ipc->rx_msg_count); kfree(rx_msg); } @@ -210,7 +212,7 @@ static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) ret |= (kthread_should_stop() || kthread_should_park()); spin_lock_irq(&cons->rx_msg_lock); - ret |= !list_empty(&cons->rx_msg_list); + ret |= !list_empty(&cons->rx_msg_list) || cons->aborted; spin_unlock_irq(&cons->rx_msg_lock); return ret; @@ -244,6 +246,12 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, return -EAGAIN; } list_del(&rx_msg->link); + if (cons->aborted) { + spin_unlock_irq(&cons->rx_msg_lock); + ret = -ECANCELED; + goto out; + } + spin_unlock_irq(&cons->rx_msg_lock); if (ipc_buf) @@ -261,6 +269,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, } ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); +out: atomic_dec(&ipc->rx_msg_count); kfree(rx_msg); @@ -522,8 +531,12 @@ void ivpu_ipc_disable(struct ivpu_device *vdev) mutex_unlock(&ipc->lock); spin_lock_irqsave(&ipc->cons_list_lock, flags); - list_for_each_entry_safe(cons, c, &ipc->cons_list, link) + list_for_each_entry_safe(cons, c, &ipc->cons_list, link) { + spin_lock(&cons->rx_msg_lock); + cons->aborted = true; + spin_unlock(&cons->rx_msg_lock); wake_up(&cons->rx_msg_wq); + } spin_unlock_irqrestore(&ipc->cons_list_lock, flags); } @@ -532,6 +545,7 @@ void ivpu_ipc_reset(struct ivpu_device *vdev) struct ivpu_ipc_info *ipc = vdev->ipc; mutex_lock(&ipc->lock); + drm_WARN_ON(&vdev->drm, ipc->on); memset(ivpu_bo_vaddr(ipc->mem_tx), 0, ivpu_bo_size(ipc->mem_tx)); memset(ivpu_bo_vaddr(ipc->mem_rx), 0, ivpu_bo_size(ipc->mem_rx)); diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 6918db23daa4..a380787f7222 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -47,8 +47,9 @@ struct ivpu_ipc_consumer { u32 channel; u32 tx_vpu_addr; u32 request_id; + bool aborted; - spinlock_t rx_msg_lock; /* Protects rx_msg_list */ + spinlock_t rx_msg_lock; /* Protects rx_msg_list and aborted */ struct list_head rx_msg_list; wait_queue_head_t rx_msg_wq; }; diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index a245b2d44db7..15a408fad494 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -578,6 +578,7 @@ static int ivpu_job_done_thread(void *arg) ivpu_ipc_consumer_add(vdev, &cons, VPU_IPC_CHAN_JOB_RET); while (!kthread_should_stop()) { + cons.aborted = false; timeout = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; jobs_submitted = !xa_empty(&vdev->submitted_jobs_xa); ret = ivpu_ipc_receive(vdev, &cons, NULL, &jsm_msg, timeout); -- 2.25.1
[PATCH 2/8] accel/ivpu: Assure device is off if power up sequence fail
We should not leave device half enabled if there is failure somewhere it power up sequence. Fix device init and resume paths. Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_pm.c | 30 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 39bac45d88b5..064cabef41bb 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -543,7 +543,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev) /* Power up early so the rest of init code can access VPU registers */ ret = ivpu_hw_power_up(vdev); if (ret) - goto err_xa_destroy; + goto err_power_down; ret = ivpu_mmu_global_context_init(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 74688cc57583..7d17f7ea4949 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -70,27 +70,31 @@ static int ivpu_resume(struct ivpu_device *vdev) ret = ivpu_hw_power_up(vdev); if (ret) { ivpu_err(vdev, "Failed to power up HW: %d\n", ret); - return ret; + goto err_power_down; } ret = ivpu_mmu_enable(vdev); if (ret) { ivpu_err(vdev, "Failed to resume MMU: %d\n", ret); - ivpu_hw_power_down(vdev); - return ret; + goto err_power_down; } ret = ivpu_boot(vdev); - if (ret) { - ivpu_mmu_disable(vdev); - ivpu_hw_power_down(vdev); - if (!ivpu_fw_is_cold_boot(vdev)) { - ivpu_warn(vdev, "Failed to resume the FW: %d. Retrying cold boot..\n", ret); - ivpu_pm_prepare_cold_boot(vdev); - goto retry; - } else { - ivpu_err(vdev, "Failed to resume the FW: %d\n", ret); - } + if (ret) + goto err_mmu_disable; + + return 0; + +err_mmu_disable: + ivpu_mmu_disable(vdev); +err_power_down: + ivpu_hw_power_down(vdev); + + if (!ivpu_fw_is_cold_boot(vdev)) { + ivpu_pm_prepare_cold_boot(vdev); + goto retry; + } else { + ivpu_err(vdev, "Failed to resume the FW: %d\n", ret); } return ret; -- 2.25.1
[PATCH 1/8] accel/ivpu/40xx: Allow to change profiling frequency
From: Krystian Pradzynski Profiling freq is a debug firmware feature. It switches default clock to higher resolution for fine-grained and more accurate firmware task profiling. We already configure it during boot up of VPU4. Add debugfs knob and helpers per HW generation that allow to change it. For vpu37xx the implementation is empty as profiling frequency can only be changed on VPU4 or newer. Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_debugfs.c | 29 + drivers/accel/ivpu/ivpu_fw.c | 7 +++ drivers/accel/ivpu/ivpu_hw.h | 12 drivers/accel/ivpu/ivpu_hw_37xx.c | 13 + drivers/accel/ivpu/ivpu_hw_40xx.c | 15 +++ 5 files changed, 76 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 6e0d56823024..19035230563d 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -14,6 +14,7 @@ #include "ivpu_fw.h" #include "ivpu_fw_log.h" #include "ivpu_gem.h" +#include "ivpu_hw.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" @@ -176,6 +177,30 @@ static const struct file_operations fw_log_fops = { .release = single_release, }; +static ssize_t +fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, +size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + bool enable; + int ret; + + ret = kstrtobool_from_user(user_buf, size, &enable); + if (ret < 0) + return ret; + + ivpu_hw_profiling_freq_drive(vdev, enable); + ivpu_pm_schedule_recovery(vdev); + + return size; +} + +static const struct file_operations fw_profiling_freq_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = fw_profiling_freq_fops_write, +}; + static ssize_t fw_trace_destination_mask_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) @@ -319,4 +344,8 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, &ivpu_reset_engine_fops); + + if (ivpu_hw_gen(vdev) >= IVPU_HW_40XX) + debugfs_create_file("fw_profiling_freq_drive", 0200, + debugfs_root, vdev, &fw_profiling_freq_fops); } diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 4a21be3a0c59..3fd74cd4205f 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -498,6 +498,13 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number; boot_params->frequency = ivpu_hw_reg_pll_freq_get(vdev); + /* +* This param is a debug firmware feature. It switches default clock +* to higher resolution one for fine-grained and more accurate firmware +* task profiling. +*/ + boot_params->perf_clk_frequency = ivpu_hw_profiling_freq_get(vdev); + /* * Uncached region of VPU address space, covers IPC buffers, job queues * and log buffers, programmable to L2$ Uncached by VPU MTRR diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index b7694b1cbc02..aa52e5c29a65 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -17,6 +17,8 @@ struct ivpu_hw_ops { int (*wait_for_idle)(struct ivpu_device *vdev); void (*wdt_disable)(struct ivpu_device *vdev); void (*diagnose_failure)(struct ivpu_device *vdev); + u32 (*profiling_freq_get)(struct ivpu_device *vdev); + void (*profiling_freq_drive)(struct ivpu_device *vdev, bool enable); u32 (*reg_pll_freq_get)(struct ivpu_device *vdev); u32 (*reg_telemetry_offset_get)(struct ivpu_device *vdev); u32 (*reg_telemetry_size_get)(struct ivpu_device *vdev); @@ -104,6 +106,16 @@ static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev) vdev->hw->ops->wdt_disable(vdev); }; +static inline u32 ivpu_hw_profiling_freq_get(struct ivpu_device *vdev) +{ + return vdev->hw->ops->profiling_freq_get(vdev); +}; + +static inline void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + return vdev->hw->ops->profiling_freq_drive(vdev, enable); +}; + /* Register indirect accesses */ static inline u32 ivpu_hw_reg_pll_freq_get(struct ivpu_device *vdev) { diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 1c8c5715095b..81f81046d39a 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/i
[PATCH 0/8] accel/ivpu: Update for -next 2023-10-28
Various driver updates: - MMU page tables handling optimizations - Rebrand to NPU - FW profiling frequency knob - job done thread suspend handling This is based on top of previous update: https://lore.kernel.org/dri-devel/20231028133415.1169975-1-stanislaw.grus...@linux.intel.com/ Jacek Lawrynowicz (2): accel/ivpu: Simplify MMU SYNC command accel/ivpu: Rename VPU to NPU in product strings Karol Wachowski (2): accel/ivpu: Print CMDQ errors after consumer timeout accel/ivpu: Make DMA allocations for MMU600 write combined Krystian Pradzynski (1): accel/ivpu/40xx: Allow to change profiling frequency Stanislaw Gruszka (3): accel/ivpu: Assure device is off if power up sequence fail accel/ivpu: Stop job_done_thread on suspend accel/ivpu: Abort pending rx ipc on reset drivers/accel/ivpu/Kconfig| 9 +- drivers/accel/ivpu/ivpu_debugfs.c | 29 +++ drivers/accel/ivpu/ivpu_drv.c | 4 +- drivers/accel/ivpu/ivpu_drv.h | 2 +- drivers/accel/ivpu/ivpu_fw.c | 7 ++ drivers/accel/ivpu/ivpu_hw.h | 12 +++ drivers/accel/ivpu/ivpu_hw_37xx.c | 13 +++ drivers/accel/ivpu/ivpu_hw_40xx.c | 15 drivers/accel/ivpu/ivpu_ipc.c | 35 +++- drivers/accel/ivpu/ivpu_ipc.h | 3 +- drivers/accel/ivpu/ivpu_job.c | 21 - drivers/accel/ivpu/ivpu_job.h | 2 + drivers/accel/ivpu/ivpu_mmu.c | 39 +++-- drivers/accel/ivpu/ivpu_mmu_context.c | 115 ++ drivers/accel/ivpu/ivpu_pm.c | 30 --- 15 files changed, 249 insertions(+), 87 deletions(-) -- 2.25.1
[PATCH 3/8] accel/ivpu: Stop job_done_thread on suspend
Stop job_done thread when going to suspend. Use kthread_park() instead of kthread_stop() to avoid memory allocation and potential failure on resume. Use separate function as thread wake up condition. Use spin lock to assure rx_msg_list is properly protected against concurrent access. Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 ++ drivers/accel/ivpu/ivpu_ipc.c | 17 +++-- drivers/accel/ivpu/ivpu_job.c | 20 drivers/accel/ivpu/ivpu_job.h | 2 ++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 064cabef41bb..60277ff6af69 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -378,6 +378,7 @@ int ivpu_boot(struct ivpu_device *vdev) enable_irq(vdev->irq); ivpu_hw_irq_enable(vdev); ivpu_ipc_enable(vdev); + ivpu_job_done_thread_enable(vdev); return 0; } @@ -389,6 +390,7 @@ int ivpu_shutdown(struct ivpu_device *vdev) disable_irq(vdev->irq); ivpu_ipc_disable(vdev); ivpu_mmu_disable(vdev); + ivpu_job_done_thread_disable(vdev); ret = ivpu_hw_power_down(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index d069d1e1f91d..270caef789bf 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -202,6 +202,20 @@ ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct v return ret; } +static int ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) +{ + int ret = 0; + + if (IS_KTHREAD()) + ret |= (kthread_should_stop() || kthread_should_park()); + + spin_lock_irq(&cons->rx_msg_lock); + ret |= !list_empty(&cons->rx_msg_list); + spin_unlock_irq(&cons->rx_msg_lock); + + return ret; +} + int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms) @@ -211,8 +225,7 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, int wait_ret, ret = 0; wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq, - (IS_KTHREAD() && kthread_should_stop()) || - !list_empty(&cons->rx_msg_list), + ivpu_ipc_rx_need_wakeup(cons), msecs_to_jiffies(timeout_ms)); if (IS_KTHREAD() && kthread_should_stop()) diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 6e96c921547d..a245b2d44db7 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -590,6 +590,11 @@ static int ivpu_job_done_thread(void *arg) ivpu_pm_schedule_recovery(vdev); } } + if (kthread_should_park()) { + ivpu_dbg(vdev, JOB, "Parked %s\n", __func__); + kthread_parkme(); + ivpu_dbg(vdev, JOB, "Unparked %s\n", __func__); + } } ivpu_ipc_consumer_del(vdev, &cons); @@ -610,9 +615,6 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev) return -EIO; } - get_task_struct(thread); - wake_up_process(thread); - vdev->job_done_thread = thread; return 0; @@ -620,6 +622,16 @@ int ivpu_job_done_thread_init(struct ivpu_device *vdev) void ivpu_job_done_thread_fini(struct ivpu_device *vdev) { + kthread_unpark(vdev->job_done_thread); kthread_stop(vdev->job_done_thread); - put_task_struct(vdev->job_done_thread); +} + +void ivpu_job_done_thread_disable(struct ivpu_device *vdev) +{ + kthread_park(vdev->job_done_thread); +} + +void ivpu_job_done_thread_enable(struct ivpu_device *vdev) +{ + kthread_unpark(vdev->job_done_thread); } diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index aa1f0b9479b0..a8e914e5affc 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -61,6 +61,8 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev); int ivpu_job_done_thread_init(struct ivpu_device *vdev); void ivpu_job_done_thread_fini(struct ivpu_device *vdev); +void ivpu_job_done_thread_disable(struct ivpu_device *vdev); +void ivpu_job_done_thread_enable(struct ivpu_device *vdev); void ivpu_jobs_abort_all(struct ivpu_device *vdev); -- 2.25.1
[PATCH v2 11/11] accel/ivpu: Add support for delayed D0i3 entry message
From: Andrzej Kacprowski Currently the VPU firmware prepares for D0i3 every time the VPU is entering D0i2 Idle state. This is not optimal as we might not enter D0i3 every time we enter D0i2 Idle and this preparation is quite costly. This optimization moves D0i3 preparation to a dedicated message sent from the host driver only when the driver is about to enter D0i3 - this reduces power consumption and latency for certain workloads, for example audio workloads that submit inference every 10 ms. The VPU needs non zero time to enter IDLE state after responding to D0i3 entry message. If the driver does not wait for the VPU to enter IDLE state it could cause warm boot failures. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.h | 10 +-- drivers/accel/ivpu/ivpu_fw.c | 48 +-- drivers/accel/ivpu/ivpu_hw.h | 6 drivers/accel/ivpu/ivpu_hw_37xx.c | 9 +- drivers/accel/ivpu/ivpu_hw_40xx.c | 10 +++ drivers/accel/ivpu/ivpu_jsm_msg.c | 21 ++ drivers/accel/ivpu/ivpu_jsm_msg.h | 1 + drivers/accel/ivpu/ivpu_pm.c | 11 ++- 8 files changed, 108 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index ada43ba565c4..1b482d1d66d9 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -87,6 +87,7 @@ struct ivpu_wa_table { bool d3hot_after_power_off; bool interrupt_clear_with_0; bool disable_clock_relinquish; + bool disable_d0i3_msg; }; struct ivpu_hw_info; @@ -125,6 +126,7 @@ struct ivpu_device { int tdr; int reschedule_suspend; int autosuspend; + int d0i3_entry_msg; } timeout; }; @@ -147,9 +149,11 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_FW_TEST BIT(0) -#define IVPU_TEST_MODE_NULL_HW BIT(1) -#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) +#define IVPU_TEST_MODE_FW_TESTBIT(0) +#define IVPU_TEST_MODE_NULL_HWBIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSIONBIT(2) +#define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4) +#define IVPU_TEST_MODE_D0I3_MSG_ENABLEBIT(5) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 383e4d9b97c8..4a21be3a0c59 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -33,12 +33,17 @@ #define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31) -#define IVPU_FW_CHECK_API(vdev, fw_hdr, name, min_major) \ +/* Check if FW API is compatible with the driver */ +#define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \ ivpu_fw_check_api(vdev, fw_hdr, #name, \ VPU_##name##_API_VER_INDEX, \ VPU_##name##_API_VER_MAJOR, \ VPU_##name##_API_VER_MINOR, min_major) +/* Check if API version is lower that the given version */ +#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \ + ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor) + static char *ivpu_firmware; module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); MODULE_PARM_DESC(firmware, "VPU firmware binary in /lib/firmware/.."); @@ -105,6 +110,19 @@ ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw return 0; } +static bool +ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr, +const char *str, int index, u16 major, u16 minor) +{ + u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16); + u16 fw_minor = (u16)(fw_hdr->api_version[index]); + + if (fw_major < major || (fw_major == major && fw_minor < minor)) + return true; + + return false; +} + static int ivpu_fw_parse(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -164,9 +182,9 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) ivpu_info(vdev, "Firmware: %s, version: %s", fw->name, (const char *)fw_hdr + VPU_FW_HEADER_SIZE); - if (IVPU_FW_CHECK_API(vdev, fw_hdr, BOOT, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3)) return -EINVAL; - if (IVPU_FW_CHECK_API(vdev, fw_hdr, JSM, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3)) return -EINVAL; fw->runtime_addr = runtime_addr; @@ -197,6 +215,24 @@ static void ivpu_fw_release(struct ivpu_device *vdev) release_firmware(vdev->fw->file); } +/* Initialize workarounds that depend on FW version */ +static void
[PATCH v2 10/11] accel/ivpu/37xx: Print warning when VPUIP is not idle during power down
Print warning if VPUIP is not idle during power down. Use warn log level also when we fail to enter reset state as this is not really an error but unexpected behavior. Reviewed-by: Krystian Pradzynski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 451c9777b237..1b47d77b4c6e 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -726,8 +726,11 @@ static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev); - if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) - ivpu_err(vdev, "Failed to reset the VPU\n"); + if (!ivpu_hw_37xx_is_idle(vdev)) { + ivpu_warn(vdev, "VPU not idle during power down\n"); + if (ivpu_hw_37xx_reset(vdev)) + ivpu_warn(vdev, "Failed to reset the VPU\n"); + } if (ivpu_pll_disable(vdev)) { ivpu_err(vdev, "Failed to disable PLL\n"); -- 2.25.1
[PATCH v2 09/11] accel/ivpu: Introduce ivpu_ipc_send_receive_active()
From: Karol Wachowski Split ivpu_ipc_send_receive() implementation to have a version that does not call pm_runtime_resume_and_get(). That implementation can be invoked when device is up and runtime resume is prohibited (for example at the end of boot sequence). The new function will be used for D0i3 entry IPC message addition in the separate change. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_ipc.c | 33 ++--- drivers/accel/ivpu/ivpu_ipc.h | 8 +--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 6e213a5afb8c..d069d1e1f91d 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -288,23 +288,20 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req return ret; } -int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms) +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, +enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, +u32 channel, unsigned long timeout_ms) { struct vpu_jsm_msg hb_req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB }; struct vpu_jsm_msg hb_resp; int ret, hb_ret; - ret = ivpu_rpm_get(vdev); - if (ret < 0) - return ret; + drm_WARN_ON(&vdev->drm, + vdev->drm.dev->power.runtime_status == RPM_SUSPENDED); - ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp_type, resp, -channel, timeout_ms); + ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp, resp, channel, timeout_ms); if (ret != -ETIMEDOUT) - goto rpm_put; + return ret; hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, @@ -314,7 +311,21 @@ int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, ivpu_pm_schedule_recovery(vdev); } -rpm_put: + return ret; +} + +int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms) +{ + int ret; + + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; + + ret = ivpu_ipc_send_receive_active(vdev, req, expected_resp, resp, channel, timeout_ms); + ivpu_rpm_put(vdev); return ret; } diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 68f5b6668e00..6918db23daa4 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -85,9 +85,11 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms); +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, +enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, +u32 channel, unsigned long timeout_ms); int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms); + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms); #endif /* __IVPU_IPC_H__ */ -- 2.25.1
[PATCH v2 08/11] accel/ivpu: Pass D0i3 residency time to the VPU firmware
From: Andrzej Kacprowski The firmware needs to know the time spent in D0i3/D3 to calculate telemetry data. The D0i3/D3 residency time is calculated by the driver and passed to the firmware in the boot parameters. The driver also passes VPU perf counter value captured right before entering D0i3 - this allows the VPU firmware to generate monotonic timestamps for the logs. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_fw.c | 17 - drivers/accel/ivpu/ivpu_hw.h | 2 ++ drivers/accel/ivpu/ivpu_hw_37xx.c | 8 drivers/accel/ivpu/ivpu_hw_37xx_reg.h | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index b81827540db9..383e4d9b97c8 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -426,14 +426,27 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->vpu_telemetry_enable); ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", boot_params->dvfs_mode); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", +boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", +boot_params->d0i3_entry_vpu_ts); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) { struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx; - /* In case of warm boot we only have to reset the entrypoint addr */ + /* In case of warm boot only update variable params */ if (!ivpu_fw_is_cold_boot(vdev)) { + boot_params->d0i3_residency_time_us = + ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts); + boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; + + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", +boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", +boot_params->d0i3_entry_vpu_ts); + boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; return; @@ -497,6 +510,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); boot_params->dvfs_mode = vdev->fw->dvfs_mode; + boot_params->d0i3_residency_time_us = 0; + boot_params->d0i3_entry_vpu_ts = 0; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index ab341237bcf9..fd4809b56168 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -57,6 +57,8 @@ struct ivpu_hw_info { u32 sku; u16 config; int dma_bits; + ktime_t d0i3_entry_host_ts; + u64 d0i3_entry_vpu_ts; }; extern const struct ivpu_hw_ops ivpu_hw_37xx_ops; diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 8340c84ed6de..451c9777b237 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -714,10 +714,18 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT); +} + static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) ivpu_err(vdev, "Failed to reset the VPU\n"); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h index 4083beb5e9db..f6fec1919202 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h @@ -240,6 +240,8 @@ #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9) +#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT 0x06029000u + #define VPU_37XX_CPU_SS_DOORBELL_0 0x0630u #define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0) -- 2.25.1
[PATCH v2 06/11] accel/ivpu: Change test_mode module param to bitmask
From: Karol Wachowski Change meaning of test_mode module parameter from integer value to bitmask allowing setting different test features with corresponding bits. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 4 ++-- drivers/accel/ivpu/ivpu_drv.h | 7 +++ drivers/accel/ivpu/ivpu_job.c | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 4ec8d25a120c..39bac45d88b5 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); -MODULE_PARM_DESC(test_mode, "Test mode: 0 - disabled , 1 - fw unit test, 2 - null hw, 3 - null submission"); +MODULE_PARM_DESC(test_mode, "Test mode mask. See IVPU_TEST_MODE_* macros."); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); @@ -315,7 +315,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) unsigned long timeout; int ret; - if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST) + if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST) return 0; ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index fdec8272da8c..ada43ba565c4 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -147,10 +147,9 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 -#define IVPU_TEST_MODE_NULL_SUBMISSION 3 +#define IVPU_TEST_MODE_FW_TEST BIT(0) +#define IVPU_TEST_MODE_NULL_HW BIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 646b8f812901..6e96c921547d 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -196,7 +196,7 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; - if (unlikely(ivpu_test_mode == IVPU_TEST_MODE_NULL_SUBMISSION)) + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION)) entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; @@ -404,7 +404,7 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id, job->engine_idx, cmdq->jobq->header.tail); - if (ivpu_test_mode == IVPU_TEST_MODE_NULL_HW) { + if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) { ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); cmdq->jobq->header.head = cmdq->jobq->header.tail; wmb(); /* Flush WC buffer for jobq header */ -- 2.25.1
[PATCH v2 07/11] accel/ivpu/40xx: Capture D0i3 entry host and device timestamps
From: Andrzej Kacprowski The driver needs to capture the D0i3 entry timestamp to calculate D0i3 residency time. The D0i3 residency time and the VPU timestamp are passed to the firmware at D0i3 exit (warm boot). Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_40xx.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index eb8218d15f01..0eb9c827f6dc 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -879,10 +879,18 @@ static bool ivpu_hw_40xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static void ivpu_hw_40xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT); +} + static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); -- 2.25.1
[PATCH v2 05/11] accel/ivpu: Add support for VPU_JOB_FLAGS_NULL_SUBMISSION_MASK
From: Andrzej Kacprowski Add test_mode = 3 that add VPU_JOB_FLAGS_NULL_SUBMISSION_MASK flag to the job send to the VPU device. Then the VPU will process the job but won't execute commands (except the command to signal the fence). This can be used to estimate job processing overhead in the host software and VPU firmware. Unlike the null hardware mode, the null submission mode will still work even if UMD uses VPU fences to track job completion. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_drv.h | 7 --- drivers/accel/ivpu/ivpu_job.c | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 8f5655dfd83f..4ec8d25a120c 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); -MODULE_PARM_DESC(test_mode, "Test mode: 0 - normal operation, 1 - fw unit test, 2 - null hw"); +MODULE_PARM_DESC(test_mode, "Test mode: 0 - disabled , 1 - fw unit test, 2 - null hw, 3 - null submission"); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 12a63f8a73e8..fdec8272da8c 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -147,9 +147,10 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED 0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_DISABLED0 +#define IVPU_TEST_MODE_FW_TEST 1 +#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_NULL_SUBMISSION 3 extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 689dc0d13b8f..646b8f812901 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -196,6 +196,8 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; + if (unlikely(ivpu_test_mode == IVPU_TEST_MODE_NULL_SUBMISSION)) + entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; wmb(); /* Flush WC buffer for jobq header */ -- 2.25.1
[PATCH v2 04/11] accel/ivpu: Remove reset from power up sequence
From: Karol Wachowski Setting a non-zero work point resets the IP hence IP_RESET trigger is redundant. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 4 drivers/accel/ivpu/ivpu_hw_40xx.c | 6 -- 2 files changed, 10 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index e5cb9d8acb82..8340c84ed6de 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -651,10 +651,6 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_37xx_reset(vdev); - if (ret) - ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); - ret = ivpu_hw_37xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 4bf4c8780044..eb8218d15f01 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -811,12 +811,6 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_40xx_reset(vdev); - if (ret) { - ivpu_err(vdev, "Failed to reset HW: %d\n", ret); - return ret; - } - ret = ivpu_hw_40xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); -- 2.25.1
[PATCH v2 02/11] accel/ivpu: Remove unneeded drm_driver declaration
Cleanup drm_driver declaration leftover. Reviewed-by: Krystian Pradzynski Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index b6aa8893ff1c..8f5655dfd83f 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -31,8 +31,6 @@ __stringify(DRM_IVPU_DRIVER_MINOR) "." #endif -static const struct drm_driver driver; - static struct lock_class_key submitted_jobs_xa_lock_class_key; int ivpu_dbg_mask; -- 2.25.1
[PATCH v2 03/11] accel/ivpu: Add dvfs_mode file to debugfs
From: Tomasz Rusinowicz Add new debugfs file to set dvfs_mode FW boot parameter and restart the FW to allow experimenting with DVFS (dynamic voltage & frequency scaling). Signed-off-by: Tomasz Rusinowicz Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_debugfs.c | 28 drivers/accel/ivpu/ivpu_fw.c | 5 + drivers/accel/ivpu/ivpu_fw.h | 1 + 3 files changed, 34 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index ea453b985b49..6e0d56823024 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -115,6 +115,31 @@ static const struct drm_debugfs_info vdev_debugfs_list[] = { {"reset_pending", reset_pending_show, 0}, }; +static ssize_t +dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + struct ivpu_fw_info *fw = vdev->fw; + u32 dvfs_mode; + int ret; + + ret = kstrtou32_from_user(user_buf, size, 0, &dvfs_mode); + if (ret < 0) + return ret; + + fw->dvfs_mode = dvfs_mode; + + ivpu_pm_schedule_recovery(vdev); + + return size; +} + +static const struct file_operations dvfs_mode_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = dvfs_mode_fops_write, +}; + static int fw_log_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = s->private; @@ -280,6 +305,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); + debugfs_create_file("dvfs_mode", 0200, debugfs_root, vdev, + &dvfs_mode_fops); + debugfs_create_file("fw_log", 0644, debugfs_root, vdev, &fw_log_fops); debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 6142b09cf55a..b81827540db9 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -182,6 +182,8 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; fw->trace_hw_component_mask = -1; + fw->dvfs_mode = 0; + ivpu_dbg(vdev, FW_BOOT, "Size: file %lu image %u runtime %u shavenn %u\n", fw->file->size, fw->image_size, fw->runtime_size, fw->shave_nn_size); ivpu_dbg(vdev, FW_BOOT, "Address: runtime 0x%llx, load 0x%llx, entry point 0x%llx\n", @@ -422,6 +424,8 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->punit_telemetry_sram_size); ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n", boot_params->vpu_telemetry_enable); + ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", +boot_params->dvfs_mode); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) @@ -492,6 +496,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_base = ivpu_hw_reg_telemetry_offset_get(vdev); boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); + boot_params->dvfs_mode = vdev->fw->dvfs_mode; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 10ae2847f0ef..66b60fa161b5 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -27,6 +27,7 @@ struct ivpu_fw_info { u32 trace_level; u32 trace_destination_mask; u64 trace_hw_component_mask; + u32 dvfs_mode; }; int ivpu_fw_init(struct ivpu_device *vdev); -- 2.25.1
[PATCH v2 01/11] accel/ivpu: Update FW API
From: Krystian Pradzynski Bump boot API to 4.20 Bump JSM API to 3.15 Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_jsm_msg.c | 17 ++ drivers/accel/ivpu/vpu_boot_api.h | 90 - drivers/accel/ivpu/vpu_jsm_api.h | 309 -- 3 files changed, 392 insertions(+), 24 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 0c2fe7142024..35a689475c68 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -36,6 +36,17 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_DESTROY_CMD_QUEUE); IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES); IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_REGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_ENGINE_RESUME); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL); IVPU_CASE_TO_STR(VPU_JSM_MSG_JOB_DONE); @@ -65,6 +76,12 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE); } #undef IVPU_CASE_TO_STR diff --git a/drivers/accel/ivpu/vpu_boot_api.h b/drivers/accel/ivpu/vpu_boot_api.h index 6b71be92ba65..04c954258563 100644 --- a/drivers/accel/ivpu/vpu_boot_api.h +++ b/drivers/accel/ivpu/vpu_boot_api.h @@ -11,7 +11,10 @@ * The bellow values will be used to construct the version info this way: * fw_bin_header->api_version[VPU_BOOT_API_VER_ID] = (VPU_BOOT_API_VER_MAJOR << 16) | * VPU_BOOT_API_VER_MINOR; - * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes. + * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes + * This information is collected by using vpuip_2/application/vpuFirmware/make_std_fw_image.py + * If a header is missing this info we ignore the header, if a header is missing or contains + * partial info a build error will be generated. */ /* @@ -24,12 +27,12 @@ * Minor version changes when API backward compatibility is preserved. * Resets to 0 if Major version is incremented. */ -#define VPU_BOOT_API_VER_MINOR 12 +#define VPU_BOOT_API_VER_MINOR 20 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_BOOT_API_VER_PATCH 2 +#define VPU_BOOT_API_VER_PATCH 4 /* * Index in the API version table @@ -63,6 +66,12 @@ struct vpu_firmware_header { /* Size of memory require for firmware execution */ u32 runtime_size; u32 shave_nn_fw_size; + /* Size of primary preemption buffer. */ + u32 preemption_buffer_1_size; + /* Size of secondary preemption buffer. */ + u32 preemption_buffer_2_size; + /* Space reserved for future preemption-related fields. */ + u32 preemption_reserved[6]; }; /* @@ -89,6 +98,14 @@ enum VPU_BOOT_L2_CACHE_CFG_TYPE { VPU_BOOT_L2_CACHE_CFG_NUM = 2 }; +/** VPU MCA ECC signalling mode. By default, no signalling is used */ +enum VPU_BOOT_MCA_ECC_SIGNAL_TYPE { + VPU_BOOT_MCA_ECC_NONE = 0, + VPU_BOOT_MCA_ECC_CORR = 1, + VPU_BOOT_MCA_ECC_FATAL = 2, + VPU_BOOT_MCA_ECC_BOTH = 3 +}; + /** * Logging destinations. * @@ -131,9 +148,11 @@ enum vpu_trace_destination { #define VPU_TRACE_PROC_BIT_ACT_SHV_3 22 #define VPU_TRACE_PROC_NO_OF_HW_DEVS 23 -/* KMB HW component IDs are sequential, so define first and last IDs. */ -#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_LRT -#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_SHV_15 +/* VPU 30xx HW component IDs are sequential, so define first and last IDs. */ +#define VPU_TRACE_PROC_BIT_30XX_FIRST VPU_TRACE_PROC_BIT_LRT +#define VPU_TRACE_PROC_BIT_
[PATCH v2 00/11] accel/ivpu: Update for -next 2023-10-25
Various driver updates: - FW api update - suspend/resume optimizations - dynamic valtage and frequency mode knob - new test modes v2: - fix spelling mistakes pointed Jeffrey - move patch 7, add note where new function will be used - change patches 8 and 9 ordering - separate print warn change from patch 10 into separate patch - squash patch 10 and 11 - rebase to latest drm-misc-next Andrzej Kacprowski (4): accel/ivpu: Add support for VPU_JOB_FLAGS_NULL_SUBMISSION_MASK accel/ivpu/40xx: Capture D0i3 entry host and device timestamps accel/ivpu: Pass D0i3 residency time to the VPU firmware accel/ivpu: Add support for delayed D0i3 entry message Karol Wachowski (3): accel/ivpu: Remove reset from power up sequence accel/ivpu: Change test_mode module param to bitmask accel/ivpu: Introduce ivpu_ipc_send_receive_active() Krystian Pradzynski (1): accel/ivpu: Update FW API Stanislaw Gruszka (2): accel/ivpu: Remove unneeded drm_driver declaration accel/ivpu/37xx: Print warning when VPUIP is not idle during power down Tomasz Rusinowicz (1): accel/ivpu: Add dvfs_mode file to debugfs drivers/accel/ivpu/ivpu_debugfs.c | 28 +++ drivers/accel/ivpu/ivpu_drv.c | 6 +- drivers/accel/ivpu/ivpu_drv.h | 10 +- drivers/accel/ivpu/ivpu_fw.c | 70 +- drivers/accel/ivpu/ivpu_fw.h | 1 + drivers/accel/ivpu/ivpu_hw.h | 8 + drivers/accel/ivpu/ivpu_hw_37xx.c | 28 ++- drivers/accel/ivpu/ivpu_hw_37xx_reg.h | 2 + drivers/accel/ivpu/ivpu_hw_40xx.c | 24 +- drivers/accel/ivpu/ivpu_ipc.c | 33 ++- drivers/accel/ivpu/ivpu_ipc.h | 8 +- drivers/accel/ivpu/ivpu_job.c | 4 +- drivers/accel/ivpu/ivpu_jsm_msg.c | 38 drivers/accel/ivpu/ivpu_jsm_msg.h | 1 + drivers/accel/ivpu/ivpu_pm.c | 11 +- drivers/accel/ivpu/vpu_boot_api.h | 90 +++- drivers/accel/ivpu/vpu_jsm_api.h | 309 -- 17 files changed, 607 insertions(+), 64 deletions(-) -- 2.25.1
Re: [PATCH 10/11] accel/ivpu: Add support for delayed D0i3 entry message
On Fri, Oct 27, 2023 at 09:07:22AM -0600, Jeffrey Hugo wrote: > > + if (!ivpu_hw_37xx_is_idle(vdev)) { > > + ivpu_warn(vdev, "VPU not idle during power down\n"); > > + if (ivpu_hw_37xx_ip_reset(vdev)) > > + ivpu_err(vdev, "Failed to reset the VPU\n"); > > + } > > This appears to be an unrelated change to $SUBJECT Ok, I think I'll separate this on v2 Regards Stanislaw
Re: [PATCH 07/11] accel/ivpu: Introduce ivpu_ipc_send_receive_active()
On Fri, Oct 27, 2023 at 08:49:21AM -0600, Jeffrey Hugo wrote: > On 10/25/2023 3:43 AM, Stanislaw Gruszka wrote: > > From: Karol Wachowski > > > > Split ivpu_ipc_send_receive() implementation to have a version > > that does not call pm_runtime_resume_and_get(). That implementation > > can be invoked when device is up and runtime resume is prohibited > > (for example at the end of boot sequence). > > There doesn't seem to be a user for this, which would make the new function > dead code. Assuming that this new function gets used later in the series, > it would be clearer to combine this change with that one. It is used in patch 10. I would prefer not to merge those, since the changes are not that related. I would reorder this patch just before patch 10 and add note it's used there. Regards Stanislaw
Re: [PATCH 11/11] accel/ivpu: Wait for VPU to enter idle state after D0i3 entry message
On Fri, Oct 27, 2023 at 09:09:16AM -0600, Jeffrey Hugo wrote: > On 10/25/2023 3:43 AM, Stanislaw Gruszka wrote: > > From: Andrzej Kacprowski > > > > The VPU needs non zero time to enter IDLE state after responding to > > D0i3 entry message. If the driver does not wait for the VPU to enter > > IDLE state it could cause warm boot failures. > > > > Signed-off-by: Andrzej Kacprowski > > Reviewed-by: Stanislaw Gruszka > > Signed-off-by: Stanislaw Gruszka > > Should this be squashed into the previous change? Feels like this is a bug > fix to an issue that the previous change introduced. Yes, I can squash those 2 patches. Regards Stanislaw
Re: [PATCH 06/11] accel/ivpu: Change test_mode module param to bitmask
On Fri, Oct 27, 2023 at 08:47:11AM -0600, Jeffrey Hugo wrote: > On 10/25/2023 3:43 AM, Stanislaw Gruszka wrote: > > From: Karol Wachowski > > > > Change meaning of test_mode module parameter from integer value > > to bitmask allowing setting different test features with corresponding > > bits. > > > > Signed-off-by: Karol Wachowski > > Reviewed-by: Stanislaw Gruszka > > Signed-off-by: Stanislaw Gruszka > > Seems like this changes the uAPI. You still haven't made a release of the > userspace, correct? Yes the user space is not yet released. However I think module parameter is not considered part of the linux kernel uAPI and there are no guaranties regarding not changing or removing or change the semantics. Obviously we don't want to brake anyone config file or script, but that's more like courtesy than hardcoded rule. Currently nobody except Intel and it's partners are using intel_vpu and all user should be aware of the change. Regards Stanislaw
Re: [PATCH 01/11] accel/ivpu: Update FW API
Hi On Fri, Oct 27, 2023 at 08:37:39AM -0600, Jeffrey Hugo wrote: > On 10/25/2023 3:43 AM, Stanislaw Gruszka wrote: > > From: Krystian Pradzynski > > > > Bump boot API to 4.20 > > Bump JSM API to 3.15 > > > > Signed-off-by: Krystian Pradzynski > > Reviewed-by: Stanislaw Gruszka > > Signed-off-by: Stanislaw Gruszka > > --- > > /* > > @@ -89,6 +98,14 @@ enum VPU_BOOT_L2_CACHE_CFG_TYPE { > > VPU_BOOT_L2_CACHE_CFG_NUM = 2 > > }; > > +/** VPU MCA ECC signalling mode. By default, no signalling is used */ > > This does not look like valid kernel-doc. Maybe you wanted "/*" instead? > > > +enum VPU_BOOT_MCA_ECC_SIGNAL_TYPE { > > + VPU_BOOT_MCA_ECC_NONE = 0, > > + VPU_BOOT_MCA_ECC_CORR = 1, > > + VPU_BOOT_MCA_ECC_FATAL = 2, > > + VPU_BOOT_MCA_ECC_BOTH = 3 > > Personal preference, but having the "=" and the interget values all line up > vetrically would make this a bit more plesant to look at. This file came from FW and I'm reluctant to make any changes here, even formatting. I'll ask if in the future we can get some improvements of formatting done by scripts or if FW can change their files. Regards Stanislaw
Re: [PATCH] accel/ivpu: Delete the TODO file
On Thu, Oct 19, 2023 at 12:43:54AM +0530, Deepak R Varma wrote: > The work items listed in the TODO file of this driver file are either > completed or dropped. The file is no more significant according > to the maintainers. Hence removing it from the sources. > > Suggested-by: Stanislaw Gruszka > Signed-off-by: Deepak R Varma Applied to drm-misc-next Thanks Stanislaw > --- > drivers/accel/ivpu/TODO | 11 --- > 1 file changed, 11 deletions(-) > delete mode 100644 drivers/accel/ivpu/TODO > > diff --git a/drivers/accel/ivpu/TODO b/drivers/accel/ivpu/TODO > deleted file mode 100644 > index 9077217ae10f.. > --- a/drivers/accel/ivpu/TODO > +++ /dev/null > @@ -1,11 +0,0 @@ > -- Move to threaded_irqs to mitigate potential infinite loop in > ivpu_ipc_irq_handler() > -- Implement support for BLOB IDs > -- Add debugfs support to improve debugging and testing > -- Add tracing events for performance debugging > -- Implement HW based scheduling support > -- Use syncobjs for submit/sync > -- Refactor IPC protocol to improve message latency > -- Implement BO cache and MADVISE IOCTL > -- Add support for user allocated buffers using prime import and dma-buf heaps > -- Refactor struct ivpu_bo to use struct drm_gem_shmem_object > -- Add driver/device documentation > -- > 2.39.2 > > >
Re: [PATCH] accel/ivpu/37xx: Fix missing VPUIP interrupts
On Tue, Oct 24, 2023 at 06:19:52PM +0200, Stanislaw Gruszka wrote: > From: Karol Wachowski > > Move sequence of masking and unmasking global interrupts from buttress > interrupt handler to generic one that handles both VPUIP and BTRS > interrupts. Unmasking global interrupts will re-trigger MSI for any > pending interrupts. > > Lack of this sequence will cause the driver to miss any > VPUIP interrupt that comes after reading VPU_37XX_HOST_SS_ICB_STATUS_0 > and before clearing all active interrupt sources. > > Signed-off-by: Karol Wachowski > Reviewed-by: Stanislaw Gruszka > Signed-off-by: Stanislaw Gruszka Added: Fixes: 35b137630f08 ("accel/ivpu: Introduce a new DRM driver for Intel VPU") Cc: sta...@vger.kernel.org and applied to drm-misc-fixes Thanks Stanislaw > --- > drivers/accel/ivpu/ivpu_hw_37xx.c | 11 +-- > 1 file changed, 5 insertions(+), 6 deletions(-) > > diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c > b/drivers/accel/ivpu/ivpu_hw_37xx.c > index 7e4e87aa7602..5c0246b9e522 100644 > --- a/drivers/accel/ivpu/ivpu_hw_37xx.c > +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c > @@ -906,9 +906,6 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device > *vdev, int irq) > if (status == 0) > return 0; > > - /* Disable global interrupt before handling local buttress interrupts */ > - REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); > - > if (REG_TEST_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) > ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x", >REGB_RD32(VPU_37XX_BUTTRESS_CURRENT_PLL)); > @@ -940,9 +937,6 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device > *vdev, int irq) > else > REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status); > > - /* Re-enable global interrupt */ > - REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); > - > if (schedule_recovery) > ivpu_pm_schedule_recovery(vdev); > > @@ -954,9 +948,14 @@ static irqreturn_t ivpu_hw_37xx_irq_handler(int irq, > void *ptr) > struct ivpu_device *vdev = ptr; > u32 ret_irqv, ret_irqb; > > + REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); > + > ret_irqv = ivpu_hw_37xx_irqv_handler(vdev, irq); > ret_irqb = ivpu_hw_37xx_irqb_handler(vdev, irq); > > + /* Re-enable global interrupts to re-trigger MSI for pending interrupts > */ > + REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); > + > return IRQ_RETVAL(ret_irqb | ret_irqv); > } > > -- > 2.25.1 >
[PATCH 10/11] accel/ivpu: Add support for delayed D0i3 entry message
From: Andrzej Kacprowski Currently the VPU firmware prepares for D0i3 every time the VPU is entering D0i2 Idle state. This is not optimal as we might not enter D0i3 every time we enter D0i2 Idle and this preparation is quite costly. This optimization moves D0i3 preparation to a dedicated message sent from the host driver only when the driver is about to enter D0i3 - this reduces power consumption and latency for certain workloads, for example audio workloads that submit inference every 10 ms. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.h | 10 +-- drivers/accel/ivpu/ivpu_fw.c | 48 +-- drivers/accel/ivpu/ivpu_hw_37xx.c | 8 -- drivers/accel/ivpu/ivpu_hw_40xx.c | 3 ++ drivers/accel/ivpu/ivpu_jsm_msg.c | 15 ++ drivers/accel/ivpu/ivpu_jsm_msg.h | 1 + drivers/accel/ivpu/ivpu_pm.c | 11 ++- 7 files changed, 87 insertions(+), 9 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 5432b5ee90df..84b170a3c323 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -88,6 +88,7 @@ struct ivpu_wa_table { bool d3hot_after_power_off; bool interrupt_clear_with_0; bool disable_clock_relinquish; + bool disable_d0i3_msg; }; struct ivpu_hw_info; @@ -126,6 +127,7 @@ struct ivpu_device { int tdr; int reschedule_suspend; int autosuspend; + int d0i3_entry_msg; } timeout; }; @@ -148,9 +150,11 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_FW_TEST BIT(0) -#define IVPU_TEST_MODE_NULL_HW BIT(1) -#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) +#define IVPU_TEST_MODE_FW_TESTBIT(0) +#define IVPU_TEST_MODE_NULL_HWBIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSIONBIT(2) +#define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4) +#define IVPU_TEST_MODE_D0I3_MSG_ENABLEBIT(5) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 51d976ba5276..3fd94c2d06c7 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -33,12 +33,17 @@ #define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31) -#define IVPU_FW_CHECK_API(vdev, fw_hdr, name, min_major) \ +/* Check if FW API is compatible with the driver */ +#define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \ ivpu_fw_check_api(vdev, fw_hdr, #name, \ VPU_##name##_API_VER_INDEX, \ VPU_##name##_API_VER_MAJOR, \ VPU_##name##_API_VER_MINOR, min_major) +/* Check if API version is lover that the given version */ +#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \ + ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor) + static char *ivpu_firmware; module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); MODULE_PARM_DESC(firmware, "VPU firmware binary in /lib/firmware/.."); @@ -105,6 +110,19 @@ ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw return 0; } +static bool +ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr, +const char *str, int index, u16 major, u16 minor) +{ + u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16); + u16 fw_minor = (u16)(fw_hdr->api_version[index]); + + if (fw_major < major || (fw_major == major && fw_minor < minor)) + return true; + + return false; +} + static int ivpu_fw_parse(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -164,9 +182,9 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) ivpu_info(vdev, "Firmware: %s, version: %s", fw->name, (const char *)fw_hdr + VPU_FW_HEADER_SIZE); - if (IVPU_FW_CHECK_API(vdev, fw_hdr, BOOT, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3)) return -EINVAL; - if (IVPU_FW_CHECK_API(vdev, fw_hdr, JSM, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3)) return -EINVAL; fw->runtime_addr = runtime_addr; @@ -197,6 +215,24 @@ static void ivpu_fw_release(struct ivpu_device *vdev) release_firmware(vdev->fw->file); } +/* Initialize workarounds that depend on FW version */ +static void +ivpu_fw_init_wa(struct ivpu_device *vdev) +{ + const struct vpu_firmware_header *fw_hdr = (const void *)vdev->fw->file->data; + + if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, BOOT, 3, 17) || +
[PATCH 11/11] accel/ivpu: Wait for VPU to enter idle state after D0i3 entry message
From: Andrzej Kacprowski The VPU needs non zero time to enter IDLE state after responding to D0i3 entry message. If the driver does not wait for the VPU to enter IDLE state it could cause warm boot failures. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw.h | 6 ++ drivers/accel/ivpu/ivpu_hw_37xx.c | 8 +++- drivers/accel/ivpu/ivpu_hw_40xx.c | 7 +++ drivers/accel/ivpu/ivpu_jsm_msg.c | 12 +--- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index bb4368168247..329721f8f010 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -15,6 +15,7 @@ struct ivpu_hw_ops { int (*power_down)(struct ivpu_device *vdev); int (*reset)(struct ivpu_device *vdev); bool (*is_idle)(struct ivpu_device *vdev); + int (*wait_for_idle)(struct ivpu_device *vdev); void (*wdt_disable)(struct ivpu_device *vdev); void (*diagnose_failure)(struct ivpu_device *vdev); u32 (*reg_pll_freq_get)(struct ivpu_device *vdev); @@ -87,6 +88,11 @@ static inline bool ivpu_hw_is_idle(struct ivpu_device *vdev) return vdev->hw->ops->is_idle(vdev); }; +static inline int ivpu_hw_wait_for_idle(struct ivpu_device *vdev) +{ + return vdev->hw->ops->wait_for_idle(vdev); +}; + static inline int ivpu_hw_power_down(struct ivpu_device *vdev) { ivpu_dbg(vdev, PM, "HW power down\n"); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index edf4776acf29..9b04dcc90de1 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -37,7 +37,7 @@ #define TIMEOUT_US (150 * USEC_PER_MSEC) #define PWR_ISLAND_STATUS_TIMEOUT_US (5 * USEC_PER_MSEC) #define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC) -#define IDLE_TIMEOUT_US (500 * USEC_PER_MSEC) +#define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC) #define ICB_0_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \ @@ -732,6 +732,11 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static int ivpu_hw_37xx_wait_for_idle(struct ivpu_device *vdev) +{ + return REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US); +} + static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) { vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); @@ -1018,6 +1023,7 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = { .info_init = ivpu_hw_37xx_info_init, .power_up = ivpu_hw_37xx_power_up, .is_idle = ivpu_hw_37xx_is_idle, + .wait_for_idle = ivpu_hw_37xx_wait_for_idle, .power_down = ivpu_hw_37xx_power_down, .reset = ivpu_hw_37xx_reset, .boot_fw = ivpu_hw_37xx_boot_fw, diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 971d8d4ecba1..fb28e83a29a3 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -39,6 +39,7 @@ #define TIMEOUT_US (150 * USEC_PER_MSEC) #define PWR_ISLAND_STATUS_TIMEOUT_US (5 * USEC_PER_MSEC) #define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC) +#define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC) #define WEIGHTS_DEFAULT 0xf711f711u #define WEIGHTS_ATS_DEFAULT 0xf711u @@ -912,6 +913,11 @@ static bool ivpu_hw_40xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static int ivpu_hw_40xx_wait_for_idle(struct ivpu_device *vdev) +{ + return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US); +} + static void ivpu_hw_40xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) { vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); @@ -1207,6 +1213,7 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = { .info_init = ivpu_hw_40xx_info_init, .power_up = ivpu_hw_40xx_power_up, .is_idle = ivpu_hw_40xx_is_idle, + .wait_for_idle = ivpu_hw_40xx_wait_for_idle, .power_down = ivpu_hw_40xx_power_down, .reset = ivpu_hw_40xx_reset, .boot_fw = ivpu_hw_40xx_boot_fw, diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 03cf6b35d73a..8cea0dd731b9 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -4,6 +4,7 @@ */ #include "ivpu_drv.h" +#include "ivpu_hw.h" #include "ivpu_ipc.h" #include "ivpu_jsm_msg.h" @@ -265,13 +266,18 @@ int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev) { struct vpu_jsm_m
[PATCH 03/11] accel/ivpu: Add dvfs_mode file to debugfs
From: Tomasz Rusinowicz Add new debugfs file to set dvfs_mode FW boot parameter and restart the FW to allow experimenting with DVFS (dynamic voltage & frequency scaling). Signed-off-by: Tomasz Rusinowicz Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_debugfs.c | 28 drivers/accel/ivpu/ivpu_fw.c | 5 + drivers/accel/ivpu/ivpu_fw.h | 1 + 3 files changed, 34 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index ea453b985b49..6e0d56823024 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -115,6 +115,31 @@ static const struct drm_debugfs_info vdev_debugfs_list[] = { {"reset_pending", reset_pending_show, 0}, }; +static ssize_t +dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + struct ivpu_fw_info *fw = vdev->fw; + u32 dvfs_mode; + int ret; + + ret = kstrtou32_from_user(user_buf, size, 0, &dvfs_mode); + if (ret < 0) + return ret; + + fw->dvfs_mode = dvfs_mode; + + ivpu_pm_schedule_recovery(vdev); + + return size; +} + +static const struct file_operations dvfs_mode_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = dvfs_mode_fops_write, +}; + static int fw_log_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = s->private; @@ -280,6 +305,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); + debugfs_create_file("dvfs_mode", 0200, debugfs_root, vdev, + &dvfs_mode_fops); + debugfs_create_file("fw_log", 0644, debugfs_root, vdev, &fw_log_fops); debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 691da521dde5..a4149fc8a1d7 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -182,6 +182,8 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; fw->trace_hw_component_mask = -1; + fw->dvfs_mode = 0; + ivpu_dbg(vdev, FW_BOOT, "Size: file %lu image %u runtime %u shavenn %u\n", fw->file->size, fw->image_size, fw->runtime_size, fw->shave_nn_size); ivpu_dbg(vdev, FW_BOOT, "Address: runtime 0x%llx, load 0x%llx, entry point 0x%llx\n", @@ -422,6 +424,8 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->punit_telemetry_sram_size); ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n", boot_params->vpu_telemetry_enable); + ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", +boot_params->dvfs_mode); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) @@ -493,6 +497,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_base = ivpu_hw_reg_telemetry_offset_get(vdev); boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); + boot_params->dvfs_mode = vdev->fw->dvfs_mode; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 10ae2847f0ef..66b60fa161b5 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -27,6 +27,7 @@ struct ivpu_fw_info { u32 trace_level; u32 trace_destination_mask; u64 trace_hw_component_mask; + u32 dvfs_mode; }; int ivpu_fw_init(struct ivpu_device *vdev); -- 2.25.1
[PATCH 09/11] accel/ivpu/40xx: Capture D0i3 entry host and device timestamps
From: Andrzej Kacprowski The driver needs to capture the D0i3 entry timestamp to calculate D0i3 residency time. The D0i3 residency time and the VPU timestamp are passed to the firmware at D0i3 exit (warm boot). Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_40xx.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 5876cfd9dd40..d8df2addd18a 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -909,10 +909,18 @@ static bool ivpu_hw_40xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static void ivpu_hw_40xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT); +} + static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); -- 2.25.1
[PATCH 08/11] accel/ivpu: Pass D0i3 residency time to the VPU firmware
From: Andrzej Kacprowski The firmware needs to know the time spend in D0i3/D3 to calculate telemetry data. The D0i3/D3 residency time is calculated by the driver and passed to the firmware in the boot parameters. The driver also passes VPU perf counter value captured right before entering D0i3 - this allows the VPU firmware to generate monotonic timestamps for the logs. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_fw.c | 17 - drivers/accel/ivpu/ivpu_hw.h | 2 ++ drivers/accel/ivpu/ivpu_hw_37xx.c | 8 drivers/accel/ivpu/ivpu_hw_37xx_reg.h | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index a4149fc8a1d7..51d976ba5276 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -426,14 +426,27 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->vpu_telemetry_enable); ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", boot_params->dvfs_mode); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", +boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", +boot_params->d0i3_entry_vpu_ts); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) { struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx; - /* In case of warm boot we only have to reset the entrypoint addr */ + /* In case of warm boot only update variable params */ if (!ivpu_fw_is_cold_boot(vdev)) { + boot_params->d0i3_residency_time_us = + ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts); + boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; + + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", +boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", +boot_params->d0i3_entry_vpu_ts); + boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; wmb(); /* Flush WC buffers after writing save_restore_ret_address */ @@ -498,6 +511,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); boot_params->dvfs_mode = vdev->fw->dvfs_mode; + boot_params->d0i3_residency_time_us = 0; + boot_params->d0i3_entry_vpu_ts = 0; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index 1079e06255ba..bb4368168247 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -58,6 +58,8 @@ struct ivpu_hw_info { u32 sku; u16 config; int dma_bits; + ktime_t d0i3_entry_host_ts; + u64 d0i3_entry_vpu_ts; }; extern const struct ivpu_hw_ops ivpu_hw_37xx_ops; diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 0da4e6117d6b..06d7db28448a 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -731,10 +731,18 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT); +} + static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_ip_reset(vdev)) ivpu_err(vdev, "Failed to reset the VPU\n"); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h index 4083beb5e9db..f6fec1919202 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h @@ -240,6 +240,8 @@ #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9) +#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT 0x06029000u + #define VPU_37XX_CPU_SS_DOORBELL_0 0x0630u #define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0) -- 2.25.1
[PATCH 07/11] accel/ivpu: Introduce ivpu_ipc_send_receive_active()
From: Karol Wachowski Split ivpu_ipc_send_receive() implementation to have a version that does not call pm_runtime_resume_and_get(). That implementation can be invoked when device is up and runtime resume is prohibited (for example at the end of boot sequence). Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_ipc.c | 33 ++--- drivers/accel/ivpu/ivpu_ipc.h | 8 +--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index a4ca40b184d4..962b3bcca460 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -285,23 +285,20 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req return ret; } -int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms) +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, +enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, +u32 channel, unsigned long timeout_ms) { struct vpu_jsm_msg hb_req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB }; struct vpu_jsm_msg hb_resp; int ret, hb_ret; - ret = ivpu_rpm_get(vdev); - if (ret < 0) - return ret; + drm_WARN_ON(&vdev->drm, + vdev->drm.dev->power.runtime_status == RPM_SUSPENDED); - ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp_type, resp, -channel, timeout_ms); + ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp, resp, channel, timeout_ms); if (ret != -ETIMEDOUT) - goto rpm_put; + return ret; hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, @@ -311,7 +308,21 @@ int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, ivpu_pm_schedule_recovery(vdev); } -rpm_put: + return ret; +} + +int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms) +{ + int ret; + + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; + + ret = ivpu_ipc_send_receive_active(vdev, req, expected_resp, resp, channel, timeout_ms); + ivpu_rpm_put(vdev); return ret; } diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 68f5b6668e00..6918db23daa4 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -85,9 +85,11 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms); +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, +enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, +u32 channel, unsigned long timeout_ms); int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms); + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms); #endif /* __IVPU_IPC_H__ */ -- 2.25.1
[PATCH 06/11] accel/ivpu: Change test_mode module param to bitmask
From: Karol Wachowski Change meaning of test_mode module parameter from integer value to bitmask allowing setting different test features with corresponding bits. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 4 ++-- drivers/accel/ivpu/ivpu_drv.h | 7 +++ drivers/accel/ivpu/ivpu_job.c | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 2a58fb1e2fcc..4dbfd05680ce 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); -MODULE_PARM_DESC(test_mode, "Test mode: 0 - disabled , 1 - fw unit test, 2 - null hw, 3 - null submission"); +MODULE_PARM_DESC(test_mode, "Test mode mask. See IVPU_TEST_MODE_* macros."); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); @@ -315,7 +315,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) unsigned long timeout; int ret; - if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST) + if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST) return 0; ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 267e03a5edf4..5432b5ee90df 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -148,10 +148,9 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 -#define IVPU_TEST_MODE_NULL_SUBMISSION 3 +#define IVPU_TEST_MODE_FW_TEST BIT(0) +#define IVPU_TEST_MODE_NULL_HW BIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 646b8f812901..6e96c921547d 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -196,7 +196,7 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; - if (unlikely(ivpu_test_mode == IVPU_TEST_MODE_NULL_SUBMISSION)) + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION)) entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; @@ -404,7 +404,7 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id, job->engine_idx, cmdq->jobq->header.tail); - if (ivpu_test_mode == IVPU_TEST_MODE_NULL_HW) { + if (ivpu_test_mode & IVPU_TEST_MODE_NULL_HW) { ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); cmdq->jobq->header.head = cmdq->jobq->header.tail; wmb(); /* Flush WC buffer for jobq header */ -- 2.25.1
[PATCH 02/11] accel/ivpu: Remove unneeded drm_driver dectaration
Cleanup drm_driver declaration leftover. Reviewed-by: Krystian Pradzynski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 790603017653..346dd7fdcacb 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -31,8 +31,6 @@ __stringify(DRM_IVPU_DRIVER_MINOR) "." #endif -static const struct drm_driver driver; - static struct lock_class_key submitted_jobs_xa_lock_class_key; int ivpu_dbg_mask; -- 2.25.1
[PATCH 01/11] accel/ivpu: Update FW API
From: Krystian Pradzynski Bump boot API to 4.20 Bump JSM API to 3.15 Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_jsm_msg.c | 17 ++ drivers/accel/ivpu/vpu_boot_api.h | 90 - drivers/accel/ivpu/vpu_jsm_api.h | 309 -- 3 files changed, 392 insertions(+), 24 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 0c2fe7142024..35a689475c68 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -36,6 +36,17 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_DESTROY_CMD_QUEUE); IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES); IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_REGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_ENGINE_RESUME); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL); IVPU_CASE_TO_STR(VPU_JSM_MSG_JOB_DONE); @@ -65,6 +76,12 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE); } #undef IVPU_CASE_TO_STR diff --git a/drivers/accel/ivpu/vpu_boot_api.h b/drivers/accel/ivpu/vpu_boot_api.h index 6b71be92ba65..04c954258563 100644 --- a/drivers/accel/ivpu/vpu_boot_api.h +++ b/drivers/accel/ivpu/vpu_boot_api.h @@ -11,7 +11,10 @@ * The bellow values will be used to construct the version info this way: * fw_bin_header->api_version[VPU_BOOT_API_VER_ID] = (VPU_BOOT_API_VER_MAJOR << 16) | * VPU_BOOT_API_VER_MINOR; - * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes. + * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes + * This information is collected by using vpuip_2/application/vpuFirmware/make_std_fw_image.py + * If a header is missing this info we ignore the header, if a header is missing or contains + * partial info a build error will be generated. */ /* @@ -24,12 +27,12 @@ * Minor version changes when API backward compatibility is preserved. * Resets to 0 if Major version is incremented. */ -#define VPU_BOOT_API_VER_MINOR 12 +#define VPU_BOOT_API_VER_MINOR 20 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_BOOT_API_VER_PATCH 2 +#define VPU_BOOT_API_VER_PATCH 4 /* * Index in the API version table @@ -63,6 +66,12 @@ struct vpu_firmware_header { /* Size of memory require for firmware execution */ u32 runtime_size; u32 shave_nn_fw_size; + /* Size of primary preemption buffer. */ + u32 preemption_buffer_1_size; + /* Size of secondary preemption buffer. */ + u32 preemption_buffer_2_size; + /* Space reserved for future preemption-related fields. */ + u32 preemption_reserved[6]; }; /* @@ -89,6 +98,14 @@ enum VPU_BOOT_L2_CACHE_CFG_TYPE { VPU_BOOT_L2_CACHE_CFG_NUM = 2 }; +/** VPU MCA ECC signalling mode. By default, no signalling is used */ +enum VPU_BOOT_MCA_ECC_SIGNAL_TYPE { + VPU_BOOT_MCA_ECC_NONE = 0, + VPU_BOOT_MCA_ECC_CORR = 1, + VPU_BOOT_MCA_ECC_FATAL = 2, + VPU_BOOT_MCA_ECC_BOTH = 3 +}; + /** * Logging destinations. * @@ -131,9 +148,11 @@ enum vpu_trace_destination { #define VPU_TRACE_PROC_BIT_ACT_SHV_3 22 #define VPU_TRACE_PROC_NO_OF_HW_DEVS 23 -/* KMB HW component IDs are sequential, so define first and last IDs. */ -#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_LRT -#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_SHV_15 +/* VPU 30xx HW component IDs are sequential, so define first and last IDs. */ +#define VPU_TRACE_PROC_BIT_30XX_FIRST VPU_TRACE_PROC_BIT_LRT +#define VPU_TRACE_PROC_BIT_
[PATCH 00/11] accel/ivpu: Update to -next 2023-10-25
Various driver updates: - FW api update - suspend/resume optimizations - dynamic valtage and freqency mode knob - new test modes Andrzej Kacprowski (5): accel/ivpu: Add support for VPU_JOB_FLAGS_NULL_SUBMISSION_MASK accel/ivpu: Pass D0i3 residency time to the VPU firmware accel/ivpu/40xx: Capture D0i3 entry host and device timestamps accel/ivpu: Add support for delayed D0i3 entry message accel/ivpu: Wait for VPU to enter idle state after D0i3 entry message Karol Wachowski (3): accel/ivpu: Remove reset from power up sequence accel/ivpu: Change test_mode module param to bitmask accel/ivpu: Introduce ivpu_ipc_send_receive_active() Krystian Pradzynski (1): accel/ivpu: Update FW API Stanislaw Gruszka (1): accel/ivpu: Remove unneeded drm_driver dectaration Tomasz Rusinowicz (1): accel/ivpu: Add dvfs_mode file to debugfs drivers/accel/ivpu/ivpu_debugfs.c | 28 +++ drivers/accel/ivpu/ivpu_drv.c | 6 +- drivers/accel/ivpu/ivpu_drv.h | 10 +- drivers/accel/ivpu/ivpu_fw.c | 70 +- drivers/accel/ivpu/ivpu_fw.h | 1 + drivers/accel/ivpu/ivpu_hw.h | 8 + drivers/accel/ivpu/ivpu_hw_37xx.c | 28 ++- drivers/accel/ivpu/ivpu_hw_37xx_reg.h | 2 + drivers/accel/ivpu/ivpu_hw_40xx.c | 24 +- drivers/accel/ivpu/ivpu_ipc.c | 33 ++- drivers/accel/ivpu/ivpu_ipc.h | 8 +- drivers/accel/ivpu/ivpu_job.c | 4 +- drivers/accel/ivpu/ivpu_jsm_msg.c | 38 drivers/accel/ivpu/ivpu_jsm_msg.h | 1 + drivers/accel/ivpu/ivpu_pm.c | 11 +- drivers/accel/ivpu/vpu_boot_api.h | 90 +++- drivers/accel/ivpu/vpu_jsm_api.h | 309 -- 17 files changed, 607 insertions(+), 64 deletions(-) -- 2.25.1
[PATCH 05/11] accel/ivpu: Add support for VPU_JOB_FLAGS_NULL_SUBMISSION_MASK
From: Andrzej Kacprowski Add test_mode = 3 that add VPU_JOB_FLAGS_NULL_SUBMISSION_MASK flag to the job send to the VPU device. Then the VPU will process the job but won't execute commands (except the command to signal the fence). This can b used to estimate job processing overhead in the host software and VPU firmware. Unlike the null hardware mode, the null submission mode will still work even if UMD uses VPU fences to track job completion. Signed-off-by: Andrzej Kacprowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_drv.h | 7 --- drivers/accel/ivpu/ivpu_job.c | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 346dd7fdcacb..2a58fb1e2fcc 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); -MODULE_PARM_DESC(test_mode, "Test mode: 0 - normal operation, 1 - fw unit test, 2 - null hw"); +MODULE_PARM_DESC(test_mode, "Test mode: 0 - disabled , 1 - fw unit test, 2 - null hw, 3 - null submission"); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 417ddeca8517..267e03a5edf4 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -148,9 +148,10 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED 0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_DISABLED0 +#define IVPU_TEST_MODE_FW_TEST 1 +#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_NULL_SUBMISSION 3 extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 689dc0d13b8f..646b8f812901 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -196,6 +196,8 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; + if (unlikely(ivpu_test_mode == IVPU_TEST_MODE_NULL_SUBMISSION)) + entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; wmb(); /* Flush WC buffer for jobq header */ -- 2.25.1
[PATCH 04/11] accel/ivpu: Remove reset from power up sequence
From: Karol Wachowski Setting a non-zero work point resets the IP hence IP_RESET trigger is redundant. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 4 drivers/accel/ivpu/ivpu_hw_40xx.c | 6 -- 2 files changed, 10 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 56b53833ede2..0da4e6117d6b 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -668,10 +668,6 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_37xx_ip_reset(vdev); - if (ret) - ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); - ret = ivpu_hw_37xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index b25d02dc541b..5876cfd9dd40 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -841,12 +841,6 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_40xx_ip_reset(vdev); - if (ret) { - ivpu_err(vdev, "Failed to reset HW: %d\n", ret); - return ret; - } - ret = ivpu_hw_40xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); -- 2.25.1
[PATCH v2] accel/ivpu: Disable PLL after VPU IP reset during FLR
From: Jacek Lawrynowicz IP reset has to followed by ivpu_pll_disable() to properly enter reset state. Fixes: 828d63042aec ("accel/ivpu: Don't enter d0i3 during FLR") Cc: sta...@vger.kernel.org Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- v2: use ivpu_hw_37xx_ip_reset() in ivpu_hw_37xx_power_up() drivers/accel/ivpu/ivpu_hw_37xx.c | 23 --- drivers/accel/ivpu/ivpu_hw_40xx.c | 23 --- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 5c0246b9e522..56b53833ede2 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -598,7 +598,7 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) return 0; } -static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) +static int ivpu_hw_37xx_ip_reset(struct ivpu_device *vdev) { int ret; u32 val; @@ -623,6 +623,23 @@ static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) return ret; } +static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) +{ + int ret = 0; + + if (ivpu_hw_37xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset VPU IP\n"); + ret = -EIO; + } + + if (ivpu_pll_disable(vdev)) { + ivpu_err(vdev, "Failed to disable PLL\n"); + ret = -EIO; + } + + return ret; +} + static int ivpu_hw_37xx_d0i3_enable(struct ivpu_device *vdev) { int ret; @@ -651,7 +668,7 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_37xx_reset(vdev); + ret = ivpu_hw_37xx_ip_reset(vdev); if (ret) ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); @@ -722,7 +739,7 @@ static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) { int ret = 0; - if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) + if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_ip_reset(vdev)) ivpu_err(vdev, "Failed to reset the VPU\n"); if (ivpu_pll_disable(vdev)) { diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index e691c49c9841..b25d02dc541b 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -742,7 +742,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) return 0; } -static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev) { int ret; u32 val; @@ -764,6 +764,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) return ret; } +static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +{ + int ret = 0; + + if (ivpu_hw_40xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset VPU IP\n"); + ret = -EIO; + } + + if (ivpu_pll_disable(vdev)) { + ivpu_err(vdev, "Failed to disable PLL\n"); + ret = -EIO; + } + + return ret; +} + static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev) { int ret; @@ -824,7 +841,7 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_40xx_reset(vdev); + ret = ivpu_hw_40xx_ip_reset(vdev); if (ret) { ivpu_err(vdev, "Failed to reset HW: %d\n", ret); return ret; @@ -902,7 +919,7 @@ static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) { int ret = 0; - if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); if (ivpu_pll_disable(vdev)) { -- 2.25.1
[PATCH] accel/ivpu/37xx: Fix missing VPUIP interrupts
From: Karol Wachowski Move sequence of masking and unmasking global interrupts from buttress interrupt handler to generic one that handles both VPUIP and BTRS interrupts. Unmasking global interrupts will re-trigger MSI for any pending interrupts. Lack of this sequence will cause the driver to miss any VPUIP interrupt that comes after reading VPU_37XX_HOST_SS_ICB_STATUS_0 and before clearing all active interrupt sources. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 11 +-- 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 7e4e87aa7602..5c0246b9e522 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -906,9 +906,6 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) if (status == 0) return 0; - /* Disable global interrupt before handling local buttress interrupts */ - REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); - if (REG_TEST_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x", REGB_RD32(VPU_37XX_BUTTRESS_CURRENT_PLL)); @@ -940,9 +937,6 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) else REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status); - /* Re-enable global interrupt */ - REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); - if (schedule_recovery) ivpu_pm_schedule_recovery(vdev); @@ -954,9 +948,14 @@ static irqreturn_t ivpu_hw_37xx_irq_handler(int irq, void *ptr) struct ivpu_device *vdev = ptr; u32 ret_irqv, ret_irqb; + REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); + ret_irqv = ivpu_hw_37xx_irqv_handler(vdev, irq); ret_irqb = ivpu_hw_37xx_irqb_handler(vdev, irq); + /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ + REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); + return IRQ_RETVAL(ret_irqb | ret_irqv); } -- 2.25.1
[PATCH] accel/ivpu: Disable PLL after VPU IP reset during FLR
From: Jacek Lawrynowicz IP reset has to followed by ivpu_pll_disable() to properly enter reset state. Fixes: 828d63042aec ("accel/ivpu: Don't enter d0i3 during FLR") Cc: sta...@vger.kernel.org Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 21 +++-- drivers/accel/ivpu/ivpu_hw_40xx.c | 23 --- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 7e4e87aa7602..899369a3c5dc 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -598,7 +598,7 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) return 0; } -static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) +static int ivpu_hw_37xx_ip_reset(struct ivpu_device *vdev) { int ret; u32 val; @@ -623,6 +623,23 @@ static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) return ret; } +static int ivpu_hw_37xx_reset(struct ivpu_device *vdev) +{ + int ret = 0; + + if (ivpu_hw_37xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset VPU IP\n"); + ret = -EIO; + } + + if (ivpu_pll_disable(vdev)) { + ivpu_err(vdev, "Failed to disable PLL\n"); + ret = -EIO; + } + + return ret; +} + static int ivpu_hw_37xx_d0i3_enable(struct ivpu_device *vdev) { int ret; @@ -722,7 +739,7 @@ static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) { int ret = 0; - if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_reset(vdev)) + if (!ivpu_hw_37xx_is_idle(vdev) && ivpu_hw_37xx_ip_reset(vdev)) ivpu_err(vdev, "Failed to reset the VPU\n"); if (ivpu_pll_disable(vdev)) { diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index e691c49c9841..b25d02dc541b 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -742,7 +742,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) return 0; } -static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev) { int ret; u32 val; @@ -764,6 +764,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) return ret; } +static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +{ + int ret = 0; + + if (ivpu_hw_40xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset VPU IP\n"); + ret = -EIO; + } + + if (ivpu_pll_disable(vdev)) { + ivpu_err(vdev, "Failed to disable PLL\n"); + ret = -EIO; + } + + return ret; +} + static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev) { int ret; @@ -824,7 +841,7 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_40xx_reset(vdev); + ret = ivpu_hw_40xx_ip_reset(vdev); if (ret) { ivpu_err(vdev, "Failed to reset HW: %d\n", ret); return ret; @@ -902,7 +919,7 @@ static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) { int ret = 0; - if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); if (ivpu_pll_disable(vdev)) { -- 2.25.1
Re: [PATCH 0/6] accel/ivpu: Update to -next 2023-10-20
On Fri, Oct 20, 2023 at 12:44:55PM +0200, Stanislaw Gruszka wrote: > Random changes across the driver. > > Karol Wachowski (1): > accel/ivpu: Read clock rate only if device is up > > Krystian Pradzynski (3): > accel/ivpu: Use ratelimited warn and err in IPC/JSM > accel/ivpu: Fix verbose version of REG_POLL macros > accel/ivpu: Print IPC type string instead of number > > Stanislaw Gruszka (2): > accel/ivpu: Do no initialize parameters on power up > accel/ivpu/37xx: Remove support for FPGA and simics Fixed typos pointed by Jeffrey and applied to drm-misc-next Thanks Stanislaw
Re: [PATCH v2 2/2] accel/qaic: Support MHI QAIC_TIMESYNC channel
On Mon, Oct 16, 2023 at 11:01:14AM -0600, Jeffrey Hugo wrote: > From: Pranjal Ramajor Asha Kanojiya > > Use QAIC_TIMESYNC MHI channel to send UTC time to device in SBL > environment. Remove support for QAIC_TIMESYNC MHI channel in AMSS > environment as it is not used in that environment. > > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > Reviewed-by: Carl Vanderlip > Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka
Re: [PATCH v2 1/2] accel/qaic: Add support for periodic timesync
On Mon, Oct 16, 2023 at 11:01:13AM -0600, Jeffrey Hugo wrote: > From: Ajit Pal Singh > > Device and Host have a time synchronization mechanism that happens once > during boot when device is in SBL mode. After that, in mission-mode there > is no timesync. In an experiment after continuous operation, device time > drifted w.r.t. host by approximately 3 seconds per day. This drift leads > to mismatch in timestamp of device and Host logs. To correct this > implement periodic timesync in driver. This timesync is carried out via > QAIC_TIMESYNC_PERIODIC MHI channel. > > Signed-off-by: Ajit Pal Singh > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > Reviewed-by: Carl Vanderlip > Reviewed-by: Pranjal Ramajor Asha Kanojiya > Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka > @@ -586,8 +587,16 @@ static int __init qaic_init(void) > goto free_pci; > } > > + ret = qaic_timesync_init(); > + if (ret) { > + pr_debug("qaic: qaic_timesync_init failed %d\n", ret); > + goto free_mhi; I would print at error level here. Or if timesync is optional do not error exit. > +#ifdef readq > +static u64 read_qtimer(const volatile void __iomem *addr) > +{ > + return readq(addr); > +} > +#else > +static u64 read_qtimer(const volatile void __iomem *addr) > +{ > + u64 low, high; > + > + low = readl(addr); > + high = readl(addr + sizeof(u32)); > + return low | (high << 32); > +} If that's only for compile on 32-bit PowerPC, I think would be better to limit supported architectures on Kconfig. Regards Stanislaw
Re: [PATCH v2] accel/qaic: Enable 1 MSI fallback mode
On Mon, Oct 16, 2023 at 11:00:36AM -0600, Jeffrey Hugo wrote: > From: Carl Vanderlip > > Several virtualization use-cases either don't support 32 MultiMSIs > (Xen/VMware) or have significant drawbacks to their use (KVM's vIOMMU, > which is required to support 32 MSI, needs to allocate an alternate > system memory space for each device using vIOMMU (e.g. 8GB VM mem and > 2 cards => 8 + 2 * 8 = 24GB host memory required)). Support these > cases by enabling a 1 MSI fallback mode. > > Whenever all 32 MSIs requested are not available, a second request for > a single MSI is made. Its success is the initiator of single MSI mode. > This mode causes all interrupts generated by the device to be directed > to the 0th MSI (firmware >=v1.10 will do this as a response to the PCIe > MSI capability configuration). Likewise, all interrupt handlers for the > device are registered to the 0th MSI. > > Since the DBC interrupt handler checks if the DBC is in use or if > there is any pending changes, the 'spurious' interrupts are > disregarded. If there is work to be done, the standard threaded IRQ > handler is dispatched. > > On every interrupt, the MHI handler wakes up its threaded interrupt > handler, and attempts to wake any waiters for MHI state events. > > Performance is within +-0.6% for test cases that typify real world > use. Larger differences ([-4,+132]%, avg +47%) exist for very simple > tasks (e.g. addition) compiled for single NSPs. It is assumed that the > small work and many interrupts typically cause contention (e.g. 16 NSPs > vs 4 CPUs), as evidenced by the standard deviation between runs also > decreasing (r=-0.48 between delta(Performace_test) and > delta(StdDev_test/Avg_test)) > > Signed-off-by: Carl Vanderlip > Reviewed-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka
[PATCH 6/6] accel/ivpu/37xx: Remove support for FPGA and simics
We do not run 37xx VPU on non-silicon platforms any longer. Remove deprecated code to make it cleaner. Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 57 +-- 1 file changed, 8 insertions(+), 49 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index 63ce5418d3fa..e5cb9d8acb82 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -68,37 +68,9 @@ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \ (REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX))) -static char *ivpu_platform_to_str(u32 platform) -{ - switch (platform) { - case IVPU_PLATFORM_SILICON: - return "IVPU_PLATFORM_SILICON"; - case IVPU_PLATFORM_SIMICS: - return "IVPU_PLATFORM_SIMICS"; - case IVPU_PLATFORM_FPGA: - return "IVPU_PLATFORM_FPGA"; - default: - return "Invalid platform"; - } -} - -static void ivpu_hw_read_platform(struct ivpu_device *vdev) -{ - u32 gen_ctrl = REGV_RD32(VPU_37XX_HOST_SS_GEN_CTRL); - u32 platform = REG_GET_FLD(VPU_37XX_HOST_SS_GEN_CTRL, PS, gen_ctrl); - - if (platform == IVPU_PLATFORM_SIMICS || platform == IVPU_PLATFORM_FPGA) - vdev->platform = platform; - else - vdev->platform = IVPU_PLATFORM_SILICON; - - ivpu_dbg(vdev, MISC, "Platform type: %s (%d)\n", -ivpu_platform_to_str(vdev->platform), vdev->platform); -} - static void ivpu_hw_wa_init(struct ivpu_device *vdev) { - vdev->wa.punit_disabled = ivpu_is_fpga(vdev); + vdev->wa.punit_disabled = false; vdev->wa.clear_runtime_mem = false; vdev->wa.d3hot_after_power_off = true; @@ -113,19 +85,11 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) { - if (ivpu_is_simics(vdev) || ivpu_is_fpga(vdev)) { - vdev->timeout.boot = 10; - vdev->timeout.jsm = 5; - vdev->timeout.tdr = 200; - vdev->timeout.reschedule_suspend = 1000; - vdev->timeout.autosuspend = -1; - } else { - vdev->timeout.boot = 1000; - vdev->timeout.jsm = 500; - vdev->timeout.tdr = 2000; - vdev->timeout.reschedule_suspend = 10; - vdev->timeout.autosuspend = 10; - } + vdev->timeout.boot = 1000; + vdev->timeout.jsm = 500; + vdev->timeout.tdr = 2000; + vdev->timeout.reschedule_suspend = 10; + vdev->timeout.autosuspend = 10; } static int ivpu_pll_wait_for_cmd_send(struct ivpu_device *vdev) @@ -220,8 +184,7 @@ static int ivpu_pll_drive(struct ivpu_device *vdev, bool enable) int ret; if (IVPU_WA(punit_disabled)) { - ivpu_dbg(vdev, PM, "Skipping PLL request on %s\n", -ivpu_platform_to_str(vdev->platform)); + ivpu_dbg(vdev, PM, "Skipping PLL request\n"); return 0; } @@ -484,10 +447,6 @@ static void ivpu_boot_pwr_island_drive(struct ivpu_device *vdev, bool enable) static int ivpu_boot_wait_for_pwr_island_status(struct ivpu_device *vdev, u32 exp_val) { - /* FPGA model (UPF) is not power aware, skipped Power Island polling */ - if (ivpu_is_fpga(vdev)) - return 0; - return REGV_POLL_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0, MSS_CPU, exp_val, PWR_ISLAND_STATUS_TIMEOUT_US); } @@ -632,7 +591,7 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) ivpu_hw_init_range(&hw->ranges.shave, 0x18000, SZ_2G); ivpu_hw_init_range(&hw->ranges.dma, 0x2, SZ_8G); - ivpu_hw_read_platform(vdev); + vdev->platform = IVPU_PLATFORM_SILICON; ivpu_hw_wa_init(vdev); ivpu_hw_timeouts_init(vdev); -- 2.25.1
[PATCH 5/6] accel/ivpu: Do no initialize parameters on power up
Initialize HW specific parameters only once. We do not have to do this on every power_up (performed during initialization and on resume). Move corresponding code to ->init_info() Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_37xx.c | 8 drivers/accel/ivpu/ivpu_hw_40xx.c | 8 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index edd4d860f135..63ce5418d3fa 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -632,6 +632,10 @@ static int ivpu_hw_37xx_info_init(struct ivpu_device *vdev) ivpu_hw_init_range(&hw->ranges.shave, 0x18000, SZ_2G); ivpu_hw_init_range(&hw->ranges.dma, 0x2, SZ_8G); + ivpu_hw_read_platform(vdev); + ivpu_hw_wa_init(vdev); + ivpu_hw_timeouts_init(vdev); + return 0; } @@ -688,10 +692,6 @@ static int ivpu_hw_37xx_power_up(struct ivpu_device *vdev) { int ret; - ivpu_hw_read_platform(vdev); - ivpu_hw_wa_init(vdev); - ivpu_hw_timeouts_init(vdev); - ret = ivpu_hw_37xx_reset(vdev); if (ret) ivpu_warn(vdev, "Failed to reset HW: %d\n", ret); diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 1c2528549635..4bf4c8780044 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -722,6 +722,10 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) ivpu_hw_init_range(&vdev->hw->ranges.shave, 0x8000 + SZ_256M, SZ_2G - SZ_256M); ivpu_hw_init_range(&vdev->hw->ranges.dma, 0x2, SZ_8G); + ivpu_hw_read_platform(vdev); + ivpu_hw_wa_init(vdev); + ivpu_hw_timeouts_init(vdev); + return 0; } @@ -813,10 +817,6 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) return ret; } - ivpu_hw_read_platform(vdev); - ivpu_hw_wa_init(vdev); - ivpu_hw_timeouts_init(vdev); - ret = ivpu_hw_40xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); -- 2.25.1
[PATCH 4/6] accel/ivpu: Print IPC type string instead of number
From: Krystian Pradzynski Introduce ivpu_jsm_msg_type_to_str() helper to print type of IPC message. This will make reading logs and debugging IPC issues easier. Co-developed-by: Maciej Falkowski Signed-off-by: Maciej Falkowski Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_ipc.c | 9 +++-- drivers/accel/ivpu/ivpu_jsm_msg.c | 64 +++ drivers/accel/ivpu/ivpu_jsm_msg.h | 2 + 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index f0137536d7c6..6e213a5afb8c 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -45,8 +45,9 @@ static void ivpu_jsm_msg_dump(struct ivpu_device *vdev, char *c, u32 *payload = (u32 *)&jsm_msg->payload; ivpu_dbg(vdev, JSM, -"%s: vpu:0x%08x (type:0x%x, status:0x%x, id: 0x%x, result: 0x%x, payload:0x%x 0x%x 0x%x 0x%x 0x%x)\n", -c, vpu_addr, jsm_msg->type, jsm_msg->status, jsm_msg->request_id, jsm_msg->result, +"%s: vpu:0x%08x (type:%s, status:0x%x, id: 0x%x, result: 0x%x, payload:0x%x 0x%x 0x%x 0x%x 0x%x)\n", +c, vpu_addr, ivpu_jsm_msg_type_to_str(jsm_msg->type), +jsm_msg->status, jsm_msg->request_id, jsm_msg->result, payload[0], payload[1], payload[2], payload[3], payload[4]); } @@ -272,8 +273,8 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req ret = ivpu_ipc_receive(vdev, &cons, NULL, resp, timeout_ms); if (ret) { - ivpu_warn_ratelimited(vdev, "IPC receive failed: type 0x%x, ret %d\n", - req->type, ret); + ivpu_warn_ratelimited(vdev, "IPC receive failed: type %s, ret %d\n", + ivpu_jsm_msg_type_to_str(req->type), ret); goto consumer_del; } diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 5d37efa8ce31..0c2fe7142024 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -7,6 +7,70 @@ #include "ivpu_ipc.h" #include "ivpu_jsm_msg.h" +const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) +{ + #define IVPU_CASE_TO_STR(x) case x: return #x + switch (type) { + IVPU_CASE_TO_STR(VPU_JSM_MSG_UNKNOWN); + IVPU_CASE_TO_STR(VPU_JSM_MSG_ENGINE_RESET); + IVPU_CASE_TO_STR(VPU_JSM_MSG_ENGINE_PREEMPT); + IVPU_CASE_TO_STR(VPU_JSM_MSG_REGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_UNREGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_QUERY_ENGINE_HB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_GET_POWER_LEVEL_COUNT); + IVPU_CASE_TO_STR(VPU_JSM_MSG_GET_POWER_LEVEL); + IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_POWER_LEVEL); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_OPEN); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_CLOSE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_SET_CONFIG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_GET_CONFIG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_GET_CAPABILITY); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_GET_NAME); + IVPU_CASE_TO_STR(VPU_JSM_MSG_SSID_RELEASE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_START); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_STOP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_UPDATE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_INFO); + IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_PRIORITY_BAND_SETUP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_CREATE_CMD_QUEUE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DESTROY_CMD_QUEUE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_REGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL); + IVPU_CASE_TO_STR(VPU_JSM_MSG_JOB_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_ENGINE_RESET_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_ENGINE_PREEMPT_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_REGISTER_DB_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_UNREGISTER_DB_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_QUERY_ENGINE_HB_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_GET_POWER_LEVEL_COUNT_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_GET_POWER_LEVEL_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_POWER_LEVEL_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_OPEN_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_METRIC_STREAMER_CLOSE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_SET_CONFIG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_GET_CONFIG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_GET_CAPABILITY_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_TRACE_GET_NAME_RSP); + IVPU_CASE_T
[PATCH 3/6] accel/ivpu: Read clock rate only if device is up
From: Karol Wachowski Do not unnecessarily wake up device to read clock rate. Return 0 as clk_rate if device is suspended. Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 18 +- drivers/accel/ivpu/ivpu_pm.c | 13 + drivers/accel/ivpu/ivpu_pm.h | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 7851ff7773ca..b6aa8893ff1c 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -131,6 +131,22 @@ static int ivpu_get_capabilities(struct ivpu_device *vdev, struct drm_ivpu_param return 0; } +static int ivpu_get_core_clock_rate(struct ivpu_device *vdev, u64 *clk_rate) +{ + int ret; + + ret = ivpu_rpm_get_if_active(vdev); + if (ret < 0) + return ret; + + *clk_rate = ret ? ivpu_hw_reg_pll_freq_get(vdev) : 0; + + if (ret) + ivpu_rpm_put(vdev); + + return 0; +} + static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct ivpu_file_priv *file_priv = file->driver_priv; @@ -154,7 +170,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f args->value = vdev->platform; break; case DRM_IVPU_PARAM_CORE_CLOCK_RATE: - args->value = ivpu_hw_reg_pll_freq_get(vdev); + ret = ivpu_get_core_clock_rate(vdev, &args->value); break; case DRM_IVPU_PARAM_NUM_CONTEXTS: args->value = ivpu_get_context_count(vdev); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index e359ba36a9c3..d14b6fd796b4 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -246,6 +246,19 @@ int ivpu_rpm_get(struct ivpu_device *vdev) return ret; } +int ivpu_rpm_get_if_active(struct ivpu_device *vdev) +{ + int ret; + + ivpu_dbg(vdev, RPM, "rpm_get_if_active count %d\n", +atomic_read(&vdev->drm.dev->power.usage_count)); + + ret = pm_runtime_get_if_active(vdev->drm.dev, false); + drm_WARN_ON(&vdev->drm, ret < 0); + + return ret; +} + void ivpu_rpm_put(struct ivpu_device *vdev) { pm_runtime_mark_last_busy(vdev->drm.dev); diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index f41c30a14a40..044db150be07 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -33,6 +33,7 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev); void ivpu_pm_reset_done_cb(struct pci_dev *pdev); int __must_check ivpu_rpm_get(struct ivpu_device *vdev); +int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev); void ivpu_rpm_put(struct ivpu_device *vdev); void ivpu_pm_schedule_recovery(struct ivpu_device *vdev); -- 2.25.1
[PATCH 2/6] accel/ivpu: Fix verbose version of REG_POLL macros
From: Krystian Pradzynski Remove two out of four _POLL macros. For two remained _POLL macros add message about polling register start and finish. Additionally avoid inconsequence when using REGV_WR/RD macros in MMU code - passing raw register offset instead of register name. Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_reg_io.h | 32 drivers/accel/ivpu/ivpu_mmu.c | 47 + 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_reg_io.h b/drivers/accel/ivpu/ivpu_hw_reg_io.h index 43c2c0c2d050..79b3f441eac4 100644 --- a/drivers/accel/ivpu/ivpu_hw_reg_io.h +++ b/drivers/accel/ivpu/ivpu_hw_reg_io.h @@ -47,22 +47,30 @@ #define REG_TEST_FLD_NUM(REG, FLD, num, val) \ ((num) == FIELD_GET(REG##_##FLD##_MASK, val)) -#define REGB_POLL(reg, var, cond, timeout_us) \ - read_poll_timeout(REGB_RD32_SILENT, var, cond, REG_POLL_SLEEP_US, timeout_us, false, reg) - -#define REGV_POLL(reg, var, cond, timeout_us) \ - read_poll_timeout(REGV_RD32_SILENT, var, cond, REG_POLL_SLEEP_US, timeout_us, false, reg) - #define REGB_POLL_FLD(reg, fld, val, timeout_us) \ ({ \ u32 var; \ - REGB_POLL(reg, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)), timeout_us); \ + int r; \ + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s started (expected 0x%x)\n", \ +__func__, #reg, reg, #fld, val); \ + r = read_poll_timeout(REGB_RD32_SILENT, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)),\ + REG_POLL_SLEEP_US, timeout_us, false, (reg)); \ + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s %s (reg val 0x%08x)\n", \ +__func__, #reg, reg, #fld, r ? "ETIMEDOUT" : "OK", var); \ + r; \ }) #define REGV_POLL_FLD(reg, fld, val, timeout_us) \ ({ \ u32 var; \ - REGV_POLL(reg, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)), timeout_us); \ + int r; \ + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s started (expected 0x%x)\n", \ +__func__, #reg, reg, #fld, val); \ + r = read_poll_timeout(REGV_RD32_SILENT, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)),\ + REG_POLL_SLEEP_US, timeout_us, false, (reg)); \ + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) Polling field %s %s (reg val 0x%08x)\n", \ +__func__, #reg, reg, #fld, r ? "ETIMEDOUT" : "OK", var); \ + r; \ }) static inline u32 @@ -71,7 +79,7 @@ ivpu_hw_reg_rd32(struct ivpu_device *vdev, void __iomem *base, u32 reg, { u32 val = readl(base + reg); - ivpu_dbg(vdev, REG, "%s RD: %s (0x%08x) => 0x%08x\n", func, name, reg, val); + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) RD: 0x%08x\n", func, name, reg, val); return val; } @@ -81,7 +89,7 @@ ivpu_hw_reg_rd64(struct ivpu_device *vdev, void __iomem *base, u32 reg, { u64 val = readq(base + reg); - ivpu_dbg(vdev, REG, "%s RD: %s (0x%08x) => 0x%016llx\n", func, name, reg, val); + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) RD: 0x%016llx\n", func, name, reg, val); return val; } @@ -89,7 +97,7 @@ static inline void ivpu_hw_reg_wr32(struct ivpu_device *vdev, void __iomem *base, u32 reg, u32 val, const char *name, const char *func) { - ivpu_dbg(vdev, REG, "%s WR: %s (0x%08x) <= 0x%08x\n", func, name, reg, val); + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) WR: 0x%08x\n", func, name, reg, val); writel(val, base + reg); } @@ -97,7 +105,7 @@ static inline void ivpu_hw_reg_wr64(struct ivpu_device *vdev, void __iomem *base, u32 reg, u64 val, const char *name, const char *func) { - ivpu_dbg(vdev, REG, "%s WR: %s (0x%08x) <= 0x%016llx\n", func, name, reg, val); + ivpu_dbg(vdev, REG, "%s : %s (0x%08x) WR: 0x%016llx\n", func, name, reg, val); writeq(val, base + reg); } diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index 473e1fc686a7..2538c78fbebe 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -18,10 +18,12 @@ #define IVPU_MMU_REG_IDR50x00200014u #define IVPU_MMU_REG_CR0 0x00200020u #define IVPU_MMU_REG_CR0ACK 0x00200024u +#define IVPU_MMU_REG_CR0ACK_VAL_MASK GENMASK(31, 0) #define IVPU_MMU_REG_CR1 0x00200028u #define IVPU_MMU_REG_CR2 0x0020002cu #define IVPU_MMU_REG_IRQ_CTRL0x00200050u #define IVPU_MMU_REG_IRQ_CTRLACK 0x00200054u +#define IVPU_MMU_REG_IRQ_CTRLACK_VAL_MASK GENMASK(31, 0) #define IVPU_MMU_REG
[PATCH 1/6] accel/ivpu: Use ratelimited warn and err in IPC/JSM
From: Krystian Pradzynski Quite often during test corner cases IPC, JSM functions can flood dmesg with warn or err messages. With that lost dmesg history. Change warn, err to ratelimited versions in IPC, JSM to suppress dmesg spam occurrence during fail test scenarios. Signed-off-by: Krystian Pradzynski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_ipc.c | 29 - drivers/accel/ivpu/ivpu_jsm_msg.c | 18 ++ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index c2541035a30f..f0137536d7c6 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -79,8 +79,8 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, tx_buf_vpu_addr = gen_pool_alloc(ipc->mm_tx, sizeof(*tx_buf)); if (!tx_buf_vpu_addr) { - ivpu_err(vdev, "Failed to reserve IPC buffer, size %ld\n", -sizeof(*tx_buf)); + ivpu_err_ratelimited(vdev, "Failed to reserve IPC buffer, size %ld\n", +sizeof(*tx_buf)); return -ENOMEM; } @@ -93,12 +93,12 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, jsm_vpu_addr = tx_buf_vpu_addr + offsetof(struct ivpu_ipc_tx_buf, jsm); if (tx_buf->ipc.status != IVPU_IPC_HDR_FREE) - ivpu_warn(vdev, "IPC message vpu:0x%x not released by firmware\n", - tx_buf_vpu_addr); + ivpu_warn_ratelimited(vdev, "IPC message vpu:0x%x not released by firmware\n", + tx_buf_vpu_addr); if (tx_buf->jsm.status != VPU_JSM_MSG_FREE) - ivpu_warn(vdev, "JSM message vpu:0x%x not released by firmware\n", - jsm_vpu_addr); + ivpu_warn_ratelimited(vdev, "JSM message vpu:0x%x not released by firmware\n", + jsm_vpu_addr); memset(tx_buf, 0, sizeof(*tx_buf)); tx_buf->ipc.data_addr = jsm_vpu_addr; @@ -266,18 +266,19 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req ret = ivpu_ipc_send(vdev, &cons, req); if (ret) { - ivpu_warn(vdev, "IPC send failed: %d\n", ret); + ivpu_warn_ratelimited(vdev, "IPC send failed: %d\n", ret); goto consumer_del; } ret = ivpu_ipc_receive(vdev, &cons, NULL, resp, timeout_ms); if (ret) { - ivpu_warn(vdev, "IPC receive failed: type 0x%x, ret %d\n", req->type, ret); + ivpu_warn_ratelimited(vdev, "IPC receive failed: type 0x%x, ret %d\n", + req->type, ret); goto consumer_del; } if (resp->type != expected_resp_type) { - ivpu_warn(vdev, "Invalid JSM response type: 0x%x\n", resp->type); + ivpu_warn_ratelimited(vdev, "Invalid JSM response type: 0x%x\n", resp->type); ret = -EBADE; } @@ -375,13 +376,13 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) while (ivpu_hw_reg_ipc_rx_count_get(vdev)) { vpu_addr = ivpu_hw_reg_ipc_rx_addr_get(vdev); if (vpu_addr == REG_IO_ERROR) { - ivpu_err(vdev, "Failed to read IPC rx addr register\n"); + ivpu_err_ratelimited(vdev, "Failed to read IPC rx addr register\n"); return -EIO; } ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr); if (!ipc_hdr) { - ivpu_warn(vdev, "IPC msg 0x%x out of range\n", vpu_addr); + ivpu_warn_ratelimited(vdev, "IPC msg 0x%x out of range\n", vpu_addr); continue; } ivpu_ipc_msg_dump(vdev, "RX", ipc_hdr, vpu_addr); @@ -390,7 +391,8 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) { jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr); if (!jsm_msg) { - ivpu_warn(vdev, "JSM msg 0x%x out of range\n", ipc_hdr->data_addr); + ivpu_warn_ratelimited(vdev, "JSM msg 0x%x out of range\n", + ipc_hdr->data_addr); ivpu_ipc_rx_mark_free(vdev, ipc_hdr, NULL); continue; } @@ -398,7 +40
[PATCH 0/6] accel/ivpu: Update to -next 2023-10-20
Random changes across the driver. Karol Wachowski (1): accel/ivpu: Read clock rate only if device is up Krystian Pradzynski (3): accel/ivpu: Use ratelimited warn and err in IPC/JSM accel/ivpu: Fix verbose version of REG_POLL macros accel/ivpu: Print IPC type string instead of number Stanislaw Gruszka (2): accel/ivpu: Do no initialize parameters on power up accel/ivpu/37xx: Remove support for FPGA and simics drivers/accel/ivpu/ivpu_drv.c | 18 ++- drivers/accel/ivpu/ivpu_hw_37xx.c | 63 -- drivers/accel/ivpu/ivpu_hw_40xx.c | 8 +-- drivers/accel/ivpu/ivpu_hw_reg_io.h | 32 ++- drivers/accel/ivpu/ivpu_ipc.c | 34 ++-- drivers/accel/ivpu/ivpu_jsm_msg.c | 82 ++--- drivers/accel/ivpu/ivpu_jsm_msg.h | 2 + drivers/accel/ivpu/ivpu_mmu.c | 47 ++--- drivers/accel/ivpu/ivpu_pm.c| 13 + drivers/accel/ivpu/ivpu_pm.h| 1 + 10 files changed, 189 insertions(+), 111 deletions(-) -- 2.25.1
Re: ivpu TODO list items
On Wed, Oct 18, 2023 at 10:49:15PM +0530, Deepak R Varma wrote: > > > > 2. Is it absolutely necessary for me to have a specialized hardware to > > > > test my > > > > patches? Is it limited to the 14thGen or above CPU or do I need more > > > > than that? > > Yes, I don't think someone can work on ivpu without hardware. > > Okay. Could you suggest what would be the minimum hardware required to explore > this driver? As you wrote, you need to have 14th gen Intel CPU i.e. Meteor Lake. Only this ... or as much as this. Regards Stanislaw
Re: [PATCH] accel/ivpu: Don't enter d0i3 during FLR
On Tue, Oct 17, 2023 at 10:43:07AM +0200, Stanislaw Gruszka wrote: > On Fri, Oct 06, 2023 at 09:25:29AM -0600, Jeffrey Hugo wrote: > > On 10/3/2023 12:42 AM, Stanislaw Gruszka wrote: > > > From: Jacek Lawrynowicz > > > > > > Fix a bug on some platforms where FLR causes complete system > > > hang when CPU is low power states (C8 or above). > > > > Why does FLR cause a complete system hang? > > This HW bug is still under debug and it is not yet root caused. > > > Why does avoiding d0i3 fix the > > issue? Feels like there could be a lot more detail here. > > We only know that we should avoid entering D0i3. > > I will change the log this way: > > Avoid HW bug on some platforms where we enter D0i3 state > and CPU is in low power states (C8 or above). Changed and applied to drm-misc-fixes Thanks Stanislaw > > Regards > Stanislaw > > > > Fixes: 852be13f3bd3 ("accel/ivpu: Add PM support") > > > Cc: sta...@vger.kernel.org > > > Signed-off-by: Jacek Lawrynowicz > > > Reviewed-by: Stanislaw Gruszka > > > Signed-off-by: Stanislaw Gruszka > > > --- > > > drivers/accel/ivpu/ivpu_drv.c | 11 --- > > > drivers/accel/ivpu/ivpu_drv.h | 1 + > > > drivers/accel/ivpu/ivpu_hw.h | 8 > > > drivers/accel/ivpu/ivpu_hw_37xx.c | 1 + > > > drivers/accel/ivpu/ivpu_hw_40xx.c | 1 + > > > drivers/accel/ivpu/ivpu_pm.c | 3 ++- > > > 6 files changed, 21 insertions(+), 4 deletions(-) > > > > > > diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c > > > index 3f4efa07ce7c..1eb232e903e8 100644 > > > --- a/drivers/accel/ivpu/ivpu_drv.c > > > +++ b/drivers/accel/ivpu/ivpu_drv.c > > > @@ -367,14 +367,19 @@ int ivpu_boot(struct ivpu_device *vdev) > > > return 0; > > > } > > > -int ivpu_shutdown(struct ivpu_device *vdev) > > > +void ivpu_prepare_for_reset(struct ivpu_device *vdev) > > > { > > > - int ret; > > > - > > > ivpu_hw_irq_disable(vdev); > > > disable_irq(vdev->irq); > > > ivpu_ipc_disable(vdev); > > > ivpu_mmu_disable(vdev); > > > +} > > > + > > > +int ivpu_shutdown(struct ivpu_device *vdev) > > > +{ > > > + int ret; > > > + > > > + ivpu_prepare_for_reset(vdev); > > > ret = ivpu_hw_power_down(vdev); > > > if (ret) > > > diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h > > > index 98380c1db9fa..a3b45032e6cf 100644 > > > --- a/drivers/accel/ivpu/ivpu_drv.h > > > +++ b/drivers/accel/ivpu/ivpu_drv.h > > > @@ -158,6 +158,7 @@ void ivpu_file_priv_put(struct ivpu_file_priv **link); > > > int ivpu_boot(struct ivpu_device *vdev); > > > int ivpu_shutdown(struct ivpu_device *vdev); > > > +void ivpu_prepare_for_reset(struct ivpu_device *vdev); > > > static inline u8 ivpu_revision(struct ivpu_device *vdev) > > > { > > > diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h > > > index ab341237bcf9..1079e06255ba 100644 > > > --- a/drivers/accel/ivpu/ivpu_hw.h > > > +++ b/drivers/accel/ivpu/ivpu_hw.h > > > @@ -13,6 +13,7 @@ struct ivpu_hw_ops { > > > int (*power_up)(struct ivpu_device *vdev); > > > int (*boot_fw)(struct ivpu_device *vdev); > > > int (*power_down)(struct ivpu_device *vdev); > > > + int (*reset)(struct ivpu_device *vdev); > > > bool (*is_idle)(struct ivpu_device *vdev); > > > void (*wdt_disable)(struct ivpu_device *vdev); > > > void (*diagnose_failure)(struct ivpu_device *vdev); > > > @@ -91,6 +92,13 @@ static inline int ivpu_hw_power_down(struct > > > ivpu_device *vdev) > > > return vdev->hw->ops->power_down(vdev); > > > }; > > > +static inline int ivpu_hw_reset(struct ivpu_device *vdev) > > > +{ > > > + ivpu_dbg(vdev, PM, "HW reset\n"); > > > + > > > + return vdev->hw->ops->reset(vdev); > > > +}; > > > + > > > static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev) > > > { > > > vdev->hw->ops->wdt_disable(vdev); > > > diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c > > > b/drivers/accel/ivpu/ivpu_hw_37xx.c > > > index edd4d860f135..1e842739e937 100644 > > > --- a/driv
Re: [PATCH] accel/ivpu: Extend address range for MMU mmap
On Wed, Oct 18, 2023 at 01:01:13PM +0200, Stanislaw Gruszka wrote: > From: "Wludzik, Jozef" > > Allow to use whole address range in MMU context mmap which is up to 48 > bits. Return invalid argument from MMU context mmap in case address is > not aligned to MMU page size, address is below MMU page size or address > is greater then 47 bits. > > This fixes problem disallowing to run large models on VPU4 > > Signed-off-by: Wludzik, Jozef > Reviewed-by: Stanislaw Gruszka > Signed-off-by: Stanislaw Gruszka Applied to drm-misc-fixes Thanks Stanislaw > --- > drivers/accel/ivpu/ivpu_mmu_context.c | 9 +++-- > 1 file changed, 3 insertions(+), 6 deletions(-) > > diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c > b/drivers/accel/ivpu/ivpu_mmu_context.c > index 0c8c65351919..c1050a2df954 100644 > --- a/drivers/accel/ivpu/ivpu_mmu_context.c > +++ b/drivers/accel/ivpu/ivpu_mmu_context.c > @@ -11,6 +11,7 @@ > #include "ivpu_mmu.h" > #include "ivpu_mmu_context.h" > > +#define IVPU_MMU_VPU_ADDRESS_MASKGENMASK(47, 12) > #define IVPU_MMU_PGD_INDEX_MASK GENMASK(47, 39) > #define IVPU_MMU_PUD_INDEX_MASK GENMASK(38, 30) > #define IVPU_MMU_PMD_INDEX_MASK GENMASK(29, 21) > @@ -328,12 +329,8 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, > struct ivpu_mmu_context *ctx, > > if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE)) > return -EINVAL; > - /* > - * VPU is only 32 bit, but DMA engine is 38 bit > - * Ranges < 2 GB are reserved for VPU internal registers > - * Limit range to 8 GB > - */ > - if (vpu_addr < SZ_2G || vpu_addr > SZ_8G) > + > + if (vpu_addr & ~IVPU_MMU_VPU_ADDRESS_MASK) > return -EINVAL; > > prot = IVPU_MMU_ENTRY_MAPPED; > -- > 2.25.1 >
Re: [PATCH] Revert "accel/ivpu: Use cached buffers for FW loading"
On Tue, Oct 17, 2023 at 02:13:53PM +0200, Stanislaw Gruszka wrote: > This reverts commit 645d694559cab36fe6a57c717efcfa27d9321396. > > The commit cause issues with memory access from the device side. > Switch back to write-combined memory mappings until the issues > will be properly addressed. > > Add extra wmb() needed when boot_params->save_restore_ret_address() is > modified. > > Reviewed-by: Karol Wachowski > Signed-off-by: Stanislaw Gruszka Applied to drm-misc-fixes Thanks Stanislaw > --- > drivers/accel/ivpu/ivpu_fw.c | 9 - > drivers/accel/ivpu/ivpu_gem.h | 5 - > 2 files changed, 4 insertions(+), 10 deletions(-) > > diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c > index 0191cf8e5964..a277bbae78fc 100644 > --- a/drivers/accel/ivpu/ivpu_fw.c > +++ b/drivers/accel/ivpu/ivpu_fw.c > @@ -220,8 +220,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) > if (ret) > return ret; > > - fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, > fw->runtime_size, > - DRM_IVPU_BO_CACHED | > DRM_IVPU_BO_NOSNOOP); > + fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, > fw->runtime_size, DRM_IVPU_BO_WC); > if (!fw->mem) { > ivpu_err(vdev, "Failed to allocate firmware runtime memory\n"); > return -ENOMEM; > @@ -331,7 +330,7 @@ int ivpu_fw_load(struct ivpu_device *vdev) > memset(start, 0, size); > } > > - clflush_cache_range(fw->mem->kvaddr, fw->mem->base.size); > + wmb(); /* Flush WC buffers after writing fw->mem */ > > return 0; > } > @@ -433,7 +432,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, > struct vpu_boot_params > if (!ivpu_fw_is_cold_boot(vdev)) { > boot_params->save_restore_ret_address = 0; > vdev->pm->is_warmboot = true; > - clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); > + wmb(); /* Flush WC buffers after writing > save_restore_ret_address */ > return; > } > > @@ -495,7 +494,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, > struct vpu_boot_params > boot_params->punit_telemetry_sram_size = > ivpu_hw_reg_telemetry_size_get(vdev); > boot_params->vpu_telemetry_enable = > ivpu_hw_reg_telemetry_enable_get(vdev); > > - clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); > + wmb(); /* Flush WC buffers after writing bootparams */ > > ivpu_fw_boot_params_print(vdev, boot_params); > } > diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h > index f4130586ff1b..6b0ceda5f253 100644 > --- a/drivers/accel/ivpu/ivpu_gem.h > +++ b/drivers/accel/ivpu/ivpu_gem.h > @@ -8,8 +8,6 @@ > #include > #include > > -#define DRM_IVPU_BO_NOSNOOP 0x1000 > - > struct dma_buf; > struct ivpu_bo_ops; > struct ivpu_file_priv; > @@ -85,9 +83,6 @@ static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) > > static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo) > { > - if (bo->flags & DRM_IVPU_BO_NOSNOOP) > - return false; > - > return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED; > } > > -- > 2.25.1 >
[PATCH] accel/ivpu: Extend address range for MMU mmap
From: "Wludzik, Jozef" Allow to use whole address range in MMU context mmap which is up to 48 bits. Return invalid argument from MMU context mmap in case address is not aligned to MMU page size, address is below MMU page size or address is greater then 47 bits. This fixes problem disallowing to run large models on VPU4 Signed-off-by: Wludzik, Jozef Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_mmu_context.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index 0c8c65351919..c1050a2df954 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -11,6 +11,7 @@ #include "ivpu_mmu.h" #include "ivpu_mmu_context.h" +#define IVPU_MMU_VPU_ADDRESS_MASKGENMASK(47, 12) #define IVPU_MMU_PGD_INDEX_MASK GENMASK(47, 39) #define IVPU_MMU_PUD_INDEX_MASK GENMASK(38, 30) #define IVPU_MMU_PMD_INDEX_MASK GENMASK(29, 21) @@ -328,12 +329,8 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE)) return -EINVAL; - /* -* VPU is only 32 bit, but DMA engine is 38 bit -* Ranges < 2 GB are reserved for VPU internal registers -* Limit range to 8 GB -*/ - if (vpu_addr < SZ_2G || vpu_addr > SZ_8G) + + if (vpu_addr & ~IVPU_MMU_VPU_ADDRESS_MASK) return -EINVAL; prot = IVPU_MMU_ENTRY_MAPPED; -- 2.25.1
Re: ivpu TODO list items
Hi On Tue, Oct 17, 2023 at 10:25:19PM +0530, Deepak R Varma wrote: > On Fri, Oct 13, 2023 at 12:54:43PM +0530, Deepak R Varma wrote: > > Hello, > > I am shortlisted as a mentee for the LF Mentorship program. I looked at the > > TODO > > file for the ivpu driver for my project tasks. Could you please answer the > > following questions: > > > > 1. Is the TODO list up to date? If not, can we have it updated? Let me know > > if I > > can help. It's not. Some of those was already implemented (but yet not submitted). Some ideas there was dropped. I think this file can be whole removed. Feel free to post patch for that. > > 2. Is it absolutely necessary for me to have a specialized hardware to test > > my > > patches? Is it limited to the 14thGen or above CPU or do I need more than > > that? Yes, I don't think someone can work on ivpu without hardware. > > 3. Is it okay for me to work on the TODO list items. Let me know if you > > have a > > preference [Please note I just started a few months ago and still learning]. I recommend you to work on items from: https://www.kernel.org/doc/html/latest/gpu/todo.html > Hello, > May I request the maintainer to review my questions and comment please? Sorry, I haven't seen this email before. Regards Stanislaw
[PATCH] Revert "accel/ivpu: Use cached buffers for FW loading"
This reverts commit 645d694559cab36fe6a57c717efcfa27d9321396. The commit cause issues with memory access from the device side. Switch back to write-combined memory mappings until the issues will be properly addressed. Add extra wmb() needed when boot_params->save_restore_ret_address() is modified. Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_fw.c | 9 - drivers/accel/ivpu/ivpu_gem.h | 5 - 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 0191cf8e5964..a277bbae78fc 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -220,8 +220,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (ret) return ret; - fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, -DRM_IVPU_BO_CACHED | DRM_IVPU_BO_NOSNOOP); + fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, DRM_IVPU_BO_WC); if (!fw->mem) { ivpu_err(vdev, "Failed to allocate firmware runtime memory\n"); return -ENOMEM; @@ -331,7 +330,7 @@ int ivpu_fw_load(struct ivpu_device *vdev) memset(start, 0, size); } - clflush_cache_range(fw->mem->kvaddr, fw->mem->base.size); + wmb(); /* Flush WC buffers after writing fw->mem */ return 0; } @@ -433,7 +432,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params if (!ivpu_fw_is_cold_boot(vdev)) { boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; - clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); + wmb(); /* Flush WC buffers after writing save_restore_ret_address */ return; } @@ -495,7 +494,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); - clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); + wmb(); /* Flush WC buffers after writing bootparams */ ivpu_fw_boot_params_print(vdev, boot_params); } diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index f4130586ff1b..6b0ceda5f253 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -8,8 +8,6 @@ #include #include -#define DRM_IVPU_BO_NOSNOOP 0x1000 - struct dma_buf; struct ivpu_bo_ops; struct ivpu_file_priv; @@ -85,9 +83,6 @@ static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo) { - if (bo->flags & DRM_IVPU_BO_NOSNOOP) - return false; - return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED; } -- 2.25.1
Re: [PATCH] accel/ivpu: Don't enter d0i3 during FLR
On Fri, Oct 06, 2023 at 09:25:29AM -0600, Jeffrey Hugo wrote: > On 10/3/2023 12:42 AM, Stanislaw Gruszka wrote: > > From: Jacek Lawrynowicz > > > > Fix a bug on some platforms where FLR causes complete system > > hang when CPU is low power states (C8 or above). > > Why does FLR cause a complete system hang? This HW bug is still under debug and it is not yet root caused. > Why does avoiding d0i3 fix the > issue? Feels like there could be a lot more detail here. We only know that we should avoid entering D0i3. I will change the log this way: Avoid HW bug on some platforms where we enter D0i3 state and CPU is in low power states (C8 or above). Regards Stanislaw > > Fixes: 852be13f3bd3 ("accel/ivpu: Add PM support") > > Cc: sta...@vger.kernel.org > > Signed-off-by: Jacek Lawrynowicz > > Reviewed-by: Stanislaw Gruszka > > Signed-off-by: Stanislaw Gruszka > > --- > > drivers/accel/ivpu/ivpu_drv.c | 11 --- > > drivers/accel/ivpu/ivpu_drv.h | 1 + > > drivers/accel/ivpu/ivpu_hw.h | 8 > > drivers/accel/ivpu/ivpu_hw_37xx.c | 1 + > > drivers/accel/ivpu/ivpu_hw_40xx.c | 1 + > > drivers/accel/ivpu/ivpu_pm.c | 3 ++- > > 6 files changed, 21 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c > > index 3f4efa07ce7c..1eb232e903e8 100644 > > --- a/drivers/accel/ivpu/ivpu_drv.c > > +++ b/drivers/accel/ivpu/ivpu_drv.c > > @@ -367,14 +367,19 @@ int ivpu_boot(struct ivpu_device *vdev) > > return 0; > > } > > -int ivpu_shutdown(struct ivpu_device *vdev) > > +void ivpu_prepare_for_reset(struct ivpu_device *vdev) > > { > > - int ret; > > - > > ivpu_hw_irq_disable(vdev); > > disable_irq(vdev->irq); > > ivpu_ipc_disable(vdev); > > ivpu_mmu_disable(vdev); > > +} > > + > > +int ivpu_shutdown(struct ivpu_device *vdev) > > +{ > > + int ret; > > + > > + ivpu_prepare_for_reset(vdev); > > ret = ivpu_hw_power_down(vdev); > > if (ret) > > diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h > > index 98380c1db9fa..a3b45032e6cf 100644 > > --- a/drivers/accel/ivpu/ivpu_drv.h > > +++ b/drivers/accel/ivpu/ivpu_drv.h > > @@ -158,6 +158,7 @@ void ivpu_file_priv_put(struct ivpu_file_priv **link); > > int ivpu_boot(struct ivpu_device *vdev); > > int ivpu_shutdown(struct ivpu_device *vdev); > > +void ivpu_prepare_for_reset(struct ivpu_device *vdev); > > static inline u8 ivpu_revision(struct ivpu_device *vdev) > > { > > diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h > > index ab341237bcf9..1079e06255ba 100644 > > --- a/drivers/accel/ivpu/ivpu_hw.h > > +++ b/drivers/accel/ivpu/ivpu_hw.h > > @@ -13,6 +13,7 @@ struct ivpu_hw_ops { > > int (*power_up)(struct ivpu_device *vdev); > > int (*boot_fw)(struct ivpu_device *vdev); > > int (*power_down)(struct ivpu_device *vdev); > > + int (*reset)(struct ivpu_device *vdev); > > bool (*is_idle)(struct ivpu_device *vdev); > > void (*wdt_disable)(struct ivpu_device *vdev); > > void (*diagnose_failure)(struct ivpu_device *vdev); > > @@ -91,6 +92,13 @@ static inline int ivpu_hw_power_down(struct ivpu_device > > *vdev) > > return vdev->hw->ops->power_down(vdev); > > }; > > +static inline int ivpu_hw_reset(struct ivpu_device *vdev) > > +{ > > + ivpu_dbg(vdev, PM, "HW reset\n"); > > + > > + return vdev->hw->ops->reset(vdev); > > +}; > > + > > static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev) > > { > > vdev->hw->ops->wdt_disable(vdev); > > diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c > > b/drivers/accel/ivpu/ivpu_hw_37xx.c > > index edd4d860f135..1e842739e937 100644 > > --- a/drivers/accel/ivpu/ivpu_hw_37xx.c > > +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c > > @@ -1036,6 +1036,7 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = { > > .power_up = ivpu_hw_37xx_power_up, > > .is_idle = ivpu_hw_37xx_is_idle, > > .power_down = ivpu_hw_37xx_power_down, > > + .reset = ivpu_hw_37xx_reset, > > .boot_fw = ivpu_hw_37xx_boot_fw, > > .wdt_disable = ivpu_hw_37xx_wdt_disable, > > .diagnose_failure = ivpu_hw_37xx_diagnose_failure, > > diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c > > b/drivers/accel/ivpu/ivpu_hw_40xx.c > > index a48cd36f9931..d7b8ec0410af 100644 > > --- a/drivers/accel/ivpu/ivpu_
[PATCH] accel/ivpu: Don't enter d0i3 during FLR
From: Jacek Lawrynowicz Fix a bug on some platforms where FLR causes complete system hang when CPU is low power states (C8 or above). Fixes: 852be13f3bd3 ("accel/ivpu: Add PM support") Cc: sta...@vger.kernel.org Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 11 --- drivers/accel/ivpu/ivpu_drv.h | 1 + drivers/accel/ivpu/ivpu_hw.h | 8 drivers/accel/ivpu/ivpu_hw_37xx.c | 1 + drivers/accel/ivpu/ivpu_hw_40xx.c | 1 + drivers/accel/ivpu/ivpu_pm.c | 3 ++- 6 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 3f4efa07ce7c..1eb232e903e8 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -367,14 +367,19 @@ int ivpu_boot(struct ivpu_device *vdev) return 0; } -int ivpu_shutdown(struct ivpu_device *vdev) +void ivpu_prepare_for_reset(struct ivpu_device *vdev) { - int ret; - ivpu_hw_irq_disable(vdev); disable_irq(vdev->irq); ivpu_ipc_disable(vdev); ivpu_mmu_disable(vdev); +} + +int ivpu_shutdown(struct ivpu_device *vdev) +{ + int ret; + + ivpu_prepare_for_reset(vdev); ret = ivpu_hw_power_down(vdev); if (ret) diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 98380c1db9fa..a3b45032e6cf 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -158,6 +158,7 @@ void ivpu_file_priv_put(struct ivpu_file_priv **link); int ivpu_boot(struct ivpu_device *vdev); int ivpu_shutdown(struct ivpu_device *vdev); +void ivpu_prepare_for_reset(struct ivpu_device *vdev); static inline u8 ivpu_revision(struct ivpu_device *vdev) { diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index ab341237bcf9..1079e06255ba 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -13,6 +13,7 @@ struct ivpu_hw_ops { int (*power_up)(struct ivpu_device *vdev); int (*boot_fw)(struct ivpu_device *vdev); int (*power_down)(struct ivpu_device *vdev); + int (*reset)(struct ivpu_device *vdev); bool (*is_idle)(struct ivpu_device *vdev); void (*wdt_disable)(struct ivpu_device *vdev); void (*diagnose_failure)(struct ivpu_device *vdev); @@ -91,6 +92,13 @@ static inline int ivpu_hw_power_down(struct ivpu_device *vdev) return vdev->hw->ops->power_down(vdev); }; +static inline int ivpu_hw_reset(struct ivpu_device *vdev) +{ + ivpu_dbg(vdev, PM, "HW reset\n"); + + return vdev->hw->ops->reset(vdev); +}; + static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev) { vdev->hw->ops->wdt_disable(vdev); diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index edd4d860f135..1e842739e937 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -1036,6 +1036,7 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = { .power_up = ivpu_hw_37xx_power_up, .is_idle = ivpu_hw_37xx_is_idle, .power_down = ivpu_hw_37xx_power_down, + .reset = ivpu_hw_37xx_reset, .boot_fw = ivpu_hw_37xx_boot_fw, .wdt_disable = ivpu_hw_37xx_wdt_disable, .diagnose_failure = ivpu_hw_37xx_diagnose_failure, diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index a48cd36f9931..d7b8ec0410af 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -1186,6 +1186,7 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = { .power_up = ivpu_hw_40xx_power_up, .is_idle = ivpu_hw_40xx_is_idle, .power_down = ivpu_hw_40xx_power_down, + .reset = ivpu_hw_40xx_reset, .boot_fw = ivpu_hw_40xx_boot_fw, .wdt_disable = ivpu_hw_40xx_wdt_disable, .diagnose_failure = ivpu_hw_40xx_diagnose_failure, diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 28a0de12..da46f95b008a 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -261,7 +261,8 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev) ivpu_dbg(vdev, PM, "Pre-reset..\n"); atomic_inc(&vdev->pm->reset_counter); atomic_set(&vdev->pm->in_reset, 1); - ivpu_shutdown(vdev); + ivpu_prepare_for_reset(vdev); + ivpu_hw_reset(vdev); ivpu_pm_prepare_cold_boot(vdev); ivpu_jobs_abort_all(vdev); ivpu_dbg(vdev, PM, "Pre-reset done.\n"); -- 2.25.1
Re: [PATCH 1/2] accel/ivpu: Update debugfs to latest changes in DRM
On Thu, Sep 07, 2023 at 09:26:09AM +0200, Stanislaw Gruszka wrote: > Use new drm debugfs helpers. This is needed after changes from > commit 78346ebf9f94 ("drm/debugfs: drop debugfs_init() for the render > and accel node v2"). Applied to drm-misc-next Thanks Stanislaw
Re: [PATCH 0/6] accel/ivpu: Fixes for linux-6.6-rc4
On Mon, Sep 25, 2023 at 02:11:31PM +0200, Stanislaw Gruszka wrote: > - dmesg flood fix > - HW power-on and interrupt handling fixes for VPU4 > - FW loading/mapping fix Pushed to drm-misc-fixes. I had to resolve conflict when rebuilding tip, hope everything is ok there. Thanks Stanislaw > Jacek Lawrynowicz (1): > accel/ivpu: Don't flood dmesg with VPU ready message > > Karol Wachowski (4): > accel/ivpu/40xx: Ensure clock resource ownership Ack before Power-Up > accel/ivpu/40xx: Disable frequency change interrupt > accel/ivpu/40xx: Fix missing VPUIP interrupts > accel/ivpu: Use cached buffers for FW loading > > Stanislaw Gruszka (1): > accel/ivpu: Do not use wait event interruptible > > drivers/accel/ivpu/ivpu_drv.c | 2 +- > drivers/accel/ivpu/ivpu_fw.c | 8 +--- > drivers/accel/ivpu/ivpu_gem.h | 5 + > drivers/accel/ivpu/ivpu_hw_40xx.c | 28 +++ > drivers/accel/ivpu/ivpu_hw_40xx_reg.h | 2 ++ > drivers/accel/ivpu/ivpu_ipc.c | 11 --- > 6 files changed, 37 insertions(+), 19 deletions(-) > > -- > 2.25.1 >
[PATCH v2 6/6] accel/ivpu: Use cached buffers for FW loading
From: Karol Wachowski Create buffers with cache coherency on the CPU side (write-back) while disabling snooping on the VPU side. These buffers require an explicit cache flush after each CPU-side modification. Configuring pages as write-combined may introduce significant delays, potentially taking hundreds of milliseconds for 64 MB buffers. Added internal DRM_IVPU_BO_NOSNOOP mask which disables snooping on the VPU side. Allocate FW runtime memory buffer (64 MB) as cached with snooping-disabled. This fixes random long FW loading times and boot params memory corruption on warmboot (due to missed wmb). Fixes: 02d5b0aacd05 ("accel/ivpu: Implement firmware parsing and booting") Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- v2: Actually use DRM_IVPU_BO_CACHED instead of DRM_IVPU_BO_WC.. drivers/accel/ivpu/ivpu_fw.c | 8 +--- drivers/accel/ivpu/ivpu_gem.h | 5 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 9827ea4d7b83..0191cf8e5964 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -220,7 +220,8 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (ret) return ret; - fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, DRM_IVPU_BO_WC); + fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, +DRM_IVPU_BO_CACHED | DRM_IVPU_BO_NOSNOOP); if (!fw->mem) { ivpu_err(vdev, "Failed to allocate firmware runtime memory\n"); return -ENOMEM; @@ -330,7 +331,7 @@ int ivpu_fw_load(struct ivpu_device *vdev) memset(start, 0, size); } - wmb(); /* Flush WC buffers after writing fw->mem */ + clflush_cache_range(fw->mem->kvaddr, fw->mem->base.size); return 0; } @@ -432,6 +433,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params if (!ivpu_fw_is_cold_boot(vdev)) { boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; + clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); return; } @@ -493,7 +495,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); - wmb(); /* Flush WC buffers after writing bootparams */ + clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); ivpu_fw_boot_params_print(vdev, boot_params); } diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index 6b0ceda5f253..f4130586ff1b 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -8,6 +8,8 @@ #include #include +#define DRM_IVPU_BO_NOSNOOP 0x1000 + struct dma_buf; struct ivpu_bo_ops; struct ivpu_file_priv; @@ -83,6 +85,9 @@ static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo) { + if (bo->flags & DRM_IVPU_BO_NOSNOOP) + return false; + return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED; } -- 2.25.1
[PATCH 3/2] accel/ivpu: Use local variable for debugfs root
Use local variable for debugfs root, just to make further changes easier. Signed-off-by: Stanislaw Gruszka --- I'll squash that patch into patch 1 drivers/accel/ivpu/ivpu_debugfs.c | 14 -- 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 9163bc6bd3ef..ea453b985b49 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -273,20 +273,22 @@ static const struct file_operations ivpu_reset_engine_fops = { void ivpu_debugfs_init(struct ivpu_device *vdev) { + struct dentry *debugfs_root = vdev->drm.debugfs_root; + drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list)); - debugfs_create_file("force_recovery", 0200, vdev->drm.debugfs_root, vdev, + debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); - debugfs_create_file("fw_log", 0644, vdev->drm.debugfs_root, vdev, + debugfs_create_file("fw_log", 0644, debugfs_root, vdev, &fw_log_fops); - debugfs_create_file("fw_trace_destination_mask", 0200, vdev->drm.debugfs_root, vdev, + debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, &fw_trace_destination_mask_fops); - debugfs_create_file("fw_trace_hw_comp_mask", 0200, vdev->drm.debugfs_root, vdev, + debugfs_create_file("fw_trace_hw_comp_mask", 0200, debugfs_root, vdev, &fw_trace_hw_comp_mask_fops); - debugfs_create_file("fw_trace_level", 0200, vdev->drm.debugfs_root, vdev, + debugfs_create_file("fw_trace_level", 0200, debugfs_root, vdev, &fw_trace_level_fops); - debugfs_create_file("reset_engine", 0200, vdev->drm.debugfs_root, vdev, + debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, &ivpu_reset_engine_fops); } -- 2.25.1
[PATCH 6/6] accel/ivpu: Use cached buffers for FW loading
From: Karol Wachowski Create buffers with cache coherency on the CPU side (write-back) while disabling snooping on the VPU side. These buffers require an explicit cache flush after each CPU-side modification. Configuring pages as write-combined may introduce significant delays, potentially taking hundreds of milliseconds for 64 MB buffers. Added internal DRM_IVPU_BO_NOSNOOP mask which disables snooping on the VPU side. Allocate FW runtime memory buffer (64 MB) as cached with snooping-disabled. This fixes random long FW loading times and boot params memory corruption on warmboot (due to missed wmb). Fixes: 02d5b0aacd05 ("accel/ivpu: Implement firmware parsing and booting") Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_fw.c | 8 +--- drivers/accel/ivpu/ivpu_gem.h | 5 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 9827ea4d7b83..301f5221d193 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -220,7 +220,8 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (ret) return ret; - fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, DRM_IVPU_BO_WC); + fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, +DRM_IVPU_BO_WC | DRM_IVPU_BO_NOSNOOP); if (!fw->mem) { ivpu_err(vdev, "Failed to allocate firmware runtime memory\n"); return -ENOMEM; @@ -330,7 +331,7 @@ int ivpu_fw_load(struct ivpu_device *vdev) memset(start, 0, size); } - wmb(); /* Flush WC buffers after writing fw->mem */ + clflush_cache_range(fw->mem->kvaddr, fw->mem->base.size); return 0; } @@ -432,6 +433,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params if (!ivpu_fw_is_cold_boot(vdev)) { boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; + clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); return; } @@ -493,7 +495,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); - wmb(); /* Flush WC buffers after writing bootparams */ + clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); ivpu_fw_boot_params_print(vdev, boot_params); } diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index 6b0ceda5f253..f4130586ff1b 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -8,6 +8,8 @@ #include #include +#define DRM_IVPU_BO_NOSNOOP 0x1000 + struct dma_buf; struct ivpu_bo_ops; struct ivpu_file_priv; @@ -83,6 +85,9 @@ static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo) { + if (bo->flags & DRM_IVPU_BO_NOSNOOP) + return false; + return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED; } -- 2.25.1
[PATCH 5/6] accel/ivpu/40xx: Fix missing VPUIP interrupts
From: Karol Wachowski Move sequence of masking and unmasking global interrupts from buttress interrupt handler to generic one that handles both VPUIP and BTRS interrupts. Unmasking global interrupts will re-trigger MSI for any pending interrupts. Lack of this sequence can randomly cause to miss any VPUIP interrupt that comes after reading VPU_40XX_HOST_SS_ICB_STATUS_0 and before clearing all active interrupt sources. Fixes: 79cdc56c4a54 ("accel/ivpu: Add initial support for VPU 4") Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_40xx.c | 11 +-- 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 87b1085d44cf..8bdb59a45da6 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -1059,9 +1059,6 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) if (status == 0) return IRQ_NONE; - /* Disable global interrupt before handling local buttress interrupts */ - REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); - if (REG_TEST_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE"); @@ -1109,9 +1106,6 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) /* This must be done after interrupts are cleared at the source. */ REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status); - /* Re-enable global interrupt */ - REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); - if (schedule_recovery) ivpu_pm_schedule_recovery(vdev); @@ -1123,9 +1117,14 @@ static irqreturn_t ivpu_hw_40xx_irq_handler(int irq, void *ptr) struct ivpu_device *vdev = ptr; irqreturn_t ret = IRQ_NONE; + REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); + ret |= ivpu_hw_40xx_irqv_handler(vdev, irq); ret |= ivpu_hw_40xx_irqb_handler(vdev, irq); + /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ + REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); + if (ret & IRQ_WAKE_THREAD) return IRQ_WAKE_THREAD; -- 2.25.1
[PATCH 4/6] accel/ivpu/40xx: Disable frequency change interrupt
From: Karol Wachowski Do not enable frequency change interrupt on 40xx as it might lead to an interrupt storm in current design. FREQ_CHANGE interrupt is triggered on D0I2 entry which will cause KMD to check VPU interrupt sources by reading VPUIP registers. Access to those registers will toggle necessary clocks and trigger another FREQ_CHANGE interrupt possibly ending in an infinite loop. FREQ_CHANGE interrupt has only debug purposes and can be permanently disabled. Fixes: 79cdc56c4a54 ("accel/ivpu: Add initial support for VPU 4") Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_40xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index f4a251a58ca4..87b1085d44cf 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -57,8 +57,7 @@ #define ICB_0_1_IRQ_MASK u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK) -#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE)) | \ - (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \ +#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \ (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI0_ERR)) | \ (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI1_ERR)) | \ (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, IMR0_ERR)) | \ -- 2.25.1
[PATCH 3/6] accel/ivpu/40xx: Ensure clock resource ownership Ack before Power-Up
From: Karol Wachowski We need to wait for the CLOCK_RESOURCE_OWN_ACK bit to be set after configuring the workpoint. This step ensures that the VPU microcontroller clock is actively toggling and ready for operation. Previously, we relied solely on the READY bit in the VPU_STATUS register, which indicated the completion of the workpoint download. However, this approach was insufficient, as the READY bit could be set while the device was still running on a sideband clock until the PLL locked. To guarantee that the PLL is locked and the device is running on the main clock source, we now wait for the CLOCK_RESOURCE_OWN_ACK before proceeding with the remainder of the power-up sequence. Fixes: 79cdc56c4a54 ("accel/ivpu: Add initial support for VPU 4") Signed-off-by: Karol Wachowski Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_hw_40xx.c | 14 ++ drivers/accel/ivpu/ivpu_hw_40xx_reg.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 00c5dbbe6847..f4a251a58ca4 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -196,6 +196,14 @@ static int ivpu_pll_wait_for_status_ready(struct ivpu_device *vdev) return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, READY, 1, PLL_TIMEOUT_US); } +static int ivpu_wait_for_clock_own_resource_ack(struct ivpu_device *vdev) +{ + if (ivpu_is_simics(vdev)) + return 0; + + return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, CLOCK_RESOURCE_OWN_ACK, 1, TIMEOUT_US); +} + static void ivpu_pll_init_frequency_ratios(struct ivpu_device *vdev) { struct ivpu_hw_info *hw = vdev->hw; @@ -556,6 +564,12 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev) { int ret; + ret = ivpu_wait_for_clock_own_resource_ack(vdev); + if (ret) { + ivpu_err(vdev, "Timed out waiting for clock own resource ACK\n"); + return ret; + } + ivpu_boot_pwr_island_trickle_drive(vdev, true); ivpu_boot_pwr_island_drive(vdev, true); diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h index 5139cfe88532..ff4a5d4f5821 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h @@ -70,6 +70,8 @@ #define VPU_40XX_BUTTRESS_VPU_STATUS_READY_MASK BIT_MASK(0) #define VPU_40XX_BUTTRESS_VPU_STATUS_IDLE_MASK BIT_MASK(1) #define VPU_40XX_BUTTRESS_VPU_STATUS_DUP_IDLE_MASK BIT_MASK(2) +#define VPU_40XX_BUTTRESS_VPU_STATUS_CLOCK_RESOURCE_OWN_ACK_MASK BIT_MASK(6) +#define VPU_40XX_BUTTRESS_VPU_STATUS_POWER_RESOURCE_OWN_ACK_MASK BIT_MASK(7) #define VPU_40XX_BUTTRESS_VPU_STATUS_PERF_CLK_MASK BIT_MASK(11) #define VPU_40XX_BUTTRESS_VPU_STATUS_DISABLE_CLK_RELINQUISH_MASK BIT_MASK(12) -- 2.25.1
[PATCH 2/6] accel/ivpu: Don't flood dmesg with VPU ready message
From: Jacek Lawrynowicz Use ivpu_dbg() to print the VPU ready message so it doesn't pollute the dmesg. Signed-off-by: Jacek Lawrynowicz Reviewed-by: Stanislaw Gruszka Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index aa7314fdbc0f..467a60235370 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -327,7 +327,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) } if (!ret) - ivpu_info(vdev, "VPU ready message received successfully\n"); + ivpu_dbg(vdev, PM, "VPU ready message received successfully\n"); else ivpu_hw_diagnose_failure(vdev); -- 2.25.1
[PATCH 1/6] accel/ivpu: Do not use wait event interruptible
If we receive signal when waiting for IPC message response in ivpu_ipc_receive() we return error and continue to operate. Then the driver can send another IPC messages and re-use occupied slot of the message still processed by the firmware. This can result in corrupting firmware memory and following FW crash with messages: [ 3698.569719] intel_vpu :00:0b.0: [drm] ivpu_ipc_send_receive_internal(): IPC receive failed: type 0x1103, ret -512 [ 3698.569747] intel_vpu :00:0b.0: [drm] ivpu_jsm_unregister_db(): Failed to unregister doorbell 3: -512 [ 3698.569756] intel_vpu :00:0b.0: [drm] ivpu_ipc_tx_prepare(): IPC message vpu:0x8898 not released by firmware [ 3698.569763] intel_vpu :00:0b.0: [drm] ivpu_ipc_tx_prepare(): JSM message vpu:0x88980040 not released by firmware [ 3698.570234] intel_vpu :00:0b.0: [drm] ivpu_ipc_send_receive_internal(): IPC receive failed: type 0x110e, ret -512 [ 3698.570318] intel_vpu :00:0b.0: [drm] *ERROR* ivpu_mmu_dump_event(): MMU EVTQ: 0x10 (Translation fault) SSID: 0 SID: 3, e[2] , e[3] 0208, in addr: 0x88988000, fetch addr: 0x0 To fix the issue don't use interruptible variant of wait event to allow firmware to finish IPC processing. Fixes: 5d7422cfb498 ("accel/ivpu: Add IPC driver and JSM messages") Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_ipc.c | 11 --- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index fa0af59e39ab..295c0d7b5039 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -209,10 +209,10 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_rx_msg *rx_msg; int wait_ret, ret = 0; - wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq, - (IS_KTHREAD() && kthread_should_stop()) || - !list_empty(&cons->rx_msg_list), - msecs_to_jiffies(timeout_ms)); + wait_ret = wait_event_timeout(cons->rx_msg_wq, + (IS_KTHREAD() && kthread_should_stop()) || + !list_empty(&cons->rx_msg_list), + msecs_to_jiffies(timeout_ms)); if (IS_KTHREAD() && kthread_should_stop()) return -EINTR; @@ -220,9 +220,6 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, if (wait_ret == 0) return -ETIMEDOUT; - if (wait_ret < 0) - return -ERESTARTSYS; - spin_lock_irq(&cons->rx_msg_lock); rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link); if (!rx_msg) { -- 2.25.1
[PATCH 0/6] accel/ivpu: Fixes for linux-6.6-rc4
- dmesg flood fix - HW power-on and interrupt handling fixes for VPU4 - FW loading/mapping fix Jacek Lawrynowicz (1): accel/ivpu: Don't flood dmesg with VPU ready message Karol Wachowski (4): accel/ivpu/40xx: Ensure clock resource ownership Ack before Power-Up accel/ivpu/40xx: Disable frequency change interrupt accel/ivpu/40xx: Fix missing VPUIP interrupts accel/ivpu: Use cached buffers for FW loading Stanislaw Gruszka (1): accel/ivpu: Do not use wait event interruptible drivers/accel/ivpu/ivpu_drv.c | 2 +- drivers/accel/ivpu/ivpu_fw.c | 8 +--- drivers/accel/ivpu/ivpu_gem.h | 5 + drivers/accel/ivpu/ivpu_hw_40xx.c | 28 +++ drivers/accel/ivpu/ivpu_hw_40xx_reg.h | 2 ++ drivers/accel/ivpu/ivpu_ipc.c | 11 --- 6 files changed, 37 insertions(+), 19 deletions(-) -- 2.25.1
Re: [PATCH] accel/ivpu: Annotate struct ivpu_job with __counted_by
On Fri, Sep 22, 2023 at 10:54:17AM -0700, Kees Cook wrote: > Prepare for the coming implementation by GCC and Clang of the __counted_by > attribute. Flexible array members annotated with __counted_by can have > their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS > (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family > functions). > > As found with Coccinelle[1], add __counted_by for struct ivpu_job. > > [1] > https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci > > Cc: Jacek Lawrynowicz > Cc: Stanislaw Gruszka > Cc: Oded Gabbay > Cc: Nathan Chancellor > Cc: Nick Desaulniers > Cc: Tom Rix > Cc: dri-devel@lists.freedesktop.org > Cc: l...@lists.linux.dev > Signed-off-by: Kees Cook Reviewed-by: Stanislaw Gruszka Please apply the patch via whatever tree is appropriate. Or if I have to take it via drm-misc, please let me know. Regards Stanislaw > --- > drivers/accel/ivpu/ivpu_job.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h > index aa1f0b9479b0..5514c2d8a609 100644 > --- a/drivers/accel/ivpu/ivpu_job.h > +++ b/drivers/accel/ivpu/ivpu_job.h > @@ -51,7 +51,7 @@ struct ivpu_job { > u32 job_id; > u32 engine_idx; > size_t bo_count; > - struct ivpu_bo *bos[]; > + struct ivpu_bo *bos[] __counted_by(bo_count); > }; > > int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file > *file); > -- > 2.34.1 >
Re: [PATCH] accel/ivpu: Add Arrow Lake pci id
On Fri, Sep 22, 2023 at 09:24:08AM -0600, Jeffrey Hugo wrote: > On 9/22/2023 7:22 AM, Stanislaw Gruszka wrote: > > Enable VPU on Arrow Lake CPUs. > > > > Reviewed-by: Krystian Pradzynski > > Reviewed-by: Karol Wachowski > > Signed-off-by: Stanislaw Gruszka > > --- > > drivers/accel/ivpu/ivpu_drv.c | 1 + > > drivers/accel/ivpu/ivpu_drv.h | 2 ++ > > 2 files changed, 3 insertions(+) > > > > diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c > > index ba79f397c9e8..aa7314fdbc0f 100644 > > --- a/drivers/accel/ivpu/ivpu_drv.c > > +++ b/drivers/accel/ivpu/ivpu_drv.c > > @@ -634,6 +634,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev) > > static struct pci_device_id ivpu_pci_ids[] = { > > { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) }, > > + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) }, > > { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) }, > > { } > > }; > > diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h > > index 9e8c075fe9ef..03b3d6532fb6 100644 > > --- a/drivers/accel/ivpu/ivpu_drv.h > > +++ b/drivers/accel/ivpu/ivpu_drv.h > > @@ -23,6 +23,7 @@ > > #define DRIVER_DATE "20230117" > > #define PCI_DEVICE_ID_MTL 0x7d1d > > +#define PCI_DEVICE_ID_ARL 0xad1d > > #define PCI_DEVICE_ID_LNL 0x643e > > I'm curious, how are these ordered? Release date? Doesn't seem like it is > alphabetical nor numerical by DID. Yes, it's release date based. > Not a problem, just something I'd like to know. > > Reviewed-by: Jeffrey Hugo Thanks Stanislaw
[PATCH] accel/ivpu: Add Arrow Lake pci id
Enable VPU on Arrow Lake CPUs. Reviewed-by: Krystian Pradzynski Reviewed-by: Karol Wachowski Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_drv.c | 1 + drivers/accel/ivpu/ivpu_drv.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index ba79f397c9e8..aa7314fdbc0f 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -634,6 +634,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev) static struct pci_device_id ivpu_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) }, { } }; diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 9e8c075fe9ef..03b3d6532fb6 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -23,6 +23,7 @@ #define DRIVER_DATE "20230117" #define PCI_DEVICE_ID_MTL 0x7d1d +#define PCI_DEVICE_ID_ARL 0xad1d #define PCI_DEVICE_ID_LNL 0x643e #define IVPU_HW_37XX 37 @@ -165,6 +166,7 @@ static inline int ivpu_hw_gen(struct ivpu_device *vdev) { switch (ivpu_device_id(vdev)) { case PCI_DEVICE_ID_MTL: + case PCI_DEVICE_ID_ARL: return IVPU_HW_37XX; case PCI_DEVICE_ID_LNL: return IVPU_HW_40XX; -- 2.25.1
Re: [RFC 3/4] accel/ivpu: Remove support for uncached buffers
On Mon, Sep 11, 2023 at 09:24:42AM -0600, Jeffrey Hugo wrote: > On 9/1/2023 10:48 AM, Stanislaw Gruszka wrote: > > From: Jacek Lawrynowicz > > > > Usages of DRM_IVPU_BO_UNCACHED should be replaced by DRM_IVPU_BO_WC. > > There is no functional benefit from DRM_IVPU_BO_UNCACHED if these > > buffers are never mapped to host VM. > > > > This allows to cut the buffer handling code in the kernel driver > > by half. > > > > Signed-off-by: Jacek Lawrynowicz > > Signed-off-by: Stanislaw Gruszka > > --- > > drivers/accel/ivpu/ivpu_fw.c | 2 +- > > drivers/accel/ivpu/ivpu_gem.c | 3 --- > > include/uapi/drm/ivpu_accel.h | 2 +- > > 3 files changed, 2 insertions(+), 5 deletions(-) > > > > diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c > > index 2fef9fe154aa..8ab0f3225205 100644 > > --- a/drivers/accel/ivpu/ivpu_fw.c > > +++ b/drivers/accel/ivpu/ivpu_fw.c > > @@ -248,7 +248,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) > > if (fw->shave_nn_size) { > > fw->mem_shave_nn = ivpu_bo_alloc_internal(vdev, > > vdev->hw->ranges.shave.start, > > - fw->shave_nn_size, > > DRM_IVPU_BO_UNCACHED); > > + fw->shave_nn_size, > > DRM_IVPU_BO_WC); > > if (!fw->mem_shave_nn) { > > ivpu_err(vdev, "Failed to allocate shavenn buffer\n"); > > ret = -ENOMEM; > > diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c > > index 915c53d7bb97..2a91eb1e3627 100644 > > --- a/drivers/accel/ivpu/ivpu_gem.c > > +++ b/drivers/accel/ivpu/ivpu_gem.c > > @@ -89,8 +89,6 @@ static int __must_check shmem_alloc_pages_locked(struct > > ivpu_bo *bo) > > if (bo->flags & DRM_IVPU_BO_WC) > > set_pages_array_wc(pages, npages); > > - else if (bo->flags & DRM_IVPU_BO_UNCACHED) > > - set_pages_array_uc(pages, npages); > > bo->pages = pages; > > return 0; > > @@ -366,7 +364,6 @@ ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 > > flags, const struct ivpu_b > > switch (flags & DRM_IVPU_BO_CACHE_MASK) { > > case DRM_IVPU_BO_CACHED: > > - case DRM_IVPU_BO_UNCACHED: > > case DRM_IVPU_BO_WC: > > break; > > default: > > diff --git a/include/uapi/drm/ivpu_accel.h b/include/uapi/drm/ivpu_accel.h > > index 262db0c3beee..de1944e42c65 100644 > > --- a/include/uapi/drm/ivpu_accel.h > > +++ b/include/uapi/drm/ivpu_accel.h > > @@ -196,7 +196,7 @@ struct drm_ivpu_bo_create { > > * > > * %DRM_IVPU_BO_UNCACHED: > > * > > -* Allocated BO will not be cached on host side nor snooped on the VPU > > side. > > +* Not supported. Use DRM_IVPU_BO_WC instead. > > * > > * %DRM_IVPU_BO_WC: > > * > > Feels like this will break existing userspace. You could see if userspace > specified UNCACHED and change it to WC before processing the request. Maybe > also use WARN_ONCE to indicate that userspace should be updated. > > Or is it the case that userspace never actually used this? Usage of those buffers was removed some time ago: https://github.com/intel/linux-vpu-driver/commit/c473c9826cb28fa3dcf8883fc804b1e84c6b5fb1 And will not be part of first user-mode driver release. I think we can safely do the change. Regards Stanislaw
Re: [RFC 1/4] accel/ivpu: Allocate vpu_addr in gem->open() callback
On Mon, Sep 11, 2023 at 09:19:03AM -0600, Jeffrey Hugo wrote: > On 9/1/2023 10:48 AM, Stanislaw Gruszka wrote: > > From: Jacek Lawrynowicz > > > > gem->open() is called during handle creation for a gem object. > > It is called during prime import and in BO_CREATE ioctl. > > I feel like the "why" is missing. This appears to start to explain how > gem->open() might be useful for the driver, but does not seem to complete > explaining the connection to the driver. From the code changes, it looks > like using gem->open() simplifies the code by allocating the vpu_addr in one > place for all BOs. If that is the goal, I feel that it should be mentioned > here. I'm going to change to: Use gem->open() callback to simplify the code and prepare for gem_shmem conversion. It is called during handle creation for a gem object - during prime import and in BO_CREATE ioctl. Hence can be used for vpu_addr allocation. On the way remove unused bo->user_ptr field. Regards Stanislaw
Re: [PATCH 0/7] accel/qaic: Extend uAPI to support undoing ATTACH_SLICE_BO
On Fri, Sep 01, 2023 at 11:22:40AM -0600, Jeffrey Hugo wrote: > A BO for a QAIC device has two states - > 1. Allocated > 2. Sliced > > A BO can be allocated at any time, and is initialized in the allocated state. > A BO can transition to the sliced state via ATTACH_SLICE_BO. This prepares > the > BO for use with an active workload. Currently a BO in the sliced state can > only be used with a single workload, and will only transition back to the > allocated state once the workload is deactivated. > > Userspace would like the ability to trigger a BO transition from the sliced > state to the allocated state. This would support the usecase of a userspace > client that has two active workloads, where the output of the first workload > becomes the input of the second workload. Currently, the client would need > two BOs, once for each workload, and copy from one BO to the other. > > To support this usecase, we create the detach slice concept which is the > inverse operation of ATTACH_SLICE_BO. We extend the uAPI with a new > DETACH_SLICE_BO ioctl that allows userspace to perform this operation. > > Since ATTACH_SLICE_BO and DETACH_SLICE_BO are related operations, they share > a decent amount of code. This series starts with restructuring the common code > for use in both ioctls before finally adding the DETACH_SLICE_BO. > > Pranjal Ramajor Asha Kanojiya (7): > accel/qaic: Remove ->size field from struct qaic_bo > accel/qaic: Update BO metadata in a central location > accel/qaic: Declare BO 'sliced' after all the operations are complete > accel/qaic: Undo slicing setup done in qaic_attach_slicing_bo() > accel/qaic: Clean up BO during flushing of transfer list > accel/qaic: Create a function to initialize BO > accel/qaic: Add QAIC_DETACH_SLICE_BO IOCTL > > Documentation/accel/qaic/qaic.rst | 10 ++ > drivers/accel/qaic/qaic.h | 6 +- > drivers/accel/qaic/qaic_data.c| 187 +++--- > drivers/accel/qaic/qaic_drv.c | 1 + > include/uapi/drm/qaic_accel.h | 24 +++- > 5 files changed, 175 insertions(+), 53 deletions(-) Do not see any serious issues with the set. Reviewed-by: Stanislaw Gruszka for the whole series.
Re: [PATCH 7/7] accel/qaic: Add QAIC_DETACH_SLICE_BO IOCTL
On Fri, Sep 01, 2023 at 11:22:47AM -0600, Jeffrey Hugo wrote: > From: Pranjal Ramajor Asha Kanojiya > > Once a BO is attached with slicing configuration that BO can only be used > for that particular setting. With this new feature user can detach slicing > configuration off an already sliced BO and attach new slicing configuration > using QAIC_ATTACH_SLICE_BO. > > This will support BO recycling. > > detach_slice_bo() detaches slicing configuration from a BO. This new > helper function can also be used in release_dbc() as we are doing the > exact same thing. > > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > [jhugo: add documentation for new ioctl] > Signed-off-by: Jeffrey Hugo > + /* Check if BO is committed to H/W for DMA */ > + spin_lock_irqsave(&dbc->xfer_lock, flags); > + if (bo->queued) { > + spin_unlock_irqrestore(&dbc->xfer_lock, flags); > + ret = -EBUSY; > + goto unlock_ch_srcu; > + } > + spin_unlock_irqrestore(&dbc->xfer_lock, flags); This looks like race condition. If some other thread will take the xfer_lock and set bo->queued (HERE just after _unlock()) we will not return -EBUSY. Something seems to be missing here or xfer_lock is not needed to protect bo->queued. Regards Stanislaw
Re: [PATCH 6/7] accel/qaic: Create a function to initialize BO
On Fri, Sep 01, 2023 at 11:22:46AM -0600, Jeffrey Hugo wrote: > From: Pranjal Ramajor Asha Kanojiya > > This makes sure that we have a single place to initialize and > re-initialize BO. > > Use this new API to cleanup release_dbc() > > We will need this for next patch to detach slicing to a BO. > > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Jeffrey Hugo > Signed-off-by: Jeffrey Hugo > --- > drivers/accel/qaic/qaic_data.c | 20 ++-- > 1 file changed, 14 insertions(+), 6 deletions(-) > > diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c > index 6e44e00937af..2acb9dbac88b 100644 > --- a/drivers/accel/qaic/qaic_data.c > +++ b/drivers/accel/qaic/qaic_data.c > @@ -635,6 +635,18 @@ static const struct drm_gem_object_funcs qaic_gem_funcs > = { > .vm_ops = &drm_vm_ops, > }; > > +static void qaic_init_bo(struct qaic_bo *bo, bool reinit) > +{ > + if (reinit) { > + bo->sliced = false; > + reinit_completion(&bo->xfer_done); > + } else { > + init_completion(&bo->xfer_done); > + } > + complete_all(&bo->xfer_done); Why do you need complete_all() here ? Regards Stanislaw
[PATCH 2/2] accel/ivpu: Compile ivpu_debugfs.c conditionally
Only compile ivpu_debugfs.c file with CONFIG_DEBUG_FS. Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/Makefile | 3 ++- drivers/accel/ivpu/ivpu_debugfs.h | 4 drivers/accel/ivpu/ivpu_drv.c | 2 -- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/Makefile b/drivers/accel/ivpu/Makefile index e4328b430564..95ff7ad16338 100644 --- a/drivers/accel/ivpu/Makefile +++ b/drivers/accel/ivpu/Makefile @@ -2,7 +2,6 @@ # Copyright (C) 2023 Intel Corporation intel_vpu-y := \ - ivpu_debugfs.o \ ivpu_drv.o \ ivpu_fw.o \ ivpu_fw_log.o \ @@ -16,4 +15,6 @@ intel_vpu-y := \ ivpu_mmu_context.o \ ivpu_pm.o +intel_vpu-$(CONFIG_DEBUG_FS) += ivpu_debugfs.o + obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o diff --git a/drivers/accel/ivpu/ivpu_debugfs.h b/drivers/accel/ivpu/ivpu_debugfs.h index 76dbce139772..49ae9ea78287 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.h +++ b/drivers/accel/ivpu/ivpu_debugfs.h @@ -8,6 +8,10 @@ struct ivpu_device; +#if defined(CONFIG_DEBUG_FS) void ivpu_debugfs_init(struct ivpu_device *vdev); +#else +static inline void ivpu_debugfs_init(struct ivpu_device *vdev) { } +#endif #endif /* __IVPU_DEBUGFS_H__ */ diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index b6aaf9811355..7851ff7773ca 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -627,9 +627,7 @@ static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; -#if defined(CONFIG_DEBUG_FS) ivpu_debugfs_init(vdev); -#endif ret = drm_dev_register(&vdev->drm, 0); if (ret) { -- 2.25.1
[PATCH 1/2] accel/ivpu: Update debugfs to latest changes in DRM
Use new drm debugfs helpers. This is needed after changes from commit 78346ebf9f94 ("drm/debugfs: drop debugfs_init() for the render and accel node v2"). Signed-off-by: Stanislaw Gruszka --- drivers/accel/ivpu/ivpu_debugfs.c | 50 +++ drivers/accel/ivpu/ivpu_debugfs.h | 4 +-- drivers/accel/ivpu/ivpu_drv.c | 8 ++--- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 5e5996fd4f9f..9163bc6bd3ef 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -17,20 +17,26 @@ #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" +static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) +{ + struct drm_debugfs_entry *entry = s->private; + + return to_ivpu_device(entry->dev); +} + static int bo_list_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; struct drm_printer p = drm_seq_file_printer(s); + struct ivpu_device *vdev = seq_to_ivpu(s); - ivpu_bo_list(node->minor->dev, &p); + ivpu_bo_list(&vdev->drm, &p); return 0; } static int fw_name_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%s\n", vdev->fw->name); return 0; @@ -38,8 +44,7 @@ static int fw_name_show(struct seq_file *s, void *v) static int fw_trace_capability_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); u64 trace_hw_component_mask; u32 trace_destination_mask; int ret; @@ -57,8 +62,7 @@ static int fw_trace_capability_show(struct seq_file *s, void *v) static int fw_trace_config_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); /** * WA: VPU_JSM_MSG_TRACE_GET_CONFIG command is not working yet, * so we use values from vdev->fw instead of calling ivpu_jsm_trace_get_config() @@ -78,8 +82,7 @@ static int fw_trace_config_show(struct seq_file *s, void *v) static int last_bootmode_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot"); @@ -88,8 +91,7 @@ static int last_bootmode_show(struct seq_file *s, void *v) static int reset_counter_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_counter)); return 0; @@ -97,14 +99,13 @@ static int reset_counter_show(struct seq_file *s, void *v) static int reset_pending_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); return 0; } -static const struct drm_info_list vdev_debugfs_list[] = { +static const struct drm_debugfs_info vdev_debugfs_list[] = { {"bo_list", bo_list_show, 0}, {"fw_name", fw_name_show, 0}, {"fw_trace_capability", fw_trace_capability_show, 0}, @@ -270,25 +271,22 @@ static const struct file_operations ivpu_reset_engine_fops = { .write = ivpu_reset_engine_fn, }; -void ivpu_debugfs_init(struct drm_minor *minor) +void ivpu_debugfs_init(struct ivpu_device *vdev) { - struct ivpu_device *vdev = to_ivpu_device(minor->dev); - - drm_debugfs_create_files(vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list), -minor->debugfs_root, minor); + drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list)); - debugfs_create_file("force_recovery", 0200, minor->debugfs_root, vdev, + debugfs_create_file("force_recovery", 0200, vdev->drm.debugfs_root, v
Re: [PATCH] accel/habanalabs/gaudi2: Fix incorrect string length computation in gaudi2_psoc_razwi_get_engines()
On Mon, Sep 04, 2023 at 09:18:36PM +0200, Christophe JAILLET wrote: > snprintf() returns the "number of characters which *would* be generated for > the given input", not the size *really* generated. > > In order to avoid too large values for 'str_size' (and potential negative > values for "PSOC_RAZWI_ENG_STR_SIZE - str_size") use scnprintf() > instead of snprintf(). > > Fixes: c0e6df916050 ("accel/habanalabs: fix address decode RAZWI handling") > Signed-off-by: Christophe JAILLET Reviewed-by: Stanislaw Gruszka
Re: [PATCH] accel/qaic: Use devm_drm_dev_alloc() instead of drm_dev_alloc()
On Fri, Sep 01, 2023 at 10:12:36AM -0600, Jeffrey Hugo wrote: > From: Pranjal Ramajor Asha Kanojiya > > Since drm_dev_alloc() is deprecated it is recommended to use > devm_drm_dev_alloc() instead. Update the driver to start using > devm_drm_dev_alloc(). > > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Carl Vanderlip > Reviewed-by: Jeffrey Hugo > Signed-off-by: Jeffrey Hugo > + /* > + * drm_dev_unregister() sets the driver data to NULL and > + * drm_dev_register() does not update the driver data. During a SOC > + * reset drm dev is unregistered and registered again leaving the > + * driver data to NULL. > + */ > + dev_set_drvdata(to_accel_kdev(qddev), drm->accel); Yeah, explicitly nullified in drm_minor_unregister() with ' /* safety belt */ comment. I think in long term goal would be device reset not require unregister/register. > + drm_dev_get(drm); > + drm_dev_unregister(drm); That looks odd. I guess there is use-after-free problem if you just do drm_dev_unregister(). Additional drm_dev_get() does not seems to be right solution, but I'm not 100% sure, so ... Reviewed-by: Stanislaw Gruszka Regards Stanislaw
Re: [PATCH] accel/qaic: Register for PCI driver at the beginning of module init
On Fri, Sep 01, 2023 at 10:10:37AM -0600, Jeffrey Hugo wrote: > From: Pranjal Ramajor Asha Kanojiya > > As qaic drivers base device is connected to host via PCI framework, it > makes sense to register in PCI framework at the beginning of module > init. > > Signed-off-by: Pranjal Ramajor Asha Kanojiya > Reviewed-by: Carl Vanderlip > Reviewed-by: Jeffrey Hugo > Signed-off-by: Jeffrey Hugo Reviewed-by: Stanislaw Gruszka