The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] usb: typec: ucsi: acpi: Disable on devices with broken firmware
@ 2026-05-11 17:59 Rong Zhang
  2026-05-11 18:25 ` Greg Kroah-Hartman
  0 siblings, 1 reply; 7+ messages in thread
From: Rong Zhang @ 2026-05-11 17:59 UTC (permalink / raw)
  To: Heikki Krogerus, Greg Kroah-Hartman
  Cc: Hans de Goede, linux-usb, platform-driver-x86, linux-kernel,
	Rong Zhang

Some Lenovo devices have broken firmware, which reads/writes half-valid-
half-garbage values.

While executing UCSI_DSM_FUNC_READ, the firmware repeatedly (> 20 times)
calls a helper function, which reads and returns a byte from the EC, and
then copies the return value from the helper function into the UCSI
buffer. The helper function internally acquires a heavily shared mutex
with a timeout. When the timeout is somehow reached, 0x00 will be
returned. Unfortunately, the return value is copied into the buffer
blindly, leaving a half-valid-half-garbage value in the buffer while the
method still succeeds.

Similar for UCSI_DSM_FUNC_WRITE, in which some bytes in the UCSI buffer
may be silently left unwritten to the EC but the method still succeeds.

What's worse, race condition could happen since the mutex only protects
a single byte read/write instead of the whole method.

All these issues lead to a lot of UCSI errors upon power events, e.g.,

  ucsi_acpi USBC000:00: ucsi_handle_connector_change: GET_CONNECTOR_STATUS failed (-5)
  ucsi_acpi USBC000:00: ucsi_handle_connector_change: GET_CONNECTOR_STATUS failed (-5)
  ucsi_acpi USBC000:00: GET_CONNECTOR_STATUS failed (-5)

  ucsi_acpi USBC000:00: ucsi_handle_connector_change: GET_CONNECTOR_STATUS failed (-110)
  ucsi_acpi USBC000:00: ucsi_handle_connector_change entered without EVENT_PENDING
  ucsi_acpi USBC000:00: ucsi_handle_connector_change: GET_CONNECTOR_STATUS failed (-110)

Given that everything is broken, disable ucsi_acpi on these devices. The
impact of disabling it is minimal, as Lenovo laptops usually have most
USCI commands more or less stubbed, and the EC can always handles USB-C
events on its own.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=221065#c33
Signed-off-by: Rong Zhang <i@rong.moe>
---
 drivers/usb/typec/ucsi/ucsi_acpi.c | 91 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index 6b92f296e985..7632b441d401 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -155,6 +155,91 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = {
 	{ }
 };
 
+static const struct dmi_system_id ucsi_acpi_broken_devices[] = {
+	/* Firmware reads/writes half-valid-half-garbage values. */
+
+	/* BIOS: P1CN??WW */
+	{
+		.ident = "Lenovo IdeaPad 5 2-in-1 14AHP9",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83DR"),
+		},
+	},
+	{
+		.ident = "Lenovo IdeaPad 5 2-in-1 16AHP9",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83DS"),
+		},
+	},
+
+	/* BIOS: R0CN??WW */
+	{
+		.ident = "Lenovo IdeaPad Slim 5 14AKP10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83NJ"),
+		},
+	},
+	{
+		.ident = "Lenovo IdeaPad Slim 5 14AKP10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83HX"),
+		},
+	},
+	{
+		.ident = "Lenovo IdeaPad Slim 5 16AKP10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83HY"),
+		},
+	},
+
+	/* BIOS: QXCN??WW */
+	{
+		.ident = "Lenovo Yoga 7 2-in-1 14AKP10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83JR"),
+		},
+	},
+	{
+		.ident = "Lenovo Yoga 7 2-in-1 16AKP10",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83JU"),
+		},
+	},
+
+	/* BIOS: LNCN??WW */
+	{
+		.ident = "Lenovo Yoga Pro 7 14ARP8",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83AU"),
+		},
+	},
+	{
+		.ident = "Lenovo Slim Pro 7 14ARP8",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83AX"),
+		},
+	},
+
+	/* BIOS: PSCN??WW */
+	{
+		.ident = "Lenovo Yoga Pro 7 14ASP9",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "83HN"),
+		},
+	},
+	{ }
+};
+
 static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
 	struct ucsi_acpi *ua = data;
@@ -181,6 +266,12 @@ static int ucsi_acpi_probe(struct platform_device *pdev)
 	if (adev->dep_unmet)
 		return -EPROBE_DEFER;
 
+	id = dmi_first_match(ucsi_acpi_broken_devices);
+	if (id) {
+		dev_warn(&pdev->dev, "broken UCSI ACPI implementation, disabling");
+		return -ENODEV;
+	}
+
 	ua = devm_kzalloc(&pdev->dev, sizeof(*ua), GFP_KERNEL);
 	if (!ua)
 		return -ENOMEM;

---
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
change-id: 20260512-ucsi-acpi-broken-devices-c93a15b70600

Thanks,
Rong


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-05-12 19:17 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 17:59 [PATCH] usb: typec: ucsi: acpi: Disable on devices with broken firmware Rong Zhang
2026-05-11 18:25 ` Greg Kroah-Hartman
2026-05-11 19:12   ` Rong Zhang
2026-05-11 23:11     ` Mark Pearson
2026-05-12 12:46       ` Rong Zhang
2026-05-12 18:28         ` Mark Pearson
2026-05-12 19:16           ` Rong Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox