--- /dev/null
+From stable+bounces-294379-greg=kroah.com@vger.kernel.org Sat Aug 1 16:04:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 10:04:07 -0400
+Subject: drm/exec: Remove the index parameter from drm_exec_for_each_locked_obj[_reverse]
+To: stable@vger.kernel.org
+Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>, "Christian König" <christian.koenig@amd.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260801140408.3645911-1-sashal@kernel.org>
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit ce44b78512e9102aea54ff6b6e521d6c8de9f31c ]
+
+Nobody makes any use of it. Possible internal future users can
+instead use the _index variable. External users shouldn't use
+it since the array it's pointing into is internal drm_exec state.
+
+v2:
+- Use a unique id for the loop variable (Christian)
+
+Assisted-by: GitHub Copilot:claude-sonnet-4.6
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patch.msgid.link/20260520101616.41284-2-thomas.hellstrom@linux.intel.com
+Stable-dep-of: af80e2bfde93 ("drm/xe: Wait on external BO kernel fences in exec IOCTL")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 9 +++------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c | 3 +--
+ drivers/gpu/drm/drm_exec.c | 6 ++----
+ drivers/gpu/drm/drm_gpuvm.c | 3 +--
+ drivers/gpu/drm/xe/xe_vm.c | 3 +--
+ include/drm/drm_exec.h | 20 ++++++++++++--------
+ 6 files changed, 20 insertions(+), 24 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -854,7 +854,6 @@ static int amdgpu_cs_parser_bos(struct a
+ struct amdgpu_vm *vm = &fpriv->vm;
+ struct amdgpu_bo_list_entry *e;
+ struct drm_gem_object *obj;
+- unsigned long index;
+ unsigned int i;
+ int r;
+
+@@ -965,7 +964,7 @@ static int amdgpu_cs_parser_bos(struct a
+ goto out_free_user_pages;
+ }
+
+- drm_exec_for_each_locked_object(&p->exec, index, obj) {
++ drm_exec_for_each_locked_object(&p->exec, obj) {
+ r = amdgpu_cs_bo_validate(p, gem_to_amdgpu_bo(obj));
+ if (unlikely(r))
+ goto out_free_user_pages;
+@@ -1191,7 +1190,6 @@ static int amdgpu_cs_sync_rings(struct a
+ struct drm_gpu_scheduler *sched;
+ struct drm_gem_object *obj;
+ struct dma_fence *fence;
+- unsigned long index;
+ unsigned int i;
+ int r;
+
+@@ -1202,7 +1200,7 @@ static int amdgpu_cs_sync_rings(struct a
+ return r;
+ }
+
+- drm_exec_for_each_locked_object(&p->exec, index, obj) {
++ drm_exec_for_each_locked_object(&p->exec, obj) {
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+
+ struct dma_resv *resv = bo->tbo.base.resv;
+@@ -1271,7 +1269,6 @@ static int amdgpu_cs_submit(struct amdgp
+ struct amdgpu_vm *vm = &fpriv->vm;
+ struct amdgpu_bo_list_entry *e;
+ struct drm_gem_object *gobj;
+- unsigned long index;
+ unsigned int i;
+ uint64_t seq;
+ int r;
+@@ -1322,7 +1319,7 @@ static int amdgpu_cs_submit(struct amdgp
+ }
+
+ p->fence = dma_fence_get(&leader->base.s_fence->finished);
+- drm_exec_for_each_locked_object(&p->exec, index, gobj) {
++ drm_exec_for_each_locked_object(&p->exec, gobj) {
+
+ ttm_bo_move_to_lru_tail_unlocked(&gem_to_amdgpu_bo(gobj)->tbo);
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
+@@ -121,7 +121,6 @@ int amdgpu_evf_mgr_rearm(struct amdgpu_e
+ {
+ struct amdgpu_eviction_fence *ev_fence;
+ struct drm_gem_object *obj;
+- unsigned long index;
+
+ /* Create and initialize a new eviction fence */
+ ev_fence = kzalloc_obj(*ev_fence);
+@@ -140,7 +139,7 @@ int amdgpu_evf_mgr_rearm(struct amdgpu_e
+ evf_mgr->ev_fence = &ev_fence->base;
+
+ /* And add it to all existing BOs */
+- drm_exec_for_each_locked_object(exec, index, obj) {
++ drm_exec_for_each_locked_object(exec, obj) {
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+
+ amdgpu_evf_mgr_attach_fence(evf_mgr, bo);
+--- a/drivers/gpu/drm/drm_exec.c
++++ b/drivers/gpu/drm/drm_exec.c
+@@ -24,7 +24,6 @@
+ *
+ * struct drm_gem_object *obj;
+ * struct drm_exec exec;
+- * unsigned long index;
+ * int ret;
+ *
+ * drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
+@@ -40,7 +39,7 @@
+ * goto error;
+ * }
+ *
+- * drm_exec_for_each_locked_object(&exec, index, obj) {
++ * drm_exec_for_each_locked_object(&exec, obj) {
+ * dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ);
+ * ...
+ * }
+@@ -56,9 +55,8 @@
+ static void drm_exec_unlock_all(struct drm_exec *exec)
+ {
+ struct drm_gem_object *obj;
+- unsigned long index;
+
+- drm_exec_for_each_locked_object_reverse(exec, index, obj) {
++ drm_exec_for_each_locked_object_reverse(exec, obj) {
+ dma_resv_unlock(obj->resv);
+ drm_gem_object_put(obj);
+ }
+--- a/drivers/gpu/drm/drm_gpuvm.c
++++ b/drivers/gpu/drm/drm_gpuvm.c
+@@ -1557,9 +1557,8 @@ drm_gpuvm_resv_add_fence(struct drm_gpuv
+ enum dma_resv_usage extobj_usage)
+ {
+ struct drm_gem_object *obj;
+- unsigned long index;
+
+- drm_exec_for_each_locked_object(exec, index, obj) {
++ drm_exec_for_each_locked_object(exec, obj) {
+ dma_resv_assert_held(obj->resv);
+ dma_resv_add_fence(obj->resv, fence,
+ drm_gpuvm_is_extobj(gpuvm, obj) ?
+--- a/drivers/gpu/drm/xe/xe_vm.c
++++ b/drivers/gpu/drm/xe/xe_vm.c
+@@ -373,7 +373,6 @@ int xe_vm_validate_rebind(struct xe_vm *
+ unsigned int num_fences)
+ {
+ struct drm_gem_object *obj;
+- unsigned long index;
+ int ret;
+
+ do {
+@@ -386,7 +385,7 @@ int xe_vm_validate_rebind(struct xe_vm *
+ return ret;
+ } while (!list_empty(&vm->gpuvm.evict.list));
+
+- drm_exec_for_each_locked_object(exec, index, obj) {
++ drm_exec_for_each_locked_object(exec, obj) {
+ ret = dma_resv_reserve_fences(obj->resv, num_fences);
+ if (ret)
+ return ret;
+--- a/include/drm/drm_exec.h
++++ b/include/drm/drm_exec.h
+@@ -65,31 +65,35 @@ drm_exec_obj(struct drm_exec *exec, unsi
+ return index < exec->num_objects ? exec->objects[index] : NULL;
+ }
+
++/* Helper for drm_exec_for_each_locked_object(). Internal use only. */
++#define __drm_exec_for_each_locked_object(exec, obj, __index) \
++ for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index)
+ /**
+ * drm_exec_for_each_locked_object - iterate over all the locked objects
+ * @exec: drm_exec object
+- * @index: unsigned long index for the iteration
+ * @obj: the current GEM object
+ *
+ * Iterate over all the locked GEM objects inside the drm_exec object.
+ */
+-#define drm_exec_for_each_locked_object(exec, index, obj) \
+- for ((index) = 0; ((obj) = drm_exec_obj(exec, index)); ++(index))
++#define drm_exec_for_each_locked_object(exec, obj) \
++ __drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec))
+
++/* Helper for drm_exec_for_each_locked_object_reverse(). Internal use only. */
++#define __drm_exec_for_each_locked_object_reverse(exec, obj, __index) \
++ for (unsigned long __index = (exec)->num_objects - 1; \
++ ((obj) = drm_exec_obj(exec, __index)); --__index)
+ /**
+ * drm_exec_for_each_locked_object_reverse - iterate over all the locked
+ * objects in reverse locking order
+ * @exec: drm_exec object
+- * @index: unsigned long index for the iteration
+ * @obj: the current GEM object
+ *
+ * Iterate over all the locked GEM objects inside the drm_exec object in
+- * reverse locking order. Note that @index may go below zero and wrap,
++ * reverse locking order. Note that the internal index may wrap around,
+ * but that will be caught by drm_exec_obj(), returning a NULL object.
+ */
+-#define drm_exec_for_each_locked_object_reverse(exec, index, obj) \
+- for ((index) = (exec)->num_objects - 1; \
+- ((obj) = drm_exec_obj(exec, index)); --(index))
++#define drm_exec_for_each_locked_object_reverse(exec, obj) \
++ __drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec))
+
+ /**
+ * drm_exec_until_all_locked - loop until all GEM objects are locked
--- /dev/null
+From stable+bounces-294159-greg=kroah.com@vger.kernel.org Fri Jul 31 19:12:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:56:54 -0400
+Subject: drm/xe: Drop unused param from xe_device_create()
+To: stable@vger.kernel.org
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>, Raag Jadav <raag.jadav@intel.com>, Gustavo Sousa <gustavo.sousa@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260731165658.883265-1-sashal@kernel.org>
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 8a09097b11ca4d436691f64c3cc0958006f36e33 ]
+
+We never used or need anything from the struct pci_device_id there.
+And while around, add simple kernel-doc for this function.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Reviewed-by: Raag Jadav <raag.jadav@intel.com>
+Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com>
+Link: https://patch.msgid.link/20260526195452.20545-3-michal.wajdeczko@intel.com
+Stable-dep-of: ba7fd1634228 ("drm/xe: Set TTM device beneficial_order to 9 (2M)")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/xe/xe_device.c | 11 +++++++++--
+ drivers/gpu/drm/xe/xe_device.h | 3 +--
+ drivers/gpu/drm/xe/xe_pci.c | 2 +-
+ 3 files changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -435,8 +435,15 @@ static void xe_device_destroy(struct drm
+ ttm_device_fini(&xe->ttm);
+ }
+
+-struct xe_device *xe_device_create(struct pci_dev *pdev,
+- const struct pci_device_id *ent)
++/**
++ * xe_device_create() - Create a new &xe_device instance
++ * @pdev: the parent &pci_dev
++ *
++ * Allocate and initialize a device managed Xe device structure.
++ *
++ * Return: pointer to new &xe_device on success, or ERR_PTR on failure.
++ */
++struct xe_device *xe_device_create(struct pci_dev *pdev)
+ {
+ struct xe_device *xe;
+ int err;
+--- a/drivers/gpu/drm/xe/xe_device.h
++++ b/drivers/gpu/drm/xe/xe_device.h
+@@ -43,8 +43,7 @@ static inline struct xe_device *ttm_to_x
+ return container_of(ttm, struct xe_device, ttm);
+ }
+
+-struct xe_device *xe_device_create(struct pci_dev *pdev,
+- const struct pci_device_id *ent);
++struct xe_device *xe_device_create(struct pci_dev *pdev);
+ int xe_device_probe_early(struct xe_device *xe);
+ int xe_device_probe(struct xe_device *xe);
+ void xe_device_remove(struct xe_device *xe);
+--- a/drivers/gpu/drm/xe/xe_pci.c
++++ b/drivers/gpu/drm/xe/xe_pci.c
+@@ -1091,7 +1091,7 @@ static int xe_pci_probe(struct pci_dev *
+ if (err)
+ return err;
+
+- xe = xe_device_create(pdev, ent);
++ xe = xe_device_create(pdev);
+ if (IS_ERR(xe))
+ return PTR_ERR(xe);
+
--- /dev/null
+From stable+bounces-294161-greg=kroah.com@vger.kernel.org Fri Jul 31 19:12:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:56:56 -0400
+Subject: drm/xe: Move xe->info.devid|revid initialization
+To: stable@vger.kernel.org
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>, Gustavo Sousa <gustavo.sousa@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260731165658.883265-3-sashal@kernel.org>
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit c03d9fbe77ec5002a2345b9be464683e0b157709 ]
+
+The xe_info_init_early() is a place where we initialize those of
+the xe->info fields that do not require any additional hardware
+probes. Move the initialization of the devid/revid also there, but
+to avoid breaking the kunit helper, which also calls this function,
+keep their initialization separate in sub-function so we can easily
+stub it when running the kunit test.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Cc: Gustavo Sousa <gustavo.sousa@intel.com>
+Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com>
+Link: https://patch.msgid.link/20260526195452.20545-5-michal.wajdeczko@intel.com
+Stable-dep-of: ba7fd1634228 ("drm/xe: Set TTM device beneficial_order to 9 (2M)")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/xe/tests/xe_pci.c | 6 ++++++
+ drivers/gpu/drm/xe/xe_device.c | 2 --
+ drivers/gpu/drm/xe/xe_pci.c | 12 ++++++++++++
+ 3 files changed, 18 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/xe/tests/xe_pci.c
++++ b/drivers/gpu/drm/xe/tests/xe_pci.c
+@@ -310,6 +310,11 @@ const void *xe_pci_id_gen_param(struct k
+ }
+ EXPORT_SYMBOL_IF_KUNIT(xe_pci_id_gen_param);
+
++static void fake_init_devid(struct xe_device *xe)
++{
++ /* Nothing to do, just keep zero. */
++}
++
+ static int fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type,
+ u32 *ver, u32 *revid)
+ {
+@@ -368,6 +373,7 @@ done:
+ xe->sriov.__mode = data && data->sriov_mode ?
+ data->sriov_mode : XE_SRIOV_MODE_NONE;
+
++ kunit_activate_static_stub(test, init_devid, fake_init_devid);
+ kunit_activate_static_stub(test, read_gmdid, fake_read_gmdid);
+ kunit_activate_static_stub(test, xe_info_probe_tile_count,
+ fake_xe_info_probe_tile_count);
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -473,8 +473,6 @@ struct xe_device *xe_device_create(struc
+ if (err)
+ return ERR_PTR(err);
+
+- xe->info.devid = pdev->device;
+- xe->info.revid = pdev->revision;
+ xe->atomic_svm_timeslice_ms = 5;
+ xe->min_run_period_lr_ms = 5;
+
+--- a/drivers/gpu/drm/xe/xe_pci.c
++++ b/drivers/gpu/drm/xe/xe_pci.c
+@@ -723,6 +723,16 @@ static int handle_gmdid(struct xe_device
+ return 0;
+ }
+
++static void init_devid(struct xe_device *xe)
++{
++ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
++
++ KUNIT_STATIC_STUB_REDIRECT(init_devid, xe);
++
++ xe->info.devid = pdev->device;
++ xe->info.revid = pdev->revision;
++}
++
+ /*
+ * Initialize device info content that only depends on static driver_data
+ * passed to the driver at probe time from PCI ID table.
+@@ -738,6 +748,8 @@ static int xe_info_init_early(struct xe_
+ xe->info.subplatform = subplatform_desc ?
+ subplatform_desc->subplatform : XE_SUBPLATFORM_NONE;
+
++ init_devid(xe);
++
+ xe->info.dma_mask_size = desc->dma_mask_size;
+ xe->info.va_bits = desc->va_bits;
+ xe->info.vm_max_level = desc->vm_max_level;
--- /dev/null
+From stable+bounces-294160-greg=kroah.com@vger.kernel.org Fri Jul 31 19:15:48 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:56:55 -0400
+Subject: drm/xe: Move xe->info.force_execlist initialization
+To: stable@vger.kernel.org
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>, Gustavo Sousa <gustavo.sousa@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260731165658.883265-2-sashal@kernel.org>
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit f1d581bb50ed54b71a8121d3d46fe2627fddd147 ]
+
+The xe_info_init_early() is a place where we initialize those of
+the xe->info fields that do not require any additional hardware
+probes. Move the initialization of the force_execlist flag there.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com>
+Link: https://patch.msgid.link/20260526195452.20545-4-michal.wajdeczko@intel.com
+Stable-dep-of: ba7fd1634228 ("drm/xe: Set TTM device beneficial_order to 9 (2M)")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/xe/xe_device.c | 1 -
+ drivers/gpu/drm/xe/xe_pci.c | 1 +
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -475,7 +475,6 @@ struct xe_device *xe_device_create(struc
+
+ xe->info.devid = pdev->device;
+ xe->info.revid = pdev->revision;
+- xe->info.force_execlist = xe_modparam.force_execlist;
+ xe->atomic_svm_timeslice_ms = 5;
+ xe->min_run_period_lr_ms = 5;
+
+--- a/drivers/gpu/drm/xe/xe_pci.c
++++ b/drivers/gpu/drm/xe/xe_pci.c
+@@ -774,6 +774,7 @@ static int xe_info_init_early(struct xe_
+ xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) &&
+ xe_modparam.probe_display &&
+ desc->has_display;
++ xe->info.force_execlist = xe_modparam.force_execlist;
+
+ xe_assert(xe, desc->max_gt_per_tile > 0);
+ xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE);
--- /dev/null
+From stable+bounces-294162-greg=kroah.com@vger.kernel.org Fri Jul 31 19:34:48 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:56:57 -0400
+Subject: drm/xe: Separate early xe_device initialization
+To: stable@vger.kernel.org
+Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>, Raag Jadav <raag.jadav@intel.com>, Gustavo Sousa <gustavo.sousa@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260731165658.883265-4-sashal@kernel.org>
+
+From: Michal Wajdeczko <michal.wajdeczko@intel.com>
+
+[ Upstream commit 2841cea001b983db79dc1fdf160e65318dfda3cd ]
+
+We would like to initialize more of the xe_device struct also from
+the kunit code, as it should be safe to use most of the generic drm
+or xe components without doing any additional tweaks. Separate early
+xe initialization code to a new function, so it can be reused.
+
+Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
+Reviewed-by: Raag Jadav <raag.jadav@intel.com>
+Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com>
+Link: https://patch.msgid.link/20260526195452.20545-6-michal.wajdeczko@intel.com
+Stable-dep-of: ba7fd1634228 ("drm/xe: Set TTM device beneficial_order to 9 (2M)")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/xe/xe_device.c | 39 ++++++++++++++++++++++++++++-----------
+ drivers/gpu/drm/xe/xe_device.h | 1 +
+ 2 files changed, 29 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -458,27 +458,45 @@ struct xe_device *xe_device_create(struc
+ if (IS_ERR(xe))
+ return xe;
+
++ err = xe_device_init_early(xe);
++ if (err)
++ return ERR_PTR(err);
++
++ return xe;
++}
++ALLOW_ERROR_INJECTION(xe_device_create, ERRNO); /* See xe_pci_probe() */
++
++/**
++ * xe_device_init_early() - Initialize a new &xe_device instance
++ * @xe: the &xe_device to initialize
++ *
++ * Return: 0 on success or a negative error code on failure.
++ */
++int xe_device_init_early(struct xe_device *xe)
++{
++ int err;
++
+ err = ttm_device_init(&xe->ttm, &xe_ttm_funcs, xe->drm.dev,
+ xe->drm.anon_inode->i_mapping,
+ xe->drm.vma_offset_manager, 0);
+- if (WARN_ON(err))
+- return ERR_PTR(err);
++ if (err)
++ return err;
+
+ xe_bo_dev_init(&xe->bo_device);
+ err = drmm_add_action_or_reset(&xe->drm, xe_device_destroy, NULL);
+ if (err)
+- return ERR_PTR(err);
++ return err;
+
+ err = xe_shrinker_create(xe);
+ if (err)
+- return ERR_PTR(err);
++ return err;
+
+ xe->atomic_svm_timeslice_ms = 5;
+ xe->min_run_period_lr_ms = 5;
+
+ err = xe_irq_init(xe);
+ if (err)
+- return ERR_PTR(err);
++ return err;
+
+ xe_validation_device_init(&xe->val);
+
+@@ -488,7 +506,7 @@ struct xe_device *xe_device_create(struc
+
+ err = xe_pagemap_shrinker_create(xe);
+ if (err)
+- return ERR_PTR(err);
++ return err;
+
+ xa_init_flags(&xe->usm.asid_to_vm, XA_FLAGS_ALLOC);
+
+@@ -507,7 +525,7 @@ struct xe_device *xe_device_create(struc
+
+ err = xe_bo_pinned_init(xe);
+ if (err)
+- return ERR_PTR(err);
++ return err;
+
+ xe->preempt_fence_wq = alloc_ordered_workqueue("xe-preempt-fence-wq",
+ WQ_MEM_RECLAIM);
+@@ -521,16 +539,15 @@ struct xe_device *xe_device_create(struc
+ * drmm_add_action_or_reset register above
+ */
+ drm_err(&xe->drm, "Failed to allocate xe workqueues\n");
+- return ERR_PTR(-ENOMEM);
++ return -ENOMEM;
+ }
+
+ err = drmm_mutex_init(&xe->drm, &xe->pmt.lock);
+ if (err)
+- return ERR_PTR(err);
++ return err;
+
+- return xe;
++ return 0;
+ }
+-ALLOW_ERROR_INJECTION(xe_device_create, ERRNO); /* See xe_pci_probe() */
+
+ static bool xe_driver_flr_disabled(struct xe_device *xe)
+ {
+--- a/drivers/gpu/drm/xe/xe_device.h
++++ b/drivers/gpu/drm/xe/xe_device.h
+@@ -44,6 +44,7 @@ static inline struct xe_device *ttm_to_x
+ }
+
+ struct xe_device *xe_device_create(struct pci_dev *pdev);
++int xe_device_init_early(struct xe_device *xe);
+ int xe_device_probe_early(struct xe_device *xe);
+ int xe_device_probe(struct xe_device *xe);
+ void xe_device_remove(struct xe_device *xe);
--- /dev/null
+From stable+bounces-294164-greg=kroah.com@vger.kernel.org Fri Jul 31 19:12:13 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:56:58 -0400
+Subject: drm/xe: Set TTM device beneficial_order to 9 (2M)
+To: stable@vger.kernel.org
+Cc: "Matthew Brost" <matthew.brost@intel.com>, "Andi Shyti" <andi.shyti@linux.intel.com>, "Thomas Hellström" <thomas.hellstrom@linux.intel.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260731165658.883265-5-sashal@kernel.org>
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit ba7fd163422877ad5a5cf31306a38c07d3932b0c ]
+
+Set the TTM device beneficial_order to 9 (2M), which is the sweet
+spot for Xe when attempting reclaim on system memory BOs, as it matches
+the large GPU page size. This ensures reclaim is attempted at the most
+effective order for the driver.
+
+This fixes an issue where an order-10 (4M) allocation cannot be found
+despite an abundance of memory. The 4M allocation triggers reclaim,
+unnecessarily evicting the working set and hurting performance. Since
+the TTM infrastructure was introduced recently, we are tagging the TTM
+patch as the Fixes target, even though this resolves an Xe-side problem.
+
+Fixes: 7e9c548d3709 ("drm/ttm: Allow drivers to specify maximum beneficial TTM pool size")
+Cc: stable@vger.kernel.org
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
+Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Link: https://patch.msgid.link/20260611235844.3725147-1-matthew.brost@intel.com
+(cherry picked from commit 0d81db90d364cb3d733410829118759f28957c5a)
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/xe/xe_device.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/xe/xe_device.c
++++ b/drivers/gpu/drm/xe/xe_device.c
+@@ -478,7 +478,8 @@ int xe_device_init_early(struct xe_devic
+
+ err = ttm_device_init(&xe->ttm, &xe_ttm_funcs, xe->drm.dev,
+ xe->drm.anon_inode->i_mapping,
+- xe->drm.vma_offset_manager, 0);
++ xe->drm.vma_offset_manager,
++ TTM_ALLOCATION_POOL_BENEFICIAL_ORDER(get_order(SZ_2M)));
+ if (err)
+ return err;
+
--- /dev/null
+From stable+bounces-294380-greg=kroah.com@vger.kernel.org Sat Aug 1 16:04:17 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 1 Aug 2026 10:04:08 -0400
+Subject: drm/xe: Wait on external BO kernel fences in exec IOCTL
+To: stable@vger.kernel.org
+Cc: "Matthew Brost" <matthew.brost@intel.com>, "Matthew Auld" <matthew.auld@intel.com>, "Thomas Hellström" <thomas.hellstrom@linux.intel.com>, "Sasha Levin" <sashal@nvidia.com>
+Message-ID: <20260801140408.3645911-2-sashal@kernel.org>
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit af80e2bfde9312c76b60cf9274248dce0410b30d ]
+
+Before arming a user job, xe_exec_ioctl() only added the VM's
+dma-resv KERNEL slot as a dependency. That slot covers rebinds and
+the kernel operations of the VM's private BOs, but not external BOs
+(bo->vm == NULL), which carry their kernel operations (evictions,
+moves, ...) in their own dma-resv KERNEL slot.
+
+The DMA_RESV_USAGE_KERNEL slot is the cross-driver contract for
+memory management operations that must complete before the BO or its
+backing store may be used: any accessor is required to wait on the
+KERNEL fences before touching the resv. By skipping the external BOs'
+KERNEL slots, the exec path violated that contract and could schedule
+a user job while a kernel operation on an external BO mapped by the VM
+was still in flight, racing against it and potentially reading or
+writing memory that was being moved.
+
+Replace the VM-only dependency with an iteration over every object
+locked by the exec, adding each object's KERNEL slot as a job
+dependency. This covers the VM resv (rebinds and private BOs) as well
+as every external BO, mirroring the drm_gpuvm_resv_add_fence() call
+that later publishes the job fence to the same set of objects.
+Long-running mode continues to skip this, as before.
+
+Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
+Cc: stable@vger.kernel.org
+Assisted-by: GitHub_Copilot:claude-opus-4.8
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Matthew Auld <matthew.auld@intel.com>
+Link: https://patch.msgid.link/20260702215805.4011228-1-matthew.brost@intel.com
+(cherry picked from commit a6b842acf3ddd1efc53a56de9260cfa718fb35e7)
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/xe/xe_exec.c | 22 ++++++++++++++++------
+ 1 file changed, 16 insertions(+), 6 deletions(-)
+
+--- a/drivers/gpu/drm/xe/xe_exec.c
++++ b/drivers/gpu/drm/xe/xe_exec.c
+@@ -292,13 +292,23 @@ retry:
+ goto err_exec;
+ }
+
+- /* Wait behind rebinds */
++ /*
++ * Wait behind rebinds and any kernel operations (evictions, defrag
++ * moves, ...) on the VM and all external BOs. The VM's private BOs
++ * carry their kernel ops in the VM dma-resv KERNEL slot, while each
++ * external BO carries them in its own dma-resv KERNEL slot; both are
++ * covered by iterating every object locked by the exec, mirroring the
++ * drm_gpuvm_resv_add_fence() below.
++ */
+ if (!xe_vm_in_lr_mode(vm)) {
+- err = xe_sched_job_add_deps(job,
+- xe_vm_resv(vm),
+- DMA_RESV_USAGE_KERNEL);
+- if (err)
+- goto err_put_job;
++ struct drm_gem_object *obj;
++
++ drm_exec_for_each_locked_object(exec, obj) {
++ err = xe_sched_job_add_deps(job, obj->resv,
++ DMA_RESV_USAGE_KERNEL);
++ if (err)
++ goto err_put_job;
++ }
+ }
+
+ for (i = 0; i < num_syncs && !err; i++)
--- /dev/null
+From stable+bounces-294964-greg=kroah.com@vger.kernel.org Tue Aug 4 03:08:50 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 3 Aug 2026 21:06:29 -0400
+Subject: media: chips-media: wave5: Support CBP profile
+To: stable@vger.kernel.org
+Cc: Jackson Lee <jackson.lee@chipsnmedia.com>, Nas Chung <nas.chung@chipsnmedia.com>, Brandon Brnich <b-brnich@ti.com>, Nicolas Dufresne <nicolas.dufresne@collabora.com>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260804010629.2350099-1-sashal@kernel.org>
+
+From: Jackson Lee <jackson.lee@chipsnmedia.com>
+
+[ Upstream commit f8505f9d6b223a26854003bfdba1a0772457886d ]
+
+Constrained Baseline Profile (CBP) and Baseline Profile (BP) have been
+treated as the same.
+Introduce the ability to differentiate between the two.
+
+Fixes: 9707a6254a8a ("media: chips-media: wave5: Add the v4l2 layer")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jackson Lee <jackson.lee@chipsnmedia.com>
+Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
+Tested-by: Brandon Brnich <b-brnich@ti.com>
+Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/platform/chips-media/wave5/wave5-hw.c | 3 +++
+ drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c | 5 ++++-
+ drivers/media/platform/chips-media/wave5/wave5-vpuapi.h | 1 +
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/platform/chips-media/wave5/wave5-hw.c
++++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
+@@ -1762,6 +1762,9 @@ int wave5_vpu_enc_init_seq(struct vpu_in
+ (p_param->skip_intra_trans << 25) |
+ (p_param->strong_intra_smooth_enable << 27) |
+ (p_param->en_still_picture << 30);
++ else if (inst->std == W_AVC_ENC)
++ reg_val |= (p_param->constraint_set1_flag << 29);
++
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SPS_PARAM, reg_val);
+
+ reg_val = (p_param->lossless_enable) |
+--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+@@ -915,6 +915,8 @@ static int wave5_vpu_enc_s_ctrl(struct v
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ inst->enc_param.profile = H264_PROFILE_BP;
+ inst->bit_depth = 8;
++ if (ctrl->val == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE)
++ inst->enc_param.constraint_set1_flag = 1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ inst->enc_param.profile = H264_PROFILE_MP;
+@@ -1190,6 +1192,7 @@ static int wave5_set_enc_openparam(struc
+ open_param->wave_param.intra_period = input.avc_idr_period;
+ }
+ } else {
++ open_param->wave_param.constraint_set1_flag = input.constraint_set1_flag;
+ open_param->wave_param.avc_idr_period = input.avc_idr_period;
+ }
+ open_param->wave_param.entropy_coding_mode = input.entropy_coding_mode;
+@@ -1662,7 +1665,7 @@ static int wave5_vpu_open_enc(struct fil
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+- 0, 1, 1, 1);
++ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION,
+ 0, 1, 1, 0);
+--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
++++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+@@ -570,6 +570,7 @@ struct enc_wave_param {
+ u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */
+ u32 mb_level_rc_enable: 1; /* enable MB-level rate control */
+ u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */
++ u32 constraint_set1_flag: 1; /* enable CBP */
+ };
+
+ struct enc_open_param {
drm-xe-rtp-de-whitelist-oa-registers-for-all-hwe-s-f.patch
drm-xe-oa-de-whitelist-oa-registers-on-oa-stream-ope.patch
drm-xe-rtp-ensure-locking-ref-counting-for-oa-whitel.patch
+usb-typec-ucsi-split-connector-lock-classes.patch
+usb-typec-ucsi-fix-race-condition-and-ordering-in-port-unregistration.patch
+drm-xe-drop-unused-param-from-xe_device_create.patch
+drm-xe-move-xe-info.force_execlist-initialization.patch
+drm-xe-move-xe-info.devid-revid-initialization.patch
+drm-xe-separate-early-xe_device-initialization.patch
+drm-xe-set-ttm-device-beneficial_order-to-9-2m.patch
+drm-exec-remove-the-index-parameter-from-drm_exec_for_each_locked_obj.patch
+drm-xe-wait-on-external-bo-kernel-fences-in-exec-ioctl.patch
+media-chips-media-wave5-support-cbp-profile.patch
--- /dev/null
+From stable+bounces-291214-greg=kroah.com@vger.kernel.org Thu Jul 30 16:06:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 10:06:26 -0400
+Subject: usb: typec: ucsi: Fix race condition and ordering in port unregistration
+To: stable@vger.kernel.org
+Cc: Andrei Kuchynski <akuchynski@chromium.org>, stable <stable@kernel.org>, Benson Leung <bleung@chromium.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260730140626.2464203-2-sashal@kernel.org>
+
+From: Andrei Kuchynski <akuchynski@chromium.org>
+
+[ Upstream commit 7aa7d4bf9d3fa9a6a47b640ad103ab433b7ff261 ]
+
+A synchronization issue exists during port unregistration where pending
+partner work items can race against workqueue destruction, leading to
+use-after-free conditions:
+
+ cros_ec_ucsi cros_ec_ucsi.3.auto: error -ETIMEDOUT: PPM init failed
+ BUG: kernel NULL pointer dereference, address: 0000000000000000
+ RIP: 0010:__queue_work+0x83/0x4a0
+ Call Trace:
+ <IRQ>
+ __cfi_delayed_work_timer_fn+0x10/0x10
+ run_timer_softirq+0x3b6/0xbd0
+ sched_clock_cpu+0xc/0x110
+ irq_exit_rcu+0x18d/0x330
+ fred_sysvec_apic_timer_interrupt+0x5e/0x80
+
+Fix this by ensuring strict ordering and proper serialization during
+teardown:
+
+1. Move ucsi_unregister_partner() to the beginning of the teardown
+sequence and protect it under the connector mutex lock.
+2. Ensure all pending partner tasks are explicitly flushed and finished
+before the workqueue is destroyed.
+3. Switch from mod_delayed_work() to a cancel_delayed_work() and
+queue_delayed_work() sequence. This guarantees that items currently marked
+as pending won't be scheduled an additional time, preventing a double
+release of resources which leads to the following crash:
+
+ Oops: general protection fault, probably for non-canonical address
+ 0xdead000000000122: 0000 [#1] SMP NOPTI
+ Workqueue: cros_ec_ucsi.3.auto-con2 ucsi_poll_worker
+ RIP: 0010:ucsi_poll_worker+0x65/0x1e0
+ Call Trace:
+ <TASK>
+ process_scheduled_works+0x218/0x6d0
+ worker_thread+0x188/0x3f0
+ __cfi_worker_thread+0x10/0x10
+ kthread+0x226/0x2a0
+
+To ensure these rules are applied identically across both the normal
+teardown and the ucsi_init() error paths, consolidate the cleanup logic
+into a new helper, ucsi_unregister_port().
+
+Cc: stable <stable@kernel.org>
+Fixes: b9aa02ca39a4 ("usb: typec: ucsi: Add polling mechanism for partner tasks like alt mode checking")
+Fixes: b13abcb7ddd8 ("usb: typec: ucsi: Fix NULL pointer access")
+Fixes: fac4b8633fd6 ("usb: ucsi: Ensure connector delayed work items are flushed")
+Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
+Reviewed-by: Benson Leung <bleung@chromium.org>
+Link: https://patch.msgid.link/20260707141736.1635698-1-akuchynski@chromium.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c | 82 +++++++++++++++++++-----------------------
+ 1 file changed, 39 insertions(+), 43 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1951,6 +1951,42 @@ out_unlock:
+ return ret;
+ }
+
++static void ucsi_unregister_port(struct ucsi_connector *con)
++{
++ struct ucsi_work *uwork;
++
++ if (con->wq) {
++ mutex_lock(&con->lock);
++ ucsi_unregister_partner(con);
++ /*
++ * queue delayed items immediately so they can execute
++ * and free themselves before the wq is destroyed
++ */
++ list_for_each_entry(uwork, &con->partner_tasks, node) {
++ if (cancel_delayed_work(&uwork->work))
++ queue_delayed_work(con->wq, &uwork->work, 0);
++ }
++ mutex_unlock(&con->lock);
++
++ destroy_workqueue(con->wq);
++ con->wq = NULL;
++ } else {
++ ucsi_unregister_partner(con);
++ }
++
++ ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
++ ucsi_unregister_port_psy(con);
++
++ usb_power_delivery_unregister_capabilities(con->port_sink_caps);
++ con->port_sink_caps = NULL;
++ usb_power_delivery_unregister_capabilities(con->port_source_caps);
++ con->port_source_caps = NULL;
++ usb_power_delivery_unregister(con->pd);
++ con->pd = NULL;
++ typec_unregister_port(con->port);
++ con->port = NULL;
++}
++
+ static u64 ucsi_get_supported_notifications(struct ucsi *ucsi)
+ {
+ u16 features = ucsi->cap.features;
+@@ -2077,22 +2113,8 @@ err_unregister:
+ for (i = 0; i < ucsi->cap.num_connectors; i++)
+ lockdep_unregister_key(&connector[i].lock_key);
+
+- for (con = connector; con->port; con++) {
+- if (con->wq)
+- destroy_workqueue(con->wq);
+- ucsi_unregister_partner(con);
+- ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
+- ucsi_unregister_port_psy(con);
+-
+- usb_power_delivery_unregister_capabilities(con->port_sink_caps);
+- con->port_sink_caps = NULL;
+- usb_power_delivery_unregister_capabilities(con->port_source_caps);
+- con->port_source_caps = NULL;
+- usb_power_delivery_unregister(con->pd);
+- con->pd = NULL;
+- typec_unregister_port(con->port);
+- con->port = NULL;
+- }
++ for (con = connector; con->port; con++)
++ ucsi_unregister_port(con);
+ kfree(connector);
+ err_reset:
+ memset(&ucsi->cap, 0, sizeof(ucsi->cap));
+@@ -2320,33 +2342,7 @@ void ucsi_unregister(struct ucsi *ucsi)
+
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+ cancel_work_sync(&ucsi->connector[i].work);
+-
+- if (ucsi->connector[i].wq) {
+- struct ucsi_work *uwork;
+-
+- mutex_lock(&ucsi->connector[i].lock);
+- /*
+- * queue delayed items immediately so they can execute
+- * and free themselves before the wq is destroyed
+- */
+- list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node)
+- mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0);
+- mutex_unlock(&ucsi->connector[i].lock);
+- destroy_workqueue(ucsi->connector[i].wq);
+- }
+-
+- ucsi_unregister_partner(&ucsi->connector[i]);
+- ucsi_unregister_altmodes(&ucsi->connector[i],
+- UCSI_RECIPIENT_CON);
+- ucsi_unregister_port_psy(&ucsi->connector[i]);
+-
+- usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
+- ucsi->connector[i].port_sink_caps = NULL;
+- usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
+- ucsi->connector[i].port_source_caps = NULL;
+- usb_power_delivery_unregister(ucsi->connector[i].pd);
+- ucsi->connector[i].pd = NULL;
+- typec_unregister_port(ucsi->connector[i].port);
++ ucsi_unregister_port(&ucsi->connector[i]);
+ lockdep_unregister_key(&ucsi->connector[i].lock_key);
+ }
+
--- /dev/null
+From sashal@kernel.org Thu Jul 30 16:06:29 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 10:06:25 -0400
+Subject: usb: typec: ucsi: split connector lock classes
+To: stable@vger.kernel.org
+Cc: Sergey Senozhatsky <senozhatsky@chromium.org>, Heikki Krogerus <heikki.krogerus@linux.intel.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260730140626.2464203-1-sashal@kernel.org>
+
+From: Sergey Senozhatsky <senozhatsky@chromium.org>
+
+[ Upstream commit 8c22256bbafad3dc5fdbe9f684d045b67ff06a68 ]
+
+Lockdep detects a possible recursive locking scenario during
+ucsi init:
+
+[ 5.418616] ============================================
+[ 5.418634] WARNING: possible recursive locking detected
+[ 5.418706] --------------------------------------------
+[ 5.418725] kworker/4:1/82 is trying to acquire lock:
+[ 5.418759] ffff888119a34648 (&con->lock){+.+.}-{3:3}, at: ucsi_init_work+0x1a78/0x2eb0 [typec_ucsi]
+[ 5.418801]
+ but task is already holding lock:
+[ 5.418835] ffff888119a34080 (&con->lock){+.+.}-{3:3}, at: ucsi_init_work+0x1a78/0x2eb0 [typec_ucsi]
+[ 5.418884]
+ other info that might help us debug this:
+[ 5.418904] Possible unsafe locking scenario:
+
+[ 5.418937] CPU0
+[ 5.418956] ----
+[ 5.418991] lock(&con->lock);
+[ 5.419013] lock(&con->lock);
+[ 5.419033]
+ *** DEADLOCK ***
+
+[ 5.419387] Call Trace:
+[ 5.419406] <TASK>
+[ 5.419425] dump_stack_lvl+0x61/0xa0
+[ 5.419448] print_deadlock_bug+0x4a6/0x650
+[ 5.419483] __lock_acquire+0x62b6/0x7f50
+[ 5.419507] lock_acquire+0x11b/0x390
+[ 5.419654] __mutex_lock+0xbc/0xcd0
+[ 5.419741] ucsi_init_work+0x1a78/0x2eb0
+[ 5.419785] ? worker_thread+0xf53/0x2bc0
+[ 5.419819] worker_thread+0xff4/0x2bc0
+[ 5.419842] kthread+0x2a7/0x330
+[ 5.419863] ? __pfx_worker_thread+0x10/0x10
+[ 5.419896] ? __pfx_kthread+0x10/0x10
+[ 5.419916] ret_from_fork+0x38/0x70
+[ 5.419936] ? __pfx_kthread+0x10/0x10
+[ 5.419969] ret_from_fork_asm+0x1b/0x30
+[ 5.419991] </TASK>
+[ 5.420009] ---[ end trace 0000000000000000 ]---
+
+The problem is that all connector locks belong to the same
+lockdep lock class, so the following loop:
+
+ for (i = 0; i < ucsi->cap.num_connectors; i++)
+ ucsi_register_port(connector[i])
+ mutex_lock(&connector[i]->lock)
+
+looks like a recursive acquire of the same mutex. Put each connector
+lock into a dedicated lock class so that lockdep doesn't see it as a
+possible recursion.
+
+Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/20260515060042.136083-1-senozhatsky@chromium.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 7aa7d4bf9d3f ("usb: typec: ucsi: Fix race condition and ordering in port unregistration")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c | 8 ++++++++
+ drivers/usb/typec/ucsi/ucsi.h | 1 +
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1796,6 +1796,7 @@ static int ucsi_register_port(struct ucs
+ INIT_WORK(&con->work, ucsi_handle_connector_change);
+ init_completion(&con->complete);
+ mutex_init(&con->lock);
++ lockdep_set_class(&con->lock, &con->lock_key);
+ INIT_LIST_HEAD(&con->partner_tasks);
+ con->ucsi = ucsi;
+
+@@ -2041,6 +2042,9 @@ static int ucsi_init(struct ucsi *ucsi)
+ goto err_reset;
+ }
+
++ for (i = 0; i < ucsi->cap.num_connectors; i++)
++ lockdep_register_key(&connector[i].lock_key);
++
+ /* Register all connectors */
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+ connector[i].num = i + 1;
+@@ -2070,6 +2074,9 @@ static int ucsi_init(struct ucsi *ucsi)
+ return 0;
+
+ err_unregister:
++ for (i = 0; i < ucsi->cap.num_connectors; i++)
++ lockdep_unregister_key(&connector[i].lock_key);
++
+ for (con = connector; con->port; con++) {
+ if (con->wq)
+ destroy_workqueue(con->wq);
+@@ -2340,6 +2347,7 @@ void ucsi_unregister(struct ucsi *ucsi)
+ usb_power_delivery_unregister(ucsi->connector[i].pd);
+ ucsi->connector[i].pd = NULL;
+ typec_unregister_port(ucsi->connector[i].port);
++ lockdep_unregister_key(&ucsi->connector[i].lock_key);
+ }
+
+ kfree(ucsi->connector);
+--- a/drivers/usb/typec/ucsi/ucsi.h
++++ b/drivers/usb/typec/ucsi/ucsi.h
+@@ -517,6 +517,7 @@ struct ucsi_connector {
+
+ struct ucsi *ucsi;
+ struct mutex lock; /* port lock */
++ struct lock_class_key lock_key;
+ struct work_struct work;
+ struct completion complete;
+ struct workqueue_struct *wq;