diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-07-10 13:03:14 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-07-10 13:03:15 +1000 |
| commit | 7978a34fd6e4eae91db0741b553e7682288d022c (patch) | |
| tree | 7829e50ec6c98620859b0e4e35f28aabd807226b /drivers | |
| parent | 58570ef9dc5d0b0465346883f492f12ea1c22369 (diff) | |
| parent | cf385cf6e713eba0720651174dac0b2d2f5bb8f8 (diff) | |
Merge tag 'drm-misc-fixes-2026-07-09' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes
drm-misc-fixes for v7.2-rc3:
- Fix uaf in amdxdna mmap failure path.
- A lot of deadlocks, access races and return value fixes in amdxdna.
- Fix analogix_dp bitshifts during link training.
- Use direct label in drm_exec.
- Fix absent indirect bo handling in v3d.
- Sync on first active crtc in fb_dirty, rather than first crtc.
- Rework try_harder in the buddy allocator.
- Make imagination function static to solve compiler warning.
- Fix imagination error checking.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/71e5b48b-307f-47f5-8fd5-b60ea43e4196@linux.intel.com
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/accel/amdxdna/aie2_ctx.c | 19 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/aie2_message.c | 4 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_ctx.c | 56 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_gem.c | 50 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_gem.h | 12 | ||||
| -rw-r--r-- | drivers/accel/amdxdna/amdxdna_pci_drv.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/buddy.c | 63 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 92 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/imagination/pvr_context.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/imagination/pvr_fw_trace.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/tests/drm_exec_test.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/v3d/v3d_submit.c | 2 |
15 files changed, 289 insertions, 80 deletions
diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index 54486960cbf5..101f324ee178 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -875,7 +875,7 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size if (!hwctx->cus) return -ENOMEM; - ret = amdxdna_pm_resume_get_locked(xdna); + ret = amdxdna_pm_resume_get(xdna); if (ret) goto free_cus; @@ -900,13 +900,16 @@ free_cus: static void aie2_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq) { struct dma_fence *out_fence = aie2_cmd_get_out_fence(hwctx, seq); + struct amdxdna_dev *xdna = hwctx->client->xdna; if (!out_fence) { - XDNA_ERR(hwctx->client->xdna, "Failed to get fence"); + XDNA_ERR(xdna, "Failed to get fence"); return; } + mutex_unlock(&xdna->dev_lock); dma_fence_wait_timeout(out_fence, false, MAX_SCHEDULE_TIMEOUT); + mutex_lock(&xdna->dev_lock); dma_fence_put(out_fence); } @@ -1039,7 +1042,7 @@ again: found = false; down_write(&xdna->notifier_lock); list_for_each_entry(mapp, &abo->mem.umap_list, node) { - if (mapp->invalid) { + if (mapp->invalid && kref_get_unless_zero(&mapp->refcnt)) { found = true; break; } @@ -1050,11 +1053,9 @@ again: up_write(&xdna->notifier_lock); return 0; } - kref_get(&mapp->refcnt); + up_write(&xdna->notifier_lock); - XDNA_DBG(xdna, "populate memory range %lx %lx", - mapp->vma->vm_start, mapp->vma->vm_end); mm = mapp->notifier.mm; if (!mmget_not_zero(mm)) { amdxdna_umap_put(mapp); @@ -1221,10 +1222,6 @@ int aie2_hwctx_heap_expand(struct amdxdna_hwctx *hwctx, u64 addr; int ret; - ret = amdxdna_pm_resume_get_locked(xdna); - if (ret) - return ret; - addr = amdxdna_obj_dma_addr(heap); ret = aie2_add_host_buf(xdna->dev_handle, hwctx->fw_ctx_id, addr, heap->mem.size); @@ -1233,7 +1230,5 @@ int aie2_hwctx_heap_expand(struct amdxdna_hwctx *hwctx, hwctx->name, heap->mem.size, ret); } - amdxdna_pm_suspend_put(xdna); - return ret; } diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index c4b364801cc0..dfe0fbdf066d 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -840,7 +840,7 @@ static struct aie2_exec_msg_ops npu_exec_message_ops = { static int aie2_init_exec_req(void *req, struct amdxdna_gem_obj *cmd_abo, size_t *size, u32 *msg_op) { - struct amdxdna_dev *xdna = cmd_abo->client->xdna; + struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(cmd_abo)->dev); int ret; u32 op; @@ -874,7 +874,7 @@ static int aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo, size_t *size, u32 *cmd_op) { - struct amdxdna_dev *xdna = cmd_abo->client->xdna; + struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(cmd_abo)->dev); int ret; u32 op; diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index 855da8c79a1c..8f8df9d04ec5 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -310,6 +310,7 @@ int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct d if (!drm_dev_enter(dev, &idx)) return -ENODEV; + mutex_lock(&xdna->client_lock); mutex_lock(&xdna->dev_lock); hwctx = xa_erase(&client->hwctx_xa, args->handle); if (!hwctx) { @@ -328,6 +329,7 @@ int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct d XDNA_DBG(xdna, "PID %d destroyed HW context %d", client->pid, args->handle); out: mutex_unlock(&xdna->dev_lock); + mutex_unlock(&xdna->client_lock); drm_dev_exit(idx); return ret; } @@ -382,16 +384,27 @@ int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct dr return -EINVAL; } - guard(mutex)(&xdna->dev_lock); + ret = amdxdna_pm_resume_get(xdna); + if (ret) { + XDNA_ERR(xdna, "Resume failed, ret %d", ret); + goto free_buf; + } + + mutex_lock(&xdna->client_lock); + mutex_lock(&xdna->dev_lock); hwctx = xa_load(&client->hwctx_xa, args->handle); if (!hwctx) { XDNA_DBG(xdna, "PID %d failed to get hwctx %d", client->pid, args->handle); ret = -EINVAL; - goto free_buf; + goto unlock; } ret = xdna->dev_info->ops->hwctx_config(hwctx, args->param_type, val, buf, buf_size); +unlock: + mutex_unlock(&xdna->dev_lock); + mutex_unlock(&xdna->client_lock); + amdxdna_pm_suspend_put(xdna); free_buf: kfree(buf); return ret; @@ -412,16 +425,27 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl) if (!gobj) return -EINVAL; + ret = amdxdna_pm_resume_get(xdna); + if (ret) { + XDNA_ERR(xdna, "Resume failed, ret %d", ret); + goto put_obj; + } + abo = to_xdna_obj(gobj); - guard(mutex)(&xdna->dev_lock); + mutex_lock(&xdna->client_lock); + mutex_lock(&xdna->dev_lock); hwctx = xa_load(&client->hwctx_xa, abo->assigned_hwctx); if (!hwctx) { ret = -EINVAL; - goto put_obj; + goto unlock; } ret = xdna->dev_info->ops->hwctx_sync_debug_bo(hwctx, debug_bo_hdl); +unlock: + mutex_unlock(&xdna->dev_lock); + mutex_unlock(&xdna->client_lock); + amdxdna_pm_suspend_put(xdna); put_obj: drm_gem_object_put(gobj); return ret; @@ -448,9 +472,7 @@ static int amdxdna_hwctx_expand_heap(struct amdxdna_hwctx *hwctx) break; } - mutex_unlock(&client->mm_lock); ret = xdna->dev_info->ops->hwctx_heap_expand(hwctx, heap); - mutex_lock(&client->mm_lock); if (ret) { amdxdna_gem_unpin(heap); drm_gem_object_put(to_gobj(heap)); @@ -469,18 +491,26 @@ int amdxdna_update_heap(struct amdxdna_client *client, struct amdxdna_hwctx *hwc unsigned long hwctx_id; int ret; - guard(mutex)(&client->mm_lock); + ret = amdxdna_pm_resume_get_locked(client->xdna); + if (ret) + return ret; - if (hwctx) - return amdxdna_hwctx_expand_heap(hwctx); + mutex_lock(&client->mm_lock); - amdxdna_for_each_hwctx(client, hwctx_id, hwctx) { + if (hwctx) { ret = amdxdna_hwctx_expand_heap(hwctx); - if (ret) - return ret; + } else { + amdxdna_for_each_hwctx(client, hwctx_id, hwctx) { + ret = amdxdna_hwctx_expand_heap(hwctx); + if (ret) + break; + } } + mutex_unlock(&client->mm_lock); - return 0; + amdxdna_pm_suspend_put(client->xdna); + + return ret; } static void diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c index 891112c2cddf..4628a2787265 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.c +++ b/drivers/accel/amdxdna/amdxdna_gem.c @@ -198,6 +198,7 @@ amdxdna_gem_destroy_obj(struct amdxdna_gem_obj *abo) */ void *amdxdna_gem_vmap(struct amdxdna_gem_obj *abo) { + struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); struct iosys_map map = IOSYS_MAP_INIT_VADDR(NULL); int ret; @@ -210,7 +211,7 @@ void *amdxdna_gem_vmap(struct amdxdna_gem_obj *abo) if (!abo->mem.kva) { ret = drm_gem_vmap(to_gobj(abo), &map); if (ret) - XDNA_ERR(abo->client->xdna, "Vmap bo failed, ret %d", ret); + XDNA_ERR(xdna, "Vmap bo failed, ret %d", ret); else abo->mem.kva = map.vaddr; } @@ -254,7 +255,7 @@ static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni, xdna = to_xdna_dev(to_gobj(abo)->dev); XDNA_DBG(xdna, "Invalidating range 0x%lx, 0x%lx, type %d", - mapp->vma->vm_start, mapp->vma->vm_end, abo->type); + mapp->range.start, mapp->range.end, abo->type); if (!mmu_notifier_range_blockable(range)) return false; @@ -284,15 +285,23 @@ static const struct mmu_interval_notifier_ops amdxdna_hmm_ops = { .invalidate = amdxdna_hmm_invalidate, }; +static inline bool compare_range(struct amdxdna_umap *mapp, + struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + return (!mapp->unmapped && mapp->notifier.mm == mm && + mapp->range.start == start && mapp->range.end == end); +} + static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo, struct vm_area_struct *vma) { struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev); struct amdxdna_umap *mapp; - down_read(&xdna->notifier_lock); + down_write(&xdna->notifier_lock); list_for_each_entry(mapp, &abo->mem.umap_list, node) { - if (!vma || mapp->vma == vma) { + if (!vma || compare_range(mapp, vma->vm_mm, vma->vm_start, vma->vm_end)) { if (!mapp->unmapped) { queue_work(xdna->notifier_wq, &mapp->hmm_unreg_work); mapp->unmapped = true; @@ -301,19 +310,16 @@ static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo, break; } } - up_read(&xdna->notifier_lock); + up_write(&xdna->notifier_lock); } static void amdxdna_umap_release(struct kref *ref) { struct amdxdna_umap *mapp = container_of(ref, struct amdxdna_umap, refcnt); struct amdxdna_gem_obj *abo = mapp->abo; - struct vm_area_struct *vma = mapp->vma; struct amdxdna_dev *xdna; mmu_interval_notifier_remove(&mapp->notifier); - if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping) - mapping_clear_unevictable(vma->vm_file->f_mapping); xdna = to_xdna_dev(to_gobj(mapp->abo)->dev); down_write(&xdna->notifier_lock); @@ -346,15 +352,30 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, unsigned long len = vma->vm_end - vma->vm_start; unsigned long addr = vma->vm_start; struct amdxdna_umap *mapp; - u32 nr_pages; + unsigned long nr_pages; int ret; - if (!amdxdna_pasid_on(abo->client)) { + /* + * When PASID is off, amdxdna_gem_obj_open() called amdxdna_dma_map_bo() + * and mem.dma_addr is valid; use the DMA address directly and skip HMM. + * Avoid dereferencing abo->client which may be NULL (cleared in close()) + * while internal kernel references are still held. + */ + if (abo->mem.dma_addr != AMDXDNA_INVALID_ADDR) { /* Need to set uva for heap uva validation */ abo->mem.uva = addr; return 0; } + down_read(&xdna->notifier_lock); + list_for_each_entry(mapp, &abo->mem.umap_list, node) { + if (compare_range(mapp, current->mm, addr, addr + len)) { + up_read(&xdna->notifier_lock); + return 0; + } + } + up_read(&xdna->notifier_lock); + mapp = kzalloc_obj(*mapp); if (!mapp) return -ENOMEM; @@ -380,13 +401,10 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, mapp->range.start = vma->vm_start; mapp->range.end = vma->vm_end; mapp->range.default_flags = HMM_PFN_REQ_FAULT; - mapp->vma = vma; mapp->abo = abo; kref_init(&mapp->refcnt); INIT_WORK(&mapp->hmm_unreg_work, amdxdna_hmm_unreg_work); - if (is_import_bo(abo) && vma->vm_file && vma->vm_file->f_mapping) - mapping_set_unevictable(vma->vm_file->f_mapping); down_write(&xdna->notifier_lock); if (list_empty(&abo->mem.umap_list)) @@ -527,6 +545,7 @@ static int amdxdna_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struc close_vma: vma->vm_ops->close(vma); + return ret; put_obj: drm_gem_object_put(gobj); return ret; @@ -652,8 +671,11 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi /* No need to set up dma addr mapping in PASID mode. */ if (!amdxdna_pasid_on(abo->client)) { ret = amdxdna_dma_map_bo(xdna, abo); - if (ret) + if (ret) { + abo->open_ref--; + abo->client = NULL; return ret; + } } amdxdna_gem_add_bo_usage(abo); diff --git a/drivers/accel/amdxdna/amdxdna_gem.h b/drivers/accel/amdxdna/amdxdna_gem.h index a3e44c7a2395..1e90e32bf3cd 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.h +++ b/drivers/accel/amdxdna/amdxdna_gem.h @@ -12,7 +12,6 @@ #include "amdxdna_pci_drv.h" struct amdxdna_umap { - struct vm_area_struct *vma; struct mmu_interval_notifier notifier; struct hmm_range range; struct work_struct hmm_unreg_work; @@ -89,12 +88,19 @@ u64 amdxdna_gem_dev_addr(struct amdxdna_gem_obj *abo); static inline u64 amdxdna_dev_bo_offset(struct amdxdna_gem_obj *abo) { - return amdxdna_gem_dev_addr(abo) - abo->client->xdna->dev_info->dev_mem_base; + return amdxdna_gem_dev_addr(abo) - to_xdna_dev(to_gobj(abo)->dev)->dev_info->dev_mem_base; } static inline u64 amdxdna_obj_dma_addr(struct amdxdna_gem_obj *abo) { - return amdxdna_pasid_on(abo->client) ? amdxdna_gem_uva(abo) : abo->mem.dma_addr; + /* + * amdxdna_gem_obj_open() calls amdxdna_dma_map_bo() only when PASID is + * off, leaving mem.dma_addr at AMDXDNA_INVALID_ADDR when PASID is on. + * Avoid dereferencing abo->client, which is cleared to NULL by + * amdxdna_gem_obj_close() while internal kernel references remain. + */ + return (abo->mem.dma_addr != AMDXDNA_INVALID_ADDR) ? + abo->mem.dma_addr : amdxdna_gem_uva(abo); } void amdxdna_umap_put(struct amdxdna_umap *mapp); diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index e94d8290a807..bb339e641416 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -109,11 +109,16 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp) { struct amdxdna_dev *xdna = to_xdna_dev(ddev); struct amdxdna_client *client; + int ret; client = kzalloc_obj(*client); if (!client) return -ENOMEM; + ret = init_srcu_struct(&client->hwctx_srcu); + if (ret) + goto free_client; + client->pid = pid_nr(rcu_access_pointer(filp->pid)); client->xdna = xdna; client->pasid = IOMMU_PASID_INVALID; @@ -125,13 +130,12 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp) XDNA_WARN(xdna, "PASID not available for pid %d", client->pid); if (!amdxdna_use_carveout(xdna)) { XDNA_ERR(xdna, "PASID unavailable and carveout not configured"); - kfree(client); - return -EINVAL; + ret = -EINVAL; + goto cleanup_srcu; } } } mmgrab(client->mm); - init_srcu_struct(&client->hwctx_srcu); xa_init_flags(&client->hwctx_xa, XA_FLAGS_ALLOC); xa_init_flags(&client->dev_heap_xa, XA_FLAGS_ALLOC); drm_mm_init(&client->dev_heap_mm, xdna->dev_info->dev_mem_base, @@ -149,6 +153,12 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp) XDNA_DBG(xdna, "pid %d opened", client->pid); return 0; + +cleanup_srcu: + cleanup_srcu_struct(&client->hwctx_srcu); +free_client: + kfree(client); + return ret; } static void amdxdna_client_cleanup(struct amdxdna_client *client) @@ -373,7 +383,10 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - drmm_mutex_init(ddev, &xdna->dev_lock); + ret = drmm_mutex_init(ddev, &xdna->dev_lock); + if (ret) + return ret; + init_rwsem(&xdna->notifier_lock); INIT_LIST_HEAD(&xdna->client_list); pci_set_drvdata(pdev, xdna); diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c index eb1457376307..b12d3a2ac630 100644 --- a/drivers/gpu/buddy.c +++ b/drivers/gpu/buddy.c @@ -1084,22 +1084,30 @@ static int __gpu_buddy_alloc_range(struct gpu_buddy *mm, blocks, total_allocated_on_err); } +static int __alloc_contig_aligned_retry(struct gpu_buddy *mm, + u64 unaligned_offset, + u64 size, + u64 min_block_size, + struct list_head *blocks) +{ + u64 aligned_offset = round_down(unaligned_offset, min_block_size); + + return __gpu_buddy_alloc_range(mm, aligned_offset, size, NULL, blocks); +} + static int __alloc_contig_try_harder(struct gpu_buddy *mm, u64 size, u64 min_block_size, struct list_head *blocks) { - u64 rhs_offset, lhs_offset, lhs_size, filled; + u64 rhs_offset, lhs_offset, filled; struct gpu_buddy_block *block; unsigned int tree, order; - LIST_HEAD(blocks_lhs); - unsigned long pages; u64 modify_size; int err; modify_size = rounddown_pow_of_two(size); - pages = modify_size >> ilog2(mm->chunk_size); - order = fls(pages) - 1; + order = ilog2(modify_size) - ilog2(mm->chunk_size); if (order == 0) return -ENOSPC; @@ -1115,31 +1123,48 @@ static int __alloc_contig_try_harder(struct gpu_buddy *mm, while (iter) { block = rbtree_get_free_block(iter); - /* Allocate blocks traversing RHS */ rhs_offset = gpu_buddy_block_offset(block); + + /* Allocate blocks traversing RHS */ err = __gpu_buddy_alloc_range(mm, rhs_offset, size, &filled, blocks); - if (!err || err != -ENOSPC) + if (err && err != -ENOSPC) return err; + if (!err && IS_ALIGNED(rhs_offset, min_block_size)) + return 0; + if (!err) { + /* Allocate the unaligned RHS offset using round_down */ + gpu_buddy_free_list_internal(mm, blocks); + err = __alloc_contig_aligned_retry(mm, rhs_offset, + size, + min_block_size, + blocks); + if (!err) + return 0; + if (err != -ENOSPC) { + gpu_buddy_free_list_internal(mm, blocks); + return err; + } + goto next; + } - lhs_size = max((size - filled), min_block_size); - if (!IS_ALIGNED(lhs_size, min_block_size)) - lhs_size = round_up(lhs_size, min_block_size); + if (size - filled > rhs_offset) + goto next; - /* Allocate blocks traversing LHS */ - lhs_offset = gpu_buddy_block_offset(block) - lhs_size; - err = __gpu_buddy_alloc_range(mm, lhs_offset, lhs_size, - NULL, &blocks_lhs); - if (!err) { - list_splice(&blocks_lhs, blocks); + lhs_offset = rhs_offset - (size - filled); + + /* Allocate the unaligned LHS offset using round_down */ + gpu_buddy_free_list_internal(mm, blocks); + err = __alloc_contig_aligned_retry(mm, lhs_offset, size, + min_block_size, blocks); + if (!err) return 0; - } else if (err != -ENOSPC) { + if (err != -ENOSPC) { gpu_buddy_free_list_internal(mm, blocks); return err; } - /* Free blocks for the next iteration */ +next: gpu_buddy_free_list_internal(mm, blocks); - iter = rb_prev(iter); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index f317f888b59f..7b6917c8a509 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -3015,6 +3015,8 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, is_compute_context = vm->is_compute_context; if (is_compute_context) { + __label__ drm_exec_retry; + /* Release the root PD lock since svm_range_restore_pages * might try to take it. * TODO: rework svm_range_restore_pages so that this isn't diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 8cf6b73bceac..5006ac181b2d 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -309,7 +309,9 @@ static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp, lane_count = dp->link_train.lane_count; for (lane = 0; lane < lane_count; lane++) { voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane); + voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT; pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); + pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT; training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | DPCD_PRE_EMPHASIS_SET(pre_emphasis); @@ -355,7 +357,9 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) for (lane = 0; lane < lane_count; lane++) { training_lane = analogix_dp_get_lane_link_training(dp, lane); voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane); + voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT; pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); + pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT; if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing && DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7b11a582f8ec..80ca785bdb26 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -225,16 +225,106 @@ static void drm_fb_helper_resume_worker(struct work_struct *work) console_unlock(); } +static int find_crtc_index_atomic(struct drm_fb_helper *helper) +{ + struct drm_device *dev = helper->dev; + int crtc_index = -EINVAL; + struct drm_modeset_acquire_ctx ctx; + struct drm_plane *plane; + int ret = 0; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + drm_for_each_plane(plane, dev) { + const struct drm_plane_state *plane_state; + + if (plane->type != DRM_PLANE_TYPE_PRIMARY) + continue; + + ret = drm_modeset_lock(&plane->mutex, &ctx); + if (ret) + goto err_drm_modeset_lock; + plane_state = plane->state; + + if (plane_state->fb == helper->fb && plane_state->crtc) { + struct drm_crtc *crtc = plane_state->crtc; + + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto err_drm_modeset_lock; + if (crtc->state->active) + crtc_index = crtc->index; + drm_modeset_unlock(&crtc->mutex); + } + drm_modeset_unlock(&plane->mutex); + + if (crtc_index >= 0) + break; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return crtc_index; + +err_drm_modeset_lock: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + return ret; +} + +static int find_crtc_index_legacy(struct drm_fb_helper *helper) +{ + struct drm_device *dev = helper->dev; + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, dev) { + struct drm_plane *plane = crtc->primary; + + if (!crtc->enabled) + continue; + if (!plane || plane->fb != helper->fb) + continue; /* CRTC doesn't display fbdev emulation */ + + return crtc->index; + } + + return -EINVAL; +} + +static int drm_fb_helper_find_crtc_index(struct drm_fb_helper *helper) +{ + struct drm_device *dev = helper->dev; + int crtc_index; + + mutex_lock(&dev->mode_config.mutex); + + if (drm_drv_uses_atomic_modeset(dev)) + crtc_index = find_crtc_index_atomic(helper); + else + crtc_index = find_crtc_index_legacy(helper); + + mutex_unlock(&dev->mode_config.mutex); + + return crtc_index; +} + static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper) { struct drm_device *dev = helper->dev; struct drm_clip_rect *clip = &helper->damage_clip; struct drm_clip_rect clip_copy; + int crtc_index; unsigned long flags; int ret; mutex_lock(&helper->lock); - drm_client_modeset_wait_for_vblank(&helper->client, 0); + crtc_index = drm_fb_helper_find_crtc_index(helper); + if (crtc_index >= 0) + drm_client_modeset_wait_for_vblank(&helper->client, crtc_index); mutex_unlock(&helper->lock); if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty)) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index e2df4becce62..9039a39c4324 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -373,13 +373,25 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->supports_virtualized_cursor_plane = req->value; break; - case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE: + case DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE: { + struct drm_plane *plane; + bool has_plane_with_color_pipeline = false; + if (!file_priv->atomic) return -EINVAL; if (req->value > 1) return -EINVAL; + drm_for_each_plane(plane, dev) { + if (plane->color_pipeline_property) { + has_plane_with_color_pipeline = true; + break; + } + } + if (!has_plane_with_color_pipeline) + return -EOPNOTSUPP; file_priv->plane_color_pipeline = req->value; break; + } default: return -EINVAL; } diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c index 52e16c1e7af0..406e0758e860 100644 --- a/drivers/gpu/drm/imagination/pvr_context.c +++ b/drivers/gpu/drm/imagination/pvr_context.c @@ -309,8 +309,8 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co goto err_free_ctx; ctx->vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); - if (IS_ERR(ctx->vm_ctx)) { - err = PTR_ERR(ctx->vm_ctx); + if (!ctx->vm_ctx) { + err = -EINVAL; goto err_free_ctx; } diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 6bb5baa6c41b..805d9f9bc1dd 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -71,7 +71,7 @@ pvr_fw_trace_init_mask_set(const char *val, const struct kernel_param *kp) return 0; } -const struct kernel_param_ops pvr_fw_trace_init_mask_ops = { +static const struct kernel_param_ops pvr_fw_trace_init_mask_ops = { .set = pvr_fw_trace_init_mask_set, .get = param_get_hexint, }; diff --git a/drivers/gpu/drm/tests/drm_exec_test.c b/drivers/gpu/drm/tests/drm_exec_test.c index 2fc47f3b463b..7a374e462348 100644 --- a/drivers/gpu/drm/tests/drm_exec_test.c +++ b/drivers/gpu/drm/tests/drm_exec_test.c @@ -180,19 +180,27 @@ static void test_multiple_loops(struct kunit *test) { struct drm_exec exec; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); - drm_exec_until_all_locked(&exec) { - break; + __label__ drm_exec_retry; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); + drm_exec_until_all_locked(&exec) + { + break; + } + drm_exec_fini(&exec); } - drm_exec_fini(&exec); - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); - drm_exec_until_all_locked(&exec) { - break; + __label__ drm_exec_retry; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); + drm_exec_until_all_locked(&exec) + { + break; + } + drm_exec_fini(&exec); } - drm_exec_fini(&exec); KUNIT_SUCCEED(test); } diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c index 1db43c6a078d..7682b24f13ec 100644 --- a/drivers/gpu/drm/v3d/v3d_submit.c +++ b/drivers/gpu/drm/v3d/v3d_submit.c @@ -495,6 +495,8 @@ v3d_get_cpu_indirect_csd_params(struct drm_file *file_priv, sizeof(indirect_csd.wg_uniform_offsets)); info->indirect = drm_gem_object_lookup(file_priv, indirect_csd.indirect); + if (!info->indirect) + return -ENOENT; return v3d_setup_csd_jobs_and_bos(file_priv, v3d, &indirect_csd.submit, &info->job, &info->clean_job, |
