https://bugzilla.kernel.org/show_bug.cgi?id=222046
Bug ID: 222046
Summary: [BUG] ACPI I2C HID touchpad never enumerates/binds:
i2c_acpi_get_info() visited gate + acpi_bind_one()
primary-node ordering
Product: ACPI
Version: 2.5
Hardware: AMD
OS: Linux
Status: NEW
Severity: normal
Priority: P3
Component: Other
Assignee: [email protected]
Reporter: [email protected]
Regression: No
On this machine an ACPI I2C HID touchpad (PNP0C50) is never
instantiated, and - after working around that - never matches its
driver, due to two compounding issues. We fixed it with a small
out-of-tree module; this report documents what we found and asks whether
our understanding of the intended behaviour is correct.
Environment
===========
- Lenovo 14w Gen2, AMD SoC (AMD I2C controller, i2c-designware builtin)
- Kernel 7.2.6-arch2-1 (Arch), i2c-designware platform driver builtin
- Controller: \_SB.I2CD -> platform device AMDI0010:01 -> i2c-1
- Touchpad: \_SB.I2CD.TPD0, acpi device ELAN0643:00
- No errors anywhere in dmesg; the failure is completely silent.
Firmware is healthy: the pad ACKs at 0x15 (i2cdetect), and _HID/_CID/
_STA/_CRS/_DSM all evaluate correctly at runtime (verified via
acpi_call). Relevant DSDT excerpt:
Device (TPD0)
{
Name (_HID, "ELAN0643")
Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */)
Method (_STA, 0, NotSerialized)
{
If ((CDAT == 0x00)) { Return (0x00) } Else { Return (0x0F) }
}
Method (_CRS, 0, NotSerialized) // returns, when EC TPTY == 1:
// I2cSerialBusV2 (slave 0x15, ResourceSource "\_SB.I2CD")
// + GpioInt (touchpad IRQ)
// (0x2C when TPTY == 2; empty otherwise)
Method (_DSM, 4, Serialized) // HID-over-I2C descriptor
}
Issue 1: i2c_acpi_get_info() bails on already-"enumerated" devices
===================================================================
i2c-1 exists but has no client at 0x15. Function tracer on unbind/bind
of AMDI0010:01 (tracing i2c_acpi_*, i2c_register_adapter,
i2c_new_client_device, acpi_dev_get_resources):
i2c_register_adapter
i2c_acpi_install_space_handler
i2c_acpi_register_devices
i2c_acpi_add_device x ~100 (acpi_ns_walk_namespace)
i2c_acpi_get_info x ~100
i2c_acpi_do_lookup x ~30
acpi_dev_get_resources x 2
i2c_acpi_fill_info x 0
i2c_new_client_device x 0
drivers/i2c/i2c-core-acpi.c (v7.2):
235 static int i2c_acpi_get_info(struct acpi_device *adev, ...)
...
247 if (acpi_device_enumerated(adev))
248 return -EINVAL; /* silent */
acpi_device_enumerated() == flags.initialized && flags.visited
(include/acpi/acpi_bus.h). Both get set during the boot-time ACPI scan:
acpi_scan_init() (subsys_initcall)
-> acpi_bus_scan()
-> acpi_bus_attach(first_pass=true)
-> ... -> acpi_default_enumeration()
-> acpi_device_set_enumerated() /* visited = true */
Our dw controller driver registers afterwards (builtin, device_initcall),
so by the time i2c_register_adapter() calls i2c_acpi_register_devices(),
every ACPI device is already "enumerated" and every get_info() returns
-EINVAL before _CRS is ever looked at (~70 of ~100 calls in the trace
die exactly there).
That is the only enumeration path: i2c_acpi_register_devices() is called
from i2c_register_adapter() only, and the ACPI reconfig ADD path goes
through the same gate. Re-binding the controller repeats the identical
walk (same counts, still zero clients) - there is no recovery path once
flags.visited is set.
Evidence that TPD0 specifically hit this gate: the boot scan created the
placeholder platform device "ELAN0643:00" (acpi_default_enumeration ->
acpi_create_platform_device), which can only happen if
acpi_bus_attach() passed its ready check and called
acpi_device_set_enumerated() on TPD0.
Issue 2: acpi_companion_match() rejects the client because a
placeholder platform device is the "primary" physical node
=============================================================
We worked around issue 1 by instantiating the client from a module via
the exported i2c_acpi_new_device_by_fwnode(). The client appears at
0x15 with a valid ACPI companion, but i2c_hid_acpi never binds and
prints nothing. Three observations on the same device:
dev name: i2c-ELAN0643:00 (i2c_dev_set_name() uses raw
ACPI_COMPANION -> non-NULL)
uevent: MODALIAS=i2c:ELAN0643 (acpi_device_uevent_modalias()
-> -ENODEV, i.e. no ACPI ids)
binding: none
i2c_device_match() -> acpi_driver_match_device() ->
__acpi_match_device(acpi_companion_match(dev), ...), and
drivers/acpi/bus.c:
877 const struct acpi_device *acpi_companion_match(const struct device
*dev)
878 {
881 adev = ACPI_COMPANION(dev); /* non-NULL for us */
885 if (list_empty(&adev->pnp.ids)) ... /* not empty
("acpi:ELAN0643:PNP0C50:") */
888 return acpi_primary_dev_companion(adev, dev); /* -> NULL */
889 }
acpi_primary_dev_companion() returns adev only if dev ==
acpi_get_first_physical_node(adev). The first physical node is the
placeholder platform device ELAN0643:00 that acpi_default_enumeration()
created during boot: acpi_bind_one() keeps physical_node_list sorted by
node_id (glue.c:257-285), so the boot-time placeholder holds id 0
permanently and a real device registered later (id 1) can never become
primary - hence no PNP ID match, no ACPI modalias, no driver.
After calling acpi_unbind_one(placeholder) before registering our
client, the client becomes node 0, matches PNP0C50 normally, and
i2c_hid_acpi probes successfully (descriptor address from TPD0's _DSM,
IRQ from _CRS GpioInt via i2c_device_probe() -> i2c_acpi_get_irq()).
Touchpad works.
Questions
=========
1. Is the visited-gate in i2c_acpi_get_info() intended to prevent
double enumeration? If yes, what is the intended path for devices
whose adapter registers after the ACPI scan? Would it be acceptable
to check for an existing i2c client with the same companion instead
of relying on scan bookkeeping?
2. On the matching side: should acpi_default_enumeration() refrain from
claiming primary-node status (or create no placeholder at all) for
devices whose _CRS contains an I2cSerialBus? Or should the
placeholder be released when a real physical device for the same
companion registers? Our module does exactly that release dance and
everything works.
3. More generally: how do machines where this works avoid issue 1? We
could not find any kernel path that creates these clients after the
scan. Is "builtin controller registers after subsys_initcall" simply
an under-tested configuration?
Reproduction / workaround
=========================
- Manual new_device does not help: new_device_store() never sets
info.fwnode, so the client gets no ACPI companion and i2c_hid_acpi
(acpi id only) refuses to bind.
- Workaround in use: ~140 line out-of-tree module that (a) releases the
placeholder via acpi_unbind_one(), (b) creates the client via
i2c_acpi_new_device_by_fwnode(), loaded via modules-load.d. Verified
across reboots.
Happy to test patches or gather additional traces on this hardware.
Thanks!
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are watching the assignee of the bug.
_______________________________________________
acpi-bugzilla mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/acpi-bugzilla