diff options
| author | James Fairweather <james.a.fairweather@gmail.com> | 2026-10-03 18:28:53 -0400 |
|---|---|---|
| committer | Tzung-Bi Shih <tzungbi@kernel.org> | 2026-10-06 10:21:08 +0000 |
| commit | ca75b38b1a3c2eabe81d231dae4ea180cf6287cd (patch) | |
| tree | c2845c33766768cd9ee336789f09d4ddacefd206 | |
| parent | 317e7abcaf60b79765dcf35c014edac8b9d37a6e (diff) | |
platform/chrome: cros_usbpd_notify: Only use drvdata when parent is GOOG0004
cros_usbpd_notify_probe_acpi() takes the EC device pointer from
dev_get_drvdata(dev->parent) and assumes it is a struct cros_ec_device.
That only holds when GOOG0003 is a child of GOOG0004. On older devices
without that hierarchy, such as Google Nami, GOOG0003 and GOOG0004 are
siblings under the ACPI EC (PNP0C09):
PNP0C09:00 (acpi-ec)
|-- GOOG0003:00 (cros-usbpd-notify-acpi)
`-- GOOG0004:00 (cros_ec_lpcs)
Before commit db65a06d10b3 ("ACPI: EC: Convert the driver to a platform
one") the parent platform device had no driver data, so the driver
warned and continued without an EC pointer, as intended for these
devices. Since that commit the ACPI EC driver stores its struct acpi_ec
there, so the driver treats a struct acpi_ec as a struct cros_ec_device
and calls cros_ec_cmd() on it for every USB-C PD host event. Plugging
or unplugging a charger then intermittently oopses, followed by soft
lockups and a hung system:
BUG: unable to handle page fault for address: ffffffff9cf03220
#PF: supervisor write access in kernel mode
Hardware name: Google Nami/Nami, BIOS 09/19/2019
Workqueue: kacpi_notify acpi_os_execute_deferred
RIP: 0010:native_queued_spin_lock_slowpath+0x29d/0x330
Call Trace:
_raw_spin_lock_irqsave+0x59/0x80
__mutex_lock.constprop.0+0x129/0x930
cros_ec_cmd_xfer+0x2a/0xf0 [cros_ec_proto]
cros_ec_cmd_xfer_status+0x1a/0x90 [cros_ec_proto]
cros_ec_cmd+0xb7/0x140 [cros_ec_proto]
cros_usbpd_get_event_and_notify+0x42/0xc0 [cros_usbpd_notify]
acpi_ev_notify_dispatch+0x4e/0x70
acpi_os_execute_deferred+0x1a/0x30
Only read the parent's driver data when the parent's ACPI node is
GOOG0004, and otherwise continue without an EC pointer. While at it,
drop the reference taken by fwnode_get_parent().
Fixes: db65a06d10b3 ("ACPI: EC: Convert the driver to a platform one")
Fixes: e4ee0bb077cd ("platform/chrome: cros_usbpd_notify: defer probe when parent EC driver isn't ready")
Cc: stable@vger.kernel.org
Assisted-by: claude-opus-5-5 checkpatch
Signed-off-by: James Fairweather <james.a.fairweather@gmail.com>
Reported-by: Sergey Tiraspolsky <stiraspo@gmail.com>
Closes: https://lore.kernel.org/all/20261003204623.18124-1-stiraspo@gmail.com
Tested-by: Sergey Tiraspolsky <stiraspo@gmail.com>
Link: https://lore.kernel.org/r/20261003222855.23707-1-james.a.fairweather@gmail.com
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
| -rw-r--r-- | drivers/platform/chrome/cros_usbpd_notify.c | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 6f5eea4938cb..25da31ec1996 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -110,26 +110,29 @@ static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev) if (!pdnotify) return -ENOMEM; - /* Get the EC device pointer needed to talk to the EC. */ - ec_dev = dev_get_drvdata(dev->parent); - if (!ec_dev) { - /* - * We continue even for older devices which don't have the - * correct device hierarchy, namely, GOOG0003 is a child - * of GOOG0004. If GOOG0003 is a child of GOOG0004 and we - * can't get a pointer to the Chrome EC device, defer the - * probe function. - */ - parent_fwnode = fwnode_get_parent(dev->fwnode); - if (parent_fwnode) { - parent_adev = to_acpi_device_node(parent_fwnode); - if (parent_adev && - acpi_dev_hid_match(parent_adev, CREC_DRV_NAME)) { - return -EPROBE_DEFER; - } + /* + * Get the EC device pointer needed to talk to the EC. The parent's + * driver data is only a struct cros_ec_device when GOOG0003 is a + * child of GOOG0004. On older devices without that hierarchy the + * parent may be bound to an unrelated driver (e.g. the ACPI EC + * driver for PNP0C09), so don't touch its driver data and continue + * without an EC pointer. If GOOG0003 is a child of GOOG0004 and we + * can't get a pointer to the Chrome EC device yet, defer the probe. + */ + ec_dev = NULL; + parent_fwnode = fwnode_get_parent(dev->fwnode); + parent_adev = to_acpi_device_node(parent_fwnode); + if (parent_adev && acpi_dev_hid_match(parent_adev, CREC_DRV_NAME)) { + ec_dev = dev_get_drvdata(dev->parent); + if (!ec_dev) { + fwnode_handle_put(parent_fwnode); + return -EPROBE_DEFER; } - dev_warn(dev, "Couldn't get Chrome EC device pointer.\n"); } + fwnode_handle_put(parent_fwnode); + + if (!ec_dev) + dev_warn(dev, "Couldn't get Chrome EC device pointer.\n"); pdnotify->dev = dev; pdnotify->ec = ec_dev; |
