]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Merge tag 'drm-misc-next-2026-04-20' of https://gitlab.freedesktop.org/drm/misc/kerne...
authorDave Airlie <airlied@redhat.com>
Wed, 6 May 2026 00:12:18 +0000 (10:12 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 6 May 2026 00:12:25 +0000 (10:12 +1000)
drm-misc-next for v7.1-rc1:

UAPI Changes:
- Expose per-client BO memory usage via fdinfo in amdxdna. (Hou)
- Change the default priority of drm scheduler to fair. (Tvrtko)

Cross-subsystem Changes:
- Revert hugetlb support in udmabuf. (Gunthorpe)
- Fix error in udmabuf with CONFIG_DMA_API_DEBUG(/ _SG). (Gavrilov)
- Add Docbook for DRM_IOCTL_SYNCOBJ_EVENTFD, (Ser)
  clarify drm_bridge_get/put. (Tvrtko)
- Change signature of drm_connector_attach_hdr_output_metadata_property. (Canal)
- Use IOVA allocations in gpusvm and pagemap APIs. (Brost)
- Fix tracepoints vs dma-fence lifetime. (Tvrtko)
- Convert st-dma*.c tests to use kunit. (Gunthorpe)

Core Changes:
- Deduplicate counter and timestamp retrieval in vblank code. (Ville)
- Parse AMD VSDB v3 in CTA extension blocks, and use it in amdgpu. (Chen)
- Prevent bridge and encoder chain changes at inopportune times. (Ceresoli)
- Map the run queue 1:1 to the drm scheduler. (Tvrtko)

Driver Changes:
- Assorted bugfixes and (documentation) updates to rockchip, bridge/synopsis,
  panfrost, tidss, accel/qaic, tilcdc, vc4, ast, imagination, panthor,
  renesas, accel/amdxdna, msxfb, bridge/imx8mp, nouveau.
  bridge/analogix_dp, bridge/exynos_dp, omap.
- Add support for CSW PNB601LS1-2, LGD LP116WHA-SPB1, panels.
- Add support for a lot of waveshare panels (Baryshkov)
- Support for AIE4 devices in accel/wamdxdna. (Zhang)
- Enable support for GEM shrinking in panthor. (Goel/Brezillon)
- Runtime Power Management is added to v3d. (Canal)
- Allow panel probing and use the panel bridge helper in analogix_dp. (Ding)
- Support XRGB1555 and C8 in mgag and XRGB1555 in ast. (Zimmermann)

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/bf31b1a1-951b-4f60-b226-22e8c083697d@linux.intel.com
Signed-off-by: Dave Airlie <airlied@redhat.com>
32 files changed:
1  2 
Documentation/devicetree/bindings/display/panel/panel-simple.yaml
drivers/dma-buf/dma-fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
drivers/gpu/drm/ast/ast_dp501.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
drivers/gpu/drm/bridge/synopsys/dw-dp.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/gpu/drm/drm_bridge.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gpusvm.c
drivers/gpu/drm/kmb/kmb_dsi.c
drivers/gpu/drm/mgag200/mgag200_g200se.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/panthor/panthor_gem.c
drivers/gpu/drm/panthor/panthor_mmu.c
drivers/gpu/drm/renesas/rcar-du/rcar_du_kms.c
drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
drivers/gpu/drm/rockchip/dw_dp-rockchip.c
drivers/gpu/drm/tidss/tidss_kms.c
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/gpu/drm/v3d/v3d_submit.c
drivers/gpu/drm/vc4/vc4_bo.c
drivers/gpu/drm/vc4/vc4_gem.c
drivers/gpu/drm/vc4/vc4_plane.c
drivers/gpu/drm/xe/xe_execlist.c
drivers/gpu/drm/xe/xe_svm.c
include/drm/drm_bridge.h
include/drm/drm_connector.h

Simple merge
Simple merge
Simple merge
index e5361a3fd6a6e4e4a62a1695dcb7caf297414401,460729fdcecd944bbb6522d67f8370ca5cd07e59..6bfb43b0760440213349e2c3f9631e2f69efac59
@@@ -1087,6 -1018,7 +1018,7 @@@ out_dp_init
  }
  
  static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
 -                                      struct drm_atomic_state *state,
