Skip to contentSkip to conversation

6.18.51-rc1 review

PATCH In review Greg Kroah-Hartman 11 participants 598 messages Sep 9 – Sep 12 Page 2 of 5

Subsystems (5)
lore
Share & tools
lore
author maintainer
#126 lore raw

PATCH 126/583 powerpc/crash: stop watchdogs before booting kdump kernel

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sourabh Jain <[email protected]>

commit fb43ba4256543ce18ca0540fc37022bda438a293 upstream.

On pseries LPAR systems, watchdog timers configured from userspace can remain active after a kernel panic. When a panic triggers kdump, the crashing kernel jumps directly to the kdump kernel without stopping active watchdogs. As a result, the watchdogs remain active after the kdump kernel starts.

If dump capture takes longer than the watchdog timeout, PHYP resets the LPAR before the dump is fully captured, causing dump capture to fail.

Fix this by issuing the H_WATCHDOG hcall during the crash shutdown sequence to stop all active watchdogs before booting the kdump kernel.

---
 arch/powerpc/include/asm/papr-watchdog.h |    6 ++++++
 arch/powerpc/platforms/pseries/setup.c   |   14 ++++++++++++++
 2 files changed, 20 insertions(+)
arch/powerpc/include/asm/papr-watchdog.h +6 -0
@@ -22,6 +22,12 @@
 #define PSERIES_WDTF_ACTION_DUMP_RESTART	0x3UL	/* dump + restart */
 
 /*
+ * R5: "watchdogNumber":
+ *       PAPR says use -1 (all ones) to stop all watchdogs.
+ */
+#define PSERIES_WDT_NUM_ALL	((unsigned long)-1)
+
+/*
  * H_WATCHDOG Output
  *
  * R3: Return code
arch/powerpc/platforms/pseries/setup.c +14 -0
@@ -76,6 +76,7 @@
 #include <asm/dtl.h>
 #include <asm/hvconsole.h>
 #include <asm/setup.h>
+#include <asm/papr-watchdog.h>
 
 #include "pseries.h"
 
@@ -187,6 +188,16 @@ static void __init fwnmi_init(void)
 #endif
 }
 
+static void pseries_crash_stop_watchdogs(void)
+{
+	long rc;
+
+	rc = plpar_hcall_norets_notrace(H_WATCHDOG, PSERIES_WDTF_OP_STOP,
+					PSERIES_WDT_NUM_ALL);
+	if (rc != H_SUCCESS && rc != H_NOOP)
+		pr_warn("Could not stop watchdogs before kdump rc=%ld\n", rc);
+}
+
 /*
  * Affix a device for the first timer to the platform bus if
  * we have firmware support for the H_WATCHDOG hypercall.
@@ -205,6 +216,9 @@ static __init int pseries_wdt_init(void)
 		return PTR_ERR(pdev);
 	}
 
+	if (crash_shutdown_register(pseries_crash_stop_watchdogs))
+		pr_warn("Could not register watchdog crash shutdown handler\n");
+
 	return 0;
 }
 machine_subsys_initcall(pseries, pseries_wdt_init);
author maintainer
#127 lore raw

PATCH 127/583 s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit 4400270ec0348d05dc0439d8f0130853ce7f9e20 upstream.

In vfio_ap_mdev_set_kvm(), kvm->arch.crypto.pqap_hook is set to &matrix_mdev->pqap_hook before the update locks are acquired and the mdev list is checked for a conflicting assignment. If another mdev is already attached to the same KVM instance, the function returns -EPERM without restoring the hook pointer, leaving kvm->arch.crypto.pqap_hook pointing at the failing matrix_mdev instead of the mdev that legitimately owns the KVM.

Since matrix_mdev->kvm is never set on this error path, vfio_ap_mdev_unset_kvm() will not clean up the hook when matrix_mdev is later closed. If matrix_mdev is subsequently freed, any PQAP instruction executed by the guest will dereference the stale pointer through pqap_hook_rwsem, resulting in a use-after-free.

Since kvm->arch.crypto.pqap_hook is only set in the vfio_ap_mdev_set_kvm() function and is cleared in the vfio_ap_mdev_unset_kvm() function, a check for 'kvm->arch.crypto.pqap_hook != NULL' is all that is needed to determine whether it belongs to another mdev. This will alleviate the need to iterate the matrix_dev->mdev_list list to see if the kvm object is assigned to another mdev.This was introduced in v3 to alleviate the need to take the mdevs_lock while iterating the list; however, this did not prevent a potential race condition.

The pqap_hook_rwsem(write) is now performed inside get_update_locks_for_kvm(), which is updated to acquire pqap_hook_rwsem(write) between kvm->lock and mdevs_lock. This ordering is consistent with the PQAP intercept path, which acquires pqap_hook_rwsem in read mode while srcu is held under vcpu->mutex, establishing the
dependency: kvm->lock -> vcpu->mutex -> srcu -> pqap_hook_rwsem(read).

The pqap_hook_rwsem is now released inside the release_update_locks_for_kvm(), which is updated to release pqap_hook_rwsem(write) between mdevs_lock and kvm->lock.

Additionally, kvm_put_kvm() in vfio_ap_mdev_unset_kvm() is moved after release_update_locks_for_kvm(). Previously it was called while kvm->lock was held; if it were ever the last reference, kvm_destroy_vm() would run under kvm->lock, which would deadlock.

Fixes 86956e70761b3 ("s390/vfio-ap: replace open coded locks for VFIO_GROUP_NOTIFY_SET_KVM notification")

Message-ID: <[email protected]>

---
 drivers/s390/crypto/vfio_ap_ops.c |   45 ++++++++++++++++----------------------
 1 file changed, 20 insertions(+), 25 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +20 -25
@@ -48,15 +48,19 @@ static void vfio_ap_mdev_reset_queue(str
  * 1. matrix_dev->guests_lock: required to use the KVM pointer to update a KVM
  *			       guest's APCB.
  * 2. kvm->lock:	       required to update a guest's APCB
- * 3. matrix_dev->mdevs_lock:  required to access data stored in a matrix_mdev
+ * 3. kvm->arch.crypto.pqap_hook_rwsem: required to update pqap_hook and
+ *					serialize against PQAP intercepts
+ * 4. matrix_dev->mdevs_lock:  required to access data stored in a matrix_mdev
  *
- * Note: If @kvm is NULL, the KVM lock will not be taken.
+ * Note: If @kvm is NULL, the KVM lock and pqap_hook_rwsem will not be taken.
  */
 static inline void get_update_locks_for_kvm(struct kvm *kvm)
 {
 	mutex_lock(&matrix_dev->guests_lock);
-	if (kvm)
+	if (kvm) {
 		mutex_lock(&kvm->lock);
+		down_write(&kvm->arch.crypto.pqap_hook_rwsem);
+	}
 	mutex_lock(&matrix_dev->mdevs_lock);
 }
 
@@ -68,16 +72,19 @@ static inline void get_update_locks_for_
  *
  * The proper unlocking order is:
  * 1. matrix_dev->mdevs_lock
- * 2. kvm->lock
- * 3. matrix_dev->guests_lock
+ * 2. kvm->arch.crypto.pqap_hook_rwsem
+ * 3. kvm->lock
+ * 4. matrix_dev->guests_lock
  *
- * Note: If @kvm is NULL, the KVM lock will not be released.
+ * Note: If @kvm is NULL, the KVM lock and pqap_hook_rwsem will not be released.
  */
 static inline void release_update_locks_for_kvm(struct kvm *kvm)
 {
 	mutex_unlock(&matrix_dev->mdevs_lock);
-	if (kvm)
+	if (kvm) {
+		up_write(&kvm->arch.crypto.pqap_hook_rwsem);
 		mutex_unlock(&kvm->lock);
+	}
 	mutex_unlock(&matrix_dev->guests_lock);
 }
 
@@ -1821,26 +1828,17 @@ static const struct attribute_group *vfi
 static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
 				struct kvm *kvm)
 {
-	struct ap_matrix_mdev *m;
-
 	if (kvm->arch.crypto.crycbd) {
-		down_write(&kvm->arch.crypto.pqap_hook_rwsem);
-		kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
-		up_write(&kvm->arch.crypto.pqap_hook_rwsem);
-
 		get_update_locks_for_kvm(kvm);
-
-		list_for_each_entry(m, &matrix_dev->mdev_list, node) {
-			if (m != matrix_mdev && m->kvm == kvm) {
-				release_update_locks_for_kvm(kvm);
-				return -EPERM;
-			}
+		if (kvm->arch.crypto.pqap_hook) {
+			release_update_locks_for_kvm(kvm);
+			return -EPERM;
 		}
+		kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
 
 		kvm_get_kvm(kvm);
 		matrix_mdev->kvm = kvm;
 		vfio_ap_mdev_update_guest_apcb(matrix_mdev);
-
 		release_update_locks_for_kvm(kvm);
 	}
 
@@ -1883,18 +1881,15 @@ static void vfio_ap_mdev_unset_kvm(struc
 	struct kvm *kvm = matrix_mdev->kvm;
 
 	if (kvm && kvm->arch.crypto.crycbd) {
-		down_write(&kvm->arch.crypto.pqap_hook_rwsem);
-		kvm->arch.crypto.pqap_hook = NULL;
-		up_write(&kvm->arch.crypto.pqap_hook_rwsem);
-
 		get_update_locks_for_kvm(kvm);
+		kvm->arch.crypto.pqap_hook = NULL;
 
 		kvm_arch_crypto_clear_masks(kvm);
 		vfio_ap_mdev_reset_queues(matrix_mdev);
-		kvm_put_kvm(kvm);
 		matrix_mdev->kvm = NULL;
 
 		release_update_locks_for_kvm(kvm);
+		kvm_put_kvm(kvm);
 	}
 }
 
author maintainer
#128 lore raw

PATCH 128/583 s390/vfio-ap: Fix stale do_remove flag across iterations in vfio_ap_mdev_cfg_remove

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit b1f092d94f621307927f145e3cc31893da51fc08 upstream.

The do_remove flag in vfio_ap_mdev_cfg_remove() is initialised to zero before the loop that iterates over the list of matrix mdevs, but is never reset at the start of each iteration. Since do_remove is OR-accumulated across iterations, a positive result from one mdev carries over to subsequent mdevs.

The fix is to set the do_remove flag with the first call to bitmap_and; for example: do_remove = bitmap_an rather than do_remove |= bitmap_and.

Fixes eeb386aeb5b7 ("s390/vfio-ap: handle config changed and scan complete notification")
---
 drivers/s390/crypto/vfio_ap_ops.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +4 -4
@@ -2598,15 +2598,15 @@ static void vfio_ap_mdev_cfg_remove(unsi
 	DECLARE_BITMAP(aprem, AP_DEVICES);
 	DECLARE_BITMAP(aqrem, AP_DOMAINS);
 	DECLARE_BITMAP(cdrem, AP_DOMAINS);
-	int do_remove = 0;
+	int do_remove;
 
 	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
 		mutex_lock(&matrix_mdev->kvm->lock);
 		mutex_lock(&matrix_dev->mdevs_lock);
 
-		do_remove |= bitmap_and(aprem, ap_remove,
-					  matrix_mdev->matrix.apm,
-					  AP_DEVICES);
+		do_remove = bitmap_and(aprem, ap_remove,
+				       matrix_mdev->matrix.apm,
+				       AP_DEVICES);
 		do_remove |= bitmap_and(aqrem, aq_remove,
 					  matrix_mdev->matrix.aqm,
 					  AP_DOMAINS);
author maintainer
#129 lore raw

PATCH 129/583 s390/vfio-ap: Fix control domain removal in vfio_ap_mdev_cfg_remove

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit 6b8a02e216f6b520cc029e43ddc83956605135d5 upstream.

The vfio_ap_config_remove function uses the bitmap_andnot function to clear bits from the matrix_mdev->matrix.adm bitmap (specifies the control domains assigned to the mdev). This prevents the explicitly unplugged control domains from being removed the KVM guest. The bitmap_and function is used instead.

Fixes eeb386aeb5b7c ("s390/vfio-ap: handle config changed and scan complete notification")
---
 drivers/s390/crypto/vfio_ap_ops.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +3 -3
@@ -2610,9 +2610,9 @@ static void vfio_ap_mdev_cfg_remove(unsi
 		do_remove |= bitmap_and(aqrem, aq_remove,
 					  matrix_mdev->matrix.aqm,
 					  AP_DOMAINS);
-		do_remove |= bitmap_andnot(cdrem, cd_remove,
-					     matrix_mdev->matrix.adm,
-					     AP_DOMAINS);
+		do_remove |= bitmap_and(cdrem, cd_remove,
+					matrix_mdev->matrix.adm,
+					AP_DOMAINS);
 
 		if (do_remove)
 			vfio_ap_mdev_hot_unplug_cfg(matrix_mdev, aprem, aqrem,
author maintainer
#130 lore raw

PATCH 130/583 s390/vfio-ap: Fix dereference matrix_mdev->kvm without checking for NULL

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit d50346801b4f144e42b49cd4f1496010498ab114 upstream.

The ap_driver structure has two fields which are function pointers to callbacks:

* .on_config_changed: called at the start of the AP bus scan function to notify the device driver that the host AP configuration has changed and the associated AP devices will be added or removed accordingly. This gives the implementor a chance to evaluate the configuration changes and respond to them before the associated devices are added or removed.

* .on_scan_complete: Called at the end of the AP bus scan function to notify the device driver that the host AP configuration has changed and the AP devices have been added or removed accordingly. This gives the implementor the opportunity to respond to the changes after the associated devices are added or removed.

These two callbacks are implemented in the vfio_ap device driver via the vfio_ap_on_cfg_changed and vfio_ap_on_scan_complete functions respectively.

Within the call stack of these two callback functions the matrix_mdev->kvm->lock mutex is taken without checking whether matrix_mdev->kvm is NULL or not. If matrix_mdev->kvm has never been set, trying to take the lock will trigger a NULL pointer dereference. This patch adds checks for matrix_mdev->kvm == NULL before taking the matrix_mdev->kvm->lock mutex.

Note that the matrix_mdev->kvm->lock mutex taken in the vfio_ap_mdev_hot_plug_config function is moved to the calling function along with the matrix_dev->mdevs_lock which is needed there to access the fields of the matrix_mdev. It makes little sense to make the change the check for matrix_mdev->kvm there before taking the kvm->lock mutex only to have to move it out via another patch, so it is done in this patch.

It is important to make note of the following:
1. The matrix_dev->guests_lock is acquired at the start of both callback functions. This ensures that matrix_mdev will not be removed via the vfio_ap_mdev_remove function because it too takes matrix_dev_guests_lock before removing the object; so, matrix_mdev will be available for the duration of the callback functions.

2. The matrix_dev->mdevs_lock mutex must be taken in order to access fields within the matrix_mdev structure

3. matrix_mdev->kvm->lock mutex must be taken before the matrix_dev->mdevs_lock to prevent a lockdep splat.

4: The kvm->lock must be held while plugging the guest's AP configuration
into its SIE state description via the vfio_ap_mdev_update_guest_apcb function.

5. The vfio_ap_mdev_update_guest_apcb checks matrix_mdev->kvm to verify it is not NULL before doing the hot plug of the guest's AP configuration.

Fixes eeb386aeb5b7c ("s390/vfio-ap: handle config changed and scan complete notification")
---
 drivers/s390/crypto/vfio_ap_ops.c |   39 +++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +30 -9
@@ -2600,8 +2600,20 @@ static void vfio_ap_mdev_cfg_remove(unsi
 	DECLARE_BITMAP(cdrem, AP_DOMAINS);
 	int do_remove;
 
+	/*
+	 * It is safe to traverse this list here because the
+	 * required guard - matrix_dev->guests_lock - is taken in the
+	 * vfio_ap_on_cfg_changed function prior to this function getting
+	 * called.
+	 */
 	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
-		mutex_lock(&matrix_mdev->kvm->lock);
+		/*
+		 * The mdevs_lock must be held to access fields within matrix_mdev,
+		 * and kvm->lock must be taken before mdevs_lock to satisfy the lock
+		 * ordering requirement and prevent a lockdep splat.
+		 */
+		if (matrix_mdev->kvm)
+			mutex_lock(&matrix_mdev->kvm->lock);
 		mutex_lock(&matrix_dev->mdevs_lock);
 
 		do_remove = bitmap_and(aprem, ap_remove,
@@ -2619,7 +2631,8 @@ static void vfio_ap_mdev_cfg_remove(unsi
 						    cdrem);
 
 		mutex_unlock(&matrix_dev->mdevs_lock);
-		mutex_unlock(&matrix_mdev->kvm->lock);
+		if (matrix_mdev->kvm)
+			mutex_unlock(&matrix_mdev->kvm->lock);
 	}
 }
 
@@ -2816,9 +2829,6 @@ static void vfio_ap_mdev_hot_plug_cfg(st
 	DECLARE_BITMAP(apm_filtered, AP_DEVICES);
 	bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false;
 
-	mutex_lock(&matrix_mdev->kvm->lock);
-	mutex_lock(&matrix_dev->mdevs_lock);
-
 	filter_adapters = bitmap_intersects(matrix_mdev->matrix.apm,
 					    matrix_mdev->apm_add, AP_DEVICES);
 	filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
@@ -2836,9 +2846,6 @@ static void vfio_ap_mdev_hot_plug_cfg(st
 		vfio_ap_mdev_update_guest_apcb(matrix_mdev);
 
 	reset_queues_for_apids(matrix_mdev, apm_filtered);
-
-	mutex_unlock(&matrix_dev->mdevs_lock);
-	mutex_unlock(&matrix_mdev->kvm->lock);
 }
 
 void vfio_ap_on_scan_complete(struct ap_config_info *new_config_info,
@@ -2849,15 +2856,29 @@ void vfio_ap_on_scan_complete(struct ap_
 	mutex_lock(&matrix_dev->guests_lock);
 
 	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
+		/*
+		 * The mdevs_lock must be held to access fields within matrix_mdev,
+		 * and kvm->lock must be taken before mdevs_lock to satisfy the lock
+		 * ordering requirement and prevent a lockdep splat.
+		 */
+		if (matrix_mdev->kvm)
+			mutex_lock(&matrix_mdev->kvm->lock);
+		mutex_lock(&matrix_dev->mdevs_lock);
+
 		if (bitmap_empty(matrix_mdev->apm_add, AP_DEVICES) &&
 		    bitmap_empty(matrix_mdev->aqm_add, AP_DOMAINS) &&
 		    bitmap_empty(matrix_mdev->adm_add, AP_DOMAINS))
-			continue;
+			goto do_unlock;
 
 		vfio_ap_mdev_hot_plug_cfg(matrix_mdev);
 		bitmap_clear(matrix_mdev->apm_add, 0, AP_DEVICES);
 		bitmap_clear(matrix_mdev->aqm_add, 0, AP_DOMAINS);
 		bitmap_clear(matrix_mdev->adm_add, 0, AP_DOMAINS);
+
+do_unlock:
+		mutex_unlock(&matrix_dev->mdevs_lock);
+		if (matrix_mdev->kvm)
+			mutex_unlock(&matrix_mdev->kvm->lock);
 	}
 
 	mutex_unlock(&matrix_dev->guests_lock);
author maintainer
#131 lore raw

PATCH 131/583 s390/vfio-ap: Fix hot-unplug skipped when last AP adapter or domain removed

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit 917f509bfb88048094dbb85c4e9dbc4d6fe4a886 upstream.

The vfio_ap_mdev_hot_unplug_cfg() function uses the return value of bitmap_andnot() to determine whether the guest APCB needs to be updated. However, bitmap_andnot() returns false when the resulting destination bitmap is empty. This means that if the only adapter, domain or control domain assigned to an mdev is removed from the host's AP configuration, the bit is correctly cleared from the shadow APCB, but bitmap_andnot() returns false because the result is an empty bitmap. Consequently, do_hotplug remains 0 and vfio_ap_mdev_update_guest_apcb() is never called, leaving the KVM guest with stale hardware access to the unplugged AP devices.

Fix this by replacing the bitmap_andnot() return value check with bitmap_intersects() to determine whether the shadow APCB actually overlaps with the removal mask. If there is an intersection, call bitmap_andnot() solely for its side effect of clearing the bits, then unconditionally set do_hotplug to trigger the guest APCB update.

Fixes eeb386aeb5b7c ("s390/vfio-ap: handle config changed and scan complete notification")
---
 drivers/s390/crypto/vfio_ap_ops.c |   30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +17 -13
@@ -2554,24 +2554,28 @@ static void vfio_ap_mdev_hot_unplug_cfg(
 					unsigned long *aqrem,
 					unsigned long *cdrem)
 {
-	int do_hotplug = 0;
+	bool do_hotplug = false;
 
-	if (!bitmap_empty(aprem, AP_DEVICES)) {
-		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.apm,
-					    matrix_mdev->shadow_apcb.apm,
-					    aprem, AP_DEVICES);
+	if (bitmap_intersects(matrix_mdev->shadow_apcb.apm, aprem, AP_DEVICES)) {
+		bitmap_andnot(matrix_mdev->shadow_apcb.apm,
+			      matrix_mdev->shadow_apcb.apm,
+			      aprem, AP_DEVICES);
+		do_hotplug = true;
 	}
 
-	if (!bitmap_empty(aqrem, AP_DOMAINS)) {
-		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.aqm,
-					    matrix_mdev->shadow_apcb.aqm,
-					    aqrem, AP_DEVICES);
+	if (bitmap_intersects(matrix_mdev->shadow_apcb.aqm, aqrem, AP_DOMAINS)) {
+		bitmap_andnot(matrix_mdev->shadow_apcb.aqm,
+			      matrix_mdev->shadow_apcb.aqm,
+			      aqrem, AP_DOMAINS);
+		do_hotplug = true;
 	}
 
-	if (!bitmap_empty(cdrem, AP_DOMAINS))
-		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.adm,
-					    matrix_mdev->shadow_apcb.adm,
-					    cdrem, AP_DOMAINS);
+	if (bitmap_intersects(matrix_mdev->shadow_apcb.adm, cdrem, AP_DOMAINS)) {
+		bitmap_andnot(matrix_mdev->shadow_apcb.adm,
+			      matrix_mdev->shadow_apcb.adm,
+			      cdrem, AP_DOMAINS);
+		do_hotplug = true;
+	}
 
 	if (do_hotplug)
 		vfio_ap_mdev_update_guest_apcb(matrix_mdev);
author maintainer
#132 lore raw

PATCH 132/583 s390/vfio-ap: Fix missing lock required to access list of ap_matrix_mdev objects

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit 7fa61c29850d05e40ca9ed41bfdf57673023f581 upstream.

In order to traverse or add/remove ap_matrix_mdev objects in the matrix_dev->mdev_list, the matrix_dev->guests_lock mutex must be held. There are two functions that access the list without holding the mutex:

vfio_ap_mdev_probe function
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The vfio_ap_mdev_probe function uses the matrix_dev->mdevs_lock mutex to guard the add of a newly created ap_matrix_mdev object to the matrix_dev->mdev_list. This mutex does not protect list access; its purpose is to guard against concurrent access to fields contained in an ap_matrix_mdev object. This could lead to kernel memory corruption or use-after-free if another mdev is created or removed concurrently.

The adding of an ap_matrix_mdev object to matrix_dev->mdev_list is now guarded by the matrix_dev->guests_lock which is the correct way to protect against concurrent mdev_list access.

Also removed the following two lines of code because the matrix_mdev is allocated via vfio_alloc_device macro which uses kzalloc, so req_trigger and cfg_chg_trigger are already zero-initialised when the struct is allocated before the call to vfio_register_emulated_iommu_dev. This prevents a window whereby these triggers are set to NULL after the device is exposed to userspace.

matrix_mdev->req_trigger = NULL;
matrix_mdev->cfg_chg_trigger = NULL;

vfio_ap_mdev_for_queue function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The status_show function that supports display of the status attribute of the devices in /sys/bus/ap/devices calls the vfio_ap_mdev_for_queue function which iterates the matrix_dev->mdev_list to find the object representing the queue device whose status is to be displayed. In order to traverse this list, the matrix_dev->guests_lock mutex must be held.

To fix this, the guests_lock mutex is taken prior to taking the matrix_dev->mdevs_lock mutex in the status_show function. It is taken there rather than the vfio_ap_mdev_for_queue function - where it is needed - because it must be taken prior to the mdevs_lock mutex in order to adhere to the proper locking order and prevent a lockdep splat; also because the mdevs_lock is needed there to access fields within the matrix_mdev object in that function.

See the vfio-ap-locking.rst in the linux kernel tree.

Fixes 2c1ee8983aa3 ("s390/vfio-ap: prepare for dynamic update of guest's APCB on queue probe/remove")
---
 drivers/s390/crypto/vfio_ap_ops.c |   27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +23 -4
@@ -807,12 +807,17 @@ static int vfio_ap_mdev_probe(struct mde
 	ret = vfio_register_emulated_iommu_dev(&matrix_mdev->vdev);
 	if (ret)
 		goto err_put_vdev;
-	matrix_mdev->req_trigger = NULL;
-	matrix_mdev->cfg_chg_trigger = NULL;
+
+	/*
+	 * Take the matrix_dev->guests_lock mutex before adding the matrix_mdev
+	 * to the mdev_list. All functions that traverse the list must also hold
+	 * this lock to guard against additions to or removals from the list
+	 * while it is being traversed.
+	 */
+	mutex_lock(&matrix_dev->guests_lock);
 	dev_set_drvdata(&mdev->dev, matrix_mdev);
-	mutex_lock(&matrix_dev->mdevs_lock);
 	list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
-	mutex_unlock(&matrix_dev->mdevs_lock);
+	mutex_unlock(&matrix_dev->guests_lock);
 	return 0;
 
 err_put_vdev:
@@ -2292,6 +2297,8 @@ static struct ap_matrix_mdev *vfio_ap_md
 	unsigned long apid = AP_QID_CARD(q->apqn);
 	unsigned long apqi = AP_QID_QUEUE(q->apqn);
 
+	lockdep_assert_held(&matrix_dev->guests_lock);
+
 	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
 		if (test_bit_inv(apid, matrix_mdev->matrix.apm) &&
 		    test_bit_inv(apqi, matrix_mdev->matrix.aqm))
@@ -2311,6 +2318,7 @@ static ssize_t status_show(struct device
 	struct ap_matrix_mdev *matrix_mdev;
 	struct ap_device *apdev = to_ap_dev(dev);
 
+	mutex_lock(&matrix_dev->guests_lock);
 	mutex_lock(&matrix_dev->mdevs_lock);
 	q = dev_get_drvdata(&apdev->device);
 	matrix_mdev = vfio_ap_mdev_for_queue(q);
@@ -2338,6 +2346,7 @@ static ssize_t status_show(struct device
 	}
 
 	mutex_unlock(&matrix_dev->mdevs_lock);
+	mutex_unlock(&matrix_dev->guests_lock);
 
 	return nchars;
 }
@@ -2760,6 +2769,12 @@ static void vfio_ap_mdev_cfg_add(unsigne
 
 	vfio_ap_filter_apid_by_qtype(apm_add, aqm_add);
 
+	/*
+	 * It is safe to traverse this list here because the
+	 * required guard - matrix_dev->guests_lock - is taken in the
+	 * vfio_ap_on_cfg_changed function prior to this function getting
+	 * called.
+	 */
 	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
 		bitmap_and(matrix_mdev->apm_add,
 			   matrix_mdev->matrix.apm, apm_add, AP_DEVICES);
@@ -2819,6 +2834,10 @@ void vfio_ap_on_cfg_changed(struct ap_co
 	if (!cur_cfg_info || !prev_cfg_info)
 		return;
 
+	/*
+	 * Take the guests_lock mutex here to guard access to the
+	 * matrix_dev->mdev_list in the two functions called below.
+	 */
 	mutex_lock(&matrix_dev->guests_lock);
 
 	vfio_ap_mdev_on_cfg_remove(cur_cfg_info, prev_cfg_info);
author maintainer
#133 lore raw

PATCH 133/583 s390/vfio-ap: Fix NULL deref in status_show() during queue probe

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit dd6f4ef6f8a37412909ad787c837332fb070159c upstream.

When vfio_ap_mdev_probe_queue() creates the sysfs attribute group, the queue's driver data has not yet been set. A concurrent read of the 'status' attribute can therefore call dev_get_drvdata() and get NULL, which is then passed directly to vfio_ap_mdev_for_queue() where q->apqn is unconditionally dereferenced, causing a NULL pointer dereference.

Fix this by acquiring the update locks before calling sysfs_create_group(). The status_show() function acquires guests_lock before reading the driver data, so any concurrent read will block until after dev_set_drvdata() has been called and the update locks are released.

As a bonus, the APQN no longer needs to be read from the queue struct after allocation — it can be read directly from apdev before allocation and stored in a local variable, which is then assigned to q->apqn once the allocation succeeds.

Fixes 260f3ea141382 ("s390/vfio-ap: move probe and remove callbacks to vfio_ap_ops.c")
---
 drivers/s390/crypto/vfio_ap_ops.c |   33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +29 -4
@@ -2321,6 +2321,23 @@ static ssize_t status_show(struct device
 	mutex_lock(&matrix_dev->guests_lock);
 	mutex_lock(&matrix_dev->mdevs_lock);
 	q = dev_get_drvdata(&apdev->device);
+
+	/*
+	 * Make sure the drvdata has been set before proceeding. There is a
+	 * possibility that the drvdata was not set if the vfio_ap_queue object
+	 * could not be allocated when the queue device was probed. In that case,
+	 * the locks used in vfio_ap_mdev_probe_queue() are released prior to
+	 * removing the sysfs status attribute to avoid a lockdep
+	 * splat. That opens a very small window where the status attribute is
+	 * still available without the vfio_ap_queue object having been
+	 * stored in the device drvdata. In that case, indicate the queue is not
+	 * assigned.
+	 */
+	if (!q) {
+		nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_UNASSIGNED);
+		goto done;
+	}
+
 	matrix_mdev = vfio_ap_mdev_for_queue(q);
 
 	/* If the queue is assigned to the matrix mediated device, then
@@ -2345,6 +2362,7 @@ static ssize_t status_show(struct device
 		nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_UNASSIGNED);
 	}
 
+done:
 	mutex_unlock(&matrix_dev->mdevs_lock);
 	mutex_unlock(&matrix_dev->guests_lock);
 
@@ -2419,14 +2437,17 @@ void vfio_ap_mdev_unregister(void)
 
 int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
 {
-	int ret;
+	int ret, apqn;
 	struct vfio_ap_queue *q;
 	DECLARE_BITMAP(apm_filtered, AP_DEVICES);
 	struct ap_matrix_mdev *matrix_mdev;
 
+	apqn = to_ap_queue(&apdev->device)->qid;
+	matrix_mdev = get_update_locks_by_apqn(apqn);
+
 	ret = sysfs_create_group(&apdev->device.kobj, &vfio_queue_attr_group);
 	if (ret)
-		return ret;
+		goto err_release_locks;
 
 	q = kzalloc(sizeof(*q), GFP_KERNEL);
 	if (!q) {
@@ -2434,11 +2455,10 @@ int vfio_ap_mdev_probe_queue(struct ap_d
 		goto err_remove_group;
 	}
 
-	q->apqn = to_ap_queue(&apdev->device)->qid;
+	q->apqn = apqn;
 	q->saved_isc = VFIO_AP_ISC_INVALID;
 	memset(&q->reset_status, 0, sizeof(q->reset_status));
 	INIT_WORK(&q->reset_work, apq_reset_check);
-	matrix_mdev = get_update_locks_by_apqn(q->apqn);
 
 	if (matrix_mdev) {
 		vfio_ap_mdev_link_queue(matrix_mdev, q);
@@ -2467,8 +2487,13 @@ done:
 	return ret;
 
 err_remove_group:
+	release_update_locks_for_mdev(matrix_mdev);
 	sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group);
 	return ret;
+
+err_release_locks:
+	release_update_locks_for_mdev(matrix_mdev);
+	return ret;
 }
 
 void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
author maintainer
#134 lore raw

PATCH 134/583 s390/vfio-ap: fix potential use of uninitialized apm_filtered bitmap

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit bf09b9d7cd7890bc3a3b7eb63d5ece15f88bfde7 upstream.

The DECLARE_BITMAP(apm_filtered, AP_DEVICES) macro allocates the bitmap on the stack without zero-initializing it.

In vfio_ap_mdev_hot_plug_cfg(), the vfio_ap_mdev_filter_matrix() function is only called to initialize and populate apm_filtered if either filter_adapters or filter_domains is true. If the hot plug configuration change only adds control domains (meaning filter_cdoms is true, but filter_adapters and filter_domains are both false), vfio_ap_mdev_filter_matrix() is bypassed.

Consequently, apm_filtered is passed to reset_queues_for_apids() with uninitialized stack garbage. This can cause reset_queues_for_apids() to interpret arbitrary stack garbage bits as valid APIDs to reset, potentially performing unintended guest hardware queue resets.

Fix this by zero-initializing the apm_filtered bitmap at the beginning of vfio_ap_mdev_hot_plug_cfg() using bitmap_zero().

Fixes eeb386aeb5b7c ("s390/vfio-ap: handle config changed and scan complete notification")
---
 drivers/s390/crypto/vfio_ap_ops.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +9 -0
@@ -2877,6 +2877,15 @@ static void vfio_ap_mdev_hot_plug_cfg(st
 	DECLARE_BITMAP(apm_filtered, AP_DEVICES);
 	bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false;
 
+	/*
+	 * Zero out the apm_filtered bitmap in case there are no adapters or
+	 * domains to be added, but only control domains. In that case,
+	 * vfio_ap_mdev_filter_matrix() - which initializes apm_filtered - will
+	 * not get called and the reset_queues_for_apids will crash because it
+	 * will access an uninitialized bitmap.
+	 */
+	bitmap_zero(apm_filtered, AP_DEVICES);
+
 	filter_adapters = bitmap_intersects(matrix_mdev->matrix.apm,
 					    matrix_mdev->apm_add, AP_DEVICES);
 	filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
author maintainer
#135 lore raw

PATCH 135/583 s390/vfio-ap: Fix required lock not held during update of ap_matrix_mdev object

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anthony Krowiak <[email protected]>

commit 5883528250be57fa92270459b33603ff52de0a91 upstream.

In the vfio_ap_mdev_cfg_add function, the apm_add, aqm_add and adm_add fields of an ap_matrix_mdev object fields are modified while not holding the matrix_dev->mdevs_lock. This lock must be held while making these to guard against a race condition with another caller that may be concurrently modifying these fields or any of the fields in the matrix_mdev->matrix.

Fixes eeb386aeb5b7c ("s390/vfio-ap: handle config changed and scan complete notification")
---
 drivers/s390/crypto/vfio_ap_ops.c |    8 ++++++++
 1 file changed, 8 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +8 -0
@@ -2801,12 +2801,20 @@ static void vfio_ap_mdev_cfg_add(unsigne
 	 * called.
 	 */
 	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
+		/*
+		 * The mdevs_lock must be held in order to access fields
+		 * within matrix_mdev
+		 */
+		mutex_lock(&matrix_dev->mdevs_lock);
+
 		bitmap_and(matrix_mdev->apm_add,
 			   matrix_mdev->matrix.apm, apm_add, AP_DEVICES);
 		bitmap_and(matrix_mdev->aqm_add,
 			   matrix_mdev->matrix.aqm, aqm_add, AP_DOMAINS);
 		bitmap_and(matrix_mdev->adm_add,
 			   matrix_mdev->matrix.adm, adm_add, AP_DEVICES);
+
+		mutex_unlock(&matrix_dev->mdevs_lock);
 	}
 }
 
author maintainer
#136 lore raw

PATCH 136/583 mtd: afs: validate v2 image info bounds

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

commit e9290031f736e99ad17c25c00311c92c266843b7 upstream.

The AFS v2 parser uses footer[8] to locate the image information block inside the current erase block, then uses the image information region_count to walk entries from a fixed local array. The footer offset and region count come from flash contents and are not checked against the erase block or the local image-info array before use.

Reject v2 entries whose image information offset would underflow the erase block calculation, and reject region counts that cannot fit in the local image-info array before walking region entries.

Fixes b7cf5e2830bb ("mtd: afs: add v2 partition parsing")
---
 drivers/mtd/parsers/afs.c |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/mtd/parsers/afs.c +7 -0
@@ -235,6 +235,9 @@ static int afs_parse_v2_partition(struct
 	pr_debug("Parsing v2 partition @%08x-%08x\n",
 		 off, off + mtd->erasesize);
 
+	if (mtd->erasesize < sizeof(footer))
+		return -EINVAL;
+
 	/* First read the footer */
 	ptr = off + mtd->erasesize - sizeof(footer);
 	ret = mtd_read(mtd, ptr, sizeof(footer), &sz, (u_char *)footer);
@@ -245,6 +248,8 @@ static int afs_parse_v2_partition(struct
 	}
 	name = (char *) &footer[0];
 	version = footer[9];
+	if (footer[8] > mtd->erasesize - sizeof(footer))
+		return -EINVAL;
 	ptr = off + mtd->erasesize - sizeof(footer) - footer[8];
 
 	pr_debug("found image \"%s\", version %08x, info @%08x\n",
@@ -278,6 +283,8 @@ static int afs_parse_v2_partition(struct
 	entrypoint = imginfo[pad];
 	attributes = imginfo[pad+1];
 	region_count = imginfo[pad+2];
+	if (region_count > (ARRAY_SIZE(imginfo) - pad - 3) / 4)
+		return -EINVAL;
 	block_start = imginfo[20];
 	block_end = imginfo[21];
 
author maintainer
#137 lore raw

PATCH 137/583 mtd: mtdoops: free page bitmap when the backing MTD is removed

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xu Rao <[email protected]>

commit 956e7da12c114f13c63d126ab1d79c3b6a819060 upstream.

mtdoops_notify_add() allocates oops_page_used when the configured MTD device is registered. mtdoops_notify_remove() detaches from that device but leaves the bitmap allocated. If the same MTD device is later registered again, the add path allocates a new bitmap and overwrites the old pointer, leaking one vmalloc allocation per remove/add cycle.

This is only visible when the backing MTD device can disappear and be registered again while mtdoops remains loaded, so the usual static MTD case does not expose it.

Free the bitmap after unregistering the dumper and flushing the pending workers, then clear the pointer and page count before a later attach can allocate fresh state. Clearing the pointer also keeps the module exit path from freeing the same bitmap a second time after a remove event.

Fixes be95745f0167 ("mtd: mtdoops: keep track of used/unused pages in an array")
---
 drivers/mtd/mtdoops.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/mtd/mtdoops.c +3 -0
@@ -392,6 +392,9 @@ static void mtdoops_notify_remove(struct
 	cxt->mtd = NULL;
 	flush_work(&cxt->work_erase);
 	flush_work(&cxt->work_write);
+	vfree(cxt->oops_page_used);
+	cxt->oops_page_used = NULL;
+	cxt->oops_pages = 0;
 }
 
 
author maintainer
#138 lore raw

PATCH 138/583 mtd: nand: realtek-ecc: add missing MODULE_DEVICE_TABLE()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

commit 5b2444b4d575d8117809c57801562ef37ca2d4af upstream.

The Realtek external ECC engine driver has an OF match table wired into its platform driver, but the table is not exported with MODULE_DEVICE_TABLE().

When the driver is built as a module, the missing OF module alias prevents automatic module loading from the compatible string.

Add the missing MODULE_DEVICE_TABLE() entry.

Fixes 3148d0e5b1c5 ("mtd: nand: realtek-ecc: Add Realtek external ECC engine support")
---
 drivers/mtd/nand/ecc-realtek.c |    1 +
 1 file changed, 1 insertion(+)
drivers/mtd/nand/ecc-realtek.c +1 -0
@@ -448,6 +448,7 @@ static const struct of_device_id rtl_ecc
 	},
 	{ /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, rtl_ecc_of_ids);
 
 static struct platform_driver rtl_ecc_driver = {
 	.driver	= {
author maintainer
#139 lore raw

PATCH 139/583 mtd: rawnand: validate ONFI extended parameter page sections

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

commit e5e415262330bd70f983e091d8919d9dcd99e475 upstream.

nand_flash_detect_ext_param_page() allocates the length declared by the ONFI parameter page, then treats the data as a fixed header followed by variable-length sections. It reads that header and advances over sections without first proving that the fixed page and each current section fit in the allocation.

Reject pages shorter than the fixed header, track the remaining variable area while walking sections, and require the ECC section to contain every field read from struct onfi_ext_ecc_info. Use device-scoped diagnostics that identify the malformed ONFI section.

Fixes 6dcbe0cdd83f ("mtd: get the ECC info from the Extended Parameter Page")
---
 drivers/mtd/nand/raw/nand_onfi.c |   27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)
drivers/mtd/nand/raw/nand_onfi.c +25 -2
@@ -35,16 +35,21 @@ static int nand_flash_detect_ext_param_p
 					    struct nand_onfi_params *p)
 {
 	struct nand_device *base = &chip->base;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	struct nand_ecc_props requirements;
 	struct onfi_ext_param_page *ep;
 	struct onfi_ext_section *s;
 	struct onfi_ext_ecc_info *ecc;
+	size_t remaining, section_len;
 	uint8_t *cursor;
 	int ret;
 	int len;
 	int i;
 
 	len = le16_to_cpu(p->ext_param_page_length) * 16;
+	if (len < sizeof(*ep))
+		return -EINVAL;
+
 	ep = kmalloc(len, GFP_KERNEL);
 	if (!ep)
 		return -ENOMEM;
@@ -77,11 +82,29 @@ static int nand_flash_detect_ext_param_p
 
 	/* find the ECC section. */
 	cursor = (uint8_t *)(ep + 1);
+	remaining = len - sizeof(*ep);
 	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
 		s = ep->sections + i;
-		if (s->type == ONFI_SECTION_TYPE_2)
+		section_len = s->length * 16;
+		if (section_len > remaining) {
+			dev_dbg(&mtd->dev,
+				"ONFI extended parameter section %d exceeds page\n",
+				i);
+			goto ext_out;
+		}
+
+		if (s->type == ONFI_SECTION_TYPE_2) {
+			if (section_len < sizeof(*ecc)) {
+				dev_dbg(&mtd->dev,
+					"ONFI extended parameter ECC section %d is too short\n",
+					i);
+				goto ext_out;
+			}
 			break;
-		cursor += s->length * 16;
+		}
+
+		cursor += section_len;
+		remaining -= section_len;
 	}
 	if (i == ONFI_EXT_SECTION_MAX) {
 		pr_debug("We can not find the ECC section.\n");
author maintainer
#140 lore raw

PATCH 140/583 batman-adv: fix stale receive device on merged fragments

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhiling Zou <[email protected]>

commit ad46c907d7d9975a285c1e89a4adde652eaa93f5 upstream.

Fragment reassembly reuses the skb from the highest-numbered buffered fragment as the merged packet. When that fragment was received on a hard interface which is deleted before the chain completes, the merged skb can re-enter the receive path with a stale skb->dev and skb_iif.

batadv_batman_skb_recv() passes such merged packets through the normal receive handlers again. DAT and bridge loop avoidance both derive the ARP header length from skb->dev, so they can dereference the freed net_device before the packet reaches the local mesh interface.

Refresh the receive device metadata from the current receive device before running the packet handlers. This keeps internally reinjected merged fragments consistent with the normal receive path after hard interface teardown.

Fixes 610bfc6bc99b ("batman-adv: Receive fragmented packets and merge")
---
 net/batman-adv/main.c |    4 ++++
 1 file changed, 4 insertions(+)
net/batman-adv/main.c +4 -0
@@ -436,6 +436,10 @@ int batadv_batman_skb_recv(struct sk_buf
 	if (!skb)
 		goto err_put;
 
+	/* Merged fragments re-enter here with reused skb metadata. */
+	skb->dev = dev;
+	skb->skb_iif = dev->ifindex;
+
 	/* packet should hold at least type and version */
 	if (unlikely(!pskb_may_pull(skb, 2)))
 		goto err_free;
author maintainer
#141 lore raw

PATCH 141/583 batman-adv: mcast: ensure unshared skb for multicast packets

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sven Eckelmann <[email protected]>

commit 82bf207f48ebb7a38157f1d91dac884fc9b8cfd8 upstream.

When a packet is transmitted via a batman-adv interface and has already enough room for the header then nothing will make sure that the skbuff is unshared. But it is not allowed to modify a currently shared skbuff.

Always make sure that the pskb_expand_head() is not only called for a too small header but also for shared skbuffs.

Fixes 90039133221e ("batman-adv: mcast: implement multicast packet generation")
---
 net/batman-adv/multicast_forw.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
net/batman-adv/multicast_forw.c +1 -2
@@ -1100,8 +1100,7 @@ static int batadv_mcast_forw_expand_head
 		return -EINVAL;
 	}
 
-	if (skb_headroom(skb) < hdr_size &&
-	    pskb_expand_head(skb, hdr_size, 0, GFP_ATOMIC) < 0)
+	if (skb_cow(skb, hdr_size) < 0)
 		return -ENOMEM;
 
 	return 0;
author maintainer
#142 lore raw

PATCH 142/583 batman-adv: mcast: linearize skbuff for packet generation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sven Eckelmann <[email protected]>

commit 6a30a59e2660afd03c975f1b8eae6a2301161197 upstream.

batadv_mcast_forw_packet() and batadv_mcast_forw_scrape() is not only called (indirectly) by the unsharing+linearizing batadv_recv_mcast_packet() handler. When it is called (indirectly) by batadv_mcast_forw_mcsend() then it will be unshared but not linearized. The SKB_LINEAR_ASSERT() can therefore cause a fatal BUG().

The linearization should happen during the expansion of the head because the scrape function can be hit already during the initial batadv_mcast_forw_mode() selection code:

* batadv_interface_tx
* batadv_mcast_forw_mode
* batadv_mcast_forw_mode_by_count()
* batadv_mcast_forw_push()
-> calls batadv_mcast_forw_expand_head() before everything else
* batadv_mcast_forw_push_tvlvs()
* batadv_mcast_forw_push_dests()
* batadv_mcast_forw_push_adjust_padding()
* batadv_mcast_forw_scrape()

Fixes 90039133221e ("batman-adv: mcast: implement multicast packet generation")
---
 net/batman-adv/multicast_forw.c |    4 ++++
 1 file changed, 4 insertions(+)
net/batman-adv/multicast_forw.c +4 -0
@@ -1103,6 +1103,10 @@ static int batadv_mcast_forw_expand_head
 	if (skb_cow(skb, hdr_size) < 0)
 		return -ENOMEM;
 
+	/* batadv_mcast_forw_scrape() + batadv_mcast_forw_packet() require linearized skb */
+	if (skb_linearize(skb) < 0)
+		return -ENOMEM;
+
 	return 0;
 }
 
author maintainer
#143 lore raw

PATCH 143/583 batman-adv: dat: avoid unaligned fault in IP extraction

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sven Eckelmann <[email protected]>

commit 0121afa52cdb88cfb4d5d7bd126a23a9100121d8 upstream.

Independent of the alignment of the ARP packet in the SKB, either the batadv_arp_ip_src or the batadv_arp_ip_dst will have an unaligned access (on HW without native unaligned read support).

Use get_unaligned() to handle this properly on all architectures.

Fixes 5c3a0e553593 ("batman-adv: Distributed ARP Table - add ARP parsing functions")
---
 net/batman-adv/distributed-arp-table.c |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
net/batman-adv/distributed-arp-table.c +6 -2
@@ -249,7 +249,10 @@ static u8 *batadv_arp_hw_src(struct sk_b
  */
 static __be32 batadv_arp_ip_src(struct sk_buff *skb, int hdr_size)
 {
-	return *(__force __be32 *)(batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN);
+	u8 *src = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN;
+	__be32 *ip = (__force __be32 *)src;
+
+	return get_unaligned(ip);
 }
 
 /**
@@ -274,8 +277,9 @@ static u8 *batadv_arp_hw_dst(struct sk_b
 static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)
 {
 	u8 *dst = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN * 2 + 4;
+	__be32 *ip = (__force __be32 *)dst;
 
-	return *(__force __be32 *)dst;
+	return get_unaligned(ip);
 }
 
 /**
author maintainer
#144 lore raw

PATCH 144/583 batman-adv: bla: fix freeing of claims on meshif deletion

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sven Eckelmann <[email protected]>

commit 8d128c932bced74e3b1625ba3d7c78ef122a88a7 upstream.

When the mesh interface is getting deleted, then batadv_bla_del_backbone_claims() (via batadv_bla_purge_backbone_gw()) could make sure that all claims gets removed. But this function is only executed when bat_priv->bla.claim_hash is not NULL. And since batadv_bla_free() is always setting it to NULL before it is (indirectly) called, it was never actually executed.

But the batadv_bla_purge_claims() -> batadv_handle_unclaim() is at the moment too fragile because the BLA code is not handling the rehashing in batadv_bla_update_orig_address(). The stored backbone address doesn't have to be the one actually used for the hash bucket selection during the initial adding of the backbone. The batadv_handle_unclaim() can therefore fail to find the respective backbone for the unclaim and then stop the deletion.

But the actual backbone_gw object is not needed for the unclaim because all relevant information is always provided by the caller. And the check for the existence of the backbone_gw doesn't provide any additional security check for the deletion of a claim.

Fixes 23721387c409 ("batman-adv: add basic bridge loop avoidance code")
---
 net/batman-adv/bridge_loop_avoidance.c |   10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +1 -9
@@ -942,26 +942,18 @@ static bool batadv_handle_unclaim(struct
 				  const u8 *backbone_addr, const u8 *claim_addr,
 				  unsigned short vid)
 {
-	struct batadv_bla_backbone_gw *backbone_gw;
-
 	/* unclaim in any case if it is our own */
 	if (primary_if && batadv_compare_eth(backbone_addr,
 					     primary_if->net_dev->dev_addr))
 		batadv_bla_send_claim(bat_priv, claim_addr, vid,
 				      BATADV_CLAIM_TYPE_UNCLAIM);
 
-	backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
-
-	if (!backbone_gw)
-		return true;
-
 	/* this must be an UNCLAIM frame */
 	batadv_dbg(BATADV_DBG_BLA, bat_priv,
 		   "%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
-		   claim_addr, batadv_print_vid(vid), backbone_gw->orig);
+		   claim_addr, batadv_print_vid(vid), backbone_addr);
 
 	batadv_bla_del_claim(bat_priv, claim_addr, vid);
-	batadv_backbone_gw_put(backbone_gw);
 	return true;
 }
 
author maintainer
#145 lore raw

PATCH 145/583 batman-adv: bla: prevent CRC corruptions after claim flush

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sven Eckelmann <[email protected]>

commit 89f3502ff6878798be96461b2eebd64ba3c3874c upstream.

When batadv_bla_del_backbone_claims() tried to remove all claims of a backbone, it sets the CRC to 0. It assumes that the it had the last reference of the claims because batadv_claim_release() (which runs after the last reference was released), is XORing the crc16 of the claim address with the backbone CRC.

If there would be a parallel holder of any of these references, it could happen that the backbone CRC is (0 ^ crc16(delayed_released_claim)). Which is the wrong starting point for the new claims it may receive when the remote answers the claim request from batadv_bla_send_request().

This reinitializations can be completely dropped to avoid this problem. batadv_claim_release() will take care of fixing the backbone CRC.

Fixes 23721387c409 ("batman-adv: add basic bridge loop avoidance code")
---
 net/batman-adv/bridge_loop_avoidance.c |    5 -----
 1 file changed, 5 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +0 -5
@@ -324,11 +324,6 @@ batadv_bla_del_backbone_claims(struct ba
 		}
 		spin_unlock_bh(list_lock);
 	}
-
-	/* all claims gone, initialize CRC */
-	spin_lock_bh(&backbone_gw->crc_lock);
-	backbone_gw->crc = BATADV_BLA_CRC_INIT;
-	spin_unlock_bh(&backbone_gw->crc_lock);
 }
 
 /**
author maintainer
#146 lore raw

PATCH 146/583 clk: clocking-wizard: fix integer overflow in rate calculation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pavel Löbl <[email protected]>

commit 4adf593c6fc5aed4639add011f71a074a1bd3966 upstream.

When using driver on Zynq-7000 (32-bit) determine_rate calculation overflows. For instance requesting 32MHz with 100MHz parent clock results in 100000000*(4*1000+0) 32-bit multiplication.

Replace the expression with mult_frac which is already used in clk_wzrd_recalc_ratef.

Fixes 7681f64e6404 ("clk: clocking-wizard: calculate dividers fractional parts")
---
 drivers/clk/xilinx/clk-xlnx-clock-wizard.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/xilinx/clk-xlnx-clock-wizard.c +2 -2
@@ -663,8 +663,8 @@ static int clk_wzrd_determine_rate_all(s
 	d = divider->d;
 	o = divider->o;
 
-	req->rate = div_u64(req->best_parent_rate * (m * 1000 + divider->m_frac),
-			    d * (o * 1000 + divider->o_frac));
+	req->rate = mult_frac(req->best_parent_rate, m * 1000 + divider->m_frac,
+			      d * (o * 1000 + divider->o_frac));
 	return 0;
 }
 
author maintainer
#147 lore raw

PATCH 147/583 clk: mediatek: mt8196: Select REGMAP_MMIO for vlpckgen

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Akari Tsuyukusa <[email protected]>

commit f63aecdb45e9dd19c340fd62df698374d95b9024 upstream.

The MediaTek MT8196 vlpckgen clock driver uses __devm_regmap_init_mmio_clk() by devm_regmap_init_mmio(), which is defined in drivers/base/regmap/regmap-mmio.c. However, the driver's Kconfig entry does not select REGMAP_MMIO. This causes a linker error when REGMAP_MMIO is not enabled.

Fix this by selecting REGMAP_MMIO in the Kconfig entry.

Fixes 2f8b3ae6f0cb ("clk: mediatek: Add MT8196 vlpckgen clock support")
---
 drivers/clk/mediatek/Kconfig |    1 +
 1 file changed, 1 insertion(+)
drivers/clk/mediatek/Kconfig +1 -0
@@ -1006,6 +1006,7 @@ config COMMON_CLK_MT8196
 	tristate "Clock driver for MediaTek MT8196"
 	depends on ARM64 || COMPILE_TEST
 	select COMMON_CLK_MEDIATEK
+	select REGMAP_MMIO
 	default ARCH_MEDIATEK
 	help
 	  This driver supports MediaTek MT8196 basic clocks.
author maintainer
#148 lore raw

PATCH 148/583 clk: meson: align gxbb_32k_clk_sel number of parents with actual count

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Martin Blumenstingl <[email protected]>

commit 628b6fee9fca292f12d07f0f1bcf1edefa949d81 upstream.

The following out-of-bounds read has been observed by Christian on a GXBB WeTek Hub:
==================================================================

BUG: KASAN: global-out-of-bounds in __clk_register+0x1b70/0x2418
Read of size 8 at addr ffffd66320cf88e0 by task swapper/0/1

CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.0.0-rc5 #1 PREEMPT
Hardware name: WeTek Hub (DT)
Call trace:
 show_stack+0x14/0x20 (C)
 dump_stack_lvl+0x74/0x94
 print_report+0x164/0x4b0
 kasan_report+0x98/0xd8
 __asan_report_load8_noabort+0x1c/0x24
 __clk_register+0x1b70/0x2418
 devm_clk_hw_register+0x74/0x15c
 meson_clkc_init+0xd4/0x20c
 meson_clkc_syscon_probe+0x5c/0x94
 platform_probe+0xbc/0x17c
 really_probe+0x184/0x844
 __driver_probe_device+0x154/0x35c
 driver_probe_device+0x60/0x188
 __driver_attach+0x168/0x4a0
 bus_for_each_dev+0xec/0x180
 driver_attach+0x38/0x58
 bus_add_driver+0x238/0x4c0
 driver_register+0x150/0x388
 __platform_driver_register+0x54/0x7c
 gxbb_clkc_driver_init+0x18/0x20
 do_one_initcall+0xb8/0x340
 kernel_init_freeable+0x49c/0x52c
 kernel_init+0x24/0x148
 ret_from_fork+0x10/0x20

The buggy address belongs to the variable:
 gxbb_32k_clk_parents+0x60/0x400

The buggy address belongs to a vmalloc virtual mapping
The buggy address belongs to the physical page:

Memory state around the buggy address:
 ffffd66320cf8780: 00 00 00 00 f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9
 ffffd66320cf8800: 00 04 f9 f9 f9 f9 f9 f9 00 04 f9 f9 f9 f9 f9 f9
>ffffd66320cf8880: 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9
                                                       ^
 ffffd66320cf8900: 00 01 f9 f9 f9 f9 f9 f9 00 06 f9 f9 f9 f9 f9 f9
 ffffd66320cf8980: 00 00 02 f9 f9 f9 f9 f9 00 00 02 f9 f9 f9 f9 f9
==================================================================

Commit 7915d7d5407c ("clk: amlogic: gxbb: drop non existing 32k clock parent") dropped a non-existing clock parent from the gxbb_32k_clk_sel mux but didn't adjust the hard-coded num_parents field. Fix the actual number of parents of that mux by using ARRAY_SIZE instead (avoiding similar problems in future).

---
 drivers/clk/meson/gxbb.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/meson/gxbb.c +1 -1
@@ -1394,7 +1394,7 @@ static struct clk_regmap gxbb_32k_clk_se
 		.name = "32k_clk_sel",
 		.ops = &clk_regmap_mux_ops,
 		.parent_data = gxbb_32k_clk_parents,
-		.num_parents = 4,
+		.num_parents = ARRAY_SIZE(gxbb_32k_clk_parents),
 		.flags = CLK_SET_RATE_PARENT,
 	},
 };
author maintainer
#149 lore raw

PATCH 149/583 clk: qcom: gcc-msm8916: Fix enable_reg for gcc_blsp1_sleep_clk

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit c5339edc6abb601ea10df910ea0b1592fa1016f3 upstream.

According to the APQ8016E TRM, the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).

---
 drivers/clk/qcom/gcc-msm8916.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8916.c +3 -2
@@ -1589,9 +1589,10 @@ static struct clk_branch gcc_blsp1_ahb_c
 
 static struct clk_branch gcc_blsp1_sleep_clk = {
 	.halt_reg = 0x01004,
+	.halt_check = BRANCH_HALT_VOTED,
 	.clkr = {
-		.enable_reg = 0x01004,
-		.enable_mask = BIT(0),
+		.enable_reg = 0x45004,
+		.enable_mask = BIT(9),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_blsp1_sleep_clk",
 			.parent_data = &(const struct clk_parent_data){
author maintainer
#150 lore raw

PATCH 150/583 clk: qcom: gcc-msm8939: Fix enable_reg for gcc_blsp1_sleep_clk

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit fc611445b021262b0d4ace6f716a360663816287 upstream.

MSM8939 is similar to MSM8916, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).

Fixes 1664014e4679 ("clk: qcom: gcc-msm8939: Add MSM8939 Generic Clock Controller")
---
 drivers/clk/qcom/gcc-msm8939.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8939.c +3 -2
@@ -1929,9 +1929,10 @@ static struct clk_branch gcc_blsp1_ahb_c
 
 static struct clk_branch gcc_blsp1_sleep_clk = {
 	.halt_reg = 0x01004,
+	.halt_check = BRANCH_HALT_VOTED,
 	.clkr = {
-		.enable_reg = 0x01004,
-		.enable_mask = BIT(0),
+		.enable_reg = 0x45004,
+		.enable_mask = BIT(9),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_blsp1_sleep_clk",
 			.ops = &clk_branch2_ops,
author maintainer
#151 lore raw

PATCH 151/583 clk: rockchip: rk3588: Dont change PLL rates when setting dclk_vop2_src

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Heiko Stuebner <[email protected]>

commit 13b10571cc353448275365ede1a5396d20dfe839 upstream.

dclk_vop2_src currently has the CLK_SET_RATE_PARENT flag set, which is very different from dclk_vop0_src or dclk_vop1_src, which don't have it.

With this flag in dclk_vop2_src, actually setting the clock then results in a lot of other peripherals breaking, because setting the rate results in the PLL source getting changed:

[   14.898718] clk_core_set_rate_nolock: setting rate for dclk_vop2 to 152840000
[   15.155017] clk_change_rate: setting rate for pll_gpll to 1680000000

[ clk adjusting every gpll user ]

This includes possibly the other vops, i2s, spdif and even the uarts. Among other possible things, this breaks the uart console on a board I use. Sometimes it recovers later on, but there will be a big block of garbled output for a while at least.

Shared PLLs should not be changed by individual users, so drop this flag from dclk_vop2_src.

---
 drivers/clk/rockchip/clk-rk3588.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/rockchip/clk-rk3588.c +1 -1
@@ -2094,7 +2094,7 @@ static struct rockchip_clk_branch rk3588
 	COMPOSITE(DCLK_VOP1_SRC, "dclk_vop1_src", gpll_cpll_v0pll_aupll_p, 0,
 			RK3588_CLKSEL_CON(111), 14, 2, MFLAGS, 9, 5, DFLAGS,
 			RK3588_CLKGATE_CON(52), 11, GFLAGS),
-	COMPOSITE(DCLK_VOP2_SRC, "dclk_vop2_src", gpll_cpll_v0pll_aupll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+	COMPOSITE(DCLK_VOP2_SRC, "dclk_vop2_src", gpll_cpll_v0pll_aupll_p, CLK_SET_RATE_NO_REPARENT,
 			RK3588_CLKSEL_CON(112), 5, 2, MFLAGS, 0, 5, DFLAGS,
 			RK3588_CLKGATE_CON(52), 12, GFLAGS),
 	COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", dclk_vop0_p,
author maintainer
#152 lore raw

PATCH 152/583 clk: qcom: gcc-mdm9607: Drop incorrect apss_tcu_clk_src

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit 38d06956f60675f906dc3f5b70b3b52103b86a7d upstream.

This clock does not exist on the specified address on MDM9607. Reading/writing the registers always results in 0 or crashes. The math in the frequency table is also broken. GPLL2 on MDM9607 runs at 480 MHz, so:

- F(155000000, P_GPLL2, 6, 0, 0), // 480 MHz/6 = 80 MHz, not 155 MHz
- F(310000000, P_GPLL2, 3, 0, 0), // 480 MHz/3 = 160 MHz, not 310 MHz

Presumably, this definition was mistakenly copied as-is from gcc-msm8916 (which uses 930 MHz for GPLL2). There are no branch consumers of this root clock inside gcc-mdm9607 (notably, gcc_apss_tcu_clk has bimc_ddr_clk_src as parent instead of this clock), so we can just drop it.

It seems like this clock does exist on this SoC on a different address, but since there is no user and reference code for it, it is still better to drop it.

---
 drivers/clk/qcom/gcc-mdm9607.c |   35 -----------------------------------
 1 file changed, 35 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +0 -35
@@ -158,20 +158,6 @@ static const struct clk_parent_data gcc_
 	{ .hw = &gpll2.clkr.hw },
 };
 
-static const struct parent_map gcc_xo_gpll0_gpll1_gpll2_map[] = {
-	{ P_XO, 0 },
-	{ P_GPLL0, 1 },
-	{ P_GPLL1, 2 },
-	{ P_GPLL2, 3 },
-};
-
-static const struct clk_parent_data gcc_xo_gpll0_gpll1_gpll2[] = {
-	{ .fw_name = "xo" },
-	{ .hw = &gpll0.clkr.hw },
-	{ .hw = &gpll1_vote.hw },
-	{ .hw = &gpll2.clkr.hw },
-};
-
 static const struct freq_tbl ftbl_apss_ahb_clk[] = {
 	F(19200000, P_XO, 1, 0, 0),
 	F(50000000, P_GPLL0, 16, 0, 0),
@@ -674,26 +660,6 @@ static struct clk_rcg2 sdcc2_apps_clk_sr
 	},
 };
 
-static const struct freq_tbl ftbl_gcc_apss_tcu_clk[] = {
-	F(155000000, P_GPLL2, 6, 0, 0),
-	F(310000000, P_GPLL2, 3, 0, 0),
-	F(400000000, P_GPLL0, 2, 0, 0),
-	{ }
-};
-
-static struct clk_rcg2 apss_tcu_clk_src = {
-	.cmd_rcgr = 0x1207c,
-	.hid_width = 5,
-	.parent_map = gcc_xo_gpll0_gpll1_gpll2_map,
-	.freq_tbl = ftbl_gcc_apss_tcu_clk,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "apss_tcu_clk_src",
-		.parent_data = gcc_xo_gpll0_gpll1_gpll2,
-		.num_parents = 4,
-		.ops = &clk_rcg2_ops,
-	},
-};
-
 static const struct freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
 	F(19200000, P_XO, 1, 0, 0),
 	F(57140000, P_GPLL0, 14, 0, 0),
@@ -1511,7 +1477,6 @@ static struct clk_regmap *gcc_mdm9607_cl
 	[PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
 	[SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
 	[SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
-	[APSS_TCU_CLK_SRC] = &apss_tcu_clk_src.clkr,
 	[USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr,
 	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
 	[GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr,
author maintainer
#153 lore raw

PATCH 153/583 clk: qcom: gcc-mdm9607: Drop incorrect system_noc_bfdcd_clk_src

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit 17784427df923a0573a7ea83f9198456ff1ec1a5 upstream.

This clock does not exist on MDM9607. Reading/writing the registers always results in 0.

Presumably, this definition was mistakenly copied from gcc-msm8916. On MSM8916, this root clock is used for multimedia subsystems (camera, display, video). MDM9607 has none of that, so this clock was probably omitted in the hardware.

There are no users inside gcc-mdm9607, so we can just drop it.

---
 drivers/clk/qcom/gcc-mdm9607.c |   13 -------------
 1 file changed, 13 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +0 -13
@@ -240,18 +240,6 @@ static struct clk_rcg2 pcnoc_bfdcd_clk_s
 	},
 };
 
-static struct clk_rcg2 system_noc_bfdcd_clk_src = {
-	.cmd_rcgr = 0x26004,
-	.hid_width = 5,
-	.parent_map = gcc_xo_gpll0_bimc_map,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "system_noc_bfdcd_clk_src",
-		.parent_data = gcc_xo_gpll0_bimc,
-		.num_parents = ARRAY_SIZE(gcc_xo_gpll0_bimc),
-		.ops = &clk_rcg2_ops,
-	},
-};
-
 static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
 	F(19200000, P_XO, 1, 0, 0),
 	F(50000000, P_GPLL0, 16, 0, 0),
@@ -1450,7 +1438,6 @@ static struct clk_regmap *gcc_mdm9607_cl
 	[BIMC_PLL_VOTE] = &bimc_pll_vote,
 	[BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr,
 	[PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr,
-	[SYSTEM_NOC_BFDCD_CLK_SRC] = &system_noc_bfdcd_clk_src.clkr,
 	[APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr,
 	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
 	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
author maintainer
#154 lore raw

PATCH 154/583 clk: qcom: gcc-mdm9607: Fix enable_reg for gcc_blsp1_sleep_clk

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit 944d0fb38cffe57a1d1ebf82c5c077bad82dcdbb upstream.

MDM9607 is similar to MSM8909, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).

---
 drivers/clk/qcom/gcc-mdm9607.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +3 -2
@@ -744,9 +744,10 @@ static struct clk_branch gcc_blsp1_ahb_c
 
 static struct clk_branch gcc_blsp1_sleep_clk = {
 	.halt_reg = 0x1004,
+	.halt_check = BRANCH_HALT_VOTED,
 	.clkr = {
-		.enable_reg = 0x1004,
-		.enable_mask = BIT(0),
+		.enable_reg = 0x45004,
+		.enable_mask = BIT(9),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_blsp1_sleep_clk",
 			.parent_data = &(const struct clk_parent_data){
author maintainer
#155 lore raw

PATCH 155/583 clk: qcom: gcc-mdm9607: Fix halt_reg for gcc_apss_axi_clk

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit ca7e6cc30cde4f0cbeff2e205a84bedf431e9156 upstream.

gcc_apss_axi_clk specifies a halt_reg of 0x4601c, but this is already used by gcc_apss_ahb_clk. The correct value according to the downstream driver is 0x46020.

---
 drivers/clk/qcom/gcc-mdm9607.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gcc-mdm9607.c +1 -1
@@ -1414,7 +1414,7 @@ static struct clk_branch gcc_apss_ahb_cl
 };
 
 static struct clk_branch gcc_apss_axi_clk = {
-	.halt_reg = 0x4601c,
+	.halt_reg = 0x46020,
 	.halt_check = BRANCH_HALT_VOTED,
 	.clkr = {
 		.enable_reg = 0x45004,
author maintainer
#156 lore raw

PATCH 156/583 clk: qcom: gcc-mdm9607: Drop incorrect BIMC PLL and related clocks

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Stephan Gerhold <[email protected]>

commit e111ddda092ad961870a634e4c9263c10a3e8485 upstream.

The gcc-mdm9607 driver was originally based on gcc-msm8916, but a closer match nowadays is gcc-msm8909. Looking at the differences between gcc-mdm9607 and gcc-msm8909, there is quite some confusion around the definitions for the BIMC PLL.

It turns out the BIMC PLL on MDM9607 is actually an Alpha PLL just like on MSM8909. We can vote for it using BIT(2), which explains why BIT(3) was used for GPLL2.

In practice, the BIMC PLL is exclusively controlled by the RPM firmware and Linux should not touch it. So far, it was defined to model the full clock hierarchy, but even in read-only mode with CLK_GET_RATE_NOCACHE this is problematic since the RPM will silently change the clock parents without notifying Linux about it. The clock framework reads the clock parent only once during boot, so the resulting rates will still be often wrong.

Follow the example of more recent SoCs and drop the BIMC PLL and all remaining related clocks to avoid reporting stale status data. This means we cannot determine the rate of these clocks anymore. This is not a big problem in practice, since these are NoC-related clocks that are independently managed through the interconnect subsystem.

---
 drivers/clk/qcom/gcc-mdm9607.c |  125 -----------------------------------------
 1 file changed, 1 insertion(+), 124 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +1 -124
@@ -26,7 +26,6 @@
 
 enum {
 	P_XO,
-	P_BIMC,
 	P_GPLL0,
 	P_GPLL1,
 	P_GPLL2,
@@ -121,7 +120,7 @@ static struct clk_alpha_pll gpll2_early
 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
 	.clkr = {
 		.enable_reg = 0x45000,
-		.enable_mask = BIT(3), /* Yeah, apparently it's not 2 */
+		.enable_mask = BIT(3), /* BIT(2) is used for BIMC PLL */
 		.hw.init = &(struct clk_init_data)
 		{
 			.name = "gpll2_early",
@@ -178,68 +177,6 @@ static struct clk_rcg2 apss_ahb_clk_src
 	},
 };
 
-static struct clk_pll bimc_pll = {
-	.l_reg = 0x23004,
-	.m_reg = 0x23008,
-	.n_reg = 0x2300c,
-	.config_reg = 0x23010,
-	.mode_reg = 0x23000,
-	.status_reg = 0x2301c,
-	.status_bit = 17,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "bimc_pll",
-		.parent_data = &(const struct clk_parent_data){
-			.fw_name = "xo",
-		},
-		.num_parents = 1,
-		.ops = &clk_pll_ops,
-	},
-};
-
-static struct clk_regmap bimc_pll_vote = {
-	.enable_reg = 0x45000,
-	.enable_mask = BIT(3),
-	.hw.init = &(struct clk_init_data){
-		.name = "bimc_pll_vote",
-		.parent_hws = (const struct clk_hw *[]){ &bimc_pll.clkr.hw },
-		.num_parents = 1,
-		.ops = &clk_pll_vote_ops,
-	},
-};
-
-static const struct parent_map gcc_xo_gpll0_bimc_map[] = {
-	{ P_XO, 0 },
-	{ P_GPLL0, 1 },
-	{ P_BIMC, 2 },
-};
-
-static const struct clk_parent_data gcc_xo_gpll0_bimc[] = {
-	{ .fw_name = "xo" },
-	{ .hw = &gpll0.clkr.hw },
-	{ .hw = &bimc_pll_vote.hw },
-};
-
-static const struct freq_tbl ftbl_pcnoc_bfdcd_clk_src[] = {
-	F(19200000, P_XO, 1, 0, 0),
-	F(50000000, P_GPLL0, 16, 0, 0),
-	F(100000000, P_GPLL0, 8, 0, 0),
-	{ }
-};
-
-static struct clk_rcg2 pcnoc_bfdcd_clk_src = {
-	.cmd_rcgr = 0x27000,
-	.freq_tbl = ftbl_pcnoc_bfdcd_clk_src,
-	.hid_width = 5,
-	.parent_map = gcc_xo_gpll0_bimc_map,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "pcnoc_bfdcd_clk_src",
-		.parent_data = gcc_xo_gpll0_bimc,
-		.num_parents = ARRAY_SIZE(gcc_xo_gpll0_bimc),
-		.ops = &clk_rcg2_ops,
-		.flags = CLK_IS_CRITICAL,
-	},
-};
-
 static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
 	F(19200000, P_XO, 1, 0, 0),
 	F(50000000, P_GPLL0, 16, 0, 0),
@@ -735,8 +672,6 @@ static struct clk_branch gcc_blsp1_ahb_c
 		.enable_mask = BIT(10),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_blsp1_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1038,8 +973,6 @@ static struct clk_branch gcc_boot_rom_ah
 		.enable_mask = BIT(7),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_boot_rom_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1053,9 +986,6 @@ static struct clk_branch gcc_crypto_ahb_
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_crypto_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1069,9 +999,6 @@ static struct clk_branch gcc_crypto_axi_
 		.enable_mask = BIT(1),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_crypto_axi_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1145,9 +1072,6 @@ static struct clk_branch gcc_mss_cfg_ahb
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_mss_cfg_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1175,9 +1099,6 @@ static struct clk_branch gcc_pdm_ahb_clk
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_pdm_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1191,9 +1112,6 @@ static struct clk_branch gcc_prng_ahb_cl
 		.enable_mask = BIT(8),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_prng_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1206,9 +1124,6 @@ static struct clk_branch gcc_sdcc1_ahb_c
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_sdcc1_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1236,9 +1151,6 @@ static struct clk_branch gcc_sdcc2_ahb_c
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_sdcc2_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1259,19 +1171,6 @@ static struct clk_branch gcc_sdcc2_apps_
 	},
 };
 
-static struct clk_rcg2 bimc_ddr_clk_src = {
-	.cmd_rcgr = 0x32004,
-	.hid_width = 5,
-	.parent_map = gcc_xo_gpll0_bimc_map,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "bimc_ddr_clk_src",
-		.parent_data = gcc_xo_gpll0_bimc,
-		.num_parents = 3,
-		.ops = &clk_rcg2_ops,
-		.flags = CLK_GET_RATE_NOCACHE,
-	},
-};
-
 static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
 	.halt_reg = 0x49004,
 	.clkr = {
@@ -1279,9 +1178,6 @@ static struct clk_branch gcc_mss_q6_bimc
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_mss_q6_bimc_axi_clk",
-			.parent_hws = (const struct clk_hw *[]){ &bimc_ddr_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1295,8 +1191,6 @@ static struct clk_branch gcc_apss_tcu_cl
 		.enable_mask = BIT(1),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_apss_tcu_clk",
-			.parent_hws = (const struct clk_hw *[]){ &bimc_ddr_clk_src.clkr.hw },
-			.num_parents = 1,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1310,9 +1204,6 @@ static struct clk_branch gcc_smmu_cfg_cl
 		.enable_mask = BIT(12),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_smmu_cfg_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1360,9 +1251,6 @@ static struct clk_branch gcc_usb_hs_phy_
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_usb_hs_phy_cfg_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1375,9 +1263,6 @@ static struct clk_branch gcc_usb_hs_ahb_
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_usb_hs_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
-			.flags = CLK_SET_RATE_PARENT,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1406,8 +1291,6 @@ static struct clk_branch gcc_apss_ahb_cl
 		.enable_mask = BIT(14),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_apss_ahb_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1421,8 +1304,6 @@ static struct clk_branch gcc_apss_axi_cl
 		.enable_mask = BIT(13),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_apss_axi_clk",
-			.parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
-			.num_parents = 1,
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1435,10 +1316,6 @@ static struct clk_regmap *gcc_mdm9607_cl
 	[GPLL1_VOTE] = &gpll1_vote,
 	[GPLL2] = &gpll2.clkr,
 	[GPLL2_EARLY] = &gpll2_early.clkr,
-	[BIMC_PLL] = &bimc_pll.clkr,
-	[BIMC_PLL_VOTE] = &bimc_pll_vote,
-	[BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr,
-	[PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr,
 	[APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr,
 	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
 	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
author maintainer
#157 lore raw

PATCH 157/583 i2c: mux: demux-pinctrl: fix OF node leak on kstrdup failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Linkai Gong <[email protected]>

commit 62edb8ca0aa44517cc23cfa26cd8a51f15ea92fe upstream.

of_parse_phandle() takes a reference on the parent node. If a later devm_kstrdup() fails, err_rollback only releases nodes for indices 0..i-1, so the current node is leaked.

of_node_put() the current parent before rolling back.

Fixes 7c0195fa9a9e ("i2c: mux: demux-pinctrl: check the return value of devm_kstrdup()")
Cc <[email protected]> # v6.6+
---
 drivers/i2c/muxes/i2c-demux-pinctrl.c |    1 +
 1 file changed, 1 insertion(+)
drivers/i2c/muxes/i2c-demux-pinctrl.c +1 -0
@@ -247,6 +247,7 @@ static int i2c_demux_pinctrl_probe(struc
 		props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL);
 		if (!props[i].name || !props[i].value) {
 			err = -ENOMEM;
+			of_node_put(adap_np);
 			goto err_rollback;
 		}
 		props[i].length = 3;
author maintainer
#158 lore raw

PATCH 158/583 ASoC: adau1761: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit cc606b6c2328b4864885db6afcad7e78c0ac7a73 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

The table lists the ADAU1761 specific registers (0x4008 and up) before the block shared with the ADAU1381/ADAU1781, which starts at ADAU17X1_CLOCK_CONTROL (0x4000), so bsearch() descends into the wrong half and 28 of the 52 entries are unreachable. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/adau1761.c |   34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)
sound/soc/codecs/adau1761.c +17 -17
@@ -68,23 +68,33 @@
 #define ADAU1761_FIRMWARE "adau1761.bin"
 
 static const struct reg_default adau1761_reg_defaults[] = {
-	{ ADAU1761_DEJITTER,			0x03 },
+	{ ADAU17X1_CLOCK_CONTROL,		0x00 },
+	{ ADAU17X1_PLL_CONTROL,			0x00 },
 	{ ADAU1761_DIGMIC_JACKDETECT,		0x00 },
+	{ ADAU17X1_REC_POWER_MGMT,		0x00 },
 	{ ADAU1761_REC_MIXER_LEFT0,		0x00 },
 	{ ADAU1761_REC_MIXER_LEFT1,		0x00 },
 	{ ADAU1761_REC_MIXER_RIGHT0,		0x00 },
 	{ ADAU1761_REC_MIXER_RIGHT1,		0x00 },
 	{ ADAU1761_LEFT_DIFF_INPUT_VOL,		0x00 },
+	{ ADAU1761_RIGHT_DIFF_INPUT_VOL,	0x00 },
+	{ ADAU17X1_MICBIAS,			0x00 },
 	{ ADAU1761_ALC_CTRL0,			0x00 },
 	{ ADAU1761_ALC_CTRL1,			0x00 },
 	{ ADAU1761_ALC_CTRL2,			0x00 },
 	{ ADAU1761_ALC_CTRL3,			0x00 },
-	{ ADAU1761_RIGHT_DIFF_INPUT_VOL,	0x00 },
-	{ ADAU1761_PLAY_LR_MIXER_LEFT,		0x00 },
+	{ ADAU17X1_SERIAL_PORT0,		0x00 },
+	{ ADAU17X1_SERIAL_PORT1,		0x00 },
+	{ ADAU17X1_CONVERTER0,			0x00 },
+	{ ADAU17X1_CONVERTER1,			0x00 },
+	{ ADAU17X1_ADC_CONTROL,			0x00 },
+	{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,	0x00 },
+	{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,	0x00 },
 	{ ADAU1761_PLAY_MIXER_LEFT0,		0x00 },
 	{ ADAU1761_PLAY_MIXER_LEFT1,		0x00 },
 	{ ADAU1761_PLAY_MIXER_RIGHT0,		0x00 },
 	{ ADAU1761_PLAY_MIXER_RIGHT1,		0x00 },
+	{ ADAU1761_PLAY_LR_MIXER_LEFT,		0x00 },
 	{ ADAU1761_PLAY_LR_MIXER_RIGHT,		0x00 },
 	{ ADAU1761_PLAY_MIXER_MONO,		0x00 },
 	{ ADAU1761_PLAY_HP_LEFT_VOL,		0x00 },
@@ -93,20 +103,6 @@ static const struct reg_default adau1761
 	{ ADAU1761_PLAY_LINE_RIGHT_VOL,		0x00 },
 	{ ADAU1761_PLAY_MONO_OUTPUT_VOL,	0x00 },
 	{ ADAU1761_POP_CLICK_SUPPRESS,		0x00 },
-	{ ADAU1761_JACK_DETECT_PIN,		0x00 },
-	{ ADAU1761_CLK_ENABLE0,			0x00 },
-	{ ADAU1761_CLK_ENABLE1,			0x00 },
-	{ ADAU17X1_CLOCK_CONTROL,		0x00 },
-	{ ADAU17X1_PLL_CONTROL,			0x00 },
-	{ ADAU17X1_REC_POWER_MGMT,		0x00 },
-	{ ADAU17X1_MICBIAS,			0x00 },
-	{ ADAU17X1_SERIAL_PORT0,		0x00 },
-	{ ADAU17X1_SERIAL_PORT1,		0x00 },
-	{ ADAU17X1_CONVERTER0,			0x00 },
-	{ ADAU17X1_CONVERTER1,			0x00 },
-	{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL,	0x00 },
-	{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,	0x00 },
-	{ ADAU17X1_ADC_CONTROL,			0x00 },
 	{ ADAU17X1_PLAY_POWER_MGMT,		0x00 },
 	{ ADAU17X1_DAC_CONTROL0,		0x00 },
 	{ ADAU17X1_DAC_CONTROL1,		0x00 },
@@ -114,12 +110,16 @@ static const struct reg_default adau1761
 	{ ADAU17X1_SERIAL_PORT_PAD,		0xaa },
 	{ ADAU17X1_CONTROL_PORT_PAD0,		0xaa },
 	{ ADAU17X1_CONTROL_PORT_PAD1,		0x00 },
+	{ ADAU1761_JACK_DETECT_PIN,		0x00 },
+	{ ADAU1761_DEJITTER,			0x03 },
 	{ ADAU17X1_DSP_SAMPLING_RATE,		0x01 },
 	{ ADAU17X1_SERIAL_INPUT_ROUTE,		0x00 },
 	{ ADAU17X1_SERIAL_OUTPUT_ROUTE,		0x00 },
 	{ ADAU17X1_DSP_ENABLE,			0x00 },
 	{ ADAU17X1_DSP_RUN,			0x00 },
 	{ ADAU17X1_SERIAL_SAMPLING_RATE,	0x00 },
+	{ ADAU1761_CLK_ENABLE0,			0x00 },
+	{ ADAU1761_CLK_ENABLE1,			0x00 },
 };
 
 static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
author maintainer
#159 lore raw

PATCH 159/583 ASoC: cs35l33: drain threaded IRQ before runtime suspend

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Runyu Xiao <[email protected]>

commit e074c12c428c633e079154301207a6079a208583 upstream.

cs35l33_runtime_suspend() currently switches the codec into regcache_cache_only(true) and powers it down without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l33_irq_thread() can still run after suspend has closed off live register access.

A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1/2 after cache_only has been enabled, ignores the regmap_read() failures, and can still drive the AMP_SHORT_RLS, CAL_ERR_RLS, OTE_RLS, and OTW_RLS release paths.

Use disable_irq() before entering cache_only/power-off so any in-flight threaded handler is drained and no new IRQ thread can run during the suspended state. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only warns if devm_request_threaded_irq() fails, track whether the IRQ was actually installed before disabling or re-enabling it.

Fixes 3333cb7187b9 ("ASoC: cs35l33: Initial commit of the cs35l33 CODEC driver.")
---
 sound/soc/codecs/cs35l33.c |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/codecs/cs35l33.c +12 -2
@@ -40,6 +40,7 @@ struct cs35l33_private {
 	struct regmap *regmap;
 	struct gpio_desc *reset_gpio;
 	bool amp_cal;
+	bool irq_requested;
 	int mclk_int;
 	struct regulator_bulk_data core_supplies[2];
 	int num_core_supplies;
@@ -881,6 +882,9 @@ static int cs35l33_runtime_resume(struct
 		goto err;
 	}
 
+	if (cs35l33->irq_requested)
+		enable_irq(to_i2c_client(dev)->irq);
+
 	return 0;
 
 err:
@@ -900,6 +904,10 @@ static int cs35l33_runtime_suspend(struc
 	/* redo the calibration in next power up */
 	cs35l33->amp_cal = false;
 
+	/* Drain and block the threaded IRQ before cache_only/power-off. */
+	if (cs35l33->irq_requested)
+		disable_irq(to_i2c_client(dev)->irq);
+
 	regcache_cache_only(cs35l33->regmap, true);
 	regcache_mark_dirty(cs35l33->regmap);
 	regulator_bulk_disable(cs35l33->num_core_supplies,
@@ -1154,10 +1162,12 @@ static int cs35l33_i2c_probe(struct i2c_
 	}
 
 	ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
-			cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
-			"cs35l33", cs35l33);
+				cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+				"cs35l33", cs35l33);
 	if (ret != 0)
 		dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+	else
+		cs35l33->irq_requested = true;
 
 	/* We could issue !RST or skip it based on AMP topology */
 	cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
author maintainer
#160 lore raw

PATCH 160/583 ASoC: cs35l34: drain threaded IRQ before runtime suspend

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Runyu Xiao <[email protected]>

commit 4105a4c0678b2808fc8046b60321b4f1cc7dae75 upstream.

cs35l34_runtime_suspend() currently switches the codec into regcache_cache_only(true), asserts reset low, and powers the device off without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l34_irq_thread() can still run after suspend has removed live hardware access.

A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1..4 after cache_only has been enabled, ignores the regmap_read() failures, and can still execute the PROT_RELEASE_CTL release sequence or the BST fault power-down writes.

Use disable_irq() before entering cache_only/reset-low/power-off so any in-flight threaded handler is drained and no new IRQ thread can run while the device is suspended. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only logs request_threaded_irq() failures and keeps going, track whether the IRQ was actually installed before disabling or re-enabling it.

Fixes c1124c09e103 ("ASoC: cs35l34: Initial commit of the cs35l34 CODEC driver.")
---
 sound/soc/codecs/cs35l34.c |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/codecs/cs35l34.c +12 -2
@@ -45,6 +45,7 @@ struct  cs35l34_private {
 	int num_core_supplies;
 	int mclk_int;
 	bool tdm_mode;
+	bool irq_requested;
 	struct gpio_desc *reset_gpio;	/* Active-low reset GPIO */
 };
 
@@ -1032,10 +1033,12 @@ static int cs35l34_i2c_probe(struct i2c_
 	}
 
 	ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
-			cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
-			"cs35l34", cs35l34);
+				cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+				"cs35l34", cs35l34);
 	if (ret != 0)
 		dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+	else
+		cs35l34->irq_requested = true;
 
 	cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
 				"reset", GPIOD_OUT_LOW);
@@ -1140,6 +1143,9 @@ static int cs35l34_runtime_resume(struct
 		dev_err(dev, "Failed to restore register cache\n");
 		goto err;
 	}
+
+	if (cs35l34->irq_requested)
+		enable_irq(to_i2c_client(dev)->irq);
 	return 0;
 err:
 	regcache_cache_only(cs35l34->regmap, true);
@@ -1153,6 +1159,10 @@ static int cs35l34_runtime_suspend(struc
 {
 	struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
 
+	/* Drain and block the threaded IRQ before cache_only/power-off. */
+	if (cs35l34->irq_requested)
+		disable_irq(to_i2c_client(dev)->irq);
+
 	regcache_cache_only(cs35l34->regmap, true);
 	regcache_mark_dirty(cs35l34->regmap);
 
author maintainer
#161 lore raw

PATCH 161/583 ASoC: cx2072x: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit b927853f70078262780a4e623631584a25eb7284 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

The table is grouped by function rather than by address: for every node the amplifier gain registers (0x41c0, 0x45c0, ...) are listed before the power state and stream format registers of the same node (0x4014, 0x4414, ...). This leaves 75 of the 132 entries unreachable. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes a497a4363706 ("ASoC: Add support for Conexant CX2072X CODEC")
---
 sound/soc/codecs/cx2072x.c |  122 ++++++++++++++++++++++-----------------------
 1 file changed, 61 insertions(+), 61 deletions(-)
sound/soc/codecs/cx2072x.c +61 -61
@@ -96,51 +96,60 @@ static const struct reg_default cx2072x_
 	{ CX2072X_GPIO_WAKE, 0x00000000 },
 	{ CX2072X_GPIO_UM_ENABLE, 0x00000000 },
 	{ CX2072X_GPIO_STICKY_MASK, 0x00000000 },
-	{ CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 },
-	{ CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a },
-	{ CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a },
 	{ CX2072X_DAC1_POWER_STATE, 0x00000433 },
 	{ CX2072X_DAC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
 	{ CX2072X_DAC1_EAPD_ENABLE, 0x00000000 },
-	{ CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 },
-	{ CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a },
-	{ CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a },
+	{ CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a },
+	{ CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a },
+	{ CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 },
 	{ CX2072X_DAC2_POWER_STATE, 0x00000433 },
 	{ CX2072X_DAC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
-	{ CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 },
+	{ CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a },
+	{ CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a },
+	{ CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 },
+	{ CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 },
+	{ CX2072X_ADC1_POWER_STATE, 0x00000433 },
+	{ CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_0, 0x0000004a },
-	{ CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_1, 0x0000004a },
-	{ CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_2, 0x0000004a },
-	{ CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_3, 0x0000004a },
-	{ CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_4, 0x0000004a },
-	{ CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_5, 0x0000004a },
-	{ CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_RIGHT_6, 0x0000004a },
+	{ CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a },
+	{ CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a },
+	{ CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a },
+	{ CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a },
+	{ CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a },
+	{ CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a },
 	{ CX2072X_ADC1_AMP_GAIN_LEFT_6, 0x0000004a },
-	{ CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 },
-	{ CX2072X_ADC1_POWER_STATE, 0x00000433 },
-	{ CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
-	{ CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 },
+	{ CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 },
+	{ CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 },
+	{ CX2072X_ADC2_POWER_STATE, 0x00000433 },
+	{ CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
 	{ CX2072X_ADC2_AMP_GAIN_RIGHT_0, 0x0000004a },
-	{ CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a },
 	{ CX2072X_ADC2_AMP_GAIN_RIGHT_1, 0x0000004a },
-	{ CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a },
 	{ CX2072X_ADC2_AMP_GAIN_RIGHT_2, 0x0000004a },
+	{ CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a },
+	{ CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a },
 	{ CX2072X_ADC2_AMP_GAIN_LEFT_2, 0x0000004a },
-	{ CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 },
-	{ CX2072X_ADC2_POWER_STATE, 0x00000433 },
-	{ CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
+	{ CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 },
+	{ CX2072X_MIXER_POWER_STATE, 0x00000433 },
+	{ CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a },
+	{ CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a },
+	{ CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a },
+	{ CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a },
 	{ CX2072X_PORTA_CONNECTION_SELECT_CTRL, 0x00000000 },
 	{ CX2072X_PORTA_POWER_STATE, 0x00000433 },
 	{ CX2072X_PORTA_PIN_CTRL, 0x000000c0 },
 	{ CX2072X_PORTA_UNSOLICITED_RESPONSE, 0x00000000 },
 	{ CX2072X_PORTA_PIN_SENSE, 0x00000000 },
 	{ CX2072X_PORTA_EAPD_BTL, 0x00000002 },
+	{ CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 },
+	{ CX2072X_PORTG_POWER_STATE, 0x00000433 },
+	{ CX2072X_PORTG_PIN_CTRL, 0x00000040 },
+	{ CX2072X_PORTG_EAPD_BTL, 0x00000002 },
 	{ CX2072X_PORTB_POWER_STATE, 0x00000433 },
 	{ CX2072X_PORTB_PIN_CTRL, 0x00000000 },
 	{ CX2072X_PORTB_UNSOLICITED_RESPONSE, 0x00000000 },
@@ -148,43 +157,16 @@ static const struct reg_default cx2072x_
 	{ CX2072X_PORTB_EAPD_BTL, 0x00000002 },
 	{ CX2072X_PORTB_GAIN_RIGHT, 0x00000000 },
 	{ CX2072X_PORTB_GAIN_LEFT, 0x00000000 },
-	{ CX2072X_PORTC_POWER_STATE, 0x00000433 },
-	{ CX2072X_PORTC_PIN_CTRL, 0x00000000 },
-	{ CX2072X_PORTC_GAIN_RIGHT, 0x00000000 },
-	{ CX2072X_PORTC_GAIN_LEFT, 0x00000000 },
 	{ CX2072X_PORTD_POWER_STATE, 0x00000433 },
 	{ CX2072X_PORTD_PIN_CTRL, 0x00000020 },
 	{ CX2072X_PORTD_UNSOLICITED_RESPONSE, 0x00000000 },
 	{ CX2072X_PORTD_PIN_SENSE, 0x00000000 },
 	{ CX2072X_PORTD_GAIN_RIGHT, 0x00000000 },
 	{ CX2072X_PORTD_GAIN_LEFT, 0x00000000 },
-	{ CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 },
-	{ CX2072X_PORTE_POWER_STATE, 0x00000433 },
-	{ CX2072X_PORTE_PIN_CTRL, 0x00000040 },
-	{ CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 },
-	{ CX2072X_PORTE_PIN_SENSE, 0x00000000 },
-	{ CX2072X_PORTE_EAPD_BTL, 0x00000002 },
-	{ CX2072X_PORTE_GAIN_RIGHT, 0x00000000 },
-	{ CX2072X_PORTE_GAIN_LEFT, 0x00000000 },
-	{ CX2072X_PORTF_POWER_STATE, 0x00000433 },
-	{ CX2072X_PORTF_PIN_CTRL, 0x00000000 },
-	{ CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 },
-	{ CX2072X_PORTF_PIN_SENSE, 0x00000000 },
-	{ CX2072X_PORTF_GAIN_RIGHT, 0x00000000 },
-	{ CX2072X_PORTF_GAIN_LEFT, 0x00000000 },
-	{ CX2072X_PORTG_POWER_STATE, 0x00000433 },
-	{ CX2072X_PORTG_PIN_CTRL, 0x00000040 },
-	{ CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 },
-	{ CX2072X_PORTG_EAPD_BTL, 0x00000002 },
-	{ CX2072X_PORTM_POWER_STATE, 0x00000433 },
-	{ CX2072X_PORTM_PIN_CTRL, 0x00000000 },
-	{ CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 },
-	{ CX2072X_PORTM_EAPD_BTL, 0x00000002 },
-	{ CX2072X_MIXER_POWER_STATE, 0x00000433 },
-	{ CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a },
-	{ CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a },
-	{ CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a },
-	{ CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a },
+	{ CX2072X_PORTC_POWER_STATE, 0x00000433 },
+	{ CX2072X_PORTC_PIN_CTRL, 0x00000000 },
+	{ CX2072X_PORTC_GAIN_RIGHT, 0x00000000 },
+	{ CX2072X_PORTC_GAIN_LEFT, 0x00000000 },
 	{ CX2072X_SPKR_DRC_ENABLE_STEP, 0x040065a4 },
 	{ CX2072X_SPKR_DRC_CONTROL, 0x007b0024 },
 	{ CX2072X_SPKR_DRC_TEST, 0x00000000 },
@@ -195,12 +177,15 @@ static const struct reg_default cx2072x_
 	{ CX2072X_I2SPCM_CONTROL3, 0x00000000 },
 	{ CX2072X_I2SPCM_CONTROL4, 0x00000000 },
 	{ CX2072X_I2SPCM_CONTROL5, 0x00000000 },
-	{ CX2072X_I2SPCM_CONTROL6, 0x00000000 },
 	{ CX2072X_UM_INTERRUPT_CRTL_E, 0x00000000 },
+	{ CX2072X_I2SPCM_CONTROL6, 0x00000000 },
+	{ CX2072X_DIGITAL_TEST16, 0x00000021 },
+	{ CX2072X_DIGITAL_TEST17, 0x00000018 },
+	{ CX2072X_DIGITAL_TEST18, 0x00000024 },
+	{ CX2072X_DIGITAL_TEST19, 0x00000001 },
+	{ CX2072X_DIGITAL_TEST20, 0x00000002 },
 	{ CX2072X_CODEC_TEST2, 0x00000000 },
 	{ CX2072X_CODEC_TEST9, 0x00000004 },
-	{ CX2072X_CODEC_TEST20, 0x00000600 },
-	{ CX2072X_CODEC_TEST26, 0x00000208 },
 	{ CX2072X_ANALOG_TEST4, 0x00000000 },
 	{ CX2072X_ANALOG_TEST5, 0x00000000 },
 	{ CX2072X_ANALOG_TEST6, 0x0000059a },
@@ -215,11 +200,26 @@ static const struct reg_default cx2072x_
 	{ CX2072X_DIGITAL_TEST11, 0x00000000 },
 	{ CX2072X_DIGITAL_TEST12, 0x00000084 },
 	{ CX2072X_DIGITAL_TEST15, 0x00000077 },
-	{ CX2072X_DIGITAL_TEST16, 0x00000021 },
-	{ CX2072X_DIGITAL_TEST17, 0x00000018 },
-	{ CX2072X_DIGITAL_TEST18, 0x00000024 },
-	{ CX2072X_DIGITAL_TEST19, 0x00000001 },
-	{ CX2072X_DIGITAL_TEST20, 0x00000002 },
+	{ CX2072X_CODEC_TEST20, 0x00000600 },
+	{ CX2072X_CODEC_TEST26, 0x00000208 },
+	{ CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 },
+	{ CX2072X_PORTE_POWER_STATE, 0x00000433 },
+	{ CX2072X_PORTE_PIN_CTRL, 0x00000040 },
+	{ CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 },
+	{ CX2072X_PORTE_PIN_SENSE, 0x00000000 },
+	{ CX2072X_PORTE_EAPD_BTL, 0x00000002 },
+	{ CX2072X_PORTE_GAIN_RIGHT, 0x00000000 },
+	{ CX2072X_PORTE_GAIN_LEFT, 0x00000000 },
+	{ CX2072X_PORTF_POWER_STATE, 0x00000433 },
+	{ CX2072X_PORTF_PIN_CTRL, 0x00000000 },
+	{ CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 },
+	{ CX2072X_PORTF_PIN_SENSE, 0x00000000 },
+	{ CX2072X_PORTF_GAIN_RIGHT, 0x00000000 },
+	{ CX2072X_PORTF_GAIN_LEFT, 0x00000000 },
+	{ CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 },
+	{ CX2072X_PORTM_POWER_STATE, 0x00000433 },
+	{ CX2072X_PORTM_PIN_CTRL, 0x00000000 },
+	{ CX2072X_PORTM_EAPD_BTL, 0x00000002 },
 };
 
 /*
author maintainer
#162 lore raw

PATCH 162/583 ASoC: fsl: mpc5200-i2s: Free DMA resources on probe failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Haoxiang Li <[email protected]>

commit 3a89ddcf0c3d9a068631e8c24d5c9e81d1e6512a upstream.

mpc5200_audio_dma_create() creates the DMA resources before registering the component. If snd_soc_register_component() fails, the function returns directly and leaves the DMA resources allocated.

Call mpc5200_audio_dma_destroy() before returning from this error path.

Fixes f515b67381de ("ASoC: fsl: mpc5200 combine psc_dma platform data")
---
 sound/soc/fsl/mpc5200_psc_i2s.c |    1 +
 1 file changed, 1 insertion(+)
sound/soc/fsl/mpc5200_psc_i2s.c +1 -0
@@ -170,6 +170,7 @@ static int psc_i2s_of_probe(struct platf
 					psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
 	if (rc != 0) {
 		pr_err("Failed to register DAI\n");
+		mpc5200_audio_dma_destroy(op);
 		return rc;
 	}
 
author maintainer
#163 lore raw

PATCH 163/583 ASoC: fsl_easrc: Use div64_u64 for 64-by-64 division

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: wangdicheng <[email protected]>

commit a46ccc71877e962783e0fffa105e41615904c511 upstream.

Fix a coccinelle warning about do_div() truncating a 64-bit divisor:

sound/soc/fsl/fsl_easrc.c:2061:2-8: WARNING: do_div() does a 64-by-32 division, please consider using div64_u64 instead.

In fsl_easrc_m2m_calc_out_len(), val1 is computed as:

  val1 = (u64)in_rate << frac_bits;   // frac_bits up to 39
  do_div(val1, out_rate);
  val1 += (s64)ctx_priv->ratio_mod << (frac_bits - 31);
  val1 = val1 >> 12;

In the worst case (in_rate=384000, out_rate=8000, frac_bits=39):
val1 = 384000 << 39 / 8000 = 26,388,279,068,672
val1 >> 12 = 6,440,497,829 (33 bits, exceeds 32-bit range)

val1 is then used as the divisor in do_div(val2, val1), where do_div() silently truncates it to 32 bits, producing incorrect results. Use div64_u64() to perform a proper 64-by-64 division.

Fixes 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers")
---
 sound/soc/fsl/fsl_easrc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/fsl/fsl_easrc.c +1 -1
@@ -2055,7 +2055,7 @@ static int fsl_easrc_m2m_calc_out_len(st
 		/* right shift 12 bit to make ratio in 32bit space */
 		val2 = (u64)in_samples << (frac_bits - 12);
 		val1 = val1 >> 12;
-		do_div(val2, val1);
+		val2 = div64_u64(val2, val1);
 		out_samples = val2;
 
 		out_length = out_samples * out_width * channels;
author maintainer
#164 lore raw

PATCH 164/583 ASoC: fsl_easrc: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 84c5d79aebe6c45e12e3112d14e68972f33c210a upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

The four REG_EASRC_RRL() entries are listed as a block before the four REG_EASRC_RRH() ones, but the two registers of a context alternate in the address map (RRL(n) at 0x110 + 8 * n, RRH(n) at 0x114 + 8 * n). This leaves REG_EASRC_RRL(1), REG_EASRC_RRL(2) and REG_EASRC_RRL(3) unreachable. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers")
---
 sound/soc/fsl/fsl_easrc.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/fsl/fsl_easrc.c +3 -3
@@ -1708,12 +1708,12 @@ static const struct reg_default fsl_easr
 	{REG_EASRC_SFS(2),	0x00000000},
 	{REG_EASRC_SFS(3),	0x00000000},
 	{REG_EASRC_RRL(0),	0x00000000},
-	{REG_EASRC_RRL(1),	0x00000000},
-	{REG_EASRC_RRL(2),	0x00000000},
-	{REG_EASRC_RRL(3),	0x00000000},
 	{REG_EASRC_RRH(0),	0x00000000},
+	{REG_EASRC_RRL(1),	0x00000000},
 	{REG_EASRC_RRH(1),	0x00000000},
+	{REG_EASRC_RRL(2),	0x00000000},
 	{REG_EASRC_RRH(2),	0x00000000},
+	{REG_EASRC_RRL(3),	0x00000000},
 	{REG_EASRC_RRH(3),	0x00000000},
 	{REG_EASRC_RUC(0),	0x00000000},
 	{REG_EASRC_RUC(1),	0x00000000},
author maintainer
#165 lore raw

PATCH 165/583 ASoC: hdac_hda: Fix hlink refcount leak on component registration failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Haoxiang Li <[email protected]>

commit 6ad4892c4f5cb437a928a02f5b7d37d496aa9268 upstream.

hdac_hda_dev_probe() gets the HDA link with snd_hdac_ext_bus_link_get() before registering the ASoC component. If component registration fails, the function returns without dropping the link reference.

Always call snd_hdac_ext_bus_link_put() after the registration attempt so the reference taken during probe is balanced on both success and failure.

Fixes 6bae5ea94989 ("ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers")
---
 sound/soc/codecs/hdac_hda.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
sound/soc/codecs/hdac_hda.c +1 -3
@@ -644,10 +644,8 @@ static int hdac_hda_dev_probe(struct hda
 						&hdac_hda_codec, hdac_hda_dais,
 						ARRAY_SIZE(hdac_hda_dais));
 
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret);
-		return ret;
-	}
 
 	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 
author maintainer
#166 lore raw

PATCH 166/583 AsoC: intel: sst: fix PCI device reference leak on probe failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Haoxiang Li <[email protected]>

commit 016f29997ebd29d6ab59c8162ce0e7f73bd1e517 upstream.

intel_sst_probe() takes a reference to the PCI device with pci_dev_get(). If sst_platform_get_resources() fails afterwards, the probe error path cleans up the driver context but does not drop the PCI device reference.

Add a pci_dev_put() error path for failures after pci_dev_get().

Fixes f533a035e4da ("ASoC: Intel: mrfld - create separate module for pci part")
---
 sound/soc/intel/atom/sst/sst_pci.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/intel/atom/sst/sst_pci.c +3 -1
@@ -130,13 +130,15 @@ static int intel_sst_probe(struct pci_de
 	sst_drv_ctx->pci = pci_dev_get(pci);
 	ret = sst_platform_get_resources(sst_drv_ctx);
 	if (ret < 0)
-		goto do_free_drv_ctx;
+		goto do_put_pci;
 
 	pci_set_drvdata(pci, sst_drv_ctx);
 	sst_configure_runtime_pm(sst_drv_ctx);
 
 	return ret;
 
+do_put_pci:
+	pci_dev_put(sst_drv_ctx->pci);
 do_free_drv_ctx:
 	sst_context_cleanup(sst_drv_ctx);
 	dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
author maintainer
#167 lore raw

PATCH 167/583 ASoC: loongson: Fix error handling in ACPI property parsing

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Binbin Zhou <[email protected]>

commit 0eb0e3c623ac1da8b85d518043fef7660af7805d upstream.

In loongson_card_parse_acpi(), the return value of device_property_read_string() for the codec-dai-name property was ignored. If the property is missing or invalid, an uninitialized pointer would be used later, potentially leading to undefined behavior.

Fix this by checking the return value and propagating the error appropriately.

---
 sound/soc/loongson/loongson_card.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
sound/soc/loongson/loongson_card.c +4 -2
@@ -91,7 +91,7 @@ static int loongson_card_parse_acpi(stru
 	const char *codec_dai_name;
 	struct acpi_device *adev;
 	struct device *phy_dev;
-	int i;
+	int i, ret;
 
 	/* fixup platform name based on reference node */
 	adev = loongson_card_acpi_find_device(card, "cpu");
@@ -108,7 +108,9 @@ static int loongson_card_parse_acpi(stru
 		return -ENOENT;
 	snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev));
 
-	device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+	ret = device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+	if (ret)
+		return ret;
 
 	for (i = 0; i < card->num_links; i++) {
 		loongson_dai_links[i].platforms->name = dev_name(phy_dev);
author maintainer
#168 lore raw

PATCH 168/583 ASoC: max9860: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 5c4cf173b7eba9bd1e8824b75380412cae2e026b upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

MAX9860_PWRMAN (0x10) is listed as the first entry, before MAX9860_INTEN (0x02), which makes MAX9860_INTEN unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

---
 sound/soc/codecs/max9860.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/max9860.c +1 -1
@@ -48,7 +48,6 @@ static int max9860_dvddio_event(struct n
 }
 
 static const struct reg_default max9860_reg_defaults[] = {
-	{ MAX9860_PWRMAN,       0x00 },
 	{ MAX9860_INTEN,        0x00 },
 	{ MAX9860_SYSCLK,       0x00 },
 	{ MAX9860_AUDIOCLKHIGH, 0x00 },
@@ -62,6 +61,7 @@ static const struct reg_default max9860_
 	{ MAX9860_MICGAIN,      0x00 },
 	{ MAX9860_MICADC,       0x00 },
 	{ MAX9860_NOISEGATE,    0x00 },
+	{ MAX9860_PWRMAN,       0x00 },
 };
 
 static bool max9860_readable(struct device *dev, unsigned int reg)
author maintainer
#169 lore raw

PATCH 169/583 ASoC: ml26124: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit d4d0e6e2355a6fe6517e5a0c3d9a0b8ab073b0b6 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

The Mic Select Control register (0xe8) is listed in the analog path control group, between 0x5a and 0x60, which makes it unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Move the entry to the end of the table, where it belongs by address.

Fixes d808fe9f3e7f ("ASoC: Add LAPIS Semiconductor ML26124 driver")
---
 sound/soc/codecs/ml26124.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/codecs/ml26124.c +3 -1
@@ -224,7 +224,6 @@ static const struct reg_default ml26124_
 	/* Analog Path Control Register */
 	{0x54, 0x00},	/* Speaker AMP Output Control */
 	{0x5a, 0x00},	/* Mic IF Control */
-	{0xe8, 0x01},	/* Mic Select Control */
 
 	/* Audio Interface Control Register */
 	{0x60, 0x00},	/* SAI-Trans Control */
@@ -287,6 +286,9 @@ static const struct reg_default ml26124_
 	{0xd0, 0x01},	/* VIDEO AMP Gain Control */
 	{0xd2, 0x01},	/* VIDEO AMP Setup 1 */
 	{0xd4, 0x01},	/* VIDEO AMP Control2 */
+
+	/* Analog Path Control Register */
+	{0xe8, 0x01},	/* Mic Select Control */
 };
 
 /* Get sampling rate value of sampling rate setting register (0x0) */
author maintainer
#170 lore raw

PATCH 170/583 ASoC: pcm512x: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 767d9ae714e3e9b0ae86237c410fbfca7056570a upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

PCM512x_AUTO_MUTE (page 0, register 59) is listed before PCM512x_ERROR_DETECT (page 0, register 37) and PCM512x_VCOM_CTRL_2 (page 1, register 9) is listed before the page 0 clocking block, so the bsearch() descends into the wrong half of the table. 24 of the 45 entries are unreachable, among them every PLL coefficient and clock divider default. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/pcm512x.c |   40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)
sound/soc/codecs/pcm512x.c +20 -20
@@ -78,28 +78,10 @@ static const struct reg_default pcm512x_
 	{ PCM512x_POWER,             0x00 },
 	{ PCM512x_MUTE,              0x00 },
 	{ PCM512x_DSP,               0x00 },
-	{ PCM512x_PLL_REF,           0x00 },
-	{ PCM512x_DAC_REF,           0x00 },
-	{ PCM512x_DAC_ROUTING,       0x11 },
-	{ PCM512x_DSP_PROGRAM,       0x01 },
-	{ PCM512x_CLKDET,            0x00 },
-	{ PCM512x_AUTO_MUTE,         0x00 },
-	{ PCM512x_ERROR_DETECT,      0x00 },
-	{ PCM512x_DIGITAL_VOLUME_1,  0x00 },
-	{ PCM512x_DIGITAL_VOLUME_2,  0x30 },
-	{ PCM512x_DIGITAL_VOLUME_3,  0x30 },
-	{ PCM512x_DIGITAL_MUTE_1,    0x22 },
-	{ PCM512x_DIGITAL_MUTE_2,    0x00 },
-	{ PCM512x_DIGITAL_MUTE_3,    0x07 },
-	{ PCM512x_OUTPUT_AMPLITUDE,  0x00 },
-	{ PCM512x_ANALOG_GAIN_CTRL,  0x00 },
-	{ PCM512x_UNDERVOLTAGE_PROT, 0x00 },
-	{ PCM512x_ANALOG_MUTE_CTRL,  0x00 },
-	{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
-	{ PCM512x_VCOM_CTRL_1,       0x00 },
-	{ PCM512x_VCOM_CTRL_2,       0x01 },
 	{ PCM512x_BCLK_LRCLK_CFG,    0x00 },
 	{ PCM512x_MASTER_MODE,       0x7c },
+	{ PCM512x_PLL_REF,           0x00 },
+	{ PCM512x_DAC_REF,           0x00 },
 	{ PCM512x_GPIO_DACIN,        0x00 },
 	{ PCM512x_GPIO_PLLIN,        0x00 },
 	{ PCM512x_SYNCHRONIZE,       0x10 },
@@ -117,8 +99,26 @@ static const struct reg_default pcm512x_
 	{ PCM512x_FS_SPEED_MODE,     0x00 },
 	{ PCM512x_IDAC_1,            0x01 },
 	{ PCM512x_IDAC_2,            0x00 },
+	{ PCM512x_ERROR_DETECT,      0x00 },
 	{ PCM512x_I2S_1,             0x02 },
 	{ PCM512x_I2S_2,             0x00 },
+	{ PCM512x_DAC_ROUTING,       0x11 },
+	{ PCM512x_DSP_PROGRAM,       0x01 },
+	{ PCM512x_CLKDET,            0x00 },
+	{ PCM512x_AUTO_MUTE,         0x00 },
+	{ PCM512x_DIGITAL_VOLUME_1,  0x00 },
+	{ PCM512x_DIGITAL_VOLUME_2,  0x30 },
+	{ PCM512x_DIGITAL_VOLUME_3,  0x30 },
+	{ PCM512x_DIGITAL_MUTE_1,    0x22 },
+	{ PCM512x_DIGITAL_MUTE_2,    0x00 },
+	{ PCM512x_DIGITAL_MUTE_3,    0x07 },
+	{ PCM512x_OUTPUT_AMPLITUDE,  0x00 },
+	{ PCM512x_ANALOG_GAIN_CTRL,  0x00 },
+	{ PCM512x_UNDERVOLTAGE_PROT, 0x00 },
+	{ PCM512x_ANALOG_MUTE_CTRL,  0x00 },
+	{ PCM512x_ANALOG_GAIN_BOOST, 0x00 },
+	{ PCM512x_VCOM_CTRL_1,       0x00 },
+	{ PCM512x_VCOM_CTRL_2,       0x01 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
author maintainer
#171 lore raw

PATCH 171/583 ASoC: pm4125-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 8dd18d9956bfd74531bfd7088e59586e3e115789 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

PM4125_SWR_HPHPA_HD2 (0x3090) is listed before PM4125_ANA_HPHPA_SPARE_CTL (0x308e), which makes the latter unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

Fixes 8ad529484937 ("ASoC: codecs: add new pm4125 audio codec driver")
---
 sound/soc/codecs/pm4125-sdw.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/pm4125-sdw.c +1 -1
@@ -154,8 +154,8 @@ static const struct reg_default pm4125_d
 	{ PM4125_ANA_HPHPA_FSM_CLK,              0x12 },
 	{ PM4125_ANA_HPHPA_L_GAIN,               0x00 },
 	{ PM4125_ANA_HPHPA_R_GAIN,               0x00 },
-	{ PM4125_SWR_HPHPA_HD2,                  0x1B },
 	{ PM4125_ANA_HPHPA_SPARE_CTL,            0x02 },
+	{ PM4125_SWR_HPHPA_HD2,                  0x1B },
 	{ PM4125_ANA_SURGE_EN,                   0x38 },
 	{ PM4125_ANA_COMBOPA_CTL,                0x35 },
 	{ PM4125_ANA_COMBOPA_CTL_4,              0x84 },
author maintainer
#172 lore raw

PATCH 172/583 ASoC: rt1017-sdca-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 5b48ce0356b134155722a61f7196516a7c2e66c5 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

rt1017_sdca_reg_defaults[] places the SDCA controls before the lower vendor registers instead, so the binary search does not find 4 of its entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes 2b7aecd58528 ("ASoC: rt1017: Add RT1017 SDCA amplifier driver")
---
 sound/soc/codecs/rt1017-sdca-sdw.h |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
sound/soc/codecs/rt1017-sdca-sdw.h +5 -5
@@ -165,19 +165,19 @@ static const struct reg_default rt1017_s
 	{ 0xdb09, 0x0f },
 	{ 0xdb0a, 0xff },
 	{ 0xdb14, 0x00 },
-
-	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
-			RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
 			RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
 			RT1017_SDCA_CTL_BYPASS, 0), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
-			RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
 			RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
 			RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+
+	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+			RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+			RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
 };
 
 #endif /* __RT1017_SDW_H__ */
author maintainer
#173 lore raw

PATCH 173/583 ASoC: rt1316-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 7b48eccfbb9bf15e9b7377a5296bfd01815c62d8 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

rt1316_reg_defaults[] is not in address order, so the binary search does not find one of its entries. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

Fixes 2b719fd20f32 ("ASoC: rt1316: Add RT1316 SDCA vendor-specific driver")
---
 sound/soc/codecs/rt1316-sdw.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/rt1316-sdw.c +1 -1
@@ -60,13 +60,13 @@ static const struct reg_default rt1316_r
 	{ 0xd101, 0x00 },
 	{ 0xd102, 0x30 },
 	{ 0xd103, 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
 };
 
 static const struct reg_sequence rt1316_blind_write[] = {
author maintainer
#174 lore raw

PATCH 174/583 ASoC: rt1318-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 3673b33633a5daf2f52aff03b57f7b25352fe234 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

rt1318_reg_defaults[] is not in address order, so the binary search does not find 3 of its entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes 6ad73a2b42ea ("ASoC: rt1318: Add RT1318 SDCA vendor-specific driver")
---
 sound/soc/codecs/rt1318-sdw.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/rt1318-sdw.c +1 -1
@@ -236,10 +236,10 @@ static const struct reg_default rt1318_r
 	{ 0xf805, 0x00 },
 	{ 0xf806, 0x07 },
 	{ 0xf807, 0xff },
-	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 };
 
author maintainer
#175 lore raw

PATCH 175/583 ASoC: rt1318: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 2a8e4b7114f6493314348bda7e3d2141d218ef61 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

The 0xdd93 and 0xdd94 entries are listed after 0xddc8 in rt1318_reg[], which leaves them unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes fe1ff61487ac ("ASoC: rt1318: Add RT1318 audio amplifier driver")
---
 sound/soc/codecs/rt1318.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/codecs/rt1318.c +2 -2
@@ -338,6 +338,8 @@ static const struct reg_default rt1318_r
 	{ 0xdd08, 0x40 },
 	{ 0xdd12, 0x00 },
 	{ 0xdd35, 0x00 },
+	{ 0xdd93, 0x00 },
+	{ 0xdd94, 0x64 },
 	{ 0xddb5, 0x00 },
 	{ 0xddb6, 0x40 },
 	{ 0xddb7, 0x00 },
@@ -346,8 +348,6 @@ static const struct reg_default rt1318_r
 	{ 0xddc6, 0x00 },
 	{ 0xddc7, 0x00 },
 	{ 0xddc8, 0x00 },
-	{ 0xdd93, 0x00 },
-	{ 0xdd94, 0x64 },
 	{ 0xdf00, 0x00 },
 	{ 0xdf5f, 0x00 },
 	{ 0xdf60, 0x00 },
author maintainer
#176 lore raw

PATCH 176/583 ASoC: rt274: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 6a147d177819b0d831831d19fbb9c23f08a03734 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

Four entries were appended to the end of rt274_reg[] instead of being inserted at their sorted position, which leaves 7 of the 33 entries unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt274.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
sound/soc/codecs/rt274.c +4 -4
@@ -184,8 +184,10 @@ static const struct reg_default rt274_re
 	{ 0x0023a000, 0x00000057 },
 	{ 0x00270500, 0x00000400 },
 	{ 0x00370500, 0x00000400 },
+	{ 0x00830000, 0x00000097 },
 	{ 0x00870500, 0x00000400 },
 	{ 0x00920000, 0x00000031 },
+	{ 0x00930000, 0x00000097 },
 	{ 0x00935000, 0x00000097 },
 	{ 0x00936000, 0x00000097 },
 	{ 0x00970500, 0x00000400 },
@@ -195,10 +197,12 @@ static const struct reg_default rt274_re
 	{ 0x00c37000, 0x00000400 },
 	{ 0x00c37100, 0x00000400 },
 	{ 0x01270500, 0x00000400 },
+	{ 0x01270700, 0x00000000 },
 	{ 0x01370500, 0x00000400 },
 	{ 0x01371f00, 0x411111f0 },
 	{ 0x01937000, 0x00000000 },
 	{ 0x01970500, 0x00000400 },
+	{ 0x01970700, 0x00000020 },
 	{ 0x02050000, 0x0000001b },
 	{ 0x02139000, 0x00000080 },
 	{ 0x0213a000, 0x00000080 },
@@ -207,10 +211,6 @@ static const struct reg_default rt274_re
 	{ 0x02170700, 0x00000000 },
 	{ 0x02270100, 0x00000000 },
 	{ 0x02370100, 0x00000000 },
-	{ 0x01970700, 0x00000020 },
-	{ 0x00830000, 0x00000097 },
-	{ 0x00930000, 0x00000097 },
-	{ 0x01270700, 0x00000000 },
 };
 
 static bool rt274_volatile_register(struct device *dev, unsigned int reg)
author maintainer
#177 lore raw

PATCH 177/583 ASoC: rt286: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit c30771968b5355617843a0ddfa0b9dcbcfd3ea84 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

Four entries were appended to the end of rt286_reg[] instead of being inserted at their sorted position and the 0x01470100 entry is listed after 0x01470c00, which leaves 7 of the 39 entries unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt286.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
sound/soc/codecs/rt286.c +6 -6
@@ -77,8 +77,10 @@ static const struct reg_default rt286_re
 	{ 0x0023a000, 0x0000007f },
 	{ 0x00270500, 0x00000400 },
 	{ 0x00370500, 0x00000400 },
+	{ 0x00830000, 0x000000c3 },
 	{ 0x00870500, 0x00000400 },
 	{ 0x00920000, 0x00000031 },
+	{ 0x00930000, 0x000000c3 },
 	{ 0x00935000, 0x000000c3 },
 	{ 0x00936000, 0x000000c3 },
 	{ 0x00970500, 0x00000400 },
@@ -88,16 +90,18 @@ static const struct reg_default rt286_re
 	{ 0x00c37000, 0x00000000 },
 	{ 0x00c37100, 0x00000080 },
 	{ 0x01270500, 0x00000400 },
+	{ 0x01270700, 0x00000000 },
 	{ 0x01370500, 0x00000400 },
 	{ 0x01371f00, 0x411111f0 },
 	{ 0x01439000, 0x00000080 },
 	{ 0x0143a000, 0x00000080 },
-	{ 0x01470700, 0x00000000 },
+	{ 0x01470100, 0x00000000 },
 	{ 0x01470500, 0x00000400 },
+	{ 0x01470700, 0x00000000 },
 	{ 0x01470c00, 0x00000000 },
-	{ 0x01470100, 0x00000000 },
 	{ 0x01837000, 0x00000000 },
 	{ 0x01870500, 0x00000400 },
+	{ 0x01870700, 0x00000020 },
 	{ 0x02050000, 0x00000000 },
 	{ 0x02139000, 0x00000080 },
 	{ 0x0213a000, 0x00000080 },
@@ -106,10 +110,6 @@ static const struct reg_default rt286_re
 	{ 0x02170700, 0x00000000 },
 	{ 0x02270100, 0x00000000 },
 	{ 0x02370100, 0x00000000 },
-	{ 0x01870700, 0x00000020 },
-	{ 0x00830000, 0x000000c3 },
-	{ 0x00930000, 0x000000c3 },
-	{ 0x01270700, 0x00000000 },
 };
 
 static bool rt286_volatile_register(struct device *dev, unsigned int reg)
author maintainer
#178 lore raw

PATCH 178/583 ASoC: rt298: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit aa4c472b0f4a469c2e4599406fa4cff9de3e02bd upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

Four entries were appended to the end of rt298_reg[] instead of being inserted at their sorted position and the 0x01470100 entry is listed after 0x01470c00, which leaves 7 of the 39 entries unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt298.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
sound/soc/codecs/rt298.c +6 -6
@@ -78,8 +78,10 @@ static const struct reg_default rt298_re
 	{ 0x0023a000, 0x0000007f },
 	{ 0x00270500, 0x00000400 },
 	{ 0x00370500, 0x00000400 },
+	{ 0x00830000, 0x000000c3 },
 	{ 0x00870500, 0x00000400 },
 	{ 0x00920000, 0x00000031 },
+	{ 0x00930000, 0x000000c3 },
 	{ 0x00935000, 0x000000c3 },
 	{ 0x00936000, 0x000000c3 },
 	{ 0x00970500, 0x00000400 },
@@ -89,16 +91,18 @@ static const struct reg_default rt298_re
 	{ 0x00c37000, 0x00000000 },
 	{ 0x00c37100, 0x00000080 },
 	{ 0x01270500, 0x00000400 },
+	{ 0x01270700, 0x00000000 },
 	{ 0x01370500, 0x00000400 },
 	{ 0x01371f00, 0x411111f0 },
 	{ 0x01439000, 0x00000080 },
 	{ 0x0143a000, 0x00000080 },
-	{ 0x01470700, 0x00000000 },
+	{ 0x01470100, 0x00000000 },
 	{ 0x01470500, 0x00000400 },
+	{ 0x01470700, 0x00000000 },
 	{ 0x01470c00, 0x00000000 },
-	{ 0x01470100, 0x00000000 },
 	{ 0x01837000, 0x00000000 },
 	{ 0x01870500, 0x00000400 },
+	{ 0x01870700, 0x00000020 },
 	{ 0x02050000, 0x00000000 },
 	{ 0x02139000, 0x00000080 },
 	{ 0x0213a000, 0x00000080 },
@@ -107,10 +111,6 @@ static const struct reg_default rt298_re
 	{ 0x02170700, 0x00000000 },
 	{ 0x02270100, 0x00000000 },
 	{ 0x02370100, 0x00000000 },
-	{ 0x01870700, 0x00000020 },
-	{ 0x00830000, 0x000000c3 },
-	{ 0x00930000, 0x000000c3 },
-	{ 0x01270700, 0x00000000 },
 };
 
 static bool rt298_volatile_register(struct device *dev, unsigned int reg)
author maintainer
#179 lore raw

PATCH 179/583 ASoC: rt700: drop duplicate reg_default entry

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 90ad6a29809dc53e8c1af23fc51bafe2133da035 upstream.

rt700_reg_defaults[] lists register 0x7303 twice with the same value. The identical rt711 table has the entry only once, so this is a copy-paste error.

Drop the duplicate. No functional change, regcache_lookup_reg() only ever finds one of the two entries.

---
 sound/soc/codecs/rt700-sdw.h |    1 -
 1 file changed, 1 deletion(-)
sound/soc/codecs/rt700-sdw.h +0 -1
@@ -313,7 +313,6 @@ static const struct reg_default rt700_re
 	{ 0x3122, 0x0000 },
 	{ 0x3123, 0x0000 },
 	{ 0x7303, 0x0057 },
-	{ 0x7303, 0x0057 },
 	{ 0x8383, 0x0057 },
 	{ 0x7308, 0x0097 },
 	{ 0x8388, 0x0097 },
author maintainer
#180 lore raw

PATCH 180/583 ASoC: rt700: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 18f21e34493b812d9c8ab9f083871470b016bed4 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

At the end of rt700_reg_defaults[] the 0x83xx entries are interleaved with the 0x73xx entries they belong to, which leaves 6 of the entries unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt700-sdw.h |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
sound/soc/codecs/rt700-sdw.h +5 -5
@@ -313,16 +313,16 @@ static const struct reg_default rt700_re
 	{ 0x3122, 0x0000 },
 	{ 0x3123, 0x0000 },
 	{ 0x7303, 0x0057 },
-	{ 0x8383, 0x0057 },
 	{ 0x7308, 0x0097 },
-	{ 0x8388, 0x0097 },
 	{ 0x7309, 0x0097 },
-	{ 0x8389, 0x0097 },
 	{ 0x7312, 0x0000 },
-	{ 0x8392, 0x0000 },
 	{ 0x7313, 0x0000 },
-	{ 0x8393, 0x0000 },
 	{ 0x7319, 0x0000 },
+	{ 0x8383, 0x0057 },
+	{ 0x8388, 0x0097 },
+	{ 0x8389, 0x0097 },
+	{ 0x8392, 0x0000 },
+	{ 0x8393, 0x0000 },
 	{ 0x8399, 0x0000 },
 	{ 0x75201a, 0x8003 },
 	{ 0x752045, 0x5289 },
author maintainer
#181 lore raw

PATCH 181/583 ASoC: rt711-sdca: sort the register default tables

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit b8fdd467bb5d2eb89b665331065e9e3ade964a3e upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

Both tables group the entries by SDCA entity instead: in rt711_sdca_reg_defaults[] the CS01 sample frequency index is listed before the FU05 controls (1 of 54 entries unreachable), and in rt711_sdca_mbq_defaults[] the MIC_ARRAY FU1E volumes are listed before the JACK_CODEC FU0F volumes (2 of 25 entries unreachable). regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort both tables by register address.

Fixes 7ad4d237e7c4 ("ASoC: rt711-sdca: Add RT711 SDCA vendor-specific driver")
---
 sound/soc/codecs/rt711-sdca-sdw.h |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/codecs/rt711-sdca-sdw.h +3 -3
@@ -58,12 +58,12 @@ static const struct reg_default rt711_sd
 	{ 0x2f0f, 0x00 },
 	{ 0x2f50, 0x03 },
 	{ 0x2f5a, 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, RT711_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
 };
@@ -86,14 +86,14 @@ static const struct reg_default rt711_sd
 	{ 0x610003f, 0xff12 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
 };
 
 #endif /* __RT711_SDW_SDCA_H__ */
author maintainer
#182 lore raw

PATCH 182/583 ASoC: rt711: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 55fe63530772fe95a99abe9497872975f3161a56 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

At the end of rt711_reg_defaults[] the 0x83xx entries are interleaved with the 0x73xx entries they belong to, which leaves 5 of the 269 entries unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt711-sdw.h |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
sound/soc/codecs/rt711-sdw.h +5 -5
@@ -256,16 +256,16 @@ static const struct reg_default rt711_re
 	{ 0x3122, 0x00 },
 	{ 0x3123, 0x00 },
 	{ 0x7303, 0x57 },
-	{ 0x8383, 0x57 },
 	{ 0x7308, 0x97 },
-	{ 0x8388, 0x97 },
 	{ 0x7309, 0x97 },
-	{ 0x8389, 0x97 },
 	{ 0x7312, 0x00 },
-	{ 0x8392, 0x00 },
 	{ 0x7313, 0x00 },
-	{ 0x8393, 0x00 },
 	{ 0x7319, 0x00 },
+	{ 0x8383, 0x57 },
+	{ 0x8388, 0x97 },
+	{ 0x8389, 0x97 },
+	{ 0x8392, 0x00 },
+	{ 0x8393, 0x00 },
 	{ 0x8399, 0x00 },
 	{ 0x752008, 0xa807 },
 	{ 0x752009, 0x1029 },
author maintainer
#183 lore raw

PATCH 183/583 ASoC: rt712-sdca-dmic: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit b9339ee3fccc79e751a2f7bde42c5dd57b38b2a9 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

rt712_sdca_dmic_reg_defaults[] is grouped by SDCA entity instead, so the binary search does not find 3 of its entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes 63a511284c9e ("ASoC: rt712-sdca: Add RT712 SDCA driver for Mic topology")
---
 sound/soc/codecs/rt712-sdca-dmic.h |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
sound/soc/codecs/rt712-sdca-dmic.h +4 -2
@@ -36,6 +36,7 @@ struct rt712_sdca_dmic_kctrl_priv {
 #define CH_03	0x03
 #define CH_04	0x04
 
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
 static const struct reg_default rt712_sdca_dmic_reg_defaults[] = {
 	{ 0x201a, 0x00 },
 	{ 0x201b, 0x00 },
@@ -72,15 +73,16 @@ static const struct reg_default rt712_sd
 	{ 0x2f59, 0x07 },
 	{ 0x3201, 0x01 },
 	{ 0x320c, 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 };
 
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
 static const struct reg_default rt712_sdca_dmic_mbq_defaults[] = {
 	{ 0x0590001e, 0x0020 },
 	{ 0x06100000, 0x0010 },
author maintainer
#184 lore raw

PATCH 184/583 ASoC: rt712-sdca-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit efd430c4d0426e60fbec400c5a8ce62d886f6e21 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

rt712_sdca_reg_defaults[] is grouped by SDCA function instead, so the binary search does not find 4 of its entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

One of them is the Mic Array Clock Source 0x1C Sample Frequency Index control, which a part without that function rejects:

soundwire_intel.link.0: Msg ignored for Slave 6, addr: 0x8e00

Sort the table by register address.

Fixes 936abb09c1c7 ("ASoC: rt712-sdca: add the function for version B")
---
 sound/soc/codecs/rt712-sdca-sdw.h |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
sound/soc/codecs/rt712-sdca-sdw.h +6 -5
@@ -11,21 +11,21 @@
 #include <linux/regmap.h>
 #include <linux/soundwire/sdw_registers.h>
 
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
 static const struct reg_default rt712_sdca_reg_defaults[] = {
-
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
@@ -34,6 +34,7 @@ static const struct reg_default rt712_sd
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 };
 
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
 static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ 0x2000004, 0xaa01 },
 	{ 0x200000e, 0x21e0 },
author maintainer
#185 lore raw

PATCH 185/583 ASoC: rt715-sdca: drop duplicate reg_default entries

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit c9875bba469c19ad7f771b91b1e4c6f1c0f0a07d upstream.

The last two entries of rt715_reg_defaults_sdca[] repeat the ADC7_27 volume mute controls for CH_01 and CH_02, which are already listed a few lines above with the same value.

Drop the duplicates. No functional change, regcache_lookup_reg() only ever finds one of the two copies.

Fixes 20d17057f0a8 ("ASoC: rt715-sdca: Add RT715 sdca vendor-specific driver")
---
 sound/soc/codecs/rt715-sdca-sdw.h |    4 ----
 1 file changed, 4 deletions(-)
sound/soc/codecs/rt715-sdca-sdw.h +0 -4
@@ -102,10 +102,6 @@ static const struct reg_default rt715_re
 		RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
 		RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 },
-	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
-		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
-	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
-		RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
 };
 
 static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
author maintainer
#186 lore raw

PATCH 186/583 ASoC: rt715-sdca: sort the register default tables

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 61a0321e4bc2ff9ecb38cda7d5a32ffacef71a75 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

Both tables group the entries by SDCA entity instead: in rt715_reg_defaults_sdca[] the CX_CLK_SEL control is listed before the ADC8_9, ADC10_11 and ADC7_27 mute controls (7 of 78 entries unreachable), and in rt715_mbq_reg_defaults_sdca[] the AMIC_GAIN_EN CH_08 entry is listed before the DMIC_GAIN_EN entries (1 of 32 entries unreachable). regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort both tables by register address.

Fixes 20d17057f0a8 ("ASoC: rt715-sdca: Add RT715 sdca vendor-specific driver")
---
 sound/soc/codecs/rt715-sdca-sdw.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
sound/soc/codecs/rt715-sdca-sdw.h +4 -4
@@ -76,8 +76,6 @@ static const struct reg_default rt715_re
 	{ 0x2f52, 0x01 },
 	{ 0x2f5a, 0x02 },
 	{ 0x2f5b, 0x05 },
-	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
-		RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
 		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
@@ -98,6 +96,8 @@ static const struct reg_default rt715_re
 		RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
 		RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+		RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
 		RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
@@ -145,8 +145,6 @@ static const struct reg_default rt715_mb
 		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
 		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
-	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
-		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
 		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
@@ -161,6 +159,8 @@ static const struct reg_default rt715_mb
 		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
 		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
 	{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
 		RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
 };
author maintainer
#187 lore raw

PATCH 187/583 ASoC: rt715: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit d729804a92dc4e74b8fb69da162f74660ea64385 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

At the end of rt715_reg_defaults[] the 0x82xx and 0x83xx entries are interleaved with the 0x72xx and 0x73xx entries they belong to, and 0x385e is listed before 0x3859. This leaves 25 of the 323 entries unreachable for the binary search. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt715-sdw.h |   32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)
sound/soc/codecs/rt715-sdw.h +16 -16
@@ -281,8 +281,8 @@ static const struct reg_default rt715_re
 	{ 0x371b, 0x00 },
 	{ 0x371d, 0x00 },
 	{ 0x3729, 0x00 },
-	{ 0x385e, 0x00 },
 	{ 0x3859, 0x00 },
+	{ 0x385e, 0x00 },
 	{ 0x4c12, 0x411111f0 },
 	{ 0x4c13, 0x411111f0 },
 	{ 0x4c1d, 0x411111f0 },
@@ -300,36 +300,36 @@ static const struct reg_default rt715_re
 	{ 0x4f1d, 0x411111f0 },
 	{ 0x4f29, 0x411111f0 },
 	{ 0x7207, 0x00 },
-	{ 0x8287, 0x00 },
 	{ 0x7208, 0x00 },
-	{ 0x8288, 0x00 },
 	{ 0x7209, 0x00 },
-	{ 0x8289, 0x00 },
 	{ 0x7227, 0x00 },
-	{ 0x82a7, 0x00 },
 	{ 0x7307, 0x97 },
-	{ 0x8387, 0x97 },
 	{ 0x7308, 0x97 },
-	{ 0x8388, 0x97 },
 	{ 0x7309, 0x97 },
-	{ 0x8389, 0x97 },
 	{ 0x7312, 0x00 },
-	{ 0x8392, 0x00 },
 	{ 0x7313, 0x00 },
-	{ 0x8393, 0x00 },
 	{ 0x7318, 0x00 },
-	{ 0x8398, 0x00 },
 	{ 0x7319, 0x00 },
-	{ 0x8399, 0x00 },
 	{ 0x731a, 0x00 },
-	{ 0x839a, 0x00 },
 	{ 0x731b, 0x00 },
-	{ 0x839b, 0x00 },
 	{ 0x731d, 0x00 },
-	{ 0x839d, 0x00 },
 	{ 0x7327, 0x97 },
-	{ 0x83a7, 0x97 },
 	{ 0x7329, 0x00 },
+	{ 0x8287, 0x00 },
+	{ 0x8288, 0x00 },
+	{ 0x8289, 0x00 },
+	{ 0x82a7, 0x00 },
+	{ 0x8387, 0x97 },
+	{ 0x8388, 0x97 },
+	{ 0x8389, 0x97 },
+	{ 0x8392, 0x00 },
+	{ 0x8393, 0x00 },
+	{ 0x8398, 0x00 },
+	{ 0x8399, 0x00 },
+	{ 0x839a, 0x00 },
+	{ 0x839b, 0x00 },
+	{ 0x839d, 0x00 },
+	{ 0x83a7, 0x97 },
 	{ 0x83a9, 0x00 },
 	{ 0x752039, 0xa500 },
 };
author maintainer
#188 lore raw

PATCH 188/583 ASoC: rt721-sdca-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 70e0481c196e4822e683bca384e6bda89d944839 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

rt721_sdca_reg_defaults[] is grouped by SDCA function instead, so the binary search does not find 12 of its entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/codecs/rt721-sdca-sdw.h |   28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
sound/soc/codecs/rt721-sdca-sdw.h +14 -14
@@ -29,14 +29,6 @@ static const struct reg_default rt721_sd
 	{ 0x2f5b, 0x07 },
 	{ 0x2f5c, 0x27 },
 	{ 0x2f5d, 0x07 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
-		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
-		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
-		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
-		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
 		RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
@@ -45,6 +37,14 @@ static const struct reg_default rt721_sd
 		RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
 		RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
+		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
+		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
 		RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
@@ -53,30 +53,30 @@ static const struct reg_default rt721_sd
 		RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
 		RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F,
 		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
 		RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
-		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
-		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
 		RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
 		RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
 		RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
-		RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
 		RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
 		RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
+		RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
 		RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
 		RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+		RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 };
 
 static const struct reg_default rt721_sdca_mbq_defaults[] = {
author maintainer
#189 lore raw

PATCH 189/583 ASoC: samsung: aries_audio_probe: double of_node_put due to direct assignment without of_node_get

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: WenTao Liang <[email protected]>

commit fb5d1b1c5f8a920ee697545fa6dee16825085717 upstream.

In aries_audio_probe(), aries_dai[0].platforms->of_node is assigned the same pointer as aries_dai[0].cpus->of_node (from of_parse_phandle) without calling of_node_get(). When the sound card is deregistered, the ASoC framework calls of_node_put() on both cpus->of_node and platforms->of_node, causing a double put on the same node and a refcount underflow.

Add of_node_get(aries_dai[0].cpus->of_node) before the assignment.

Fixes 7a3a7671fa6c ("ASoC: samsung: Add driver for Aries boards")
---
 sound/soc/samsung/aries_wm8994.c |    1 +
 1 file changed, 1 insertion(+)
sound/soc/samsung/aries_wm8994.c +1 -0
@@ -658,6 +658,7 @@ static int aries_audio_probe(struct plat
 		goto out;
 	}
 
+	of_node_get(aries_dai[0].cpus->of_node);
 	aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node;
 
 	/* Set CPU of_node for BT DAI */
author maintainer
#190 lore raw

PATCH 190/583 ASoC: sgtl5000: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 437fbdeb60693b8f2e8250d44d29e513a95df298 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

SGTL5000_CHIP_SHORT_CTRL (0x003c) is listed before SGTL5000_CHIP_ANA_TEST2 (0x003a), which makes the former unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

---
 sound/soc/codecs/sgtl5000.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/sgtl5000.c +1 -1
@@ -56,8 +56,8 @@ static const struct reg_default sgtl5000
 	{ SGTL5000_CHIP_PLL_CTRL,		0x5000 },
 	{ SGTL5000_CHIP_CLK_TOP_CTRL,		0x0000 },
 	{ SGTL5000_CHIP_ANA_STATUS,		0x0000 },
-	{ SGTL5000_CHIP_SHORT_CTRL,		0x0000 },
 	{ SGTL5000_CHIP_ANA_TEST2,		0x0000 },
+	{ SGTL5000_CHIP_SHORT_CTRL,		0x0000 },
 	{ SGTL5000_DAP_CTRL,			0x0000 },
 	{ SGTL5000_DAP_PEQ,			0x0000 },
 	{ SGTL5000_DAP_BASS_ENHANCE,		0x0040 },
author maintainer
#191 lore raw

PATCH 191/583 ASoC: sti-sas: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit bbd73fb224caa1badfe2aa338fe9c9dcf40a6e96 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

STIH407_AUDIO_DAC_CTRL (0xa8) is listed before STIH407_AUDIO_GLUE_CTRL (0xa4), which makes the latter unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

---
 sound/soc/codecs/sti-sas.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/sti-sas.c +1 -1
@@ -44,8 +44,8 @@ enum {
 };
 
 static const struct reg_default stih407_sas_reg_defaults[] = {
-	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 },
 	{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
+	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 },
 };
 
 struct sti_dac_audio {
author maintainer
#192 lore raw

PATCH 192/583 ASoC: tas2552: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 1cc0cb62d306bb7c42e3d4649863df7c279ac850 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

TAS2552_OUTPUT_DATA (0x07), TAS2552_PDM_CFG (0x11), TAS2552_PGA_GAIN (0x12) and TAS2552_BOOST_APT_CTRL (0x14) are listed before TAS2552_RESERVED_0D (0x0d), TAS2552_LIMIT_RATE_HYS (0x0e) and TAS2552_CFG_2 (0x02), which leaves 7 of the 21 entries unreachable. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes 5df7f71d5cdf ("ASoC: tas2552: Support TI TAS2552 Amplifier")
---
 sound/soc/codecs/tas2552.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
sound/soc/codecs/tas2552.c +7 -7
@@ -31,25 +31,25 @@
 
 static const struct reg_default tas2552_reg_defs[] = {
 	{TAS2552_CFG_1, 0x22},
+	{TAS2552_CFG_2, 0xef},
 	{TAS2552_CFG_3, 0x80},
 	{TAS2552_DOUT, 0x00},
-	{TAS2552_OUTPUT_DATA, 0xc0},
-	{TAS2552_PDM_CFG, 0x01},
-	{TAS2552_PGA_GAIN, 0x00},
-	{TAS2552_BOOST_APT_CTRL, 0x0f},
-	{TAS2552_RESERVED_0D, 0xbe},
-	{TAS2552_LIMIT_RATE_HYS, 0x08},
-	{TAS2552_CFG_2, 0xef},
 	{TAS2552_SER_CTRL_1, 0x00},
 	{TAS2552_SER_CTRL_2, 0x00},
+	{TAS2552_OUTPUT_DATA, 0xc0},
 	{TAS2552_PLL_CTRL_1, 0x10},
 	{TAS2552_PLL_CTRL_2, 0x00},
 	{TAS2552_PLL_CTRL_3, 0x00},
 	{TAS2552_BTIP, 0x8f},
 	{TAS2552_BTS_CTRL, 0x80},
+	{TAS2552_RESERVED_0D, 0xbe},
+	{TAS2552_LIMIT_RATE_HYS, 0x08},
 	{TAS2552_LIMIT_RELEASE, 0x04},
 	{TAS2552_LIMIT_INT_COUNT, 0x00},
+	{TAS2552_PDM_CFG, 0x01},
+	{TAS2552_PGA_GAIN, 0x00},
 	{TAS2552_EDGE_RATE_CTRL, 0x40},
+	{TAS2552_BOOST_APT_CTRL, 0x0f},
 	{TAS2552_VBAT_DATA, 0x00},
 };
 
author maintainer
#193 lore raw

PATCH 193/583 ASoC: tas2764: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit e7643c3f7eb3292f8a98c2ddbf46ba78d848b83d upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

TAS2764_DVC (0x1a) is listed before TAS2764_CHNL_0 (0x03), which makes it unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

Fixes 827ed8a0fa50 ("ASoC: tas2764: Add the driver for the TAS2764")
---
 sound/soc/codecs/tas2764.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/tas2764.c +1 -1
@@ -783,13 +783,13 @@ static const struct reg_default tas2764_
 	{ TAS2764_PAGE, 0x00 },
 	{ TAS2764_SW_RST, 0x00 },
 	{ TAS2764_PWR_CTRL, 0x1a },
-	{ TAS2764_DVC, 0x00 },
 	{ TAS2764_CHNL_0, 0x28 },
 	{ TAS2764_TDM_CFG0, 0x09 },
 	{ TAS2764_TDM_CFG1, 0x02 },
 	{ TAS2764_TDM_CFG2, 0x0a },
 	{ TAS2764_TDM_CFG3, 0x10 },
 	{ TAS2764_TDM_CFG5, 0x42 },
+	{ TAS2764_DVC, 0x00 },
 	{ TAS2764_INT_CLK_CFG, 0x19 },
 };
 
author maintainer
#194 lore raw

PATCH 194/583 ASoC: tas2780: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit e725093e9e53db9298e38e7332a44dcaac2fd135 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

TAS2780_DVC (0x1a) is listed before TAS2780_CHNL_0 (0x03), which makes it unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

---
 sound/soc/codecs/tas2780.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/tas2780.c +1 -1
@@ -530,13 +530,13 @@ static const struct reg_default tas2780_
 	{ TAS2780_PAGE, 0x00 },
 	{ TAS2780_SW_RST, 0x00 },
 	{ TAS2780_PWR_CTRL, 0x1a },
-	{ TAS2780_DVC, 0x00 },
 	{ TAS2780_CHNL_0, 0x00 },
 	{ TAS2780_TDM_CFG0, 0x09 },
 	{ TAS2780_TDM_CFG1, 0x02 },
 	{ TAS2780_TDM_CFG2, 0x0a },
 	{ TAS2780_TDM_CFG3, 0x10 },
 	{ TAS2780_TDM_CFG5, 0x42 },
+	{ TAS2780_DVC, 0x00 },
 };
 
 static const struct regmap_range_cfg tas2780_regmap_ranges[] = {
author maintainer
#195 lore raw

PATCH 195/583 ASoC: tas2783-sdw: drop duplicate reg_default entry

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit ceba07ca24fab54e0e38ec96d196fca3e638d671 upstream.

TAS2783_AMP_LEVEL is defined as TASDEV_REG_SDW(0x0, 0x00, 0x03), so tas2783_reg_default[] lists that register twice. Drop the open coded second entry.

Fixes 4cc9bd8d7b32 ("ASoc: tas2783A: Add soundwire based codec driver")
---
 sound/soc/codecs/tas2783-sdw.c |    1 -
 1 file changed, 1 deletion(-)
sound/soc/codecs/tas2783-sdw.c +0 -1
@@ -87,7 +87,6 @@ struct tas2783_prv {
 
 static const struct reg_default tas2783_reg_default[] = {
 	{TAS2783_AMP_LEVEL, 0x28},
-	{TASDEV_REG_SDW(0, 0, 0x03), 0x28},
 	{TASDEV_REG_SDW(0, 0, 0x04), 0x21},
 	{TASDEV_REG_SDW(0, 0, 0x05), 0x41},
 	{TASDEV_REG_SDW(0, 0, 0x06), 0x00},
author maintainer
#196 lore raw

PATCH 196/583 ASoC: tas2783-sdw: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit b45fc97ebcfb27ec250025329a4f79ce5e327ec3 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

tas2783_reg_default[] is grouped by SDCA entity name instead, so the binary search does not find 120 of its 196 entries. regcache_reg_needs_sync() then cannot compare those against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

Fixes 4cc9bd8d7b32 ("ASoc: tas2783A: Add soundwire based codec driver")
---
 sound/soc/codecs/tas2783-sdw.c |  170 ++++++++++++++++++++---------------------
 1 file changed, 85 insertions(+), 85 deletions(-)
sound/soc/codecs/tas2783-sdw.c +85 -85
@@ -122,6 +122,7 @@ static const struct reg_default tas2783_
 	{TASDEV_REG_SDW(0, 0, 0x41), 0x14},
 	{TASDEV_REG_SDW(0, 0, 0x5c), 0x19},
 	{TASDEV_REG_SDW(0, 0, 0x5d), 0x80},
+	{TASDEV_REG_SDW(0, 0, 0x60), 0x21},
 	{TASDEV_REG_SDW(0, 0, 0x63), 0x48},
 	{TASDEV_REG_SDW(0, 0, 0x65), 0x08},
 	{TASDEV_REG_SDW(0, 0, 0x66), 0xb2},
@@ -137,7 +138,6 @@ static const struct reg_default tas2783_
 	{TASDEV_REG_SDW(0, 0, 0x73), 0x08},
 	{TASDEV_REG_SDW(0, 0, 0x75), 0xe0},
 	{TASDEV_REG_SDW(0, 0, 0x7a), 0x60},
-	{TASDEV_REG_SDW(0, 0, 0x60), 0x21},
 	{TASDEV_REG_SDW(0, 1, 0x02), 0x00},
 	{TASDEV_REG_SDW(0, 1, 0x17), 0xc0},
 	{TASDEV_REG_SDW(0, 1, 0x19), 0x60},
@@ -156,63 +156,44 @@ static const struct reg_default tas2783_
 	{TASDEV_REG_SDW(0, 0xfd, 0x39), 0x00},
 	{TASDEV_REG_SDW(0, 0xfd, 0x3e), 0x00},
 	{TASDEV_REG_SDW(0, 0xfd, 0x45), 0x00},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x01, 1), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x02, 1), 0x9c00},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 0), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 1), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x0b, 1), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0},
@@ -222,19 +203,60 @@ static const struct reg_default tas2783_
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x11, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 1), 0x0},
@@ -244,6 +266,14 @@ static const struct reg_default tas2783_
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
+	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 8), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 9), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xa), 0x0},
@@ -252,36 +282,6 @@ static const struct reg_default tas2783_
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xd), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xe), 0x0},
 	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xf), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
-	{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
 };
 
 static const struct reg_sequence tas2783_init_seq[] = {
author maintainer
#197 lore raw

PATCH 197/583 ASoC: tegra210_mixer: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit f70bc276fc7f712ff5c8e995d5050558a3198df2 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

TEGRA210_MIXER_ENABLE (0x400) is the last entry of the table, after TEGRA210_MIXER_PEAKM_RAM_CTRL (0x434), which makes it unreachable. regcache_reg_needs_sync() then cannot compare it against its default and reports that a sync is needed, so it is written to the device on every regcache_sync() even when it was never touched.

Sort the table by register address.

Fixes 05bb3d5ec64a ("ASoC: tegra: Add Tegra210 based Mixer driver")
---
 sound/soc/tegra/tegra210_mixer.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/tegra/tegra210_mixer.c +1 -1
@@ -57,10 +57,10 @@ static const struct reg_default tegra210
 	MIXER_TX_REG_DEFAULTS(3),
 	MIXER_TX_REG_DEFAULTS(4),
 
+	{ TEGRA210_MIXER_ENABLE, 0x1 },
 	{ TEGRA210_MIXER_CG, 0x00000001},
 	{ TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000},
 	{ TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000},
-	{ TEGRA210_MIXER_ENABLE, 0x1 },
 };
 
 /* Default gain parameters */
author maintainer
#198 lore raw

PATCH 198/583 ASoC: tegra: Sort MBDRC register defaults

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jon Hunter <[email protected]>

commit abb5bed6f48d54d3b82724a430fd462579ecd876 upstream.

Commit 4b05ccb17f92 ("regcache: Sort the local copy of an unsorted reg_defaults array") exposed an issue with the Tegra MBDRC driver and now the following warning is observed:

tegra210-ope 2908000.processing-engine: Driver needs fixing: Unsorted
reg_defaults, sorting the copy

This warning occurs because register defaults in the structure tegra210_mbdrc_reg_defaults are not specified in ascending order which is required by regmap. Fix this by sorting the register defaults according to their address. Note that in order to do this it is necessary to replace the macro MBDRC_FILTER_REG_DEFAULTS with a per register macro MBDRC_FILTER_PARAM_REG_DEFAULTS.

Fixes 7358a803c778 ("ASoC: tegra: Add Tegra210 based OPE driver")
---
 sound/soc/tegra/tegra210_mbdrc.c |   42 +++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 21 deletions(-)
sound/soc/tegra/tegra210_mbdrc.c +21 -21
@@ -20,33 +20,33 @@
 #define MBDRC_FILTER_REG(reg, id)					    \
 	((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
 
-#define MBDRC_FILTER_REG_DEFAULTS(id)					    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff},    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082},   \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b},  \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002},    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666},	    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e},    \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c},   \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a},   \
-	{ MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000}
+#define MBDRC_FILTER_PARAM_REG_DEFAULTS(reg, val)			    \
+	{ MBDRC_FILTER_REG(reg, 0), val},				    \
+	{ MBDRC_FILTER_REG(reg, 1), val},				    \
+	{ MBDRC_FILTER_REG(reg, 2), val}
 
 static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
 	{ TEGRA210_MBDRC_CFG, 0x0030de51},
 	{ TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
 	{ TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
 
-	MBDRC_FILTER_REG_DEFAULTS(0),
-	MBDRC_FILTER_REG_DEFAULTS(1),
-	MBDRC_FILTER_REG_DEFAULTS(2),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_IIR_CFG, 0x00000005),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_IN_ATTACK, 0x3e48590c),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_IN_RELEASE, 0x08414e9f),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_FAST_ATTACK, 0x7fffffff),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_IN_THRESHOLD, 0x06145082),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_OUT_THRESHOLD, 0x060d379b),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_RATIO_1ST, 0x0000a000),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_RATIO_2ND, 0x00002000),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_RATIO_3RD, 0x00000b33),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_RATIO_4TH, 0x00000800),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_RATIO_5TH, 0x0000019a),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_MAKEUP_GAIN, 0x00000002),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_INIT_GAIN, 0x00066666),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_GAIN_ATTACK, 0x00d9ba0e),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_GAIN_RELEASE, 0x3e48590c),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_FAST_RELEASE, 0x7ffff26a),
+	MBDRC_FILTER_PARAM_REG_DEFAULTS(TEGRA210_MBDRC_CFG_RAM_CTRL, 0x4000),
 };
 
 /* Default MBDRC parameters */
author maintainer
#199 lore raw

PATCH 199/583 ASoC: tegra: Sort ADMAIF register defaults

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jon Hunter <[email protected]>

commit 18d48bfd1bc178da7cfc7a1be3eaa1c8cb10f05c upstream.

Commit 4b05ccb17f92 ("regcache: Sort the local copy of an unsorted reg_defaults array") exposed an issue in the Tegra ADMAIF driver and now the following warning is observed:

tegra210-admaif 290f000.admaif: Driver needs fixing: Unsorted
reg_defaults, sorting the copy

This warning occurs because register defaults in the structures tegra186_admaif_reg_defaults and tegra264_admaif_reg_defaults are not specified in ascending order which is required by regmap. Fix this by sorting the register defaults according to their address. Note that in order to do this it is necessary to split the macro ADMAIF_REG_DEFAULTS into separate RX and TX macros to the RX and TX registers.

Fixes f74028e159bb ("ASoC: tegra: Add Tegra210 based ADMAIF driver")
---
 sound/soc/tegra/tegra210_admaif.c |  208 +++++++++++++++++++++++++-------------
 1 file changed, 138 insertions(+), 70 deletions(-)
sound/soc/tegra/tegra210_admaif.c +138 -70
@@ -25,94 +25,162 @@
 
 #define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
 
-#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base, cif_ctrl)	       \
+#define RX_REG_DEFAULTS(id, rx_ctrl, rx_base, cif_ctrl)			       \
 	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \
 	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), cif_ctrl },     \
-	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \
+	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl }
+
+#define TX_REG_DEFAULTS(id, tx_ctrl, tx_base, cif_ctrl)			       \
 	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \
 	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), cif_ctrl },     \
 	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
 
-#define ADMAIF_REG_DEFAULTS(id, chip)					       \
-	REG_DEFAULTS((id) - 1,						       \
+#define ADMAIF_RX_REG_DEFAULTS(id, chip)				       \
+	RX_REG_DEFAULTS((id) - 1,					       \
 		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
+		chip ## _ADMAIF_RX_BASE,				       \
+		chip ## _ADMAIF_CIF_REG_DEFAULT)
+
+#define ADMAIF_TX_REG_DEFAULTS(id, chip)				       \
+	TX_REG_DEFAULTS((id) - 1,					       \
 		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
 		chip ## _ADMAIF_TX_BASE,				       \
-		chip ## _ADMAIF_RX_BASE,				       \
 		chip ## _ADMAIF_CIF_REG_DEFAULT)
 
 static const struct reg_default tegra186_admaif_reg_defaults[] = {
-	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
-	ADMAIF_REG_DEFAULTS(1, TEGRA186),
-	ADMAIF_REG_DEFAULTS(2, TEGRA186),
-	ADMAIF_REG_DEFAULTS(3, TEGRA186),
-	ADMAIF_REG_DEFAULTS(4, TEGRA186),
-	ADMAIF_REG_DEFAULTS(5, TEGRA186),
-	ADMAIF_REG_DEFAULTS(6, TEGRA186),
-	ADMAIF_REG_DEFAULTS(7, TEGRA186),
-	ADMAIF_REG_DEFAULTS(8, TEGRA186),
-	ADMAIF_REG_DEFAULTS(9, TEGRA186),
-	ADMAIF_REG_DEFAULTS(10, TEGRA186),
-	ADMAIF_REG_DEFAULTS(11, TEGRA186),
-	ADMAIF_REG_DEFAULTS(12, TEGRA186),
-	ADMAIF_REG_DEFAULTS(13, TEGRA186),
-	ADMAIF_REG_DEFAULTS(14, TEGRA186),
-	ADMAIF_REG_DEFAULTS(15, TEGRA186),
-	ADMAIF_REG_DEFAULTS(16, TEGRA186),
-	ADMAIF_REG_DEFAULTS(17, TEGRA186),
-	ADMAIF_REG_DEFAULTS(18, TEGRA186),
-	ADMAIF_REG_DEFAULTS(19, TEGRA186),
-	ADMAIF_REG_DEFAULTS(20, TEGRA186)
+	ADMAIF_RX_REG_DEFAULTS(1, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(2, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(3, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(4, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(5, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(6, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(7, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(8, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(9, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(10, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(11, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(12, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(13, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(14, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(15, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(16, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(17, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(18, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(19, TEGRA186),
+	ADMAIF_RX_REG_DEFAULTS(20, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(1, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(2, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(3, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(4, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(5, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(6, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(7, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(8, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(9, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(10, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(11, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(12, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(13, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(14, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(15, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(16, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(17, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(18, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(19, TEGRA186),
+	ADMAIF_TX_REG_DEFAULTS(20, TEGRA186),
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003}
 };
 
 static const struct reg_default tegra210_admaif_reg_defaults[] = {
-	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
-	ADMAIF_REG_DEFAULTS(1, TEGRA210),
-	ADMAIF_REG_DEFAULTS(2, TEGRA210),
-	ADMAIF_REG_DEFAULTS(3, TEGRA210),
-	ADMAIF_REG_DEFAULTS(4, TEGRA210),
-	ADMAIF_REG_DEFAULTS(5, TEGRA210),
-	ADMAIF_REG_DEFAULTS(6, TEGRA210),
-	ADMAIF_REG_DEFAULTS(7, TEGRA210),
-	ADMAIF_REG_DEFAULTS(8, TEGRA210),
-	ADMAIF_REG_DEFAULTS(9, TEGRA210),
-	ADMAIF_REG_DEFAULTS(10, TEGRA210)
+	ADMAIF_RX_REG_DEFAULTS(1, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(2, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(3, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(4, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(5, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(6, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(7, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(8, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(9, TEGRA210),
+	ADMAIF_RX_REG_DEFAULTS(10, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(1, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(2, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(3, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(4, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(5, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(6, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(7, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(8, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(9, TEGRA210),
+	ADMAIF_TX_REG_DEFAULTS(10, TEGRA210),
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003}
 };
 
 static const struct reg_default tegra264_admaif_reg_defaults[] = {
-	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA264_ADMAIF_GLOBAL_BASE), 0x00000003},
-	ADMAIF_REG_DEFAULTS(1, TEGRA264),
-	ADMAIF_REG_DEFAULTS(2, TEGRA264),
-	ADMAIF_REG_DEFAULTS(3, TEGRA264),
-	ADMAIF_REG_DEFAULTS(4, TEGRA264),
-	ADMAIF_REG_DEFAULTS(5, TEGRA264),
-	ADMAIF_REG_DEFAULTS(6, TEGRA264),
-	ADMAIF_REG_DEFAULTS(7, TEGRA264),
-	ADMAIF_REG_DEFAULTS(8, TEGRA264),
-	ADMAIF_REG_DEFAULTS(9, TEGRA264),
-	ADMAIF_REG_DEFAULTS(10, TEGRA264),
-	ADMAIF_REG_DEFAULTS(11, TEGRA264),
-	ADMAIF_REG_DEFAULTS(12, TEGRA264),
-	ADMAIF_REG_DEFAULTS(13, TEGRA264),
-	ADMAIF_REG_DEFAULTS(14, TEGRA264),
-	ADMAIF_REG_DEFAULTS(15, TEGRA264),
-	ADMAIF_REG_DEFAULTS(16, TEGRA264),
-	ADMAIF_REG_DEFAULTS(17, TEGRA264),
-	ADMAIF_REG_DEFAULTS(18, TEGRA264),
-	ADMAIF_REG_DEFAULTS(19, TEGRA264),
-	ADMAIF_REG_DEFAULTS(20, TEGRA264),
-	ADMAIF_REG_DEFAULTS(21, TEGRA264),
-	ADMAIF_REG_DEFAULTS(22, TEGRA264),
-	ADMAIF_REG_DEFAULTS(23, TEGRA264),
-	ADMAIF_REG_DEFAULTS(24, TEGRA264),
-	ADMAIF_REG_DEFAULTS(25, TEGRA264),
-	ADMAIF_REG_DEFAULTS(26, TEGRA264),
-	ADMAIF_REG_DEFAULTS(27, TEGRA264),
-	ADMAIF_REG_DEFAULTS(28, TEGRA264),
-	ADMAIF_REG_DEFAULTS(29, TEGRA264),
-	ADMAIF_REG_DEFAULTS(30, TEGRA264),
-	ADMAIF_REG_DEFAULTS(31, TEGRA264),
-	ADMAIF_REG_DEFAULTS(32, TEGRA264)
+	ADMAIF_RX_REG_DEFAULTS(1, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(2, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(3, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(4, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(5, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(6, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(7, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(8, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(9, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(10, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(11, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(12, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(13, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(14, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(15, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(16, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(17, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(18, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(19, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(20, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(21, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(22, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(23, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(24, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(25, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(26, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(27, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(28, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(29, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(30, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(31, TEGRA264),
+	ADMAIF_RX_REG_DEFAULTS(32, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(1, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(2, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(3, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(4, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(5, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(6, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(7, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(8, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(9, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(10, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(11, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(12, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(13, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(14, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(15, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(16, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(17, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(18, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(19, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(20, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(21, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(22, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(23, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(24, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(25, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(26, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(27, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(28, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(29, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(30, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(31, TEGRA264),
+	ADMAIF_TX_REG_DEFAULTS(32, TEGRA264),
+	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA264_ADMAIF_GLOBAL_BASE), 0x00000003}
 };
 
 static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
author maintainer
#200 lore raw

PATCH 200/583 ASoC: tegra: Fix the MIXER enable default value

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jon Hunter <[email protected]>

commit 5442b8093a2f94ecd4696b3875194be09e2676c5 upstream.

Commit 4b05ccb17f92 ("regcache: Sort the local copy of an unsorted reg_defaults array") exposed an issue in the Tegra MIXER driver where the register default for the TEGRA210_MIXER_ENABLE is specified as 1, but the hardware default is actually 0. After this commit was added the MIXER driver is no longer working and so fix this by correcting the default value for this register and explicitly configuring the MIXER_ENABLE register when runtime resuming the MIXER device.

Fixes 05bb3d5ec64a ("ASoC: tegra: Add Tegra210 based Mixer driver")
---
 sound/soc/tegra/tegra210_mixer.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
sound/soc/tegra/tegra210_mixer.c +7 -3
@@ -57,7 +57,7 @@ static const struct reg_default tegra210
 	MIXER_TX_REG_DEFAULTS(3),
 	MIXER_TX_REG_DEFAULTS(4),
 
-	{ TEGRA210_MIXER_ENABLE, 0x1 },
+	{ TEGRA210_MIXER_ENABLE, 0x0 },
 	{ TEGRA210_MIXER_CG, 0x00000001},
 	{ TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000},
 	{ TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000},
@@ -86,11 +86,15 @@ static int tegra210_mixer_runtime_suspen
 static int tegra210_mixer_runtime_resume(struct device *dev)
 {
 	struct tegra210_mixer *mixer = dev_get_drvdata(dev);
+	int err;
 
 	regcache_cache_only(mixer->regmap, false);
-	regcache_sync(mixer->regmap);
+	err = regcache_sync(mixer->regmap);
+	if (err)
+		return err;
 
-	return 0;
+	return regmap_write(mixer->regmap, TEGRA210_MIXER_ENABLE,
+			    TEGRA210_MIXER_EN);
 }
 
 static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
author maintainer
#201 lore raw

PATCH 201/583 ASoC: tegra210_i2s: sort the Tegra264 register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 82da8df388004af4540e930ab3de2ce5787207e7 upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

TEGRA264_I2S_ENABLE (0x100), TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE (0x30) and TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE (0xb0) are listed at the end of the table, after TEGRA264_I2S_TIMING (0x130), which leaves 4 of the 9 entries unreachable. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/tegra/tegra210_i2s.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/tegra/tegra210_i2s.c +3 -3
@@ -39,13 +39,13 @@ static const struct reg_default tegra210
 static const struct reg_default tegra264_i2s_reg_defaults[] = {
 	{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
 	{ TEGRA210_I2S_RX_CIF_CTRL, 0x00003f00 },
+	{ TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE, 0x1 },
 	{ TEGRA264_I2S_TX_INT_MASK, 0x00000003 },
 	{ TEGRA264_I2S_TX_CIF_CTRL, 0x00003f00 },
+	{ TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE, 0x1 },
+	{ TEGRA264_I2S_ENABLE, 0x1 },
 	{ TEGRA264_I2S_CG, 0x1 },
 	{ TEGRA264_I2S_TIMING, 0x0000001f },
-	{ TEGRA264_I2S_ENABLE, 0x1 },
-	{ TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE, 0x1 },
-	{ TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE, 0x1 },
 };
 
 static void tegra210_i2s_set_slot_ctrl(struct tegra210_i2s *i2s,
author maintainer
#202 lore raw

PATCH 202/583 ASoC: tegra210_i2s: sort the register default table

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Peter Ujfalusi <[email protected]>

commit 597273563d90d03fda852a29c3a76c41a22bf6ac upstream.

reg_defaults must be sorted by ascending register address, as regcache_lookup_reg() locates entries in it with bsearch(). See commit fd80df352ba1 ("regcache: Add support for sorting defaults arrays").

TEGRA210_I2S_ENABLE (0x80) is listed after TEGRA210_I2S_CG (0x88) and TEGRA210_I2S_TIMING (0xa4), so both it and TEGRA210_I2S_TIMING are unreachable. regcache_reg_needs_sync() then cannot compare them against their default and reports that a sync is needed, so they are written to the device on every regcache_sync() even when they were never touched.

Sort the table by register address.

---
 sound/soc/tegra/tegra210_i2s.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/tegra/tegra210_i2s.c +1 -1
@@ -24,9 +24,9 @@ static const struct reg_default tegra210
 	{ TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
 	{ TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
 	{ TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
+	{ TEGRA210_I2S_ENABLE, 0x1 },
 	{ TEGRA210_I2S_CG, 0x1 },
 	{ TEGRA210_I2S_TIMING, 0x0000001f },
-	{ TEGRA210_I2S_ENABLE, 0x1 },
 	/*
 	 * Below update does not have any effect on Tegra186 and Tegra194.
 	 * On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
author maintainer
#203 lore raw

PATCH 203/583 iio: adc: adi-axi-adc: add data size support for AD408X backend

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Antoniu Miclaus <[email protected]>

commit 60f6f7fd5f89c7f55991c5dc59f3ccc74cd6efd7 upstream.

The AD408X AXI core can pack the sample data on the bus using different word widths. Expose this through the data_size_set backend operation so that frontends can program the packet format field (bits 3:2 of the CNTRL_3 register) according to the ADC resolution: 20-bit, 16-bit and 14-bit map to packet format values 0, 1 and 2 respectively.

---
 drivers/iio/adc/adi-axi-adc.c |   30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
drivers/iio/adc/adi-axi-adc.c +30 -0
@@ -54,6 +54,10 @@
 #define   AXI_AD485X_PACKET_FORMAT_24BIT	0x1
 #define   AXI_AD485X_PACKET_FORMAT_32BIT	0x2
 #define   AXI_AD408X_CNTRL_3_FILTER_EN_MSK	BIT(0)
+#define   AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK	GENMASK(3, 2)
+#define   AXI_AD408X_PACKET_FORMAT_20BIT	0x0
+#define   AXI_AD408X_PACKET_FORMAT_16BIT	0x1
+#define   AXI_AD408X_PACKET_FORMAT_14BIT	0x2
 
 #define ADI_AXI_ADC_REG_SYNC_STATUS		0x0068
 #define   ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK	BIT(0)
@@ -437,6 +441,31 @@ static int axi_adc_ad408x_filter_type_se
 				 AXI_AD408X_CNTRL_3_FILTER_EN_MSK);
 }
 
+static int axi_adc_ad408x_data_size_set(struct iio_backend *back,
+					unsigned int size)
+{
+	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+	unsigned int val;
+
+	switch (size) {
+	case 20:
+		val = AXI_AD408X_PACKET_FORMAT_20BIT;
+		break;
+	case 16:
+		val = AXI_AD408X_PACKET_FORMAT_16BIT;
+		break;
+	case 14:
+		val = AXI_AD408X_PACKET_FORMAT_14BIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
+				  AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK,
+				  FIELD_PREP(AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK, val));
+}
+
 static int axi_adc_ad408x_interface_data_align(struct iio_backend *back,
 					       u32 timeout_us)
 {
@@ -661,6 +690,7 @@ static const struct iio_backend_ops adi_
 	.free_buffer = axi_adc_free_buffer,
 	.data_sample_trigger = axi_adc_data_sample_trigger,
 	.filter_type_set = axi_adc_ad408x_filter_type_set,
+	.data_size_set = axi_adc_ad408x_data_size_set,
 	.interface_data_align = axi_adc_ad408x_interface_data_align,
 	.num_lanes_set = axi_adc_num_lanes_set,
 	.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
author maintainer
#204 lore raw

PATCH 204/583 iio: adc: max34408: add missing select REGMAP_I2C to Kconfig

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Joshua Crofts <[email protected]>

commit 947f1079074a260ba200419d5cba6b8549d5ac0c upstream.

The Kconfig entry for the MAX34408 is missing a 'select REGMAP_I2C', causing build failures.

Fixes cf27775838c5 ("iio: adc: Add driver support for MAX34408/9")
---
 drivers/iio/adc/Kconfig |    1 +
 1 file changed, 1 insertion(+)
drivers/iio/adc/Kconfig +1 -0
@@ -1026,6 +1026,7 @@ config MAX1363
 config MAX34408
 	tristate "Maxim max34408/max344089 ADC driver"
 	depends on I2C
+	select REGMAP_I2C
 	help
 	  Say yes here to build support for Maxim max34408/max34409 current sense
 	  monitor with 8-bits ADC interface with overcurrent delay/threshold and
author maintainer
#205 lore raw

PATCH 205/583 iio: adc: pac1921: fix wrong channel used in trigger handler read

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cong Nguyen <[email protected]>

commit 3364c56b20c1c496bdb8c8df32f96a9947dbf98e upstream.

pac1921_trigger_handler() walks the enabled channels with iio_for_each_active_channel(), which yields the scan index (bit) of each active channel, while ch is a separate counter used to pack the samples contiguously into the scan buffer.

The register to read was looked up with the packing counter instead of the scan index:

	ret = pac1921_read_res(priv, idev->channels[ch].address, &val);

pac1921_channels[] is ordered by scan index, so channels[bit] is the channel that is actually enabled, whereas channels[ch] is merely the ch-th array entry. These coincide only when the enabled channels form a contiguous prefix (e.g. all channels enabled). With a sparse scan mask - for example when only the power channel (scan index 3) is enabled - the handler reads the wrong register (VBUS instead of VPOWER) and pushes it to userspace as the enabled channel's data.

Index the channel array by the scan index (bit) to read the correct register, keeping ch only for contiguous packing into the scan buffer.

Fixes 371f778b83cd ("iio: adc: add support for pac1921")
Assisted-by Claude:claude-opus-4
---
 drivers/iio/adc/pac1921.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/adc/pac1921.c +1 -1
@@ -1037,7 +1037,7 @@ static irqreturn_t pac1921_trigger_handl
 	iio_for_each_active_channel(idev, bit) {
 		u16 val;
 
-		ret = pac1921_read_res(priv, idev->channels[ch].address, &val);
+		ret = pac1921_read_res(priv, idev->channels[bit].address, &val);
 		if (ret)
 			goto done;
 
author maintainer
#206 lore raw

PATCH 206/583 iio: buffer: Fix potential use-after-free in anonymous buffer release

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lars-Peter Clausen <[email protected]>

commit 6288b593e76eb10329326f2cd51e32557203b9e5 upstream.

An anonymous buffer handle holds a reference to the underlying IIO device. The reference is dropped in the buffer handle's release function. If the device has been removed, either through unbind or hot-unplug, the buffer handle might hold the last reference.

The release function takes the mutex for the buffer using a guard, which means the unlock happens after all the code in the function, including iio_device_put(). If the anonymous buffer holds the last reference this might free both the IIO device and the buffer, which contains the mutex, leading to use-after-free when the mutex is unlocked.

Fix this by using a scoped guard just around the buffer dmabuf list access, making sure the mutex is unlocked before releasing the IIO device.

Version 10 of the patch that introduced this issue used this exact scheme of first unlocking and then dropping the reference [1]. During review it was suggested to use a guard instead, and version 11 made that change [2].

---
 drivers/iio/industrialio-buffer.c |   16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/iio/industrialio-buffer.c +10 -6
@@ -1599,12 +1599,16 @@ static int iio_buffer_chrdev_release(str
 
 	wake_up(&buffer->pollq);
 
-	guard(mutex)(&buffer->dmabufs_mutex);
-
-	/* Close all attached DMABUFs */
-	list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) {
-		list_del_init(&priv->entry);
-		iio_buffer_dmabuf_put(priv->attach);
+	/*
+	 * The mutex must be unlocked before iio_device_put(), which might drop the
+	 * last reference and free the buffer.
+	 */
+	scoped_guard(mutex, &buffer->dmabufs_mutex) {
+		/* Close all attached DMABUFs */
+		list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) {
+			list_del_init(&priv->entry);
+			iio_buffer_dmabuf_put(priv->attach);
+		}
 	}
 
 	kfree(ib);
author maintainer
#207 lore raw

PATCH 207/583 iio: buffer: Make IIO DMA fence release RCU-safe

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lars-Peter Clausen <[email protected]>

commit 8662e56c31cf23b61ca3d11b516efb94c35b8026 upstream.

The dma_fence documentation states that if a custom release implementation is provided, the dma_fence object must be freed in an RCU-safe way. The current iio_dma_fence implementation uses kfree(), which might result in a use-after-free.

Remove the custom release implementation. This makes the DMA fence core fall back to dma_fence_free(), which calls kfree_rcu() on the fence. This requires that the fence be the first member of struct iio_dma_fence.

Using the default release method for extended DMA fence structures is a common pattern.

Reported-by codex:gpt-5.6
Fixes 3e26d9f08fbe ("iio: core: Add new DMABUF interface infrastructure")
---
 drivers/iio/industrialio-buffer.c |   13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)
drivers/iio/industrialio-buffer.c +4 -9
@@ -57,6 +57,10 @@ struct iio_dmabuf_priv {
 };
 
 struct iio_dma_fence {
+	/*
+	 * Must remain the first member so the default release callback can pass
+	 * the fence directly to dma_fence_free().
+	 */
 	struct dma_fence base;
 	struct iio_dmabuf_priv *priv;
 	struct work_struct work;
@@ -1811,18 +1815,9 @@ iio_buffer_dma_fence_get_driver_name(str
 	return "iio";
 }
 
-static void iio_buffer_dma_fence_release(struct dma_fence *fence)
-{
-	struct iio_dma_fence *iio_fence =
-		container_of(fence, struct iio_dma_fence, base);
-
-	kfree(iio_fence);
-}
-
 static const struct dma_fence_ops iio_buffer_dma_fence_ops = {
 	.get_driver_name	= iio_buffer_dma_fence_get_driver_name,
 	.get_timeline_name	= iio_buffer_dma_fence_get_driver_name,
-	.release		= iio_buffer_dma_fence_release,
 };
 
 static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
author maintainer
#208 lore raw

PATCH 208/583 iio: buffer: Tie IIO dma fence lock lifetime to the fence

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lars-Peter Clausen <[email protected]>

commit f25ec4627d935dedfb5fe83bd2c2678cdcc19611 upstream.

The iio_dma_fence implementation currently uses a lock embedded in the iio_dmabuf_priv. But the iio_dma_fence can outlive the iio_dmabuf_priv, which can cause a use-after-free.

Tie the lifetime of the lock to the lifetime of the fence by embedding them in the same struct.

We can't just hold a reference to the iio_dmabuf_priv from the iio_dma_fence since iio_buffer_dmabuf_release() might sleep and the fence release callback is not allowed to sleep.

Note that the dma_fence framework now has an internal lock that gets used when the passing NULL for lock in dma_fence_init(), but in order to allow this patch to be backportable use an external lock.

Reported-by codex:gpt-5.6
Fixes 3e26d9f08fbe ("iio: core: Add new DMABUF interface infrastructure")
---
 drivers/iio/industrialio-buffer.c |    9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/iio/industrialio-buffer.c +4 -5
@@ -47,9 +47,6 @@ struct iio_dmabuf_priv {
 
 	u64 context;
 
-	/* Spinlock used for locking the dma_fence */
-	spinlock_t lock;
-
 	struct dma_buf_attachment *attach;
 	struct sg_table *sgt;
 	enum dma_data_direction dir;
@@ -62,6 +59,7 @@ struct iio_dma_fence {
 	 * the fence directly to dma_fence_free().
 	 */
 	struct dma_fence base;
+	spinlock_t lock; /* protects base */
 	struct iio_dmabuf_priv *priv;
 	struct work_struct work;
 };
@@ -1690,7 +1688,6 @@ static int iio_buffer_attach_dmabuf(stru
 	if (!priv)
 		return -ENOMEM;
 
-	spin_lock_init(&priv->lock);
 	priv->context = dma_fence_context_alloc(1);
 
 	dmabuf = dma_buf_get(fd);
@@ -1871,6 +1868,8 @@ static int iio_buffer_enqueue_dmabuf(str
 		goto err_attachment_put;
 	}
 
+	spin_lock_init(&fence->lock);
+
 	fence->priv = priv;
 
 	seqno = atomic_add_return(1, &priv->seqno);
@@ -1881,7 +1880,7 @@ static int iio_buffer_enqueue_dmabuf(str
 	 * the dma_fence.
 	 */
 	dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops,
-		       &priv->lock, priv->context, seqno);
+		       &fence->lock, priv->context, seqno);
 
 	ret = iio_dma_resv_lock(dmabuf, nonblock);
 	if (ret)
author maintainer
#209 lore raw

PATCH 209/583 iio: chemical: atlas-sensor: fix PM reference leak in buffer postenable

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Moksh Panicker <[email protected]>

commit bcd3f72e26314edfce7eaf8d7160b3119c7b7fed upstream.

atlas_buffer_postenable() acquires a runtime PM reference with pm_runtime_resume_and_get() but returns the result of atlas_set_interrupt() directly. If atlas_set_interrupt() fails, the runtime PM reference is leaked and the device can never autosuspend.

Add pm_runtime_put_autosuspend() on the error path to balance the reference.

Fixes 0e4f336f50de ("iio: chemical: atlas-sensor: Balance runtime pm + pm_runtime_resume_and_get()")
---
 drivers/iio/chemical/atlas-sensor.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/iio/chemical/atlas-sensor.c +5 -1
@@ -413,7 +413,11 @@ static int atlas_buffer_postenable(struc
 	if (ret)
 		return ret;
 
-	return atlas_set_interrupt(data, true);
+	ret = atlas_set_interrupt(data, true);
+	if (ret)
+		pm_runtime_put_autosuspend(&data->client->dev);
+
+	return ret;
 }
 
 static int atlas_buffer_predisable(struct iio_dev *indio_dev)
author maintainer
#210 lore raw

PATCH 210/583 iio: chemical: atlas-sensor: use iio_trigger_poll_nested() to fix remove UAF

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fan Wu <[email protected]>

commit be61c8c6252671ecf1fee0ad90f87669e0be1e20 upstream.

The atlas driver requests its hardware data-ready IRQ with devm_request_threaded_irq(); its threaded handler queues an irq_work, atlas_work_handler(), that calls iio_trigger_poll(data->trig).

The IRQ is devm-managed, so free_irq() runs from the devres unwind after atlas_remove() returns without flushing that irq_work. Once a buffer is enabled, conversion-complete IRQs keep firing and queueing it; a pending irq_work can therefore run after the unwind has freed atlas_data/indio_dev and the trigger, when atlas_work_handler() derives the atlas_data pointer via container_of() and dereferences data->trig, a use-after-free.

Call iio_trigger_poll_nested() directly from the threaded handler instead of bouncing through irq_work. free_irq() then drains the threaded handler, closing the window; other iio drivers with a threaded data-ready IRQ do the same (e.g. bmi270).

This issue was found by an in-house static analysis tool.

Fixes 7103b99b031c ("iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips")
Assisted-by Codex:gpt-5.6
---
 drivers/iio/chemical/atlas-sensor.c |   13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/iio/chemical/atlas-sensor.c +1 -12
@@ -13,7 +13,6 @@
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/irq.h>
-#include <linux/irq_work.h>
 #include <linux/i2c.h>
 #include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
@@ -88,7 +87,6 @@ struct atlas_data {
 	struct iio_trigger *trig;
 	const struct atlas_device *chip;
 	struct regmap *regmap;
-	struct irq_work work;
 	unsigned int interrupt_enabled;
 	/* 96-bit data + 32-bit pad + 64-bit timestamp */
 	__be32 buffer[6] __aligned(8);
@@ -441,13 +439,6 @@ static const struct iio_buffer_setup_ops
 	.predisable = atlas_buffer_predisable,
 };
 
-static void atlas_work_handler(struct irq_work *work)
-{
-	struct atlas_data *data = container_of(work, struct atlas_data, work);
-
-	iio_trigger_poll(data->trig);
-}
-
 static irqreturn_t atlas_trigger_handler(int irq, void *private)
 {
 	struct iio_poll_func *pf = private;
@@ -474,7 +465,7 @@ static irqreturn_t atlas_interrupt_handl
 	struct iio_dev *indio_dev = private;
 	struct atlas_data *data = iio_priv(indio_dev);
 
-	irq_work_queue(&data->work);
+	iio_trigger_poll_nested(data->trig);
 
 	return IRQ_HANDLED;
 }
@@ -670,8 +661,6 @@ static int atlas_probe(struct i2c_client
 		goto unregister_trigger;
 	}
 
-	init_irq_work(&data->work, atlas_work_handler);
-
 	if (client->irq > 0) {
 		/* interrupt pin toggles on new conversion */
 		ret = devm_request_threaded_irq(&client->dev, client->irq,
author maintainer
#211 lore raw

PATCH 211/583 iio: chemical: sgp30: Handle IAQ thread creation failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Linmao Li <[email protected]>

commit 1135d6875d2dbda3f6ec718f3421a6ce4378bd63 upstream.

kthread_run() can fail and return an error pointer, but sgp_probe() stores it and returns success, so the device is registered without its IAQ thread and sgp_remove() later passes the error pointer to kthread_stop(). Return the error from probe instead.

Fixes ce514124161a ("iio: chemical: sgp30: Support Sensirion SGP30/SGPC3 sensors")
---
 drivers/iio/chemical/sgp30.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/iio/chemical/sgp30.c +3 -0
@@ -548,6 +548,9 @@ static int sgp_probe(struct i2c_client *
 
 	data->iaq_thread = kthread_run(sgp_iaq_threadfn, data,
 				       "%s-iaq", data->client->name);
+	if (IS_ERR(data->iaq_thread))
+		return dev_err_probe(dev, PTR_ERR(data->iaq_thread),
+				     "failed to start IAQ thread\n");
 
 	return 0;
 }
author maintainer
#212 lore raw

PATCH 212/583 iio: dac: ad3552r-hs: fix scnprintf() buffer bound in data source show

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Babanpreet Singh <[email protected]>

commit f2c5c76306fadb834dd5ea76cab0b7cd447e6035 upstream.

ad3552r_hs_show_data_source_avail() formats the available data source names into a 128-byte stack buffer, but bounds each scnprintf() with PAGE_SIZE instead of the buffer size, so the bound does not protect the destination at all.

This cannot overflow today - dbgfs_attr_source[] has two entries, "normal" and "ramp-16bit", 18 bytes formatted - but the bound stops protecting the stack the day the table grows. Use sizeof(buf) so the bound matches the destination.

Found by smatch:

drivers/iio/dac/ad3552r-hs.c:593 ad3552r_hs_show_data_source_avail()
error: scnprintf() 'buf[len]' too small (128 vs 4096)

Fixes b1c5d68ea66e ("iio: dac: ad3552r-hs: add support for internal ramp")
Assisted-by Claude:claude-sonnet-5
---
 drivers/iio/dac/ad3552r-hs.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/dac/ad3552r-hs.c +1 -1
@@ -591,7 +591,7 @@ static ssize_t ad3552r_hs_show_data_sour
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(dbgfs_attr_source); i++) {
-		len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
+		len += scnprintf(buf + len, sizeof(buf) - len, "%s ",
 				 dbgfs_attr_source[i]);
 	}
 	buf[len - 1] = '\n';
author maintainer
#213 lore raw

PATCH 213/583 iio: dac: m62332: Fix regulator reference count imbalance

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Erick Henrique <[email protected]>

commit a130404ce0b69ca1438126bd81c1985d3b4d2e6f upstream.

m62332_set_value() enables the Vcc regulator on every write of a non-zero value and disables it on every write of zero, without tracking the channel's current state. Because the regulator is reference counted, changing a channel directly from one non-zero value to another enables it more than once, while a later write of zero disables it only once. The reference count never returns to zero and the regulator is left enabled indefinitely.

Only enable the regulator on the transition from zero to non-zero, and only disable it on the transition from non-zero to zero, using the previously stored channel value to detect the edge. Balance the regulator on the I2C error path so the reference count stays consistent if the write fails.

---
 drivers/iio/dac/m62332.c |   17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/iio/dac/m62332.c +12 -5
@@ -32,6 +32,7 @@ static int m62332_set_value(struct iio_d
 {
 	struct m62332_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
+	bool enabling, disabling;
 	u8 outbuf[2];
 	int res;
 
@@ -43,7 +44,10 @@ static int m62332_set_value(struct iio_d
 
 	mutex_lock(&data->mutex);
 
-	if (val) {
+	enabling = val && !data->raw[channel];
+	disabling = !val && data->raw[channel];
+
+	if (enabling) {
 		res = regulator_enable(data->vcc);
 		if (res)
 			goto out;
@@ -52,14 +56,17 @@ static int m62332_set_value(struct iio_d
 	res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));
 	if (res >= 0 && res != ARRAY_SIZE(outbuf))
 		res = -EIO;
-	if (res < 0)
+	if (res < 0) {
+		if (enabling)
+			regulator_disable(data->vcc);
 		goto out;
+	}
 
-	data->raw[channel] = val;
-
-	if (!val)
+	if (disabling)
 		regulator_disable(data->vcc);
 
+	data->raw[channel] = val;
+
 	mutex_unlock(&data->mutex);
 
 	return 0;
author maintainer
#214 lore raw

PATCH 214/583 iio: gyro: mpu3050: fix sign of raw angular velocity readings

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cong Nguyen <[email protected]>

commit 06fab97602fe400bea843176f485bbac07a668e2 upstream.

The MPU-3050 gyroscope output registers hold 16-bit two's complement values; the angular velocity channels are declared with .sign = 's'. When mpu3050_read_raw() handles IIO_CHAN_INFO_RAW it reads the register via a big-endian regmap_bulk_read() and assigns it with:

	*val = be16_to_cpu(raw_val);

be16_to_cpu() yields an unsigned 16-bit quantity, so negative rates (bit 15 set) are reported to userspace as large positive integers (e.g. -1 becomes 65535) instead of the correct negative value.

Cast to s16 before the assignment, matching the temperature channel a few lines above which already handles the sign correctly.

Fixes 3904b28efb2c ("iio: gyro: Add driver for the MPU-3050 gyroscope")
Assisted-by Claude:claude-opus-4
---
 drivers/iio/gyro/mpu3050-core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/gyro/mpu3050-core.c +1 -1
@@ -356,7 +356,7 @@ static int mpu3050_read_raw(struct iio_d
 				goto out_read_raw_unlock;
 			}
 
-			*val = be16_to_cpu(raw_val);
+			*val = (s16)be16_to_cpu(raw_val);
 			ret = IIO_VAL_INT;
 
 			goto out_read_raw_unlock;
author maintainer
#215 lore raw

PATCH 215/583 iio: light: cm32181: return zero after writing calibscale

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Giorgi Tchankvetadze <[email protected]>

commit 8756acd30919a3e9f547ea4a1d4b7f7895f4d340 upstream.

The write_raw callback is documented to return 0 on success or a negative error code. However, the IIO_CHAN_INFO_CALIBSCALE case returns 'val' (the user-supplied value) instead of 0.

Fix it by returning 0 on success, matching the behavior of other calibscale implementations in the subsystem.

Fixes 971672c0b3cc ("iio: add Capella CM32181 ambient light sensor driver.")
---
 drivers/iio/light/cm32181.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/cm32181.c +1 -1
@@ -369,7 +369,7 @@ static int cm32181_write_raw(struct iio_
 	switch (mask) {
 	case IIO_CHAN_INFO_CALIBSCALE:
 		cm32181->calibscale = val;
-		return val;
+		return 0;
 	case IIO_CHAN_INFO_INT_TIME:
 		ret = cm32181_write_als_it(cm32181, val2);
 		return ret;
author maintainer
#216 lore raw

PATCH 216/583 iio: light: gp2ap002: Disable regulators on resume failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Laxman Acharya Padhya <[email protected]>

commit a41000ba3a230bed1e422f283486ff8f77fe0d30 upstream.

If enabling VIO fails after VDD has been enabled, runtime resume returns without disabling VDD. Likewise, if device reinitialization fails, both supplies remain enabled. The runtime PM core keeps the device suspended when its resume callback fails, so the supplies must be restored to the suspended state.

Disable the supplies enabled by the callback before returning an error.

Fixes 97d642e23037 ("iio: light: Add a driver for Sharp GP2AP002x00F")
Assisted-by Codex:gpt-5
---
 drivers/iio/light/gp2ap002.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/iio/light/gp2ap002.c +8 -2
@@ -669,7 +669,7 @@ static int gp2ap002_runtime_resume(struc
 	ret = regulator_enable(gp2ap002->vio);
 	if (ret) {
 		dev_err(dev, "failed to enable VIO regulator in resume path\n");
-		return ret;
+		goto out_disable_vdd;
 	}
 
 	msleep(20);
@@ -677,13 +677,19 @@ static int gp2ap002_runtime_resume(struc
 	ret = gp2ap002_init(gp2ap002);
 	if (ret) {
 		dev_err(dev, "re-initialization failed\n");
-		return ret;
+		goto out_disable_vio;
 	}
 
 	/* Re-activate the IRQ */
 	enable_irq(gp2ap002->irq);
 
 	return 0;
+
+out_disable_vio:
+	regulator_disable(gp2ap002->vio);
+out_disable_vdd:
+	regulator_disable(gp2ap002->vdd);
+	return ret;
 }
 
 static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
author maintainer
#217 lore raw

PATCH 217/583 iio: light: ltrf216a: fix runtime PM reference leak in error path

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vidhu Sarwal <[email protected]>

commit c132aef0e757a39036b1d40faf0569f2e343b13e upstream.

ltrf216a_get_lux() acquires a runtime PM reference by calling ltrf216a_set_power_state(data, true). However, if ltrf216a_read_data() fails, the function returns immediately without dropping the reference.

This leaves the runtime PM usage count unbalanced, preventing the device from autosuspending after a failed read.

Fix this by releasing the runtime PM reference before returning from the error path.

Fixes 83f0bcd40d5c ("iio: light: Add support for ltrf216a sensor")
---
 drivers/iio/light/ltrf216a.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iio/light/ltrf216a.c +1 -2
@@ -248,11 +248,10 @@ static int ltrf216a_get_lux(struct ltrf2
 		return ret;
 
 	greendata = ltrf216a_read_data(data, LTRF216A_ALS_DATA_0);
+	ltrf216a_set_power_state(data, false);
 	if (greendata < 0)
 		return greendata;
 
-	ltrf216a_set_power_state(data, false);
-
 	lux = greendata * data->info->lux_multiplier * LTRF216A_WIN_FAC;
 
 	return lux;
author maintainer
#218 lore raw

PATCH 218/583 iio: pressure: dps310: fix NULL pointer dereference on ACPI probe

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Rupesh Majhi <[email protected]>

commit 26e9213898fc949923188ef0aeea31fc87708836 upstream.

When the device is enumerated through its ACPI HID (IFX3100), i2c_client_get_device_id() returns NULL: the ACPI-derived client name does not match the driver's i2c_device_id table. dps310_probe() then dereferences that NULL pointer in "iio->name = id->name" and crashes the kernel during probe.

The IIO device name is always "dps310", so set it directly and drop the now-unused device-id lookup.

Fixes 72ff282819d0 ("iio: pressure: dps310: Add ACPI HID table")
---
 drivers/iio/pressure/dps310.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iio/pressure/dps310.c +1 -2
@@ -845,7 +845,6 @@ static const struct iio_info dps310_info
 
 static int dps310_probe(struct i2c_client *client)
 {
-	const struct i2c_device_id *id = i2c_client_get_device_id(client);
 	struct dps310_data *data;
 	struct iio_dev *iio;
 	int rc;
@@ -858,7 +857,7 @@ static int dps310_probe(struct i2c_clien
 	data->client = client;
 	mutex_init(&data->lock);
 
-	iio->name = id->name;
+	iio->name = DPS310_DEV_NAME;
 	iio->channels = dps310_channels;
 	iio->num_channels = ARRAY_SIZE(dps310_channels);
 	iio->info = &dps310_info;
author maintainer
#219 lore raw

PATCH 219/583 iio: pressure: mpl115: Fix runtime PM cleanup

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Can Peng <[email protected]>

commit 0b5e142ced4bcf20532da051934bd694d1bbd470 upstream.

mpl115_probe() enables runtime PM when a shutdown GPIO is present and then returns the result of devm_iio_device_register(). If registration fails, runtime PM remains enabled and autosuspend remains selected.

The same unmanaged runtime PM state is also left behind on driver unbind, as the IIO device registration is managed but the runtime PM setup is not.

Use devm_pm_runtime_enable() so runtime PM is disabled automatically on probe failure and driver unbind, and check pm_runtime_set_active() so setup errors are reported.

Set the autosuspend parameters before enabling runtime PM. Once probe has completed, the driver core queues an idle request for the device, so an explicit pm_runtime_get_noresume()/pm_runtime_put() pair is not needed to start autosuspend.

Fixes 0c3a333524a3 ("iio: pressure: mpl115: Implementing low power mode by shutdown gpio")
Suggested-by [email protected]
---
 drivers/iio/pressure/mpl115.c |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/iio/pressure/mpl115.c +7 -4
@@ -203,9 +203,9 @@ int mpl115_probe(struct device *dev, con
 
 	if (data->shutdown) {
 		/* Enable runtime PM */
-		pm_runtime_get_noresume(dev);
-		pm_runtime_set_active(dev);
-		pm_runtime_enable(dev);
+		ret = pm_runtime_set_active(dev);
+		if (ret)
+			return ret;
 
 		/*
 		 * As the device takes 3 ms to come up with a fresh
@@ -215,7 +215,10 @@ int mpl115_probe(struct device *dev, con
 		 */
 		pm_runtime_set_autosuspend_delay(dev, 2000);
 		pm_runtime_use_autosuspend(dev);
-		pm_runtime_put(dev);
+
+		ret = devm_pm_runtime_enable(dev);
+		if (ret)
+			return ret;
 
 		dev_dbg(dev, "low-power mode enabled");
 	} else
author maintainer
#220 lore raw

PATCH 220/583 iio: srf04: fix pm_runtime handling on probe error path

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cong Nguyen <[email protected]>

commit a40b2e7a17f26e38ab054363c9c7cde149588357 upstream.

When pm_runtime_set_active() fails during probe, the driver logs the error and unregisters the IIO device, but then falls through and still calls pm_runtime_enable() before returning the error.

Since probe returns an error, srf04_remove() is never called, so runtime PM is left enabled without a matching pm_runtime_disable(). This leaks the enable and triggers an "Unbalanced pm_runtime_enable!" warning on a subsequent bind of the device.

Return the error right after unregistering the IIO device so that runtime PM is not enabled on the failure path.

Fixes 2251157b335b ("iio: srf04: add power management feature")
---
 drivers/iio/proximity/srf04.c |    1 +
 1 file changed, 1 insertion(+)
drivers/iio/proximity/srf04.c +1 -0
@@ -331,6 +331,7 @@ static int srf04_probe(struct platform_d
 		if (ret) {
 			dev_err(data->dev, "pm_runtime_set_active: %d\n", ret);
 			iio_device_unregister(indio_dev);
+			return ret;
 		}
 
 		pm_runtime_enable(data->dev);
author maintainer
#221 lore raw

PATCH 221/583 iio: temperature: hid-sensor-temperature: switch to non-devm iio_device_register()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sanjay Chitroda <[email protected]>

commit 967d066f5334740f656577bc51c381a1bb707b61 upstream.

Avoid using devm_iio_device_register(), as this driver requires explicit error handling and teardown ordering.

With devm_iio_device_register(), IIO device remains registered until the devres cleanup phase. However, driver's remove() callback removes the sensor hub callback and trigger support. This can create a race window where IIO device is still visible and read_raw() requests are issued. These requests might call sensor_hub_input_attr_get_raw_value(), which waits up to 5 seconds for a response from the sensor hub callback that has already been removed.

Add an explicit iio_device_unregister() call in the teardown path to ensure deterministic cleanup, so that userspace can no longer access the device once backend resources begin to be dismantled.

---
 drivers/iio/temperature/hid-sensor-temperature.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/iio/temperature/hid-sensor-temperature.c +2 -1
@@ -244,7 +244,7 @@ static int hid_temperature_probe(struct
 	if (ret)
 		goto error_remove_trigger;
 
-	ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
+	ret = iio_device_register(indio_dev);
 	if (ret)
 		goto error_remove_callback;
 
@@ -264,6 +264,7 @@ static void hid_temperature_remove(struc
 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 	struct temperature_state *temp_st = iio_priv(indio_dev);
 
+	iio_device_unregister(indio_dev);
 	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
 	hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
 }
author maintainer
#222 lore raw

PATCH 222/583 iio: ti-ads7138: Disable STATS_EN bit while reading conversion results

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Paul Geurts <[email protected]>

commit bcb721c1bcb02ab225b3937bf131a0bc6fc1fecd upstream.

There is a data race in reading the STATS registers, resulting in wrong data being read. When the data in the RECENT register switches between 0x24F0 and 0x2500, occasionally value 0x2400 or 0x25F0 is read. This happens when the value is updated in between reading MSB and LSB.

The data sheet says: "Until a new conversion result is available, previous values can be read from the statistics registers. Before reading the statistics registers, set STATS_EN to 0 to prevent any updates to this register block." As the STATS_EN is currently not cleared, the values of the stats registers might change mid read, giving faulty values.

Disable the STATS_EN bit before reading one of the statistics registers to make sure the device does not update the register mid read. This is applicable to registers MAX_CHn_xSB, MIN_CHn_xSB and RECENT_CHn_xSB.

This means reading one of the statistics registers resets the MAX and MIN registers. This is unfortunate, but necessary to get correct data from the device.

Fixes 024b08fee342 ("iio: adc: Add driver for ADS7128 / ADS7138")
---
 drivers/iio/adc/ti-ads7138.c |   42 +++++++++++++++++++++++++++++++++---------
 1 file changed, 33 insertions(+), 9 deletions(-)
drivers/iio/adc/ti-ads7138.c +33 -9
@@ -227,6 +227,26 @@ static int ads7138_osr_to_bits(int osr)
 	return -EINVAL;
 }
 
+static int ads7138_read_statistics(const struct i2c_client *client, u8 reg,
+				   u8 *out_values, u8 length)
+{
+	int ret;
+
+	/* Disable statistics update so the value is not updated mid read */
+	ret = ads7138_i2c_clear_bit(client, ADS7138_REG_GENERAL_CFG,
+				    ADS7138_GENERAL_CFG_STATS_EN);
+	if (ret)
+		return ret;
+
+	ret = ads7138_i2c_read_block(client, reg, out_values, length);
+	if (ret)
+		return ret;
+
+	/* Enable statistics update after read */
+	return ads7138_i2c_set_bit(client, ADS7138_REG_GENERAL_CFG,
+				   ADS7138_GENERAL_CFG_STATS_EN);
+}
+
 static int ads7138_read_raw(struct iio_dev *indio_dev,
 			    struct iio_chan_spec const *chan, int *val,
 			    int *val2, long mask)
@@ -236,28 +256,32 @@ static int ads7138_read_raw(struct iio_d
 	u8 values[2];
 
 	switch (mask) {
+	/*
+	 * Reading the statistics registers reinitializes them. This is
+	 * unfortunate but necessary to prevent data races.
+	 */
 	case IIO_CHAN_INFO_RAW:
-		ret = ads7138_i2c_read_block(data->client,
-					     ADS7138_REG_RECENT_LSB_CH(chan->channel),
-					     values, ARRAY_SIZE(values));
+		ret = ads7138_read_statistics(data->client,
+					      ADS7138_REG_RECENT_LSB_CH(chan->channel),
+					      values, ARRAY_SIZE(values));
 		if (ret)
 			return ret;
 
 		*val = get_unaligned_le16(values);
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_PEAK:
-		ret = ads7138_i2c_read_block(data->client,
-					     ADS7138_REG_MAX_LSB_CH(chan->channel),
-					     values, ARRAY_SIZE(values));
+		ret = ads7138_read_statistics(data->client,
+					      ADS7138_REG_MAX_LSB_CH(chan->channel),
+					      values, ARRAY_SIZE(values));
 		if (ret)
 			return ret;
 
 		*val = get_unaligned_le16(values);
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_TROUGH:
-		ret = ads7138_i2c_read_block(data->client,
-					     ADS7138_REG_MIN_LSB_CH(chan->channel),
-					     values, ARRAY_SIZE(values));
+		ret = ads7138_read_statistics(data->client,
+					      ADS7138_REG_MIN_LSB_CH(chan->channel),
+					      values, ARRAY_SIZE(values));
 		if (ret)
 			return ret;
 
author maintainer
#223 lore raw

PATCH 223/583 iio: light: opt4060: Reject integration times with a non-zero seconds part

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vidhu Sarwal <[email protected]>

commit b7e6e9af0d723afdec92364d5e7e064eeef44c8e upstream.

When setting the integration time, opt4060_write_raw() only uses val2 and ignores val. As a result, a write such as 1.000600 is accepted and programmed as 600 us, silently discarding the whole seconds part.

Since all supported integration times are less than one second, any non-zero val represents an invalid input. Reject such values instead of silently accepting them.

Fixes 0c6db4506ad0 ("iio: light: Add support for TI OPT4060 color sensor")
---
 drivers/iio/light/opt4060.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/iio/light/opt4060.c +3 -0
@@ -650,6 +650,9 @@ static int opt4060_write_raw(struct iio_
 
 	switch (mask) {
 	case IIO_CHAN_INFO_INT_TIME:
+		if (val)
+			return -EINVAL;
+
 		int_time = opt4060_als_time_to_index(val2);
 		if (int_time < 0)
 			return int_time;
author maintainer
#224 lore raw

PATCH 224/583 iio: light: opt4060: Fix incorrect register name in threshold read error message

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vidhu Sarwal <[email protected]>

commit ad367638212a9f2495ecfa59c886f0cfb7934e9c upstream.

opt4060_get_thresholds() correctly reads OPT4060_THRESHOLD_HIGH, but logs "Failed to read THRESHOLD_LOW." if the read fails. This is a copy-and-paste mistake, as the preceding low-threshold read already uses the correct error message.

Update the error message to reference OPT4060_THRESHOLD_HIGH.

Fixes 0c6db4506ad0 ("iio: light: Add support for TI OPT4060 color sensor")
---
 drivers/iio/light/opt4060.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/opt4060.c +1 -1
@@ -826,7 +826,7 @@ static int opt4060_get_thresholds(struct
 
 	ret = regmap_read(chip->regmap, OPT4060_THRESHOLD_HIGH, &regval);
 	if (ret) {
-		dev_err(chip->dev, "Failed to read THRESHOLD_LOW.\n");
+		dev_err(chip->dev, "Failed to read THRESHOLD_HIGH.\n");
 		return ret;
 	}
 	*th_hi = opt4060_calc_val_from_th_reg(regval);
author maintainer
#225 lore raw

PATCH 225/583 iio: light: opt4001: Fix power down clearing bits of the wrong register

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nikhil Gautam <[email protected]>

commit 3b2cd82c524c75a2173f2e3f874652a75f81cd1d upstream.

opt4001_power_down() intends to clear the operating mode bits in the CTRL register but reads OPT4001_DEVICE_ID instead of OPT4001_CTRL, so the value written back to CTRL contains device ID bits rather than the current configuration.

Fix and simplify this by using regmap_clear_bits() on the CTRL register directly in the devm action, and drop opt4001_power_down() which has no other users.

Fixes 9a9608418292 ("iio: light: Add support for TI OPT4001 light sensor")
---
 drivers/iio/light/opt4001.c |   27 ++++-----------------------
 1 file changed, 4 insertions(+), 23 deletions(-)
drivers/iio/light/opt4001.c +4 -23
@@ -222,33 +222,14 @@ static int opt4001_set_conf(struct opt40
 	return ret;
 }
 
-static int opt4001_power_down(struct opt4001_chip *chip)
-{
-	struct device *dev = &chip->client->dev;
-	int ret;
-	unsigned int reg;
-
-	ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, &reg);
-	if (ret) {
-		dev_err(dev, "Failed to read configuration\n");
-		return ret;
-	}
-
-	/* MODE_OFF is 0x0 so just set bits to 0 */
-	reg &= ~OPT4001_CTRL_OPER_MODE_MASK;
-
-	ret = regmap_write(chip->regmap, OPT4001_CTRL, reg);
-	if (ret)
-		dev_err(dev, "Failed to set configuration to power down\n");
-
-	return ret;
-}
-
 static void opt4001_chip_off_action(void *data)
 {
 	struct opt4001_chip *chip = data;
+	int ret;
 
-	opt4001_power_down(chip);
+	ret = regmap_clear_bits(chip->regmap, OPT4001_CTRL, OPT4001_CTRL_OPER_MODE_MASK);
+	if (ret)
+		dev_err(&chip->client->dev, "Failed to power down\n");
 }
 
 static const struct iio_chan_spec opt4001_channels[] = {
author maintainer
#226 lore raw

PATCH 226/583 iio: light: opt4001: Fix incompatible pointer type passed to div_u64_rem()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nikhil Gautam <[email protected]>

commit afa28741c9a2cf6edb2e41e25ff146a562160bb3 upstream.

div_u64_rem() takes a u32 * for the remainder but is passed val2, which is an int *. There is no functional impact as int and u32 have the same size and representation on all supported architectures and the remainder is always smaller than the divisor, so it fits in the positive range of int. Fix the type mismatch by using a local u32 for the remainder and assigning the result to *val2.

Fixes 9a9608418292 ("iio: light: Add support for TI OPT4001 light sensor")
---
 drivers/iio/light/opt4001.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/iio/light/opt4001.c +3 -2
@@ -173,6 +173,7 @@ static int opt4001_read_lux_value(struct
 	u8 crc;
 	u8 calc_crc;
 	u64 lux_raw;
+	u32 rem;
 	int ret;
 
 	ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1);
@@ -199,8 +200,8 @@ static int opt4001_read_lux_value(struct
 
 	lux_raw = lux_raw << exp;
 	lux_raw = lux_raw * chip->chip_info->mul;
-	*val = div_u64_rem(lux_raw, chip->chip_info->div, val2);
-	*val2 = *val2 * 100;
+	*val = div_u64_rem(lux_raw, chip->chip_info->div, &rem);
+	*val2 = rem * 100;
 
 	return IIO_VAL_INT_PLUS_NANO;
 }
author maintainer
#227 lore raw

PATCH 227/583 iio: light: opt4001: Reject integration times with a non-zero seconds part

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nikhil Gautam <[email protected]>

commit d0f21621f8b2b46661ea066d20705dbf7253db87 upstream.

opt4001_write_raw() only looks at val2 when setting the integration time, so a write such as 1.000600 is silently accepted as 600 us. Return -EINVAL if val is non-zero.

Fixes 9a9608418292 ("iio: light: Add support for TI OPT4001 light sensor")
---
 drivers/iio/light/opt4001.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/iio/light/opt4001.c +3 -0
@@ -269,6 +269,9 @@ static int opt4001_write_raw(struct iio_
 
 	switch (mask) {
 	case IIO_CHAN_INFO_INT_TIME:
+		if (val)
+			return -EINVAL;
+
 		int_time = opt4001_als_time_to_index(val2);
 		if (int_time < 0)
 			return int_time;
author maintainer
#228 lore raw

PATCH 228/583 iio: light: opt4001: Fix reversed GENMASK() arguments in fault count mask

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nikhil Gautam <[email protected]>

commit d64bfd9f3352b9d9bdeca06de1a0a1c1bd47b896 upstream.

GENMASK(h, l) requires h >= l, but OPT4001_CTRL_FAULT_COUNT is defined as GENMASK(0, 1). The define is currently unused so there is no functional impact, but fix it before anyone builds on it, and add the _MASK suffix for consistency with the neighbouring definitions.

Fixes 9a9608418292 ("iio: light: Add support for TI OPT4001 light sensor")
---
 drivers/iio/light/opt4001.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/opt4001.c +1 -1
@@ -39,7 +39,7 @@
 #define OPT4001_CTRL_OPER_MODE_MASK      GENMASK(5, 4)
 #define OPT4001_CTRL_LATCH_MASK          GENMASK(3, 3)
 #define OPT4001_CTRL_INT_POL_MASK        GENMASK(2, 2)
-#define OPT4001_CTRL_FAULT_COUNT         GENMASK(0, 1)
+#define OPT4001_CTRL_FAULT_COUNT_MASK    GENMASK(1, 0)
 
 /* OPT4001 constants */
 #define OPT4001_DEVICE_ID_VAL            0x121
author maintainer
#229 lore raw

PATCH 229/583 KVM: PPC: Book3S HV: Validate arch_compat against host compatibility mode

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Amit Machhiwal <[email protected]>

commit 884ea0283f4effac97ee8f451464a7d1be480d7c upstream.

On IBM POWER systems, newer processor generations can operate in compatibility modes corresponding to earlier generations. This becomes relevant for nested virtualization, where nested KVM guests may need to run with a specific processor compatibility level.

Currently, when running a nested KVM guest (L2) inside a Power11 pSeries logical partition (L1) booted in Power10 compatibility mode, the guest fails to boot while setting 'arch_compat'. This happens because the CPU class is derived from the hardware PVR (via mfspr()), which reflects the physical processor generation (Power11), rather than the effective compatibility mode (Power10).

As a result, userspace may request a Power11 arch_compat for the L2 guest. However, the L1 partition, running in Power10 compatibility, has only negotiated support up to Power10 with the Power Hypervisor (L0). When H_GUEST_SET_STATE is invoked with a Power11 Logical PVR, the hypervisor rejects the request, leading to a late guest boot failure:

KVM-NESTEDv2: couldn't set guest wide elements
[..KVM reg dump..]

This situation should be detected earlier and rejected by KVM. Without proper validation, if userspace ignores the error, the guest may continue to boot in Power11 raw mode on a Power10 compatibility host, which should not be allowed.

Introduce a validation mechanism that detects unsupported arch_compat values early in the guest initialization path. When an unsupported arch_compat is requested (e.g., Power11 on a Power10 compatibility mode host), kvmppc_set_arch_compat() uses cpu_has_feature(CPU_FTR_P11_PVR) to detect the mismatch and sets arch_compat to PVR_ARCH_INVALID (0xffffffff). This sentinel value is architecturally safe: PAPR specifies that valid logical PVR values must have 0x0f as the first byte, ensuring 0xffffffff lies permanently outside the specification-defined range. Setting this value triggers kvmppc_sanity_check() to mark the vCPU as invalid by setting vcpu->arch.sane to false. On the next vCPU run, kvmppc_vcpu_run_hv() checks this flag and returns -EINVAL, preventing the guest from running with an invalid processor compatibility configuration.

With this, when a Power11 arch_compat is requested on a Power10 compatibility mode host, the guest fails early during boot with:

error: kvm run failed Invalid argument

This provides a much clearer failure mode compared to the previous behavior where the guest could boot in Power11 raw mode (if userspace ignored the error) or fail late during H_GUEST_SET_STATE.

---
 arch/powerpc/include/asm/reg.h |   12 ++++++++++++
 arch/powerpc/kvm/book3s_hv.c   |   15 ++++++++++++++-
 arch/powerpc/kvm/powerpc.c     |    6 ++++++
 3 files changed, 32 insertions(+), 1 deletion(-)
arch/powerpc/include/asm/reg.h +12 -0
@@ -1357,6 +1357,18 @@
 #define PVR_ARCH_31	0x0f000006
 #define PVR_ARCH_31_P11	0x0f000007
 
+/*
+ * Kernel-internal sentinel for invalid processor compatibility modes.
+ * PAPR specifies that the first byte of a valid logical PVR value is
+ * 0x0f. So 0xffffffff lies permanently outside the PAPR-defined range
+ * and is safe to repurpose. KVM stores it in vcpu->arch.arch_compat
+ * when userspace requests an unsupported compatibility mode (e.g.,
+ * Power11 PVR on a Power11 host booted in Power10 compat).
+ * kvmppc_sanity_check() detects this and prevents the vCPU from
+ * running with an unsupported arch_compat.
+ */
+#define PVR_ARCH_INVALID	0xffffffff
+
 /* Macros for setting and retrieving special purpose registers */
 #ifndef __ASSEMBLER__
 
arch/powerpc/kvm/book3s_hv.c +14 -1
@@ -447,7 +447,19 @@ static int kvmppc_set_arch_compat(struct
 			guest_pcr_bit = PCR_ARCH_300;
 			break;
 		case PVR_ARCH_31:
+			guest_pcr_bit = PCR_ARCH_31;
+			break;
 		case PVR_ARCH_31_P11:
+			/*
+			 * Need to check this for ISA 3.1, as Power10 and
+			 * Power11 share the same PCR. For any subsequent ISA
+			 * versions, this will be taken care of by the guest vs
+			 * host PCR comparison below.
+			 */
+			if (!cpu_has_feature(CPU_FTR_P11_PVR)) {
+				arch_compat = PVR_ARCH_INVALID;
+				goto out;
+			}
 			guest_pcr_bit = PCR_ARCH_31;
 			break;
 		default:
@@ -470,6 +482,7 @@ static int kvmppc_set_arch_compat(struct
 			return -EINVAL;
 	}
 
+out:
 	spin_lock(&vc->lock);
 	vc->arch_compat = arch_compat;
 	kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LOGICAL_PVR);
@@ -480,7 +493,7 @@ static int kvmppc_set_arch_compat(struct
 	vc->pcr = (host_pcr_bit - guest_pcr_bit) | PCR_MASK;
 	spin_unlock(&vc->lock);
 
-	return 0;
+	return kvmppc_sanity_check(vcpu);
 }
 
 static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
arch/powerpc/kvm/powerpc.c +6 -0
@@ -258,6 +258,12 @@ int kvmppc_sanity_check(struct kvm_vcpu
 	if (!vcpu->arch.pvr)
 		goto out;
 
+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
+	if (vcpu->arch.vcore &&
+	    vcpu->arch.vcore->arch_compat == PVR_ARCH_INVALID)
+		goto out;
+#endif
+
 	/* PAPR only works with book3s_64 */
 	if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled)
 		goto out;
author maintainer
#230 lore raw

PATCH 230/583 KVM: nVMX: Always flush vpid02 on first use

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yosry Ahmed <[email protected]>

commit f0772389413dce9657c7d6950abf3edbbd511356 upstream.

Make sure vpid02 is always flushed on first use by setting last_vpid=0 when allocating vpid02. nested_vmx_transition_tlb_flush() will always detect a VPID change on first VM-Enter after VMXON, because VPID=0 in vmcs12 is not allowed if L1 enables VPID.

This avoids using stale TLB entries from a previous lifetime of the VPID, that might have been associated with a different vCPU (or a completely different VM).

Note that last_vpid is already being initialized as 0 when the vCPU is created, but it is not reset when vpid02 is freed on VMXOFF. Hence, the problem can only occur if L1 does VMXOFF -> VMXON, runs an L2, and KVM happens to reuse a VPID that has TLB entries on the physical CPU.

---
 arch/x86/kvm/vmx/nested.c |   10 ++++++++++
 1 file changed, 10 insertions(+)
arch/x86/kvm/vmx/nested.c +10 -0
@@ -1269,6 +1269,9 @@ static void nested_vmx_transition_tlb_fl
 	 * is the VPID incorporated into the MMU context.  I.e. KVM must assume
 	 * that the new vpid12 has never been used and thus represents a new
 	 * guest ASID that cannot have entries in the TLB.
+	 *
+	 * Note, last_vpid is initialized as 0, so the first nested VM-Enter
+	 * after VMXON will always flush the TLB to avoid using stale entries.
 	 */
 	if (is_vmenter && vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
 		vmx->nested.last_vpid = vmcs12->virtual_processor_id;
@@ -5514,6 +5517,13 @@ static int enter_vmx_operation(struct kv
 
 	vmx->nested.vpid02 = allocate_vpid();
 
+	/*
+	 * Clear last_vpid to ensure that the VPID is flushed on the first
+	 * nested VM-Enter. Otherwise, stale TLB entries from a previous life of
+	 * the VPID (e.g. different vCPU or even different VM) could be used.
+	 */
+	vmx->nested.last_vpid = 0;
+
 	vmx->nested.vmcs02_initialized = false;
 	vmx->nested.vmxon = true;
 
author maintainer
#231 lore raw

PATCH 231/583 KVM: nVMX: Decouple INVVPID operand checks from flushing of vpid02

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit 32912404b4b1ee98400744941c78f019a63d6e8f upstream.

Separate the INVVPID operand checks from the actual flushing of vpid02 so the flushing can be adjusted to do the right thing when vmcs02 was last loaded on a different pCPU, without having to duplicate the logic across multiple case-statements.

Opportunistically let the VM-Fail paths poke out past 80 chars.

No functional change intended.

---
 arch/x86/kvm/vmx/nested.c |   43 +++++++++++++------------------------------
 1 file changed, 13 insertions(+), 30 deletions(-)
arch/x86/kvm/vmx/nested.c +13 -30
@@ -6151,7 +6151,6 @@ static int handle_invvpid(struct kvm_vcp
 		u64 vpid;
 		u64 gla;
 	} operand;
-	u16 vpid02;
 	int r, gpr_index;
 
 	if (!(vmx->nested.msrs.secondary_ctls_high &
@@ -6186,8 +6185,15 @@ static int handle_invvpid(struct kvm_vcp
 		return kvm_handle_memory_failure(vcpu, r, &e);
 
 	if (operand.vpid >> 16)
-		return nested_vmx_fail(vcpu,
-			VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+		return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+
+	if (type != VMX_VPID_EXTENT_ALL_CONTEXT && !operand.vpid)
+		return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+
+	/* LAM doesn't apply to addresses that are inputs to TLB invalidation. */
+	if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR &&
+	    is_noncanonical_invlpg_address(operand.gla, vcpu))
+		return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
 
 	/*
 	 * Always flush the effective vpid02, i.e. never flush the current VPID
@@ -6195,33 +6201,10 @@ static int handle_invvpid(struct kvm_vcp
 	 * VMCS, and so whether or not the current vmcs12 has VPID enabled is
 	 * irrelevant (and there may not be a loaded vmcs12).
 	 */
-	vpid02 = nested_get_vpid02(vcpu);
-	switch (type) {
-	case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
-		/*
-		 * LAM doesn't apply to addresses that are inputs to TLB
-		 * invalidation.
-		 */
-		if (!operand.vpid ||
-		    is_noncanonical_invlpg_address(operand.gla, vcpu))
-			return nested_vmx_fail(vcpu,
-				VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
-		vpid_sync_vcpu_addr(vpid02, operand.gla);
-		break;
-	case VMX_VPID_EXTENT_SINGLE_CONTEXT:
-	case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
-		if (!operand.vpid)
-			return nested_vmx_fail(vcpu,
-				VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
-		vpid_sync_context(vpid02);
-		break;
-	case VMX_VPID_EXTENT_ALL_CONTEXT:
-		vpid_sync_context(vpid02);
-		break;
-	default:
-		WARN_ON_ONCE(1);
-		return kvm_skip_emulated_instruction(vcpu);
-	}
+	if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR)
+		vpid_sync_vcpu_addr(nested_get_vpid02(vcpu), operand.gla);
+	else
+		vpid_sync_context(nested_get_vpid02(vcpu));
 
 	/*
 	 * Sync the shadow page tables if EPT is disabled, L1 is invalidating
author maintainer
#232 lore raw

PATCH 232/583 KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit 11722439fb206c88e6f31be54173efa9880b4ccb upstream.

Always check and clear KVM_REQ_GET_NESTED_STATE_PAGES when emulating a nested VM-Exit to ensure the request is cleared, even when KVM was built with CONFIG_KVM_HYPERV=n, as KVM subtly relies on the "check" to clear the flag and thus avoid double-mapping the vmcs12 pages, e.g. if KVM manages to bail from VM-Enter without processing the request, and then emulates VMLAUNCH or VMRESUME.

---
 arch/x86/kvm/vmx/nested.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/nested.c +3 -2
@@ -5135,8 +5135,9 @@ void __nested_vmx_vmexit(struct kvm_vcpu
 	/* trying to cancel vmlaunch/vmresume is a bug */
 	WARN_ON_ONCE(vmx->nested.nested_run_pending);
 
-#ifdef CONFIG_KVM_HYPERV
+	/* Note, "checking" the request also clears the request. */
 	if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
+#ifdef CONFIG_KVM_HYPERV
 		/*
 		 * KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
 		 * Enlightened VMCS after migration and we still need to
@@ -5144,8 +5145,8 @@ void __nested_vmx_vmexit(struct kvm_vcpu
 		 * the first L2 run.
 		 */
 		(void)nested_get_evmcs_page(vcpu);
-	}
 #endif
+	}
 
 	/* Service pending TLB flush requests for L2 before switching to L1. */
 	kvm_service_local_tlb_flush_requests(vcpu);
author maintainer
#233 lore raw

PATCH 233/583 KVM: nVMX: Service local TLB flushes on failed nested VM-Enter

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yosry Ahmed <[email protected]>

commit 05a0b701d1089fb57beeb8982f23c3bbafe0fa8b upstream.

KVM services local TLB flushes on "full" nested VM-Exits (through __nested_vmx_vmexit()), but not if a nested VM-Enter fails (e.g. due to failed VMCS checks in nested_vmx_enter_non_root_mode()).

However, it is possible that KVM had queued TLB flushes that need to be performed, even if the nested VM-Enter was not successful. For example, if VPID is disabled for L2 (via nested_vmx_transition_tlb_flush(), or if via the MSR load lists, as the SDM says:

If any MSR is being loaded in such a way that would architecturally require a TLB flush, the TLBs are updated so that, after VM entry, the logical processor will not use any translations that were cached before the transition.

The SDM is unclear about when the TLB flush should occur, and whether or not a failed VM entry would flush the TLB, so it is safer to always do the TLB flush in this case.

More concretely, KVM also updates the last VPID L1 used for L2 in nested_vmx_transition_tlb_flush() (i.e. last_vpid), even if the VM entry ultimately fails. With the current code, KVM could miss a TLB flush if L1 changes L2's VPID, then does a failed VM entry followed by a successful one, as the failed VM entry would update last_vpid but not actually flush the TLB. Servicing local TLB flushes on failed VM entries makes sure that the TLB is always flushed when last_vpid is updated.

---
 arch/x86/kvm/vmx/nested.c |    8 ++++++++
 1 file changed, 8 insertions(+)
arch/x86/kvm/vmx/nested.c +8 -0
@@ -3801,6 +3801,14 @@ enum nvmx_vmentry_status nested_vmx_ente
 vmentry_fail_vmexit_guest_mode:
 	if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
 		vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
+
+	/*
+	 * Handle any TLB flush requests that were queued for L2 if KVM made it
+	 * far enough along to switch to L2 context.  Note, loading host state
+	 * will generate any flushes for L1 required by VM-Exit.
+	 */
+	kvm_service_local_tlb_flush_requests(vcpu);
+
 	leave_guest_mode(vcpu);
 
 vmentry_fail_vmexit:
author maintainer
#234 lore raw

PATCH 234/583 KVM: nVM: Ensure INVVPID is emulated on the correct physical CPU

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yosry Ahmed <[email protected]>

commit 6d00e67326d831e6e610933a3800712f4ffe6ec1 upstream.

When emulating INVVPID, KVM executes INVVPID on the physical CPU using vpid02 (instead of the L1 assigned VPID), after doing some validations on the operands. However, it is possible that the physical CPU KVM executes INVVPID on is different from the CPU L2 is running on.

For example, in the following scenario:
- L2 runs on CPU #1 and exits to L1 (vmx->nested.vmcs02.cpu=1)
- L1 migrates to CPU #2 and executes INVVPID
- KVM executes INVVPID on CPU #2
- L1 migrates back to CPU #1 and runs L2 (vmx->nested.vmcs02.cpu=1)

The TLB entries on CPU #1 are never invalidated, because INVVPID was executed on CPU #2, and vmcs02 never ran on a different pCPU (i.e. vmx_vcpu_load_vmcs() will *not* request KVM_REQ_TLB_FLUSH).

Ensure that INVVPID is being executed on the same pCPU that L2 last ran on, and if not, fallback to clearing last_vpid=0 to trigger a full VPID flush on the next nested VM-Enter (as KVM will detect L1 using a different VPID for L2). If L2 ends up running on a different pCPU, KVM will flush the TLB anyway through vmx_vcpu_load_vmcs().

---
 arch/x86/kvm/vmx/nested.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/nested.c +10 -1
@@ -6161,6 +6161,7 @@ static int handle_invvpid(struct kvm_vcp
 		u64 gla;
 	} operand;
 	int r, gpr_index;
+	int cpu;
 
 	if (!(vmx->nested.msrs.secondary_ctls_high &
 	      SECONDARY_EXEC_ENABLE_VPID) ||
@@ -6209,11 +6210,19 @@ static int handle_invvpid(struct kvm_vcp
 	 * and never explicitly flush vpid01.  INVVPID targets a VPID, not a
 	 * VMCS, and so whether or not the current vmcs12 has VPID enabled is
 	 * irrelevant (and there may not be a loaded vmcs12).
+	 *
+	 * If vmcs02 was last loaded on a different pCPU, then defer the flush
+	 * by invalidating the nested VPID tracking to ensure that KVM performs
+	 * the invalidation on the correct pCPU.
 	 */
-	if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR)
+	cpu = get_cpu();
+	if (cpu != vmx->nested.vmcs02.cpu)
+		vmx->nested.last_vpid = 0;
+	else if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR)
 		vpid_sync_vcpu_addr(nested_get_vpid02(vcpu), operand.gla);
 	else
 		vpid_sync_context(nested_get_vpid02(vcpu));
+	put_cpu();
 
 	/*
 	 * Sync the shadow page tables if EPT is disabled, L1 is invalidating
author maintainer
#235 lore raw

PATCH 235/583 KVM: x86/mmu: Fold kvm_mmu_zap_memslot() into kvm_arch_flush_shadow_memslot()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit 06d38eaa78fdac1cc889f261fa420eba8e9caa1a upstream.

Fold kvm_mmu_zap_memslot() into its sole caller so that its GFN range structure can be used to trigger guest_memfd invalidations regardless of whether KVM will do a partial or full zap of the MMU.

No functional change intended.

---
 arch/x86/kvm/mmu/mmu.c |   35 +++++++++++++++--------------------
 1 file changed, 15 insertions(+), 20 deletions(-)
arch/x86/kvm/mmu/mmu.c +15 -20
@@ -7335,8 +7335,14 @@ out_flush:
 	kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush);
 }
 
-static void kvm_mmu_zap_memslot(struct kvm *kvm,
-				struct kvm_memory_slot *slot)
+static inline bool kvm_memslot_flush_zap_all(struct kvm *kvm)
+{
+	return kvm->arch.vm_type == KVM_X86_DEFAULT_VM &&
+	       kvm_check_has_quirk(kvm, KVM_X86_QUIRK_SLOT_ZAP_ALL);
+}
+
+void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+				   struct kvm_memory_slot *slot)
 {
 	struct kvm_gfn_range range = {
 		.slot = slot,
@@ -7347,25 +7353,14 @@ static void kvm_mmu_zap_memslot(struct k
 	};
 	bool flush;
 
-	write_lock(&kvm->mmu_lock);
-	flush = kvm_unmap_gfn_range(kvm, &range);
-	kvm_mmu_zap_memslot_pages_and_flush(kvm, slot, flush);
-	write_unlock(&kvm->mmu_lock);
-}
-
-static inline bool kvm_memslot_flush_zap_all(struct kvm *kvm)
-{
-	return kvm->arch.vm_type == KVM_X86_DEFAULT_VM &&
-	       kvm_check_has_quirk(kvm, KVM_X86_QUIRK_SLOT_ZAP_ALL);
-}
-
-void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
-				   struct kvm_memory_slot *slot)
-{
-	if (kvm_memslot_flush_zap_all(kvm))
+	if (kvm_memslot_flush_zap_all(kvm)) {
 		kvm_mmu_zap_all_fast(kvm);
-	else
-		kvm_mmu_zap_memslot(kvm, slot);
+	} else {
+		write_lock(&kvm->mmu_lock);
+		flush = kvm_unmap_gfn_range(kvm, &range);
+		kvm_mmu_zap_memslot_pages_and_flush(kvm, slot, flush);
+		write_unlock(&kvm->mmu_lock);
+	}
 }
 
 void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen)
author maintainer
#236 lore raw

PATCH 236/583 KVM: x86/mmu: Split kvm_mmu_zap_all_fast() into "front" and "back" halves

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit b27622c4eeb125814081baaefe9175191be5b94d upstream.

Split kvm_mmu_zap_all_fast() into a "front half" and a "back half", where the front half is everything that runs with mmu_lock held for write, and the back half is the code that runs outside of mmu_lock. This will allow putting more code inside kvm_arch_flush_shadow_memslot()'s critical section without having to take mmu_lock twice in quick succession.

No functional change intended.

---
 arch/x86/kvm/mmu/mmu.c |   37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)
arch/x86/kvm/mmu/mmu.c +25 -12
@@ -6696,20 +6696,11 @@ restart:
 	kvm_mmu_commit_zap_page(kvm, &invalid_list);
 }
 
-/*
- * Fast invalidate all shadow pages and use lock-break technique
- * to zap obsolete pages.
- *
- * It's required when memslot is being deleted or VM is being
- * destroyed, in these cases, we should ensure that KVM MMU does
- * not use any resource of the being-deleted slot or all slots
- * after calling the function.
- */
-static void kvm_mmu_zap_all_fast(struct kvm *kvm)
+static void __kvm_mmu_zap_all_fast_front_half(struct kvm *kvm)
 {
 	lockdep_assert_held(&kvm->slots_lock);
+	lockdep_assert_held_write(&kvm->mmu_lock);
 
-	write_lock(&kvm->mmu_lock);
 	trace_kvm_mmu_zap_all_fast(kvm);
 
 	/*
@@ -6746,8 +6737,12 @@ static void kvm_mmu_zap_all_fast(struct
 	kvm_make_all_cpus_request(kvm, KVM_REQ_MMU_FREE_OBSOLETE_ROOTS);
 
 	kvm_zap_obsolete_pages(kvm);
+}
 
-	write_unlock(&kvm->mmu_lock);
+static void __kvm_mmu_zap_all_fast_back_half(struct kvm *kvm)
+{
+	lockdep_assert_held(&kvm->slots_lock);
+	lockdep_assert_not_held(&kvm->mmu_lock);
 
 	/*
 	 * Zap the invalidated TDP MMU roots, all SPTEs must be dropped before
@@ -6761,6 +6756,24 @@ static void kvm_mmu_zap_all_fast(struct
 		kvm_tdp_mmu_zap_invalidated_roots(kvm, true);
 }
 
+/*
+ * Fast invalidate all shadow pages and use lock-break technique
+ * to zap obsolete pages.
+ *
+ * It's required when memslot is being deleted or VM is being
+ * destroyed, in these cases, we should ensure that KVM MMU does
+ * not use any resource of the being-deleted slot or all slots
+ * after calling the function.
+ */
+static void kvm_mmu_zap_all_fast(struct kvm *kvm)
+{
+	write_lock(&kvm->mmu_lock);
+	__kvm_mmu_zap_all_fast_front_half(kvm);
+	write_unlock(&kvm->mmu_lock);
+
+	__kvm_mmu_zap_all_fast_back_half(kvm);
+}
+
 int kvm_mmu_init_vm(struct kvm *kvm)
 {
 	int r, i;
author maintainer
#237 lore raw

PATCH 237/583 KVM: x86/mmu: Use CMPXCHG when clearing Accessed bit in TDP MMU

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit 3d679b7cb31f74bf2303123ce4ee3266eeee999a upstream.

Use LOCK CMPXCHG instead of LOCK AND to clear the Accessed bit when aging SPTEs in the TDP MMU, as doing a LOCK AND can corrupt a FROZEN SPTE and allow a third CPU to effectively overwrite the FROZEN SPTE. As pointed out by AI of some kind, because the magic FROZEN_SPTE value is a "full" SPTE, not a single bit, and includes the Accessed bit, clearing the Accessed bit in a FROZEN SPTE will result in is_frozen_spte() getting a false negative.

E.g. if CPU0 freezes an SPTE, and CPU1 clears the Accessed bit in the frozen SPTE, then CPU2 could come along and overwrite the frozen SPTE with a shadow-present SPTE.

Thankfully, the false negative is largely benign, because outside of TDX, which doesn't support aging, KVM only freezes leaf SPTEs when removing an upper level shadow page. So while KVM could clobber a frozen SPTE back to a shadow-present SPTE, and could even use the new SPTE, the subsequent TLB flush will make the orphaned, shadow-present SPTE unreachable. Failure to ever zap the orphaned leaf SPTE would show up in KVM's stats, but otherwise is benign (because KVM no longer keeps an elevated refcount for leaf SPTEs).

Opportunistically add a comment to warn future developers away from using kvm_tdp_mmu_write_spte_atomic() and tdp_mmu_clear_spte_bits_atomic(), as they are generally unsafe. Keep the helpers, e.g. instead of open-coding the atomic64_fetch_and() in tdp_mmu_clear_spte_bits(), as scary warnings usually are more effective deterrent against recidivism than removal of the dangerous code.

Alternatively, KVM could use different bits for the magic FROZEN_SPTE value, e.g. setting the Dirty bits (with effective IPAT and Global aliases) would likely be "ok", as IPAT/Global are extremely unlikely to be cleared without doing a full SPTE write, and KVM's clearing of Dirty bits shares logic with Write-Protection, which must do a full SPTE write (via cmpxchg64() in the TDP MMU) to ensure KVM isn't clobbering state. But there is zero reason to carry that risk (beyond stubbornness in wanting to preserve a "cute" idea), as the cost of LOCK CMPXCHG and LOCK AND are within 1-2 uops of each other on modern hardware.

---
 arch/x86/kvm/mmu/tdp_iter.h |    7 +++++++
 arch/x86/kvm/mmu/tdp_mmu.c  |   20 +++++++++-----------
 2 files changed, 16 insertions(+), 11 deletions(-)
arch/x86/kvm/mmu/tdp_iter.h +7 -0
@@ -19,6 +19,13 @@ static inline u64 kvm_tdp_mmu_read_spte(
 	return READ_ONCE(*rcu_dereference(sptep));
 }
 
+/*
+ * WARNING!  mmu_lock must be held for write when using the "write atomic" or
+ * "clear bits atomic" APIs, otherwise KVM could overwrite the "wrong" old SPTE
+ * value, i.e. clobber an update from a different CPU.  The only exception is
+ * when KVM is freezing a leaf SPTE for removal, in which case KVM doesn't care
+ * about the exact old SPTE value (KVM will react to the actual old value).
+ */
 static inline u64 kvm_tdp_mmu_write_spte_atomic(tdp_ptep_t sptep, u64 new_spte)
 {
 	KVM_MMU_WARN_ON(is_ept_ve_possible(new_spte));
arch/x86/kvm/mmu/tdp_mmu.c +9 -11
@@ -1380,19 +1380,17 @@ static void kvm_tdp_mmu_age_spte(struct
 {
 	u64 new_spte;
 
-	if (spte_ad_enabled(iter->old_spte)) {
-		iter->old_spte = tdp_mmu_clear_spte_bits_atomic(iter->sptep,
-								shadow_accessed_mask);
+	if (spte_ad_enabled(iter->old_spte))
 		new_spte = iter->old_spte & ~shadow_accessed_mask;
-	} else {
+	else
 		new_spte = mark_spte_for_access_track(iter->old_spte);
-		/*
-		 * It is safe for the following cmpxchg to fail. Leave the
-		 * Accessed bit set, as the spte is most likely young anyway.
-		 */
-		if (__tdp_mmu_set_spte_atomic(kvm, iter, new_spte))
-			return;
-	}
+
+	/*
+	 * Don't bother retrying if another CPU modified the SPTE, the SPTE is
+	 * either being zapped or is likely still in-use, i.e. is still young.
+	 */
+	if (__tdp_mmu_set_spte_atomic(kvm, iter, new_spte))
+		return;
 
 	trace_kvm_tdp_mmu_spte_changed(iter->as_id, iter->gfn, iter->level,
 				       iter->old_spte, new_spte);
author maintainer
#238 lore raw

PATCH 238/583 KVM: x86/mmu: Use split "zap all fast" helpers when invalidating memslot

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit db095727ff5739f4f46ee641ee6ef450032886db upstream.

Manually invoke the front half and back half of the "zap all fast" flow when invalidating a memslot so that mmu_lock is acquired at function scope
in kvm_arch_flush_shadow_memslot(). This will allow putting more code
inside the critical section without having to take mmu_lock twice in quick succession.

Opportunistically open code checking whether or not to do the fast zap, to discourage removing the local "zap_all" in a future cleanup, i.e. to ensure the SLOT_ZAP_ALL quirk is queried exactly once. Processing the front half but not the back half of the fast zap (if SLOT_ZAP_ALL were disabled concurrently) would result in KVM unnecessarily keeping invalid TDP MMU roots until the VM is destroyed.

No functional change intended.

---
 arch/x86/kvm/mmu/mmu.c |   21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
arch/x86/kvm/mmu/mmu.c +11 -10
@@ -7348,12 +7348,6 @@ out_flush:
 	kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, flush);
 }
 
-static inline bool kvm_memslot_flush_zap_all(struct kvm *kvm)
-{
-	return kvm->arch.vm_type == KVM_X86_DEFAULT_VM &&
-	       kvm_check_has_quirk(kvm, KVM_X86_QUIRK_SLOT_ZAP_ALL);
-}
-
 void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
 				   struct kvm_memory_slot *slot)
 {
@@ -7364,16 +7358,23 @@ void kvm_arch_flush_shadow_memslot(struc
 		.may_block = true,
 		.attr_filter = KVM_FILTER_PRIVATE | KVM_FILTER_SHARED,
 	};
+	bool zap_all = kvm->arch.vm_type == KVM_X86_DEFAULT_VM &&
+		       kvm_check_has_quirk(kvm, KVM_X86_QUIRK_SLOT_ZAP_ALL);
 	bool flush;
 
-	if (kvm_memslot_flush_zap_all(kvm)) {
-		kvm_mmu_zap_all_fast(kvm);
+	write_lock(&kvm->mmu_lock);
+
+	if (zap_all) {
+		__kvm_mmu_zap_all_fast_front_half(kvm);
 	} else {
-		write_lock(&kvm->mmu_lock);
 		flush = kvm_unmap_gfn_range(kvm, &range);
 		kvm_mmu_zap_memslot_pages_and_flush(kvm, slot, flush);
-		write_unlock(&kvm->mmu_lock);
 	}
+
+	write_unlock(&kvm->mmu_lock);
+
+	if (zap_all)
+		__kvm_mmu_zap_all_fast_back_half(kvm);
 }
 
 void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen)
author maintainer
#239 lore raw

PATCH 239/583 KVM: x86/mmu: Consume the locked rmap value in the lockless rmap walk

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Phil Rosenthal <[email protected]>

commit e428f9779a43737d830111238816f1928b07aefb upstream.

__kvm_rmap_lock() deliberately elides the rmap lock when it observes an empty rmap. In that case kvm_rmap_lock_readonly() also re-enables preemption and returns zero, so the caller holds neither the rmap lock nor a preemption reference. The elision documents the invariant it relies on:

* Elide the lock if the rmap is empty, as lockless walkers (read-only
* mode) don't need to (and can't) walk an empty rmap, nor can they add
* entries to the rmap. I.e. the only paths that process empty rmaps
* do so while holding mmu_lock for write, and are mutually exclusive.

kvm_rmap_age_gfn_range() ignores the returned value and unconditionally enters for_each_rmap_spte_lockless(). The iterator started with rmap_get_first(), which re-reads rmap_head->val rather than using the value returned by the lock. If a writer populates the rmap between the lock's read and the iterator's re-read, the aging path walks the newly installed rmap without holding its lock.

For a KVM_RMAP_MANY rmap this leaves the walker following a pte_list_desc chain that it never locked. A writer holding mmu_lock for write may free that chain (e.g. kvm_zap_all_rmap_sptes() on the recycle path, or any rmap zap) via kmem_cache_free() while the walk is in progress, giving a slab use-after-free. Nothing serialises the two: the aging path runs without mmu_lock when CONFIG_KVM_MMU_LOCKLESS_AGING=y, and the rmap lock that would otherwise exclude the writer was elided. Because the empty path re-enables preemption, the interval between the two reads can span an arbitrary scheduling delay.

Fix the class of bug by having the lockless walk consume the value returned by the lock instead of re-reading the rmap. Split rmap_get_first() into __rmap_get_first(), which starts an iterator from an already-read rmap value, and make for_each_rmap_spte_lockless() take that value and call __rmap_get_first() directly. kvm_rmap_age_gfn_range() passes the value returned by kvm_rmap_lock_readonly(): when the lock was elided the value is zero, __rmap_get_first() returns NULL, and the walk is skipped. No lockless walker re-reads the rmap, so the lock-elision invariant cannot be violated, and no lock()-without-paired-unlock() path is added to the aging code.

Fixes af3b6a9eba48 ("KVM: x86/mmu: Walk rmaps (shadow MMU) without holding mmu_lock when aging gfns")
---
 arch/x86/kvm/mmu/mmu.c |   33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)
arch/x86/kvm/mmu/mmu.c +19 -14
@@ -1218,18 +1218,9 @@ struct rmap_iterator {
 	int pos;			/* index of the sptep */
 };
 
-/*
- * Iteration must be started by this function.  This should also be used after
- * removing/dropping sptes from the rmap link because in such cases the
- * information in the iterator may not be valid.
- *
- * Returns sptep if found, NULL otherwise.
- */
-static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head,
-			   struct rmap_iterator *iter)
+static u64 *__rmap_get_first(unsigned long rmap_val,
+			     struct rmap_iterator *iter)
 {
-	unsigned long rmap_val = kvm_rmap_get(rmap_head);
-
 	if (!rmap_val)
 		return NULL;
 
@@ -1244,6 +1235,19 @@ static u64 *rmap_get_first(struct kvm_rm
 }
 
 /*
+ * Iteration must be started by this function.  This should also be used after
+ * removing/dropping sptes from the rmap link because in such cases the
+ * information in the iterator may not be valid.
+ *
+ * Returns sptep if found, NULL otherwise.
+ */
+static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head,
+			   struct rmap_iterator *iter)
+{
+	return __rmap_get_first(kvm_rmap_get(rmap_head), iter);
+}
+
+/*
  * Must be used with a valid iterator: e.g. after rmap_get_first().
  *
  * Returns sptep if found, NULL otherwise.
@@ -1277,8 +1281,9 @@ static u64 *rmap_get_next(struct rmap_it
 	__for_each_rmap_spte(_rmap_head_, _iter_, _sptep_)			\
 		if (!WARN_ON_ONCE(!is_shadow_present_pte(*(_sptep_))))	\
 
-#define for_each_rmap_spte_lockless(_rmap_head_, _iter_, _sptep_, _spte_)	\
-	__for_each_rmap_spte(_rmap_head_, _iter_, _sptep_)			\
+#define for_each_rmap_spte_lockless(_rmap_val_, _iter_, _sptep_, _spte_)	\
+	for (_sptep_ = __rmap_get_first(_rmap_val_, _iter_);			\
+	     _sptep_; _sptep_ = rmap_get_next(_iter_))				\
 		if (is_shadow_present_pte(_spte_ = mmu_spte_get_lockless(sptep)))
 
 static void drop_spte(struct kvm *kvm, u64 *sptep)
@@ -1716,7 +1721,7 @@ static bool kvm_rmap_age_gfn_range(struc
 			rmap_head = gfn_to_rmap(gfn, level, range->slot);
 			rmap_val = kvm_rmap_lock_readonly(rmap_head);
 
-			for_each_rmap_spte_lockless(rmap_head, &iter, sptep, spte) {
+			for_each_rmap_spte_lockless(rmap_val, &iter, sptep, spte) {
 				if (!is_accessed_spte(spte))
 					continue;
 
author maintainer
#240 lore raw

PATCH 240/583 KVM: x86: hyper-v: Clamp stimer deadline to avoid livelock

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Carlos López <[email protected]>

commit 0ca49fbd2883cd53d32d85b50feef17fa04d0fbf upstream.

Fix an issue where userspace or the guest can program an Hyper-V synthetic timer to have a deadline in the past via integer overflow, preventing the CPU from making progress and triggering an RCU stall.

Hyper-V's SynIC exposes 4 per-vCPU synthetic timers to the guest, which are emulated by KVM. Each is programmed through the HV_X64_MSR_STIMERi_CONFIG and HV_X64_MSR_STIMERi_COUNT MSRs. Depending on CONFIG, COUNT represents either the absolute expiration time or the period of a periodic timer, both expressed in 100ns ticks. These timers may be set both by the guest (WRMSR) and the host (KVM_SET_MSRS).

When the timer is enabled, stimer_start() translates COUNT to an absolute monotonic deadline and arms an hrtimer. If COUNT is set to a value close to U64_MAX, the deadline calculation can overflow.

    ktime_add_ns(ktime_now, 100 * (stimer->exp_time - time_now))

This can result in a CPU livelock. stimer_start() arms the timer via hrtimer_start() with a deadline in the past, which causes it to immediately fire. The stimer callback then raises KVM_RQ_HV_STIMER, with the intention of causing KVM to deliver a synthetic interrupt on the next vCPU guest enter.

Then, once userspace issues KVM_RUN, vcpu_enter_guest() consumes the request, calling kvm_hv_process_stimers(). This would normally disable the timer via stimer_expiration() once the deadline is in the past. However, the deadline comparison is done between the KVM reference counter and stime->exp_time, which is a big value close to U64_MAX, so this never happens for a few thousand years.

kvm_hv_process_timers() then re-arms the timer via stimer_start(), since it was not disabled, which again fires immediately. Before entering the guest, kvm_vcpu_exit_request() checks kvm_request_pending(), which returns true due to the newly raised KVM_REQ_HV_STIMER. Then vcpu_enter_guest() aborts the guest entry, returning early into vcpu_run(), which loops back again into vcpu_enter_guest(), restarting the cycle.

Since there are no manual yields in this loop, a task with SCHED_FIFO may starve RCU grace-period kthreads, which exposes the stalls found by syzcaller:

    rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
    rcu:    (detected by 1, t=10502 jiffies, g=14269, q=1142 ncpus=2)
    rcu: All QSes seen, last rcu_preempt kthread activity 10500 (4294965239-4294954739), jiffies_till_next_fqs=1, root ->qsmask 0x0
    rcu: rcu_preempt kthread starved for 10500 jiffies! g14269 f0x2 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=0
    rcu:    Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
        ( ... )
    Call Trace:
     <IRQ>
     __run_hrtimer kernel/time/hrtimer.c:1773 [inline]
     __hrtimer_run_queues+0x408/0xc30 kernel/time/hrtimer.c:1841
     hrtimer_interrupt+0x45b/0xaa0 kernel/time/hrtimer.c:1903
     local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1045 [inline]
     __sysvec_apic_timer_interrupt+0x102/0x3e0 arch/x86/kernel/apic/apic.c:1062
     instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1056 [inline]
     sysvec_apic_timer_interrupt+0xa1/0xc0 arch/x86/kernel/apic/apic.c:1056
     </IRQ>
     <TASK>
     asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697
    RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:152 [inline]
    RIP: 0010:_raw_spin_unlock_irqrestore+0xa8/0x110 kernel/locking/spinlock.c:194
    Code: 74 05 e8 0b f4 5f f6 48 c7 44 24 20 00 00 00 00 9c 8f 44 24 20 f6 44 24 21 02 75 4f f7 c3 00 02 00 00 74 01 fb bf 01 00 00 00 <e8> 23 6b 27 f6 65 8b 05 7c 60 5a 07 85 c0 74 40 48 c7 04 24 0e 36
    RSP: 0018:ffffc900040a7320 EFLAGS: 00000206
    RAX: 5de15cb931505900 RBX: 0000000000000a06 RCX: 5de15cb931505900
    RDX: 0000000000000007 RSI: ffffffff8daa9dc3 RDI: 0000000000000001
    RBP: ffffc900040a73b0 R08: ffffffff8fc3d077 R09: 1ffffffff1f87a0e
    R10: dffffc0000000000 R11: fffffbfff1f87a0f R12: dffffc0000000000
    R13: 0000000000000000 R14: ffff8880b8628240 R15: 1ffff92000814e64
     hrtimer_start include/linux/hrtimer.h:259 [inline]
     stimer_start arch/x86/kvm/hyperv.c:682 [inline]
     kvm_hv_process_stimers+0xd0a/0x16a0 arch/x86/kvm/hyperv.c:893
     vcpu_enter_guest arch/x86/kvm/x86.c:11193 [inline]
     vcpu_run+0x2240/0x76b0 arch/x86/kvm/x86.c:11639
     kvm_arch_vcpu_ioctl_run+0x1148/0x1c90 arch/x86/kvm/x86.c:11984
     kvm_vcpu_ioctl+0x99a/0xed0 virt/kvm/kvm_main.c:4492
     vfs_ioctl fs/ioctl.c:51 [inline]
     __do_sys_ioctl fs/ioctl.c:597 [inline]
     __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
     do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
     do_syscall_64+0xfa/0xf80 arch/x86/entry/syscall_64.c:94
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    RIP: 0033:0x7f635278f749
    Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
    RSP: 002b:00007f635365c038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
    RAX: ffffffffffffffda RBX: 00007f63529e5fa0 RCX: 00007f635278f749
    RDX: 0000000000000000 RSI: 000000000000ae80 RDI: 0000000000000005
    RBP: 00007f6352813f91 R08: 0000000000000000 R09: 0000000000000000
    R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
    R13: 00007f63529e6038 R14: 00007f63529e5fa0 R15: 00007ffd5b219358
     </TASK>

Fix this by clamping the deadline computation to KTIME_MAX, which preserves the intent of arming a timer very far in the future. ktime_add_safe() already does this type of clamping, so use it after checking that that multiplying by the 100ns time tick also does not overflow.

---
 arch/x86/kvm/hyperv.c |   25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)
arch/x86/kvm/hyperv.c +18 -7
@@ -627,6 +627,18 @@ static enum hrtimer_restart stimer_timer
 }
 
 /*
+ * Translate a stimer expiry given in 100ns reference ticks into an
+ * an absolute deadline. Saturates on overflow.
+ */
+static ktime_t stimer_add_delta(ktime_t now, u64 delta_100ns)
+{
+	if (delta_100ns >= KTIME_MAX / 100)
+		return KTIME_MAX;
+
+	return ktime_add_safe(now, 100 * delta_100ns);
+}
+
+/*
  * stimer_start() assumptions:
  * a) stimer->count is not equal to 0
  * b) stimer->config has HV_STIMER_ENABLE flag
@@ -635,6 +647,7 @@ static int stimer_start(struct kvm_vcpu_
 {
 	u64 time_now;
 	ktime_t ktime_now;
+	ktime_t deadline;
 
 	time_now = get_time_ref_counter(hv_stimer_to_vcpu(stimer)->kvm);
 	ktime_now = ktime_get();
@@ -657,10 +670,8 @@ static int stimer_start(struct kvm_vcpu_
 					stimer->index,
 					time_now, stimer->exp_time);
 
-		hrtimer_start(&stimer->timer,
-			      ktime_add_ns(ktime_now,
-					   100 * (stimer->exp_time - time_now)),
-			      HRTIMER_MODE_ABS);
+		deadline = stimer_add_delta(ktime_now, stimer->exp_time - time_now);
+		hrtimer_start(&stimer->timer, deadline, HRTIMER_MODE_ABS);
 		return 0;
 	}
 	stimer->exp_time = stimer->count;
@@ -679,9 +690,9 @@ static int stimer_start(struct kvm_vcpu_
 					   stimer->index,
 					   time_now, stimer->count);
 
-	hrtimer_start(&stimer->timer,
-		      ktime_add_ns(ktime_now, 100 * (stimer->count - time_now)),
-		      HRTIMER_MODE_ABS);
+	deadline = stimer_add_delta(ktime_now, stimer->count - time_now);
+	hrtimer_start(&stimer->timer, deadline, HRTIMER_MODE_ABS);
+
 	return 0;
 }
 
author maintainer
#241 lore raw

PATCH 241/583 KVM: x86: Serialize writes to disabled_quirks using kvm->lock

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit ba76b23ed36ab230fc2577aba24f65851114902f upstream.

Protect writes to disabled_quirks with kvm->lock to ensure KVM doesn't clobber state in the unlikely scenario that userspace disables disparate quirks from multiple tasks. More importantly, this will allow wrapping accesses with {READ,WRITE}_ONCE without "needing" to also guard the writer with a useless and confusing READ_ONCE (since the RMW wouldn't be atomic anyways).

Ideally, KVM would disallow disabling quirks once quirks are "live", but that would be a potentially breaking userspace ABI change, and while all existing quirks are fully live only after vCPUs have been created, several MMU-related quirks, IGNORE_GUEST_PAT and SLOT_ZAP_ALL, are partially live at all times. Because populating MMUs requires a vCPU, the guest-visible behavior of IGNORE_GUEST_PAT and SLOT_ZAP_ALL requires a vCPU, but for KVM itself, processing the quirk (or not) has functional impact, i.e. for all intents and purposes, KVM can't prevent those quirks from being disabled after they've been consumed.

---
 arch/x86/kvm/x86.c |    2 ++
 1 file changed, 2 insertions(+)
arch/x86/kvm/x86.c +2 -0
@@ -6774,7 +6774,9 @@ int kvm_vm_ioctl_enable_cap(struct kvm *
 			break;
 		fallthrough;
 	case KVM_CAP_DISABLE_QUIRKS:
+		mutex_lock(&kvm->lock);
 		kvm->arch.disabled_quirks |= cap->args[0] & kvm_caps.supported_quirks;
+		mutex_unlock(&kvm->lock);
 		r = 0;
 		break;
 	case KVM_CAP_SPLIT_IRQCHIP: {
author maintainer
#242 lore raw

PATCH 242/583 KVM: x86: Ensure runtime reads of disabled_quirks are resolved once

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean Christopherson <[email protected]>

commit ed15cb21999217e549414c128b4a0485debf6278 upstream.

Wrap the sole reader of disabled_quirks with READ_ONCE(), and wrap the post-VM-creation write to disabled_quirks with WRITE_ONCE(), to ensure checking the status of a quirk doesn't re-read disabled_quirks *if* the caller needs such a guarantee. This will allow splitting the "fast" MMU zap into front and back halves, without potentially skipping the back half if SLOT_ZAP_ALL were concurrently disabled (which would be "fine" in the current code base, but far from ideal).

---
 arch/x86/kvm/x86.c |    3 ++-
 arch/x86/kvm/x86.h |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +2 -1
@@ -6775,7 +6775,8 @@ int kvm_vm_ioctl_enable_cap(struct kvm *
 		fallthrough;
 	case KVM_CAP_DISABLE_QUIRKS:
 		mutex_lock(&kvm->lock);
-		kvm->arch.disabled_quirks |= cap->args[0] & kvm_caps.supported_quirks;
+		WRITE_ONCE(kvm->arch.disabled_quirks,
+			   kvm->arch.disabled_quirks | (cap->args[0] & kvm_caps.supported_quirks));
 		mutex_unlock(&kvm->lock);
 		r = 0;
 		break;
arch/x86/kvm/x86.h +1 -1
@@ -417,7 +417,7 @@ static inline void kvm_register_write(st
 
 static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
 {
-	return !(kvm->arch.disabled_quirks & quirk);
+	return !(READ_ONCE(kvm->arch.disabled_quirks) & quirk);
 }
 
 void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip);
author maintainer
#243 lore raw

PATCH 243/583 KVM: s390: Fix length check __import_wp_info()

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit 4c07680a467e2f7697245bcd11691bffb2a6f0ed upstream.

struct kvm_hw_breakpoint::len is a __u64 that is fully controlled by user space. This is then assigned to wp_info->len, which is an int. The bounds check is done on the truncated value while the allocation uses the untruncated one:

	wp_info->len = bp_data->len;
	[...]
	if (wp_info->len < 0 || wp_info->len > MAX_WP_SIZE)
		return -EINVAL;

	wp_info->old_data = kmalloc(bp_data->len, GFP_KERNEL_ACCOUNT);

Use the validated value for the allocation as intended. Without this fix userspace can trigger >4GB allocations which will fail and result in a WARN due to MAX_PAGE_ORDER.

Fixes 27291e2165b6 ("KVM: s390: hardware support for guest debugging")

Message-ID: <[email protected]>

---
 arch/s390/kvm/guestdbg.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kvm/guestdbg.c +1 -1
@@ -184,7 +184,7 @@ static int __import_wp_info(struct kvm_v
 	if (wp_info->len < 0 || wp_info->len > MAX_WP_SIZE)
 		return -EINVAL;
 
-	wp_info->old_data = kmalloc(bp_data->len, GFP_KERNEL_ACCOUNT);
+	wp_info->old_data = kmalloc(wp_info->len, GFP_KERNEL_ACCOUNT);
 	if (!wp_info->old_data)
 		return -ENOMEM;
 	/* try to backup the original value */
author maintainer
#244 lore raw

PATCH 244/583 KVM: s390: Fix memory leak in guest debug handling

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit 121ea1de927c8b9bfdf53c31cad27b86d5de0293 upstream.

bp_data is freed only for the error case by kfree(bp_data). Every successful KVM_SET_GUEST_DEBUG will leak bp_data.

Fixes 27291e2165b6 ("KVM: s390: hardware support for guest debugging")

Message-ID: <[email protected]>

---
 arch/s390/kvm/guestdbg.c |    1 +
 1 file changed, 1 insertion(+)
arch/s390/kvm/guestdbg.c +1 -0
@@ -271,6 +271,7 @@ int kvm_s390_import_bp_data(struct kvm_v
 	vcpu->arch.guestdbg.hw_bp_info = bp_info;
 	vcpu->arch.guestdbg.nr_hw_wp = nr_wp;
 	vcpu->arch.guestdbg.hw_wp_info = wp_info;
+	kfree(bp_data);
 	return 0;
 error:
 	kfree(bp_data);
author maintainer
#245 lore raw

PATCH 245/583 KVM: s390: Fix old_data leak in guest debug error path

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit aa9c8e8baf1e765fa65b93212522c636f25d846f upstream.

__import_wp_info() allocates a per-watchpoint old_data buffer to back up the original guest memory contents. If a later watchpoint of the same KVM_SET_GUEST_DEBUG request fails to import, kvm_s390_import_bp_data() jumps to the error label, which frees the wp_info array but not the old_data buffers of the entries that were imported successfully. Up to MAX_BP_COUNT - 1 buffers of up to MAX_WP_SIZE bytes are leaked per failed request, and the request can be repeated.

Create error handling for cleaning up all created old_data memory areas.

Fixes 27291e2165b6 ("KVM: s390: hardware support for guest debugging")

Message-ID: <[email protected]>

---
 arch/s390/kvm/guestdbg.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
arch/s390/kvm/guestdbg.c +5 -1
@@ -256,7 +256,7 @@ int kvm_s390_import_bp_data(struct kvm_v
 			ret = __import_wp_info(vcpu, &bp_data[i],
 					       &wp_info[nr_wp]);
 			if (ret)
-				goto error;
+				goto error_wp;
 			nr_wp++;
 			break;
 		case KVM_HW_BP:
@@ -273,6 +273,10 @@ int kvm_s390_import_bp_data(struct kvm_v
 	vcpu->arch.guestdbg.hw_wp_info = wp_info;
 	kfree(bp_data);
 	return 0;
+
+error_wp:
+	while (nr_wp--)
+		kfree(wp_info[nr_wp].old_data);
 error:
 	kfree(bp_data);
 	kfree(wp_info);
author maintainer
#246 lore raw

PATCH 246/583 KVM: s390: Free guest debug data on vcpu destroy

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit e7f698b09d4a7c36b299acf680fc50fe868e2bcd upstream.

kvm_s390_clear_bp_data() is only called from kvm_arch_vcpu_ioctl_set_guest_debug(), i.e. when user space changes or disables debugging. A vCPU that is destroyed while hardware breakpoints are still armed - the normal case when the VMM just exits or crashes - leaks hw_bp_info, hw_wp_info and all old_data buffers, since generic KVM frees the vCPU right after kvm_arch_vcpu_destroy().

That is bounded by MAX_BP_COUNT entries, so roughly 8 KiB per vCPU, but it is unbounded over VM lifetimes. The allocations are GFP_KERNEL_ACCOUNT, so the charge also outlives the exiting process and pins dying memcgs.

Fix by clearing the debug data on vCPU destruction. Calling it unconditionally is fine: struct kvm_vcpu is zero allocated, so for a vCPU that never enabled debugging the counters are 0 and the pointers NULL.

Fixes 27291e2165b6 ("KVM: s390: hardware support for guest debugging")

Message-ID: <[email protected]>

---
 arch/s390/kvm/kvm-s390.c |    1 +
 1 file changed, 1 insertion(+)
arch/s390/kvm/kvm-s390.c +1 -0
@@ -3488,6 +3488,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vc
 	trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
 	kvm_s390_clear_local_irqs(vcpu);
 	kvm_clear_async_pf_completion_queue(vcpu);
+	kvm_s390_clear_bp_data(vcpu);
 	if (!kvm_is_ucontrol(vcpu->kvm))
 		sca_del_vcpu(vcpu);
 	kvm_s390_update_topology_change_report(vcpu->kvm, 1);
author maintainer
#247 lore raw

PATCH 247/583 KVM: s390: Take srcu when importing watchpoint data

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit a4e482def8533ebace517d9f67f1465841b1f982 upstream.

__import_wp_info() backs up the original guest memory contents of a watchpoint with read_guest_abs(), which is kvm_read_guest() and therefore resolves the memslot via __kvm_memslots(). That requires kvm->srcu (or kvm->slots_lock) to be held, otherwise a concurrent memslot update can free the memslots array under us once its SRCU grace period has elapsed.

As this is not fast path, following lock ordering (mutex first, then srcu) take the big hammer and hold the srcu for the full import.

Fixes 27291e2165b6 ("KVM: s390: hardware support for guest debugging")

Message-ID: <[email protected]>

---
 arch/s390/kvm/kvm-s390.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kvm/kvm-s390.c +4 -2
@@ -4445,8 +4445,10 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(
 		/* enforce guest PER */
 		kvm_s390_set_cpuflags(vcpu, CPUSTAT_P);
 
-		if (dbg->control & KVM_GUESTDBG_USE_HW_BP)
-			rc = kvm_s390_import_bp_data(vcpu, dbg);
+		if (dbg->control & KVM_GUESTDBG_USE_HW_BP) {
+			scoped_guard(srcu, &vcpu->kvm->srcu)
+				rc = kvm_s390_import_bp_data(vcpu, dbg);
+		}
 	} else {
 		kvm_s390_clear_cpuflags(vcpu, CPUSTAT_P);
 		vcpu->arch.guestdbg.last_bp = 0;
author maintainer
#248 lore raw

PATCH 248/583 KVM: s390: Zero initialize irq in reinject_machine_check

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit b239410c7653ff6781d4cf1d63cfc52a1bb71788 upstream.

kvm_s390_reinject_machine_check() fills cr14, mcic, ext_damage_code and failing_storage_address of the on-stack struct kvm_s390_irq, but struct kvm_s390_mchk_info also has a pad word and a 16 byte fixed_logout array. struct mcck_volatile_info carries no logout data, so there is nothing to copy there and both stay whatever was on the stack.

__inject_mchk() then memcpy()s fixed_logout into the vcpu local interrupt state unconditionally. This will reach the guest during deliver and userspace during migration.

Reflecting zeroes is the correct behaviour here, as KVM has no logout data for a reinjected machine check.

This needs a host machine check while the cpu is in SIE so not trivial to trigger.

Fixes 4d62fcc0b692 ("KVM: s390: Inject machine check into the guest")

Message-ID: <[email protected]>

---
 arch/s390/kvm/interrupt.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kvm/interrupt.c +1 -1
@@ -2864,7 +2864,7 @@ void kvm_s390_reinject_machine_check(str
 				     struct mcck_volatile_info *mcck_info)
 {
 	struct kvm_s390_interrupt_info inti;
-	struct kvm_s390_irq irq;
+	struct kvm_s390_irq irq = {};
 	struct kvm_s390_mchk_info *mchk;
 	union mci mci;
 	__u64 cr14 = 0;         /* upper bits are not used */
author maintainer
#249 lore raw

PATCH 249/583 KVM: s390: Fix memory corruption by not reinjecting CK machine checks

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit 546dde823a36d7283dcf46127c2f3d093443860f upstream.

Channel-subsystem damage machine checks are for the host channel subsystem. The guest channel subsystem is emulated in the userspace VMM. There is no point in forwarding such machine checks into the guest.

This also simplifies the machine check reinjection and avoids kfree of a stack variable as reported by sashiko. There might be still machine checks that have the ck bit set with another bit (like instruction damage), mask out the CK bit in s390_backup_mcck_info(), like the CP and ED bits already are.

Fixes 4d62fcc0b692 ("KVM: s390: Inject machine check into the guest")

Message-ID: <[email protected]>

---
 arch/s390/include/asm/nmi.h |    3 +++
 arch/s390/kernel/nmi.c      |    5 +----
 arch/s390/kvm/interrupt.c   |   24 ++++++++----------------
 3 files changed, 12 insertions(+), 20 deletions(-)
arch/s390/include/asm/nmi.h +3 -0
@@ -22,6 +22,7 @@
 #define MCCK_CODE_SYSTEM_DAMAGE		BIT(63)
 #define MCCK_CODE_EXT_DAMAGE		BIT(63 - 5)
 #define MCCK_CODE_CP			BIT(63 - 9)
+#define MCCK_CODE_CK			BIT(63 - 11)
 #define MCCK_CODE_STG_ERROR		BIT(63 - 16)
 #define MCCK_CODE_STG_KEY_ERROR		BIT(63 - 18)
 #define MCCK_CODE_STG_DEGRAD		BIT(63 - 19)
@@ -33,6 +34,8 @@
 #define MCCK_CODE_FC_VALID		BIT(63 - 43)
 #define MCCK_CODE_CPU_TIMER_VALID	BIT(63 - 46)
 
+#define MCCK_CODE_NO_GUEST	(MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE | MCCK_CODE_CK)
+
 #ifndef __ASSEMBLER__
 
 union mci {
arch/s390/kernel/nmi.c +1 -4
@@ -344,8 +344,7 @@ static void notrace s390_backup_mcck_inf
 
 	sie_page = container_of(sie_block, struct sie_page, sie_block);
 	mcck_backup = &sie_page->mcck_info;
-	mcck_backup->mcic = get_lowcore()->mcck_interruption_code &
-				~(MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE);
+	mcck_backup->mcic = get_lowcore()->mcck_interruption_code & ~MCCK_CODE_NO_GUEST;
 	mcck_backup->ext_damage_code = get_lowcore()->external_damage_code;
 	mcck_backup->failing_storage_address = get_lowcore()->failing_storage_address;
 }
@@ -357,8 +356,6 @@ NOKPROBE_SYMBOL(s390_backup_mcck_info);
 #define ED_STP_ISLAND	6	/* External damage STP island check */
 #define ED_STP_SYNC	7	/* External damage STP sync check */
 
-#define MCCK_CODE_NO_GUEST	(MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE)
-
 /*
  * machine check handler.
  */
arch/s390/kvm/interrupt.c +8 -16
@@ -2863,9 +2863,7 @@ static int set_adapter_int(struct kvm_ke
 void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
 				     struct mcck_volatile_info *mcck_info)
 {
-	struct kvm_s390_interrupt_info inti;
 	struct kvm_s390_irq irq = {};
-	struct kvm_s390_mchk_info *mchk;
 	union mci mci;
 	__u64 cr14 = 0;         /* upper bits are not used */
 	int rc;
@@ -2878,20 +2876,14 @@ void kvm_s390_reinject_machine_check(str
 	if (mci.w)
 		cr14 |= CR14_WARNING_SUBMASK;
 
-	mchk = mci.ck ? &inti.mchk : &irq.u.mchk;
-	mchk->cr14 = cr14;
-	mchk->mcic = mcck_info->mcic;
-	mchk->ext_damage_code = mcck_info->ext_damage_code;
-	mchk->failing_storage_address = mcck_info->failing_storage_address;
-	if (mci.ck) {
-		/* Inject the floating machine check */
-		inti.type = KVM_S390_MCHK;
-		rc = __inject_vm(vcpu->kvm, &inti);
-	} else {
-		/* Inject the machine check to specified vcpu */
-		irq.type = KVM_S390_MCHK;
-		rc = kvm_s390_inject_vcpu(vcpu, &irq);
-	}
+	irq.u.mchk.cr14 = cr14;
+	irq.u.mchk.mcic = mcck_info->mcic;
+	irq.u.mchk.ext_damage_code = mcck_info->ext_damage_code;
+	irq.u.mchk.failing_storage_address = mcck_info->failing_storage_address;
+
+	/* Inject the machine check to specified vcpu */
+	irq.type = KVM_S390_MCHK;
+	rc = kvm_s390_inject_vcpu(vcpu, &irq);
 	WARN_ON_ONCE(rc);
 }
 
author maintainer
#250 lore raw

PATCH 250/583 KVM: s390: pv: Fix rc/rrc offset for PVM_DUMP

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit 1e3c8e7b3465fb8a49d3623d2d0f449c0b5b48f3 upstream.

The rc/rrc value is copied to the cmd location of the cmd in the kvm_pv_cmd structure. Fix the offset.

Fixes 8aba09588d2a ("KVM: s390: Add CPU dump functionality")

Message-ID: <[email protected]>

---
 arch/s390/kvm/kvm-s390.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kvm/kvm-s390.c +1 -1
@@ -6008,7 +6008,7 @@ long kvm_arch_vcpu_ioctl(struct file *fi
 		r = kvm_s390_handle_pv_vcpu_dump(vcpu, &cmd);
 
 		/* Always copy over UV rc / rrc data */
-		if (copy_to_user((__u8 __user *)argp, &cmd.rc,
+		if (copy_to_user(argp + offsetof(struct kvm_pv_cmd, rc), &cmd.rc,
 				 sizeof(cmd.rc) + sizeof(cmd.rrc)))
 			r = -EFAULT;
 		break;
author maintainer
#251 lore raw

PATCH 251/583 KVM: s390: Restore sigset on error path

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Christian Borntraeger <[email protected]>

commit c44d36d8e6501c4934412d9014e5e02da9efdb8f upstream.

kvm_sigset_activate() installs vcpu->sigset via sigprocmask() and stashes the caller's mask in current->real_blocked; only kvm_sigset_deactivate() restores it.

For KVM_RUN on a STOPPED vcpu the error path will not restore the userspace mask. Re-arrange the error handling to also restore the signal mask.

Fixes 6352e4d2dd9a3 ("KVM: s390: implement KVM_(S|G)ET_MP_STATE for user space state control")

Message-ID: <[email protected]>

---
 arch/s390/kvm/kvm-s390.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kvm/kvm-s390.c +4 -2
@@ -5355,7 +5355,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v
 		pr_err_ratelimited("can't run stopped vcpu %d\n",
 				   vcpu->vcpu_id);
 		rc = -EINVAL;
-		goto out;
+		goto out_sigset;
 	}
 
 	kernel_fpu_begin(&fpu, KERNEL_FPC | KERNEL_VXR);
@@ -5384,9 +5384,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v
 	store_regs(vcpu);
 	kernel_fpu_end(&fpu, KERNEL_FPC | KERNEL_VXR);
 
+	vcpu->stat.exit_userspace++;
+
+out_sigset:
 	kvm_sigset_deactivate(vcpu);
 
-	vcpu->stat.exit_userspace++;
 out:
 	vcpu_put(vcpu);
 	return rc;
author maintainer
#252 lore raw

PATCH 252/583 KVM: arm64: Consider SCTLR_EL2.M when mapping the L1 VNCR page

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

commit 8c774604b6ecaca495fa3d27c21593269627f48f upstream.

We record a VNCR TLB even when SCTLR_EL2.M is 0 in order to make our life easier. But this is not something that the architecture anticipate.

As a consequence, a hypervisor is free to set VNCR_EL2 to some PA when SCTLR_EL2.M==0, use it to run a guest which indirectly accesses the VNCR page, then eventually set SCTLR_EL2.M==1 with the same VA. Yes, this is odd, but apparently legal.

A common trick in HW is to invalidate the TLBs on SCTLR_ELx.M being flipped. But doing this is a not a good idea for us (we'd need to trap SCTLR accesses), and wouldn't scale as we nest deeper.

Instead, use the fact that the S1 MMU being off at the point of translation is cached in our TLB, and if it doesn't match the current MMU state, leave the VNCR unmapped.

Fixes 2a359e072596f ("KVM: arm64: nv: Handle mapping of VNCR_EL2 at EL2")
---
 arch/arm64/include/asm/kvm_nested.h |    7 +++++++
 arch/arm64/kvm/at.c                 |    2 --
 arch/arm64/kvm/nested.c             |    4 ++++
 3 files changed, 11 insertions(+), 2 deletions(-)
arch/arm64/include/asm/kvm_nested.h +7 -0
@@ -353,6 +353,8 @@ struct s1_walk_result {
 	bool	failed;
 };
 
+#define S1_MMU_DISABLED		(-127)
+
 static inline void fail_s1_walk(struct s1_walk_result *wr, u8 fst, bool s1ptw)
 {
 	wr->fst		= fst;
@@ -361,6 +363,11 @@ static inline void fail_s1_walk(struct s
 	wr->failed	= true;
 }
 
+static inline bool s1_walk_translated(struct s1_walk_result *wr)
+{
+	return wr->level != S1_MMU_DISABLED;
+}
+
 int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
 		       struct s1_walk_result *wr, u64 va);
 int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa,
arch/arm64/kvm/at.c +0 -2
@@ -10,8 +10,6 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-#define S1_MMU_DISABLED		(-127)
-
 static int get_ia_size(struct s1_walk_info *wi)
 {
 	return 64 - wi->txsz;
arch/arm64/kvm/nested.c +4 -0
@@ -1413,6 +1413,10 @@ static void kvm_map_l1_vncr(struct kvm_v
 	if (!vt->valid)
 		return;
 
+	/* We cache the MMU state in the TLB. Check that it matches. */
+	if (!!(vcpu_read_sys_reg(vcpu, SCTLR_EL2) & SCTLR_ELx_M) != s1_walk_translated(&vt->wr))
+		return;
+
 	if (read_vncr_el2(vcpu) != vt->gva)
 		return;
 
author maintainer
#253 lore raw

PATCH 253/583 KVM: arm64: Handle negative S1 walk levels in VNCR TLB size evaluation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

commit 8053393680d4fa3eb962667d2be95dd39f0940e5 upstream.

Computing the effects of a TLB invalidation involves looking at the size of the mapping cached by the TLB. For S1 mappings such as VNCR, this is deducted from the combination of the base granule size and the mapping level.

However, this implies that the S1 MMU is *on*. When the MMU is off, we indicate this with the level being set to a "creative" value of -127 (S1_MMU_DISABLED).

This ends-up being misinterpreted by pgshift_level_to_ttl() as it doesn't handle negative levels at all (the level is immediately cast to a u8 and only the bottom two bits considered), leading to an invalidation size of 0. Not helpful.

Tidy-up pgshift_level_to_ttl() to handle these negative levels, and ttl_to_size() to always return SZ_1G when no valid TTL is present. This allows the removal of open-coded checks for similar situations.

Note that the check for a negative value not explicitely checking for S1_MMU_DISABLED is deliberate, so that actual negative levels introduced with LVA2 and D128 can take the same path if we ever support them.

---
 arch/arm64/kvm/nested.c |   26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)
arch/arm64/kvm/nested.c +19 -7
@@ -387,7 +387,7 @@ int kvm_walk_nested_s2(struct kvm_vcpu *
 	return ret;
 }
 
-static unsigned int ttl_to_size(u8 ttl)
+static unsigned int __ttl_to_size(u8 ttl)
 {
 	int level = ttl & 3;
 	int gran = (ttl >> 2) & 3;
@@ -443,10 +443,22 @@ static unsigned int ttl_to_size(u8 ttl)
 	return max_size;
 }
 
-static u8 pgshift_level_to_ttl(u16 shift, u8 level)
+static unsigned int ttl_to_size(u8 ttl)
+{
+	return __ttl_to_size(ttl) ?: SZ_1G;
+}
+
+static u8 pgshift_level_to_ttl(u16 shift, s8 level)
 {
 	u8 ttl;
 
+	/*
+	 * If we don't have a proper level, fallback to the maximum
+	 * size.
+	 */
+	if (level < 0)
+		return 0;
+
 	switch(shift) {
 	case 12:
 		ttl = TLBI_TTL_TG_4K;
@@ -556,7 +568,11 @@ unsigned long compute_tlb_inval_range(st
 		ttl = get_guest_mapping_ttl(mmu, addr);
 	}
 
-	max_size = ttl_to_size(ttl);
+	/*
+	 * Don't use the default 1GB fallback, as we can adapt to the
+	 * max mapping size we allow at S2.
+	 */
+	max_size = __ttl_to_size(ttl);
 
 	if (!max_size) {
 		/* Compute the maximum extent of the invalidation */
@@ -993,8 +1009,6 @@ static void compute_s1_tlbi_range(struct
 	case OP_TLBI_VALE1OSNXS:
 		scope->type = TLBI_VA;
 		scope->size = ttl_to_size(FIELD_GET(TLBI_TTL_MASK, val));
-		if (!scope->size)
-			scope->size = SZ_1G;
 		scope->va = tlbi_va_s1_to_va(val) & ~(scope->size - 1);
 		scope->asid = FIELD_GET(TLBIR_ASID_MASK, val);
 		break;
@@ -1021,8 +1035,6 @@ static void compute_s1_tlbi_range(struct
 	case OP_TLBI_VAALE1OSNXS:
 		scope->type = TLBI_VAA;
 		scope->size = ttl_to_size(FIELD_GET(TLBI_TTL_MASK, val));
-		if (!scope->size)
-			scope->size = SZ_1G;
 		scope->va = tlbi_va_s1_to_va(val) & ~(scope->size - 1);
 		break;
 	case OP_TLBI_RVAE2:
author maintainer
#254 lore raw

PATCH 254/583 KVM: arm64: Correctly handle end of VA space TLBI invalidation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

commit 34af2c3e31f91a739dc175459fdbd99ed952b457 upstream.

Our TLB invalidation by VA code is based on comparing two ranges, one defined by the TLB, and one defined by the TLBI instruction.

Each range is defined by a start and a size. However, the way the comparison is done doesn't account for address rollover, as it compares an address with (base + size). This works nicely until this expression represent the last page/block in the TTBR1 VA space, as the result is a big fat 0. And a failed TLB invalidation.

Rewrite the comparison in a way that is immune to the address rollover (making the end address inclusive instead of exclusive), and move this into a common helper that is used by both VA and IPA invalidations, as suggested by Hyunwoo Kim (although the IPA version didn't suffer from this particular problem, obviously).

Fixes 4ffa72ad8f37e ("KVM: arm64: nv: Add S1 TLB invalidation primitive for VNCR_EL2")
---
 arch/arm64/kvm/nested.c |   43 +++++++++++++++++++------------------------
 1 file changed, 19 insertions(+), 24 deletions(-)
arch/arm64/kvm/nested.c +19 -24
@@ -868,6 +868,20 @@ static void invalidate_vncr(struct vncr_
 		clear_fixmap(vncr_fixmap(vt->cpu));
 }
 
+static bool vncr_tlb_intersects(struct vncr_tlb *vt, u64 addr,
+				u64 scope_start, u64 scope_size)
+{
+	u64 tlb_size, tlb_start, tlb_end, scope_end;
+
+	tlb_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift, vt->wr.level));
+
+	tlb_start = addr & ~(tlb_size - 1);
+	tlb_end = tlb_start + tlb_size - 1;
+	scope_end = scope_start + scope_size - 1;
+
+	return !(tlb_end < scope_start || tlb_start > scope_end);
+}
+
 /*
  * VNCR TLB invalidation occurs from MMU notifiers or TLBI instructions, and
  * either can race against a vcpu not being onlined yet (no pseudo-TLB
@@ -890,19 +904,9 @@ static void kvm_invalidate_vncr_ipa(stru
 	if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY))
 		return;
 
-	kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) {
-		u64 ipa_start, ipa_end, ipa_size;
-
-		ipa_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift,
-							    vt->wr.level));
-		ipa_start = vt->wr.pa & ~(ipa_size - 1);
-		ipa_end = ipa_start + ipa_size;
-
-		if (ipa_end <= start || ipa_start >= end)
-			continue;
-
-		invalidate_vncr(vt);
-	}
+	kvm_for_each_vncr_tlb(i, vcpu, vt, kvm)
+		if (vncr_tlb_intersects(vt, vt->wr.pa, start, end - start))
+			invalidate_vncr(vt);
 }
 
 struct s1e2_tlbi_scope {
@@ -928,28 +932,19 @@ static void invalidate_vncr_va(struct kv
 	lockdep_assert_held_write(&kvm->mmu_lock);
 
 	kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) {
-		u64 va_start, va_end, va_size;
-
-		va_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift,
-							   vt->wr.level));
-		va_start = vt->gva & ~(va_size - 1);
-		va_end = va_start + va_size;
-
 		switch (scope->type) {
 		case TLBI_ALL:
 			break;
 
 		case TLBI_VA:
-			if (va_end <= scope->va ||
-			    va_start >= (scope->va + scope->size))
+			if (!vncr_tlb_intersects(vt, vt->gva, scope->va, scope->size))
 				continue;
 			if (vt->wr.nG && vt->wr.asid != scope->asid)
 				continue;
 			break;
 
 		case TLBI_VAA:
-			if (va_end <= scope->va ||
-			    va_start >= (scope->va + scope->size))
+			if (!vncr_tlb_intersects(vt, vt->gva, scope->va, scope->size))
 				continue;
 			break;
 
author maintainer
#255 lore raw

PATCH 255/583 KVM: arm64: Make VNCR invalidation participate in MMU invalidation retry

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

commit 2b7324f3a0c1072b9d578b8d42f199506753f26e upstream.

A VNCR TLB invalidation can occur on one vcpu while another vcpu is faulting in this same page. Without correctly handling this, we can end up with the following scenario:

- vcpu A walks the PTs to translate VNCR
- before vcpu A is able to grab the MMU lock to insert the TLB, vcpu B updates the S1 PTs with an invalid entry, and issues a TLBI S1E2 for this VA
- vcpu A inserts the TLB for something that is now invalid

This isn't a new problem, and we manage S2 by having the MMU notifier to bump up mmu_invalidate_seq on invalidation so that the fault can be replayed.

We can perform something similar here, and extend invalidate_vncr_va() to update the same counter, clearly indicating that the context has changed under our feet. This is safe as the invalidation always happen while holding the MMU lock for write, and that we sample the sequence number before walking S1.

---
 arch/arm64/kvm/nested.c |   21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)
arch/arm64/kvm/nested.c +18 -3
@@ -904,6 +904,12 @@ static void kvm_invalidate_vncr_ipa(stru
 	if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY))
 		return;
 
+	/*
+	 * Note that invalidating the VNCR on the back of an MMU notifier
+	 * doesn't require messing with the invalidation counter for a
+	 * parallel walk. The notifier itself will have bumped the counter,
+	 * making sure we rewalk.
+	 */
 	kvm_for_each_vncr_tlb(i, vcpu, vt, kvm)
 		if (vncr_tlb_intersects(vt, vt->wr.pa, start, end - start))
 			invalidate_vncr(vt);
@@ -931,6 +937,15 @@ static void invalidate_vncr_va(struct kv
 
 	lockdep_assert_held_write(&kvm->mmu_lock);
 
+	/*
+	 * We might be performing a parallel S1 walk, so bump up the
+	 * invalidation counter even in the absence of an actual VNCR TLB
+	 * invalidation, as this could indicate that the guest has gone
+	 * through a BBM sequence.
+	 */
+	kvm->mmu_invalidate_seq++;
+	smp_wmb();
+
 	kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) {
 		switch (scope->type) {
 		case TLBI_ALL:
@@ -1243,15 +1258,15 @@ static int kvm_translate_vncr(struct kvm
 
 	va =  read_vncr_el2(vcpu);
 
+	mmu_seq = vcpu->kvm->mmu_invalidate_seq;
+	smp_rmb();
+
 	ret = __kvm_translate_va(vcpu, &vt->wi, &vt->wr, va);
 	if (ret)
 		return ret;
 
 	write_fault = kvm_is_write_fault(vcpu);
 
-	mmu_seq = vcpu->kvm->mmu_invalidate_seq;
-	smp_rmb();
-
 	gfn = vt->wr.pa >> PAGE_SHIFT;
 	memslot = gfn_to_memslot(vcpu->kvm, gfn);
 	if (!memslot) {
author maintainer
#256 lore raw

PATCH 256/583 KVM: arm64: Sign-extend VA for range-based TLBI invalidation

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

commit 2393470085649f0b973ecceb26fe8fc71edde0c1 upstream.

When the decode_range_tlbi() helper was moved to be used for S1 TLBIs, the required sign extension was omitted. Add it.

As a result, special care must be taken to not overflow PA bits when this is used for S2 invalidation.

---
 arch/arm64/include/asm/kvm_nested.h |    7 +++++++
 arch/arm64/kvm/sys_regs.c           |   11 +++++++++++
 2 files changed, 18 insertions(+)
arch/arm64/include/asm/kvm_nested.h +7 -0
@@ -257,6 +257,13 @@ static inline u64 decode_range_tlbi(u64
 
 	base	= (val & GENMASK(36, 0)) << shift;
 
+	/*
+	 * We only deal with at most 48bit VA/IPA, so 48 is where we
+	 * sign-extend from. Should we support FEAT_L{VP}A* at some point,
+	 * this will need to be revisited.
+	 */
+	base	= (u64)sign_extend64(base, 48);
+
 	if (asid)
 		*asid = FIELD_GET(TLBIR_ASID_MASK, val);
 
arch/arm64/kvm/sys_regs.c +11 -0
@@ -3943,6 +3943,7 @@ static bool handle_ripas2e1is(struct kvm
 	u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
 	u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
 	u64 base, range;
+	int pa_bits;
 
 	if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding))
 		return undef_access(vcpu, p, r);
@@ -3954,6 +3955,16 @@ static bool handle_ripas2e1is(struct kvm
 	 */
 	base = decode_range_tlbi(p->regval, &range, NULL);
 
+	/*
+	 * Ignore TLBIs that start out of PA_bits range, and cap the
+	 * invalidation to the [base:bit(PA_bits)] interval.
+	 */
+	pa_bits = kvm_get_pa_bits(vcpu->kvm);
+	if (fls64(base) > pa_bits)
+		return true;
+
+	range = min(range, BIT_ULL(pa_bits) - base);
+
 	kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr),
 				   &(union tlbi_info) {
 					   .range = {
author maintainer
#257 lore raw

PATCH 257/583 KVM: arm64: vgic-v3: take an LPI reference in vgic_v3_save_pending_tables

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Qihang <[email protected]>

commit f5b8f203bfc07a5a257dff859e66d2c500f9f509 upstream.

vgic_v3_save_pending_tables() iterates dist->lpi_xa using xa_for_each() and dereferences the returned struct vgic_irq in the loop body without holding a reference on the LPI.

The xarray iterator only provides temporary RCU coverage while looking up the current entry. That is not sufficient for this loop body, which reads fields from struct vgic_irq and performs guest memory accesses before the iteration completes.

A concurrent path can trigger this race: the irqfd cached injection path (vgic_its_inject_cached_translation) obtains a transient LPI reference via vgic_its_check_cache() without holding kvm->lock, vcpu->mutex, config_lock, or its_lock. If guest ITS DISCARD then drops the cache and ITE references under its_lock, the transient inject reference may become the final one. When vgic_put_irq() drops it, the LPI is erased from lpi_xa and freed via kfree_rcu(). Meanwhile, vgic_v3_save_pending_tables() may still hold a stale pointer obtained from the xarray iterator and dereference it after the RCU grace period completes.

Fix this by re-fetching each iterated LPI via vgic_get_irq(), which takes a stable reference, and dropping it with vgic_put_irq() on all paths. This matches the pattern already used by other lpi_xa iterators in the vgic ITS code.

---
 arch/arm64/kvm/vgic/vgic-v3.c |   12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
arch/arm64/kvm/vgic/vgic-v3.c +9 -3
@@ -420,9 +420,13 @@ int vgic_v3_save_pending_tables(struct k
 		bool is_pending;
 		bool stored;
 
+		irq = vgic_get_irq(kvm, index);
+		if (!irq)
+			continue;
+
 		vcpu = irq->target_vcpu;
 		if (!vcpu)
-			continue;
+			goto put_irq;
 
 		pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
 
@@ -433,7 +437,7 @@ int vgic_v3_save_pending_tables(struct k
 		if (ptr != last_ptr) {
 			ret = kvm_read_guest_lock(kvm, ptr, &val, 1);
 			if (ret)
-				goto out;
+				goto put_irq;
 			last_ptr = ptr;
 		}
 
@@ -445,7 +449,7 @@ int vgic_v3_save_pending_tables(struct k
 			vgic_v4_get_vlpi_state(irq, &is_pending);
 
 		if (stored == is_pending)
-			continue;
+			goto put_irq;
 
 		if (is_pending)
 			val |= 1 << bit_nr;
@@ -453,6 +457,8 @@ int vgic_v3_save_pending_tables(struct k
 			val &= ~(1 << bit_nr);
 
 		ret = vgic_write_guest_lock(kvm, ptr, &val, 1);
+put_irq:
+		vgic_put_irq(kvm, irq);
 		if (ret)
 			goto out;
 	}
author maintainer
#258 lore raw

PATCH 258/583 KVM: arm64: vgic: Fix detection of MI on no pending LR

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kajetan Puchalski <[email protected]>

commit a342faadc5acbd5d9fd894fd4499d4fd614dfcf6 upstream.

As per the ARM GICv3 spec, the maintenance interrupt identified by ICH_MISR_EL2.NP is asserted when it is enabled and no List register is in pending state. This is further described in the document as "no List registers with the State field set to 0b01 (pending)". By checking only the pending bit of the LR (bit 62), KVM currently asserts the MI when there are no LRs in "pending" or "pending and active" states. Fix the detection logic to consider only the "pending" state.

---
 arch/arm64/kvm/vgic/vgic-v3-nested.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/kvm/vgic/vgic-v3-nested.c +1 -1
@@ -149,7 +149,7 @@ static void vgic_compute_mi_state(struct
 			eisr |= BIT(i);
 		if (!(lr & ICH_LR_STATE))
 			elrsr |= BIT(i);
-		pend |= (lr & ICH_LR_PENDING_BIT);
+		pend |= (lr & ICH_LR_STATE) == ICH_LR_PENDING_BIT;
 	}
 
 	mi_state->eisr	= eisr;
author maintainer
#259 lore raw

PATCH 259/583 KVM: arm64: vgic: Reset in_kernel on private IRQ allocation failure

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

commit 43347154e7ab642474c886bc54ad090166c0d9c9 upstream.

kvm_vgic_create() sets vgic.in_kernel before allocating the per-vCPU private IRQs, but the allocation-failure path resets only vgic_model and leaves in_kernel set. As irqchip_in_kernel() is !!in_kernel, the VM is left with an in-kernel irqchip but no model, and the -EEXIST guard at the top of kvm_vgic_create() rejects every retry, so userspace cannot recover from a transient -ENOMEM.

Reset in_kernel alongside vgic_model on the failure path.

Fixes 9435c1e1431003 ("KVM: arm64: gic: Set vgic_model before initing private IRQs")
---
 arch/arm64/kvm/vgic/vgic-init.c |    1 +
 1 file changed, 1 insertion(+)
arch/arm64/kvm/vgic/vgic-init.c +1 -0
@@ -173,6 +173,7 @@ int kvm_vgic_create(struct kvm *kvm, u32
 		}
 
 		kvm->arch.vgic.vgic_model = 0;
+		kvm->arch.vgic.in_kernel = false;
 		goto out_unlock;
 	}
 
author maintainer
#260 lore raw

PATCH 260/583 KVM: arm64: vgic-its: Dont dereference a NULL collection on ITT save

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fuad Tabba <[email protected]>

commit c6c156d931c33b92362383cf76f6d6e1291dcbfe upstream.

MAPC with V=0 drops ite->collection but leaves the ITE on the device's ITT list, and vgic_its_save_ite() dereferences it unconditionally. A guest that issues MAPD, MAPTI and then MAPC(V=0) therefore oopses the host when the VMM issues KVM_DEV_ARM_ITS_SAVE_TABLES to migrate it. That sequence is UNPREDICTABLE per the architecture, but KVM already handles the resulting state in the translate, MOVI and DISCARD paths.

Save a zeroed entry, which vgic_its_restore_ite() reads back as invalid. Skipping the ITE instead would leave the ITT slot holding whatever is in guest memory, and restore rejects an entry naming a collection the restored collection table does not have.

Fixes eff484e0298da ("KVM: arm64: vgic-its: ITT save and restore")
---
 arch/arm64/kvm/vgic/vgic-its.c |    8 ++++++++
 1 file changed, 8 insertions(+)
arch/arm64/kvm/vgic/vgic-its.c +8 -0
@@ -2112,6 +2112,14 @@ static int vgic_its_save_ite(struct vgic
 	u32 next_offset;
 	u64 val;
 
+	/*
+	 * MAPC with V=0 keeps the ITEs mapped but drops their collection,
+	 * and with it the ICID. Save a zeroed entry, which the restore path
+	 * reads back as invalid.
+	 */
+	if (!ite->collection)
+		return vgic_its_write_entry_lock(its, gpa, 0ULL, ite);
+
 	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
 	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
 	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
author maintainer
#261 lore raw

PATCH 261/583 KVM: arm64: Correctly cap TLBI Range to the architural limit

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marc Zyngier <[email protected]>

commit 69a598288195947a1662b53de702eb6976af96b7 upstream.

TLB Invalidation by Range has a fairly powerful way of encoding pretty large ranges in a small number of bits. This range can be based on an arbitrary VA, which means it is pretty easy for a guest to generate an overflow should the hypervisor be naive enough to add the range to the base...

Make sure the range is capped to the limit dictated by the address bit that determines the VA range. For an IPA invalidation, this is further corrected down the line to ignore the upper range.

---
 arch/arm64/include/asm/kvm_nested.h |    6 ++++++
 1 file changed, 6 insertions(+)
arch/arm64/include/asm/kvm_nested.h +6 -0
@@ -271,6 +271,12 @@ static inline u64 decode_range_tlbi(u64
 	num	= FIELD_GET(GENMASK(43, 39), val);
 	*range	= __TLBI_RANGE_PAGES(num, scale) << shift;
 
+	/* Cap the range to the correct half of the address space */
+	if (!(base & BIT(48)))
+		*range = min(*range, (BIT(48) - base));
+	else
+		*range = min(*range, ~base + 1);
+
 	return base;
 }
 
author maintainer
#262 lore raw

PATCH 262/583 LoongArch: KVM: Fix PC double advance in kernel MMIO read fast path

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zeng Chi <[email protected]>

commit fd4021529faa931818186b6e83bd46f5de7517eb upstream.

In the in-kernel MMIO read fast path of kvm_emu_mmio_read(), kvm_complete_mmio_read() already advances the guest PC via update_pc(). The explicit update_pc() call right after it advances the PC a second time, so PC moves forward by 8 bytes instead of 4, and the instruction following the MMIO read is silently skipped.

The user space MMIO read completion path in kvm_arch_vcpu_ioctl_run() calls kvm_complete_mmio_read() only once, and the MMIO write fast path advances the PC exactly once as well.

Here remove the redundant update_pc() so the kernel MMIO read fast path advances the PC by a single instruction.

Fixes 80edf90831a2 ("LoongArch: KVM: Add sign extension with kernel MMIO read emulation")
---
 arch/loongarch/kvm/exit.c | 1 -
 1 file changed, 1 deletion(-)
arch/loongarch/kvm/exit.c +0 -1
index 8572b63478bb..482ba17bcd3d 100644
@@ -481,7 +481,6 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst)
 		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		if (!ret) {
 			kvm_complete_mmio_read(vcpu, run);
-			update_pc(&vcpu->arch);
 			vcpu->mmio_needed = 0;
 			return EMULATE_DONE;
 		}
Signature · 1 line
2.55.0
author maintainer
#263 lore raw

PATCH 263/583 LoongArch: KVM: Fix TOCTOU race on pv_features

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tao Cui <[email protected]>

commit 9296375902579f9b0e456bbb76e5cf179e5a4e0b upstream.

In kvm_loongarch_cpucfg_set_attr() the check-then-set on kvm->arch.pv_features is lockless, so two vCPUs can race past the validation and set different values. Add a spinlock to protect it.

---
 arch/loongarch/include/asm/kvm_host.h |    1 +
 arch/loongarch/kvm/vcpu.c             |    6 +++++-
 arch/loongarch/kvm/vm.c               |    1 +
 3 files changed, 7 insertions(+), 1 deletion(-)
arch/loongarch/include/asm/kvm_host.h +1 -0
@@ -122,6 +122,7 @@ struct kvm_arch {
 	unsigned int  pte_shifts[MAX_PGTABLE_LEVELS];
 	unsigned int  root_level;
 	spinlock_t    phyid_map_lock;
+	spinlock_t    pv_setting_lock;
 	struct kvm_phyid_map  *phyid_map;
 	/* Enabled PV features */
 	unsigned long pv_features;
arch/loongarch/kvm/vcpu.c +5 -1
@@ -1120,10 +1120,14 @@ static int kvm_loongarch_cpucfg_set_attr
 			return -EINVAL;
 
 		/* All vCPUs need set the same PV features */
+		spin_lock(&kvm->arch.pv_setting_lock);
 		if ((kvm->arch.pv_features & LOONGARCH_PV_FEAT_UPDATED)
-				&& ((kvm->arch.pv_features & valid) != val))
+				&& ((kvm->arch.pv_features & valid) != val)) {
+			spin_unlock(&kvm->arch.pv_setting_lock);
 			return -EINVAL;
+		}
 		kvm->arch.pv_features = val | LOONGARCH_PV_FEAT_UPDATED;
+		spin_unlock(&kvm->arch.pv_setting_lock);
 		return 0;
 	default:
 		return -ENXIO;
arch/loongarch/kvm/vm.c +1 -0
@@ -40,6 +40,7 @@ int kvm_arch_init_vm(struct kvm *kvm, un
 		return -ENOMEM;
 	}
 	spin_lock_init(&kvm->arch.phyid_map_lock);
+	spin_lock_init(&kvm->arch.pv_setting_lock);
 
 	kvm_init_vmcs(kvm);
 
author maintainer
#264 lore raw

PATCH 264/583 LoongArch: KVM: Free init resources if kvm_init() fails

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chaithanya Lagisetty <[email protected]>

commit f7a1064cce3b100b54780c68529176232d8eb01e upstream.

kvm_loongarch_init() calls kvm_loongarch_env_init() to allocate the per-CPU kvm_context (vmcs) and kvm_loongarch_ops and to register the perf callbacks, and then calls kvm_init(). If kvm_init() fails its result is returned directly, but since module_init() does not run the module_exit() stuff on failure, so kvm_loongarch_env_exit() is never called and those resources are leaked.

So call kvm_loongarch_env_exit() when kvm_init() fails, matching the teardown-on-failure pattern used by riscv_kvm_init().

Fixes 2bd6ac687261 ("LoongArch: KVM: Implement kvm module related interface")
---
 arch/loongarch/kvm/main.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
arch/loongarch/kvm/main.c +5 -1
@@ -413,7 +413,11 @@ static int kvm_loongarch_init(void)
 	if (r)
 		return r;
 
-	return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
+	r = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
+	if (r)
+		kvm_loongarch_env_exit();
+
+	return r;
 }
 
 static void kvm_loongarch_exit(void)
author maintainer
#265 lore raw

PATCH 265/583 LoongArch: KVM: Preserve memslot arch flags on KVM_MR_FLAGS_ONLY

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zeng Chi <[email protected]>

commit 27a9bfee3bbcb3cabb77797354f07e0e44e49831 upstream.

kvm_arch_prepare_memory_region() computes new->arch.flags, i.e. whether a memslot is KVM_MEM_HUGEPAGE_CAPABLE or KVM_MEM_HUGEPAGE_INCAPABLE, only for KVM_MR_CREATE and KVM_MR_MOVE, and returns early for every other change. But the generic code allocates a zeroed memslot for every change and never copies old->arch, so after a KVM_MR_FLAGS_ONLY update, e.g. toggling KVM_MEM_LOG_DIRTY_PAGES for live migration, the active memslot has arch.flags == 0.

With both flags clear, fault_supports_huge_mapping() falls through to the alignment check on the HVA range alone, which no longer verifies that the GPA and HVA have the same offset within a PMD. A memslot that was marked KVM_MEM_HUGEPAGE_INCAPABLE because of a GPA/HVA offset mismatch can then be mapped with PMD entries on read faults, and since kvm_map_page() aligns the gfn and the pfn independently, the guest ends up accessing the wrong host pages, exactly the "d -> f, e -> g" case described in the comment above the check.

Carry the arch flags over from the old memslot for KVM_MR_FLAGS_ONLY, as the GPA, HVA and size are guaranteed to be unchanged for that case.

Fixes 7ab6fb505b2a ("LoongArch: KVM: Optimization for memslot hugepage checking")
---
 arch/loongarch/kvm/mmu.c |   10 ++++++++++
 1 file changed, 10 insertions(+)
arch/loongarch/kvm/mmu.c +10 -0
@@ -383,6 +383,16 @@ int kvm_arch_prepare_memory_region(struc
 	hva_t hva_start;
 	size_t size, gpa_offset, hva_offset;
 
+	/*
+	 * The generic code allocates a fresh, zeroed memslot for every change,
+	 * so the arch flags computed below must be carried over when only the
+	 * userspace flags change, e.g. when dirty logging is toggled.
+	 */
+	if (change == KVM_MR_FLAGS_ONLY) {
+		new->arch = old->arch;
+		return 0;
+	}
+
 	if ((change != KVM_MR_MOVE) && (change != KVM_MR_CREATE))
 		return 0;
 	/*
author maintainer
#266 lore raw

PATCH 266/583 LoongArch: Add DIRECT_MAP_PHYSMEM_END definition

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Han Gao <[email protected]>

commit 2677f97a67fdbc62a82ce1faa67791f54451d36f upstream.

get_free_mem_region() and mhp_get_pluggable_range() bound their search to DIRECT_MAP_PHYSMEM_END. LoongArch does not define it, so the fallback in include/linux/mm.h applies: under CONFIG_SPARSEMEM_VMEMMAP it is (1ULL << MAX_PHYSMEM_BITS) - 1, a compile-time constant that does not adapt to the CPU's physical address space bits (cpu_pabits, probed from CPUCFG1).

The vmemmap window only covers physical space below 2^(cpu_pabits+1) (i.e. VMEMMAP_SIZE), so on CPUs with fewer physical address bits than MAX_PHYSMEM_BITS the fallback allows get_free_mem_region() to return a ZONE_DEVICE region outside the vmemmap window; vmemmap_populate() then wraps the memmap range around and maps it into low memory, silently corrupting the page tables. The same search also picked the top-of- address-space region that crashed memmap_init_zone_device() with amdkfd on Loongson-3C6000 in 6.16 [1]; the commit 2969b42c8f99 ("LoongArch/mm:
align vmemmap to maximal folio size") keeps that region in bounds on current Loongson-3C6000 configs, but CPUs with smaller cpu_pabits (e.g. the Loongson-2K series) are still affected.

Define DIRECT_MAP_PHYSMEM_END as the vmemmap-covered physical range, (1ULL << (cpu_pabits + 1)) - 1, capped at (1ULL << MAX_PHYSMEM_BITS) - 1 under CONFIG_SPARSEMEM, similar to the commit f3336b48cf9d ("riscv: mm:
Define DIRECT_MAP_PHYSMEM_END").

[1] https://lore.kernel.org/amd-gfx/[email protected]/

---
 arch/loongarch/include/asm/pgtable.h |    7 +++++++
 1 file changed, 7 insertions(+)
arch/loongarch/include/asm/pgtable.h +7 -0
@@ -106,6 +106,13 @@ extern unsigned long empty_zero_page[PAG
 #define KFENCE_AREA_START	(VMEMMAP_END + 1)
 #define KFENCE_AREA_END		(KFENCE_AREA_START + KFENCE_AREA_SIZE - 1)
 
+/* Needed to limit get_free_mem_region() */
+#ifndef CONFIG_SPARSEMEM
+#define DIRECT_MAP_PHYSMEM_END ((1ULL << (cpu_pabits + 1)) - 1)
+#else
+#define DIRECT_MAP_PHYSMEM_END min((1ULL << (cpu_pabits + 1)) - 1, (1ULL << MAX_PHYSMEM_BITS) - 1)
+#endif
+
 #define ptep_get(ptep) READ_ONCE(*(ptep))
 #define pmdp_get(pmdp) READ_ONCE(*(pmdp))
 
author maintainer
#267 lore raw

PATCH 267/583 LoongArch: BPF: Optimize redundant TCC loads in epilogue

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tiezhu Yang <[email protected]>

commit fd3cb1bfeb9d98618bd709bfee9c1133e9f189e6 upstream.

The legacy epilogue implementation pops the tail call counter (TCC) context via a redundant double-load pattern. It first decrements the load_offset by 2 slots to fetch 'tcc_ptr', and then immediately bumps it back up by 1 slot to load the original 'tcc' value into REG_TCC, unnecessarily overwriting the register.

Optimize this sequence by adjusting the load_offset by only 1 slot. This aligns the offset directly with the higher stack slot containing the entry TCC counter (or caller state), allowing us to restore the REG_TCC register safely with a single load.

This removes one redundant instruction from the epilogue hot path, improves code readability, and ensures the correct TCC register context is handed back cleanly upon normal return.

Fixes c0fcc955ff82 ("LoongArch: BPF: Fix the tailcall hierarchy")
Fixes ef54c517a937 ("LoongArch: BPF: Implement PROBE_MEM32 pseudo instructions")
---
 arch/loongarch/net/bpf_jit.c |   10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)
arch/loongarch/net/bpf_jit.c +2 -8
@@ -228,14 +228,8 @@ static void __build_epilogue(struct jit_
 	load_offset -= sizeof(long);
 	emit_insn(ctx, ldd, LOONGARCH_GPR_S5, LOONGARCH_GPR_SP, load_offset);
 
-	/*
-	 * When push into the stack, follow the order of tcc then tcc_ptr.
-	 * When pop from the stack, first pop tcc_ptr then followed by tcc.
-	 */
-	load_offset -= 2 * sizeof(long);
-	emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, load_offset);
-
-	load_offset += sizeof(long);
+	/* Only restore the TCC state into REG_TCC from the higher slot */
+	load_offset -= sizeof(long);
 	emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, load_offset);
 
 	emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, stack_adjust);
author maintainer
#268 lore raw

PATCH 268/583 LoongArch: BPF: Refactor jump offset calculation in tail call

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tiezhu Yang <[email protected]>

commit 37d545d12f21c4d50612ecaebd7ae1e5bf91b2d8 upstream.

The old macro-based jmp_offset calculation derives the jump distance from a stale prior-pass code stride, which can lead to wrong branch offsets and soft lockups under extra JIT passes.

Fix this by calculating the offset directly on the absolute target:
"ctx->offset[insn + 1] - ctx->idx".

To avoid a false 16-bit range check abort during size estimation, add a "ctx->image == NULL" guard to inject a safe dummy offset.

Fixes cd39d9e6b7e4 ("LoongArch: BPF: Fix jump offset calculation in tailcall")
---
 arch/loongarch/net/bpf_jit.c |   12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)
arch/loongarch/net/bpf_jit.c +4 -8
@@ -266,17 +266,13 @@ bool bpf_jit_supports_far_kfunc_call(voi
 
 static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
 {
-	int off, tc_ninsn = 0;
+	int off, jmp_offset;
 	int tcc_ptr_off = BPF_TAIL_CALL_CNT_PTR_STACK_OFF(ctx->stack_size);
 	u8 a1 = LOONGARCH_GPR_A1;
 	u8 a2 = LOONGARCH_GPR_A2;
 	u8 t1 = LOONGARCH_GPR_T1;
 	u8 t2 = LOONGARCH_GPR_T2;
 	u8 t3 = LOONGARCH_GPR_T3;
-	const int idx0 = ctx->idx;
-
-#define cur_offset (ctx->idx - idx0)
-#define jmp_offset (tc_ninsn - (cur_offset))
 
 	/*
 	 * a0: &ctx
@@ -286,12 +282,12 @@ static int emit_bpf_tail_call(struct jit
 	 * if (index >= array->map.max_entries)
 	 *	 goto out;
 	 */
-	tc_ninsn = insn ? ctx->offset[insn+1] - ctx->offset[insn] : ctx->offset[0];
 	emit_zext_32(ctx, a2, true);
 
 	off = offsetof(struct bpf_array, map.max_entries);
 	emit_insn(ctx, ldwu, t1, a1, off);
 	/* bgeu $a2, $t1, jmp_offset */
+	jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0;
 	if (emit_tailcall_jmp(ctx, BPF_JGE, a2, t1, jmp_offset) < 0)
 		goto toofar;
 
@@ -302,6 +298,7 @@ static int emit_bpf_tail_call(struct jit
 	emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off);
 	emit_insn(ctx, ldd, t3, REG_TCC, 0);
 	emit_insn(ctx, addid, t2, LOONGARCH_GPR_ZERO, MAX_TAIL_CALL_CNT);
+	jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0;
 	if (emit_tailcall_jmp(ctx, BPF_JSGE, t3, t2, jmp_offset) < 0)
 		goto toofar;
 
@@ -316,6 +313,7 @@ static int emit_bpf_tail_call(struct jit
 	off = offsetof(struct bpf_array, ptrs);
 	emit_insn(ctx, ldd, t2, t2, off);
 	/* beq $t2, $zero, jmp_offset */
+	jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0;
 	if (emit_tailcall_jmp(ctx, BPF_JEQ, t2, LOONGARCH_GPR_ZERO, jmp_offset) < 0)
 		goto toofar;
 
@@ -331,8 +329,6 @@ static int emit_bpf_tail_call(struct jit
 toofar:
 	pr_info_once("tail_call: jump too far\n");
 	return -1;
-#undef cur_offset
-#undef jmp_offset
 }
 
 static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx)
author maintainer
#269 lore raw

PATCH 269/583 LoongArch: Fix acpi_package_ids[] array overflow

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bibo Mao <[email protected]>

commit 2a2367d46d7a4ee4122b7a86e57125542dbbe963 upstream.

With LoongArch virt machine, a typical setting is one core per socket, there will max 256 sockets (packages) on one VM. With PPTT acpi table, array acpi_package_ids[] will be overflowed.

Here change the array size of acpi_package_ids[] with the max value of MAX_PACKAGES and KVM_MAX_VCPUS.

Fixes 4e8f58620f67 ("LoongArch: Retrieve CPU package ID from PPTT when available")
---
 arch/loongarch/kernel/acpi.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/loongarch/kernel/acpi.c +2 -1
@@ -13,6 +13,7 @@
 #include <linux/export.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
+#include <linux/kvm_host.h>
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/serial_core.h>
@@ -202,7 +203,7 @@ static void __init acpi_process_madt(voi
 
 int pptt_enabled;
 static int acpi_nr_packages;
-static int acpi_package_ids[MAX_PACKAGES];
+static int acpi_package_ids[MAX(MAX_PACKAGES, KVM_MAX_VCPUS)];
 
 int __init parse_acpi_topology(void)
 {
author maintainer
#270 lore raw

PATCH 270/583 LoongArch: Do not select HAVE_RUST when KASAN is enabled

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nathan Chancellor <[email protected]>

commit 63b6a48c951d63bf39d44603ada48a987ccf66eb upstream.

After commit 2625480a1bf7 ("hardening: Default randstruct off with rust for better allmodconfig support"), which allows Rust to be enabled for allmodconfig, ARCH=loongarch allmodconfig starts failing with:

error: kernel-address sanitizer is not supported for this target

error: aborting due to 1 previous error

make[4]: *** [rust/Makefile:741: rust/core.o] Error 1

For the same reason as the commit 84a0f7caafc679f7 ("ARM: Do not select HAVE_RUST when KASAN is enabled"), do not select HAVE_RUST when KASAN is enabled until the loongarch64-unknown-none-softfloat target in rustc supports KASAN.

Fixes 90868ff9cade ("LoongArch: Enable initial Rust support")
---
 arch/loongarch/Kconfig |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/loongarch/Kconfig +1 -1
@@ -173,7 +173,7 @@ config LOONGARCH
 	select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC
 	select HAVE_RETHOOK
 	select HAVE_RSEQ
-	select HAVE_RUST
+	select HAVE_RUST if !KASAN
 	select HAVE_SAMPLE_FTRACE_DIRECT
 	select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
 	select HAVE_SETUP_PER_CPU_AREA if NUMA
author maintainer
#271 lore raw

PATCH 271/583 LoongArch: Do not save/restore percpu base register in rethook trampoline

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Wentao Guan <[email protected]>

commit c3f2feace5e4f4b01b68b9f947b19adb4155c32e upstream.

The rethook trampoline saves $r21 ($u0), the percpu base, into its frame at entry and restores it at exit. Inbetween rethook_trampoline_handler() may schedule via preempt_enable_notrace().

If the task migrates to another CPU, the frame's $r21 holds the old CPU's percpu base, and restoring it poisons $r21 on the new CPU. Until the next user->kernel transition heals $r21, all this_cpu_*() accesses (runqueues, RCU per-CPU data, timer tick programming, FPU ownership) hit the wrong CPU's percpu area.

Under kretprobe-heavy preemptible load this can corrupt scheduler and timer state: scheduling-while-atomic splats, wrong-CPU RCU warnings, WARN_ON_ONCE(rq != this_rq()) in nohz_balance_exit_idle(), and CPUs parking in the idle loop with the constant timer never re-armed (hard lockup). Reproduces on a Loongson-3A6000 with kretprobes on VFS paths plus heavy file churn (OS install / unsquashfs).

By convention $r21 always holds the current CPU's percpu base in kernel
mode: SAVE_SOME() at exception entry reloads it only when coming from user mode, and RESTORE_SOME() restores it only when returning to user mode; the context-switch path never writes it. Therefore the live $r21 at trampoline exit is already correct, and nothing inbetween can change it legitimately (kernel C code cannot write a global register variable). The same flaw existed even in the pre-rethook kretprobe trampoline since v6.3; it was carried over when rethook replaced it. Drop both the save and the restore here. Drop the restore is enough to solve the issue, and drop the save is to keep the code tidy and no need to clear it.

Fixes 3f5536860086d ("LoongArch: Add kretprobes support")
Assisted-by Kimi:Kimi-K3 # debug and root-cause analysis
---
 arch/loongarch/kernel/rethook_trampoline.S |    2 --
 1 file changed, 2 deletions(-)
arch/loongarch/kernel/rethook_trampoline.S +0 -2
@@ -24,7 +24,6 @@
 	cfi_st	t6, PT_R18
 	cfi_st	t7, PT_R19
 	cfi_st	t8, PT_R20
-	cfi_st	u0, PT_R21
 	cfi_st	fp, PT_R22
 	cfi_st	s0, PT_R23
 	cfi_st	s1, PT_R24
@@ -59,7 +58,6 @@
 	cfi_ld	t6, PT_R18
 	cfi_ld	t7, PT_R19
 	cfi_ld	t8, PT_R20
-	cfi_ld	u0, PT_R21
 	cfi_ld	fp, PT_R22
 	cfi_ld	s0, PT_R23
 	cfi_ld	s1, PT_R24
author maintainer
#272 lore raw

PATCH 272/583 LoongArch: Avoid preempt count underflow without probe

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jérémy Jean <[email protected]>

commit 72ce4b24676e8b3b75376c4c559dd81c1ac52d5a upstream.

LoongArch uses break 11 for the breakpoint placed after an instruction that Kprobes executes out of line. Since userspace can issue the same break instruction, do_bp() can reach kprobe_singlestep_handler() when there is no current probe.

The handler actually returns false in this case, but it first calls preempt_enable_no_resched(). The corresponding preempt_disable() is done by kprobe_breakpoint_handler() on a real Kprobe hit, so it has not run here. As a result, an ordinary userspace breakpoint (code 11) underflows the current task's preempt count.

This also makes in_interrupt() return true until the task schedules. One visible consequence is the socket cgroup attribution: cgroup_sk_alloc() treats the allocation as interrupt context and assigns the socket to the root cgroup. A socket opened from the SIGTRAP handler can then avoid a BPF_CGROUP_INET_SOCK_CREATE policy attached to the task's own cgroup.

Return as soon as kprobe_running() reports no active probe.

The same check has appeared in [PATCH v10 2/4] of the original LoongArch Kprobes series, but was dropped before the feature reached mainline.

Fixes 6d4cc40fb5f5 ("LoongArch: Add kprobes support")
Assisted-by Codex:gpt-5
---
 arch/loongarch/kernel/kprobes.c |    3 +++
 1 file changed, 3 insertions(+)
arch/loongarch/kernel/kprobes.c +3 -0
@@ -275,6 +275,9 @@ bool kprobe_singlestep_handler(struct pt
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 	unsigned long addr = instruction_pointer(regs);
 
+	if (!cur)
+		return false;
+
 	if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) &&
 	    ((unsigned long)&cur->ainsn.insn[1] == addr)) {
 		restore_local_irqflag(kcb, regs);
author maintainer
#273 lore raw

PATCH 273/583 rust: drm: ioctl: fix unbounded lifetimes in ioctl handler arguments

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Danilo Krummrich <[email protected]>

commit 68b151bc6145dea3db5598ebaf4b776cd205e395 upstream.

References to dev, data, and file in the declare_drm_ioctls! macro are created via unsafe pointer dereferences, producing unbounded lifetimes. If an ioctl handler explicitly annotates its parameters with 'static, the compiler accepts this, allowing the handler to stash references that outlive the ioctl call.

Fix this by adding a higher-ranked function pointer coercion that enforces the handler accepts universally quantified lifetimes:

  let _: for<'a> fn(&'a _, &'a mut _, &'a _) -> _ = $func;

Since the handler must be coercible to a function pointer accepting any lifetime 'a, it can no longer demand 'static on any parameter.

---
 rust/kernel/drm/ioctl.rs | 6 ++++++
 1 file changed, 6 insertions(+)
rust/kernel/drm/ioctl.rs +6 -0
index cf328101dde4..ccf4150d83b6 100644
@@ -135,6 +135,12 @@ macro_rules! declare_drm_ioctls {
                             // dev/file match the current driver these ioctls are being declared
                             // for, and it's not clear how to enforce this within the type system.
                             let dev = $crate::drm::device::Device::from_raw(raw_dev);
+
+                            // Enforce that the handler accepts higher-ranked
+                            // lifetimes, preventing it from requiring 'static
+                            // references that could escape this scope.
+                            let _: for<'a> fn(&'a _, &'a mut _, &'a _) -> _ = $func;
+
                             // SAFETY: The ioctl argument has size `_IOC_SIZE(cmd)`, which we
                             // asserted above matches the size of this type, and all bit patterns of
                             // UAPI structs must be valid.
Signature · 1 line
2.55.0
author maintainer
#274 lore raw

PATCH 274/583 media: airspy: use vb2_video_unregister_device() on disconnect to fix NULL deref

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Valery Borovsky <[email protected]>

commit 2f378dc45e685fc825d2dd08e7864666d6fcc009 upstream.

airspy_disconnect() clears s->udev under v4l2_lock, but airspy_stop_streaming() unconditionally calls airspy_ctrl_msg() and airspy_free_stream_bufs() afterwards. If a streaming user closes the device after disconnect, stop_streaming() runs and dereferences the NULL s->udev:

airspy_stop_streaming()

    airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0)
      usb_sndctrlpipe(s->udev, 0)         /* NULL deref */
    airspy_free_stream_bufs(s)
      usb_free_coherent(s->udev, ...)     /* NULL deref */

The airspy driver uses vb2_fop_release() in its file_operations, so replace video_unregister_device(&s->vdev) with vb2_video_unregister_device(&s->vdev) and move it before clearing s->udev. vb2_video_unregister_device() releases the vb2 queue, which synchronously runs airspy_stop_streaming() if streaming is active, so the URBs, coherent DMA stream buffers and the hardware stop control message all execute while s->udev is still valid.

vb2_video_unregister_device() locks vdev->queue->lock (vb_queue_lock) internally, and stop_streaming() locks v4l2_lock, so the previous outer mutex_lock(&s->vb_queue_lock) / mutex_lock(&s->v4l2_lock) pair around the unregister sequence would self-deadlock and has been removed. A short v4l2_lock critical section around s->udev = NULL remains so any ioctl path that still holds the file descriptor sees coherent state.

Issue identified by automated review of the INV-003 series at
https://sashiko.dev/

Fixes 634fe5033951 ("[media] airspy: AirSpy SDR driver")
---
 drivers/media/usb/airspy/airspy.c |   17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/media/usb/airspy/airspy.c +12 -5
@@ -464,14 +464,21 @@ static void airspy_disconnect(struct usb
 
 	dev_dbg(s->dev, "\n");
 
-	mutex_lock(&s->vb_queue_lock);
+	/*
+	 * vb2_video_unregister_device() releases the vb2 queue, which
+	 * triggers airspy_stop_streaming() if streaming is active.
+	 * stop_streaming() dereferences s->udev via airspy_ctrl_msg() and
+	 * airspy_free_stream_bufs(), so it must run before s->udev is
+	 * cleared. vb2_video_unregister_device() locks vb_queue_lock
+	 * internally and stop_streaming() locks v4l2_lock, so neither may
+	 * be held by the caller.
+	 */
+	v4l2_device_disconnect(&s->v4l2_dev);
+	vb2_video_unregister_device(&s->vdev);
+
 	mutex_lock(&s->v4l2_lock);
-	/* No need to keep the urbs around after disconnection */
 	s->udev = NULL;
-	v4l2_device_disconnect(&s->v4l2_dev);
-	video_unregister_device(&s->vdev);
 	mutex_unlock(&s->v4l2_lock);
-	mutex_unlock(&s->vb_queue_lock);
 
 	v4l2_device_put(&s->v4l2_dev);
 }
author maintainer
#275 lore raw

PATCH 275/583 media: amphion: Remove obsolete frame_count check in venc_start_session

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ming Qian <[email protected]>

commit 2be6ee86385badab95b1bace984735bde6e0fec0 upstream.

The dev_err() log warning about no input when starting was originally meaningful when min_queued_buffers was set, as it indicated an abnormal condition. However, since commit 5633ec763a2a ("media: amphion: Drop min_queued_buffers assignment") removed the min_queued_buffers assignment, having frame_count == 0 at start is a normal condition.

Remove this misleading log that no longer serves any purpose.

Fixes 5633ec763a2a ("media: amphion: Drop min_queued_buffers assignment")
---
 drivers/media/platform/amphion/venc.c |    2 --
 1 file changed, 2 deletions(-)
drivers/media/platform/amphion/venc.c +0 -2
@@ -977,8 +977,6 @@ static int venc_start_session(struct vpu
 	venc->ready_count = 0;
 	venc->stopped = false;
 	vpu_process_output_buffer(inst);
-	if (venc->frame_count == 0)
-		dev_err(inst->dev, "[%d] there is no input when starting\n", inst->id);
 
 	return 0;
 error:
author maintainer
#276 lore raw

PATCH 276/583 media: cec: core: Fix kmemleak due to missed rc_free_device() call

In reply to Greg Kroah-Hartman

6.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jonas Karlman <[email protected]>

commit a24ba0653f7154e671dc8d2bf64682ab2d042792 upstream.

The commit dccc0c3ddf8f ("media: rc: fix race between unregister and urb/irq callbacks") removed the implicit call to rc_free_device() from rc_unregister_device(). However, the commit missed to remove the NULL assignment of adap->rc that is now causing rc_free_device() to never be called on an allocated rc device.

kmemleak reports following after e.g. dw-hdmi unbind:

unreferenced object 0xffff00010ac10000 (size 4096):
comm "kworker/u16:1", pid 39, jiffies 4294897739 hex dump (first 32 bytes):

    20 23 4b 0a 01 00 ff ff 08 00 c1 0a 01 00 ff ff   #K.............
    08 00 c1 0a 01 00 ff ff 00 00 00 00 00 00 00 00  ................
  backtrace (crc e11baccc):
    kmemleak_alloc+0x38/0x44
    __kmalloc_cache_noprof+0x4a8/0x5e0
    rc_allocate_device+0x48/0x2a0
    cec_allocate_adapter+0x3ac/0x800
    dw_hdmi_cec_probe+0x264/0x634
    platform_probe+0xc0/0x188
    really_probe+0x4a4/0x8e0
    __driver_probe_device+0x2f8/0x440
    driver_probe_device+0x60/0x160
    __device_attach_driver+0x1a0/0x2a0
    bus_for_each_drv+0x100/0x1a0
    __device_attach+0x174/0x350
    device_initial_probe+0x90/0xb0
    bus_probe_device+0x4c/0x120
    device_add+0xdec/0x116c
    platform_device_add+0x354/0x598

Remove the assignment of adap->rc to NULL to let cec_delete_adapter() free the allocated rc device after last user of the cec device exits to fix the kmemleak.

Fixes dccc0c3ddf8f ("media: rc: fix race between unregister and urb/irq callbacks")
---
 drivers/media/cec/core/cec-core.c |    2 --
 1 file changed, 2 deletions(-)
drivers/media/cec/core/cec-core.c +0 -2
@@ -371,9 +371,7 @@ void cec_unregister_adapter(struct cec_a
 		return;
 
 #ifdef CONFIG_MEDIA_CEC_RC
-	/* Note: rc_unregister also calls rc_free */
 	rc_unregister_device(adap->rc);
-	adap->rc = NULL;
 #endif
 	debugfs_remove_recursive(adap->cec_dir);
 #ifdef CONFIG_CEC_NOTIFIER