]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.13-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Mar 2025 20:57:10 +0000 (21:57 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Mar 2025 20:57:10 +0000 (21:57 +0100)
added patches:
acpi-typec-ucsi-introduce-a-poll_cci-method.patch

queue-6.13/acpi-typec-ucsi-introduce-a-poll_cci-method.patch [new file with mode: 0644]
queue-6.13/series

diff --git a/queue-6.13/acpi-typec-ucsi-introduce-a-poll_cci-method.patch b/queue-6.13/acpi-typec-ucsi-introduce-a-poll_cci-method.patch
new file mode 100644 (file)
index 0000000..aa4d871
--- /dev/null
@@ -0,0 +1,209 @@
+From 976e7e9bdc7719a023a4ecccd2e3daec9ab20a40 Mon Sep 17 00:00:00 2001
+From: "Christian A. Ehrhardt" <lk@c--e.de>
+Date: Mon, 17 Feb 2025 13:54:39 +0300
+Subject: acpi: typec: ucsi: Introduce a ->poll_cci method
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+commit 976e7e9bdc7719a023a4ecccd2e3daec9ab20a40 upstream.
+
+For the ACPI backend of UCSI the UCSI "registers" are just a memory copy
+of the register values in an opregion. The ACPI implementation in the
+BIOS ensures that the opregion contents are synced to the embedded
+controller and it ensures that the registers (in particular CCI) are
+synced back to the opregion on notifications. While there is an ACPI call
+that syncs the actual registers to the opregion there is rarely a need to
+do this and on some ACPI implementations it actually breaks in various
+interesting ways.
+
+The only reason to force a sync from the embedded controller is to poll
+CCI while notifications are disabled. Only the ucsi core knows if this
+is the case and guessing based on the current command is suboptimal, i.e.
+leading to the following spurious assertion splat:
+
+WARNING: CPU: 3 PID: 76 at drivers/usb/typec/ucsi/ucsi.c:1388 ucsi_reset_ppm+0x1b4/0x1c0 [typec_ucsi]
+CPU: 3 UID: 0 PID: 76 Comm: kworker/3:0 Not tainted 6.12.11-200.fc41.x86_64 #1
+Hardware name: LENOVO 21D0/LNVNB161216, BIOS J6CN45WW 03/17/2023
+Workqueue: events_long ucsi_init_work [typec_ucsi]
+RIP: 0010:ucsi_reset_ppm+0x1b4/0x1c0 [typec_ucsi]
+Call Trace:
+ <TASK>
+ ucsi_init_work+0x3c/0xac0 [typec_ucsi]
+ process_one_work+0x179/0x330
+ worker_thread+0x252/0x390
+ kthread+0xd2/0x100
+ ret_from_fork+0x34/0x50
+ ret_from_fork_asm+0x1a/0x30
+ </TASK>
+
+Thus introduce a ->poll_cci() method that works like ->read_cci() with an
+additional forced sync and document that this should be used when polling
+with notifications disabled. For all other backends that presumably don't
+have this issue use the same implementation for both methods.
+
+Fixes: fa48d7e81624 ("usb: typec: ucsi: Do not call ACPI _DSM method for UCSI read operations")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Tested-by: Fedor Pchelkin <boddah8794@gmail.com>
+Signed-off-by: Fedor Pchelkin <boddah8794@gmail.com>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://lore.kernel.org/r/20250217105442.113486-2-boddah8794@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c           |   10 +++++-----
+ drivers/usb/typec/ucsi/ucsi.h           |    2 ++
+ drivers/usb/typec/ucsi/ucsi_acpi.c      |   21 ++++++++++++++-------
+ drivers/usb/typec/ucsi/ucsi_ccg.c       |    1 +
+ drivers/usb/typec/ucsi/ucsi_glink.c     |    1 +
+ drivers/usb/typec/ucsi/ucsi_stm32g0.c   |    1 +
+ drivers/usb/typec/ucsi/ucsi_yoga_c630.c |    1 +
+ 7 files changed, 25 insertions(+), 12 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1346,7 +1346,7 @@ static int ucsi_reset_ppm(struct ucsi *u
+       mutex_lock(&ucsi->ppm_lock);
+-      ret = ucsi->ops->read_cci(ucsi, &cci);
++      ret = ucsi->ops->poll_cci(ucsi, &cci);
+       if (ret < 0)
+               goto out;
+@@ -1364,7 +1364,7 @@ static int ucsi_reset_ppm(struct ucsi *u
+               tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
+               do {
+-                      ret = ucsi->ops->read_cci(ucsi, &cci);
++                      ret = ucsi->ops->poll_cci(ucsi, &cci);
+                       if (ret < 0)
+                               goto out;
+                       if (cci & UCSI_CCI_COMMAND_COMPLETE)
+@@ -1393,7 +1393,7 @@ static int ucsi_reset_ppm(struct ucsi *u
+               /* Give the PPM time to process a reset before reading CCI */
+               msleep(20);
+-              ret = ucsi->ops->read_cci(ucsi, &cci);
++              ret = ucsi->ops->poll_cci(ucsi, &cci);
+               if (ret)
+                       goto out;
+@@ -1929,8 +1929,8 @@ struct ucsi *ucsi_create(struct device *
+       struct ucsi *ucsi;
+       if (!ops ||
+-          !ops->read_version || !ops->read_cci || !ops->read_message_in ||
+-          !ops->sync_control || !ops->async_control)
++          !ops->read_version || !ops->read_cci || !ops->poll_cci ||
++          !ops->read_message_in || !ops->sync_control || !ops->async_control)
+               return ERR_PTR(-EINVAL);
+       ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL);
+--- a/drivers/usb/typec/ucsi/ucsi.h
++++ b/drivers/usb/typec/ucsi/ucsi.h
+@@ -61,6 +61,7 @@ struct dentry;
+  * struct ucsi_operations - UCSI I/O operations
+  * @read_version: Read implemented UCSI version
+  * @read_cci: Read CCI register
++ * @poll_cci: Read CCI register while polling with notifications disabled
+  * @read_message_in: Read message data from UCSI
+  * @sync_control: Blocking control operation
+  * @async_control: Non-blocking control operation
+@@ -75,6 +76,7 @@ struct dentry;
+ struct ucsi_operations {
+       int (*read_version)(struct ucsi *ucsi, u16 *version);
+       int (*read_cci)(struct ucsi *ucsi, u32 *cci);
++      int (*poll_cci)(struct ucsi *ucsi, u32 *cci);
+       int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
+       int (*sync_control)(struct ucsi *ucsi, u64 command);
+       int (*async_control)(struct ucsi *ucsi, u64 command);
+--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
++++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
+@@ -59,19 +59,24 @@ static int ucsi_acpi_read_version(struct
+ static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci)
+ {
+       struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
+-      int ret;
+-
+-      if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
+-              ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
+-              if (ret)
+-                      return ret;
+-      }
+       memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci));
+       return 0;
+ }
++static int ucsi_acpi_poll_cci(struct ucsi *ucsi, u32 *cci)
++{
++      struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
++      int ret;
++
++      ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
++      if (ret)
++              return ret;
++
++      return ucsi_acpi_read_cci(ucsi, cci);
++}
++
+ static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
+ {
+       struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
+@@ -94,6 +99,7 @@ static int ucsi_acpi_async_control(struc
+ static const struct ucsi_operations ucsi_acpi_ops = {
+       .read_version = ucsi_acpi_read_version,
+       .read_cci = ucsi_acpi_read_cci,
++      .poll_cci = ucsi_acpi_poll_cci,
+       .read_message_in = ucsi_acpi_read_message_in,
+       .sync_control = ucsi_sync_control_common,
+       .async_control = ucsi_acpi_async_control
+@@ -142,6 +148,7 @@ static int ucsi_gram_sync_control(struct
+ static const struct ucsi_operations ucsi_gram_ops = {
+       .read_version = ucsi_acpi_read_version,
+       .read_cci = ucsi_acpi_read_cci,
++      .poll_cci = ucsi_acpi_poll_cci,
+       .read_message_in = ucsi_gram_read_message_in,
+       .sync_control = ucsi_gram_sync_control,
+       .async_control = ucsi_acpi_async_control
+--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
++++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
+@@ -664,6 +664,7 @@ err_put:
+ static const struct ucsi_operations ucsi_ccg_ops = {
+       .read_version = ucsi_ccg_read_version,
+       .read_cci = ucsi_ccg_read_cci,
++      .poll_cci = ucsi_ccg_read_cci,
+       .read_message_in = ucsi_ccg_read_message_in,
+       .sync_control = ucsi_ccg_sync_control,
+       .async_control = ucsi_ccg_async_control,
+--- a/drivers/usb/typec/ucsi/ucsi_glink.c
++++ b/drivers/usb/typec/ucsi/ucsi_glink.c
+@@ -206,6 +206,7 @@ static void pmic_glink_ucsi_connector_st
+ static const struct ucsi_operations pmic_glink_ucsi_ops = {
+       .read_version = pmic_glink_ucsi_read_version,
+       .read_cci = pmic_glink_ucsi_read_cci,
++      .poll_cci = pmic_glink_ucsi_read_cci,
+       .read_message_in = pmic_glink_ucsi_read_message_in,
+       .sync_control = ucsi_sync_control_common,
+       .async_control = pmic_glink_ucsi_async_control,
+--- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c
++++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c
+@@ -424,6 +424,7 @@ static irqreturn_t ucsi_stm32g0_irq_hand
+ static const struct ucsi_operations ucsi_stm32g0_ops = {
+       .read_version = ucsi_stm32g0_read_version,
+       .read_cci = ucsi_stm32g0_read_cci,
++      .poll_cci = ucsi_stm32g0_read_cci,
+       .read_message_in = ucsi_stm32g0_read_message_in,
+       .sync_control = ucsi_sync_control_common,
+       .async_control = ucsi_stm32g0_async_control,
+--- a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c
++++ b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c
+@@ -74,6 +74,7 @@ static int yoga_c630_ucsi_async_control(
+ const struct ucsi_operations yoga_c630_ucsi_ops = {
+       .read_version = yoga_c630_ucsi_read_version,
+       .read_cci = yoga_c630_ucsi_read_cci,
++      .poll_cci = yoga_c630_ucsi_read_cci,
+       .read_message_in = yoga_c630_ucsi_read_message_in,
+       .sync_control = ucsi_sync_control_common,
+       .async_control = yoga_c630_ucsi_async_control,
index 83dc9526f737a4c55c4210ad0447ef7894fbd1a4..0538077979b70579fce968e3ce1ea7107b72a61f 100644 (file)
@@ -172,3 +172,4 @@ usb-gadget-set-self-powered-based-on-maxpower-and-bmattributes.patch
 usb-gadget-fix-setting-self-powered-state-on-suspend.patch
 usb-gadget-check-bmattributes-only-if-configuration-is-valid.patch
 kbuild-userprogs-use-correct-lld-when-linking-through-clang.patch
+acpi-typec-ucsi-introduce-a-poll_cci-method.patch