++                                      struct drm_atomic_commit *state,
                                        const struct drm_display_mode *mode)
  {
        struct analogix_dp_device *dp = to_dp(bridge);
index 218780a38565b16172a6f61e37a21b199783f3de,986e4c79a4e0bce1644f0acf7bf421261d2e9b5a..d33ca20991352f3b6d4b856b6d664a6f0549ee29
@@@ -1019,16 -1022,13 +1022,13 @@@ EXPORT_SYMBOL(drm_atomic_bridge_chain_p
   *
   * Note: the bridge passed should be the one closest to the encoder
   */
- void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
+ void drm_atomic_bridge_chain_enable(struct drm_bridge *first_bridge,
 -                                  struct drm_atomic_state *state)
 +                                  struct drm_atomic_commit *state)
  {
-       struct drm_encoder *encoder;
-       if (!bridge)
+       if (!first_bridge)
                return;
  
-       encoder = bridge->encoder;
-       list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+       drm_for_each_bridge_in_chain_from(first_bridge, bridge)
                if (bridge->funcs->atomic_enable) {
                        bridge->funcs->atomic_enable(bridge, state);
                } else if (bridge->funcs->enable) {
Simple merge
Simple merge
Simple merge
index cd49859da89b15b2b05e19d598adb330969f2502,69cef05b6ef785e5d8fc61603c246b09a5677bae..13295d7a593df27f074e449075cf7760dd5219d5
@@@ -593,11 -1221,356 +1221,356 @@@ panthor_gem_sync(struct drm_gem_object 
                 *
                 * for the flush+invalidate case.
                 */
-               dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE);
+               dma_sync_single_for_device(dma_dev, paddr, len, DMA_TO_DEVICE);
                if (type == DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE)
-                       dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE);
+                       dma_sync_single_for_cpu(dma_dev, paddr, len, DMA_FROM_DEVICE);
+       }
+       ret = 0;
+ out_unlock:
+       dma_resv_unlock(bo->base.resv);
+       return ret;
+ }
+ /**
+  * panthor_kernel_bo_destroy() - Destroy a kernel buffer object
+  * @bo: Kernel buffer object to destroy. If NULL or an ERR_PTR(), the destruction
+  * is skipped.
+  */
+ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo)
+ {
+       struct panthor_device *ptdev;
+       struct panthor_vm *vm;
+       if (IS_ERR_OR_NULL(bo))
+               return;
+       ptdev = container_of(bo->obj->dev, struct panthor_device, base);
+       vm = bo->vm;
+       panthor_kernel_bo_vunmap(bo);
+       drm_WARN_ON(bo->obj->dev,
+                   to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm));
+       panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size);
+       panthor_vm_free_va(vm, &bo->va_node);
+       if (vm == panthor_fw_vm(ptdev))
+               panthor_gem_unpin(to_panthor_bo(bo->obj));
+       drm_gem_object_put(bo->obj);
+       panthor_vm_put(vm);
+       kfree(bo);
+ }
+ /**
+  * panthor_kernel_bo_create() - Create and map a GEM object to a VM
+  * @ptdev: Device.
 - * @vm: VM to map the GEM to. If NULL, the kernel object is not GPU mapped.
++ * @vm: VM to map the GEM to.
+  * @size: Size of the buffer object.
+  * @bo_flags: Combination of drm_panthor_bo_flags flags.
+  * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those
+  * that are related to map operations).
+  * @gpu_va: GPU address assigned when mapping to the VM.
+  * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be
+  * automatically allocated.
+  * @name: Descriptive label of the BO's contents
+  *
+  * Return: A valid pointer in case of success, an ERR_PTR() otherwise.
+  */
+ struct panthor_kernel_bo *
+ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
+                        size_t size, u32 bo_flags, u32 vm_map_flags,
+                        u64 gpu_va, const char *name)
+ {
+       struct panthor_kernel_bo *kbo;
+       struct panthor_gem_object *bo;
+       u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL;
+       int ret;
+       if (drm_WARN_ON(&ptdev->base, !vm))
+               return ERR_PTR(-EINVAL);
+       kbo = kzalloc_obj(*kbo);
+       if (!kbo)
+               return ERR_PTR(-ENOMEM);
+       if (vm == panthor_fw_vm(ptdev))
+               debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED;
+       bo = panthor_gem_create(&ptdev->base, size, bo_flags, vm, debug_flags);
+       if (IS_ERR(bo)) {
+               ret = PTR_ERR(bo);
+               goto err_free_kbo;
+       }
+       kbo->obj = &bo->base;
+       if (vm == panthor_fw_vm(ptdev)) {
+               ret = panthor_gem_pin(bo);
+               if (ret)
+                       goto err_put_obj;
+       }
+       panthor_gem_kernel_bo_set_label(kbo, name);
+       /* The system and GPU MMU page size might differ, which becomes a
+        * problem for FW sections that need to be mapped at explicit address
+        * since our PAGE_SIZE alignment might cover a VA range that's
+        * expected to be used for another section.
+        * Make sure we never map more than we need.
+        */
+       size = ALIGN(size, panthor_vm_page_size(vm));
+       ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node);
+       if (ret)
+               goto err_unpin;
+       ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags);
+       if (ret)
+               goto err_free_va;
+       kbo->vm = panthor_vm_get(vm);
+       return kbo;
+ err_free_va:
+       panthor_vm_free_va(vm, &kbo->va_node);
+ err_unpin:
+       if (vm == panthor_fw_vm(ptdev))
+               panthor_gem_unpin(bo);
+ err_put_obj:
+       drm_gem_object_put(&bo->base);
+ err_free_kbo:
+       kfree(kbo);
+       return ERR_PTR(ret);
+ }
+ static bool can_swap(void)
+ {
+       return get_nr_swap_pages() > 0;
+ }
+ static bool can_block(struct shrink_control *sc)
+ {
+       /* If direct reclaim is allowed, we can always block.
+        * If kswapd reclaim is allowed, we can block, but only if we're called
+        * by the kswapd thread.
+        */
+       return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) ||
+              ((sc->gfp_mask & __GFP_KSWAPD_RECLAIM) && current_is_kswapd());
+ }
+ static unsigned long
+ panthor_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
+ {
+       struct panthor_device *ptdev = shrinker->private_data;
+       unsigned long count;
+       /* We currently don't have a flag to tell when the content of a
+        * BO can be discarded.
+        */
+       if (!can_swap())
+               return 0;
+       /* This is racy, but that's okay because the returned count is just a
+        * hint. That's also what MSM is doing (no atomic var, it's relying on
+        * the fact unsigned long access is usually atomic), so if it's good
+        * enough for them, it's good enough for us too.
+        */
+       count = ptdev->reclaim.unused.count;
+       count += ptdev->reclaim.mmapped.count;
+       if (can_block(sc))
+               count += ptdev->reclaim.gpu_mapped_count;
+       return count ? count : SHRINK_EMPTY;
+ }
+ static bool panthor_gem_try_evict_no_resv_wait(struct drm_gem_object *obj,
+                                              struct ww_acquire_ctx *ticket)
+ {
+       /*
+        * Track last locked entry for unwinding locks in error and
+        * success paths
+        */
+       struct panthor_gem_object *bo = to_panthor_bo(obj);
+       struct drm_gpuvm_bo *vm_bo, *last_locked = NULL;
+       enum panthor_gem_reclaim_state old_state;
+       int ret = 0;
+       /* To avoid potential lock ordering issue between bo_gpuva and
+        * mapping->i_mmap_rwsem, unmap the pages from CPU side before
+        * acquring the bo_gpuva lock. As the bo_resv lock is held, CPU
+        * page fault handler won't be able to map in the pages whilst
+        * eviction is in progress.
+        */
+       drm_vma_node_unmap(&bo->base.vma_node, bo->base.dev->anon_inode->i_mapping);
+       /* We take this lock when walking the list to prevent
+        * insertion/deletion.
+        */
+       /* We can only trylock in that path, because
+        * - allocation might happen while some of these locks are held
+        * - lock ordering is different in other paths
+        *     vm_resv -> bo_resv -> bo_gpuva
+        *     vs
+        *     bo_resv -> bo_gpuva -> vm_resv
+        *
+        * If we fail to lock that's fine, we back off and will get
+        * back to it later.
+        */
+       if (!mutex_trylock(&bo->base.gpuva.lock))
+               return false;
+       drm_gem_for_each_gpuvm_bo(vm_bo, obj) {
+               struct dma_resv *resv = drm_gpuvm_resv(vm_bo->vm);
+               if (resv == obj->resv)
+                       continue;
+               if (!dma_resv_trylock(resv)) {
+                       ret = -EDEADLK;
+                       goto out_unlock;
+               }
+               last_locked = vm_bo;
+       }
+       /* Update the state before trying to evict the buffer, if the state was
+        * updated to something that's harder to reclaim (higher value in the
+        * enum), skip it (will be processed when the relevant LRU is).
+        */
+       panthor_gem_update_reclaim_state_locked(bo, &old_state);
+       if (old_state < bo->reclaim_state) {
+               ret = -EAGAIN;
+               goto out_unlock;
+       }
+       /* Couldn't teardown the GPU mappings? Skip. */
+       ret = panthor_vm_evict_bo_mappings_locked(bo);
+       if (ret)
+               goto out_unlock;
+       /* If everything went fine, evict the object. */
+       panthor_gem_evict_locked(bo);
+ out_unlock:
+       if (last_locked) {
+               drm_gem_for_each_gpuvm_bo(vm_bo, obj) {
+                       struct dma_resv *resv = drm_gpuvm_resv(vm_bo->vm);
+                       if (resv == obj->resv)
+                               continue;
+                       dma_resv_unlock(resv);
+                       if (last_locked == vm_bo)
+                               break;
+               }
        }
+       mutex_unlock(&bo->base.gpuva.lock);
+       return ret == 0;
+ }
+ static bool panthor_gem_try_evict(struct drm_gem_object *obj,
+                                 struct ww_acquire_ctx *ticket)
+ {
+       struct panthor_gem_object *bo = to_panthor_bo(obj);
+       /* Wait was too long, skip. */
+       if (dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_BOOKKEEP, false, 10) <= 0)
+               return false;
+       return panthor_gem_try_evict_no_resv_wait(&bo->base, ticket);
+ }
+ static unsigned long
+ panthor_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
+ {
+       struct panthor_device *ptdev = shrinker->private_data;
+       unsigned long remaining = 0;
+       unsigned long freed = 0;
+       if (!can_swap())
+               goto out;
+       freed += drm_gem_lru_scan(&ptdev->reclaim.unused,
+                                 sc->nr_to_scan - freed, &remaining,
+                                 panthor_gem_try_evict_no_resv_wait, NULL);
+       if (freed >= sc->nr_to_scan)
+               goto out;
+       freed += drm_gem_lru_scan(&ptdev->reclaim.mmapped,
+                                 sc->nr_to_scan - freed, &remaining,
+                                 panthor_gem_try_evict_no_resv_wait, NULL);
+       if (freed >= sc->nr_to_scan)
+               goto out;
+       if (!can_block(sc))
+               goto out;
+       freed += panthor_mmu_reclaim_priv_bos(ptdev, sc->nr_to_scan - freed,
+                                             &remaining, panthor_gem_try_evict);
+       if (freed >= sc->nr_to_scan)
+               goto out;
+       freed += drm_gem_lru_scan(&ptdev->reclaim.gpu_mapped_shared,
+                                 sc->nr_to_scan - freed, &remaining,
+                                 panthor_gem_try_evict, NULL);
+ out:
+ #ifdef CONFIG_DEBUG_FS
+       /* This is racy, but that's okay, because this is just debugfs
+        * reporting and doesn't need to be accurate.
+        */
+       ptdev->reclaim.nr_pages_reclaimed_on_last_scan = freed;
+ #endif
+       /* If there are things to reclaim, try a couple times before giving up. */
+       if (!freed && remaining > 0 &&
+           atomic_inc_return(&ptdev->reclaim.retry_count) < 2)
+               return 0;
+       atomic_set(&ptdev->reclaim.retry_count, 0);
+       if (freed)
+               return freed;
+       /* There's nothing left to reclaim, or the resources are contended. Give up now. */
+       return SHRINK_STOP;
+ }
+ int panthor_gem_shrinker_init(struct panthor_device *ptdev)
+ {
+       struct shrinker *shrinker;
+       int ret;
+       ret = drmm_mutex_init(&ptdev->base, &ptdev->reclaim.lock);
+       if (ret)
+               return ret;
+       INIT_LIST_HEAD(&ptdev->reclaim.vms);
+       drm_gem_lru_init(&ptdev->reclaim.unused, &ptdev->reclaim.lock);
+       drm_gem_lru_init(&ptdev->reclaim.mmapped, &ptdev->reclaim.lock);
+       drm_gem_lru_init(&ptdev->reclaim.gpu_mapped_shared, &ptdev->reclaim.lock);
+       ptdev->reclaim.gpu_mapped_count = 0;
+       /* Teach lockdep about lock ordering wrt. shrinker: */
+       fs_reclaim_acquire(GFP_KERNEL);
+       might_lock(&ptdev->reclaim.lock);
+       fs_reclaim_release(GFP_KERNEL);
+       shrinker = shrinker_alloc(0, "drm-panthor-gem");
+       if (!shrinker)
+               return -ENOMEM;
  
+       shrinker->count_objects = panthor_gem_shrinker_count;
+       shrinker->scan_objects = panthor_gem_shrinker_scan;
+       shrinker->private_data = ptdev;
+       ptdev->reclaim.shrinker = shrinker;
+       shrinker_register(shrinker);
        return 0;
  }
  
Simple merge
index e5402cb430faae9a865ac808480df2d82fb35f6f,715872130780f98f314b8e1bdf2072dbfe3712a2..40fd6e1eeab5d7b6f7eed31eb66a19e2f34b3818
@@@ -1039,9 -1034,12 +1034,12 @@@ static void rzg2l_mipi_dsi_atomic_pre_e
  }
  
  static void rzg2l_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
 -                                       struct drm_atomic_state *state)
 +                                       struct drm_atomic_commit *state)
  {
        struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
+       const struct drm_display_mode *mode;
+       struct drm_connector *connector;
+       struct drm_crtc *crtc;
        int ret;
  
        ret = rzg2l_mipi_dsi_start_hs_clock(dsi);
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge