soc_button_array: ignored -EPROBE_DEFER loses the buttons on 68% of boots (Surface Pro 11)

From: Sergey Lebedev

Date: Sun Aug 30 2026 - 10:14:22 EST


Hello,

On a Microsoft Surface Pro 11 for Business (Intel, Lunar Lake) the power and
volume buttons fail to appear on most boots. The probe runs, gives up
silently, and the device is lost until something rebinds it by hand.

Measured across the 40 boots in this machine's journal, using the monotonic
offset of the first "input: gpio-keys" message:

driver attached on its own 13 boots at 1.28 - 1.78 s
did not attach 27 boots 68 %

The timing is binary. Either the inputs appear at about 1.3 s, or they never
appear at all - no intermediate values in 40 boots.

Where it fails
--------------

Nothing at all is logged on a failing boot, so I built with
soc_button_array.dyndbg=+p on the kernel command line. On four consecutive
failing boots the probe printed exactly one line:

[ 1.286567] soc_button_array MSHW0040:00: OEM Platform Revision 129

That eliminates most of the possibilities:

- the probe does run
- it passes soc_device_check_MSHW0040() - oem_platform_rev is 129, not 0
- it passes gpiod_count() - the dev_dbg("no GPIO attached, ignoring...")
would have printed with dyndbg on, and did not

By elimination the buttons are lost inside soc_button_device_create(), at

error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index,
&gpio, &irq);
if (error || irq < 0) {
/*
* Skip GPIO if not present. Note we deliberately
* ignore -EPROBE_DEFER errors here. ...
*/
continue;
}

Every button is skipped, n_buttons stays 0, and the two returns that follow
are both silent:

if (n_buttons == 0) { error = -ENODEV; goto err_free_mem; }
and
if (!priv->children[0] && !priv->children[1]) return -ENODEV;

which is why nothing reaches the log.

The GPIO controller here is INTC105D, five gpiochips driven by
pinctrl-intel-platform. Both that and soc_button_array are modules in this
config:

CONFIG_INPUT_SOC_BUTTON_ARRAY=m
CONFIG_PINCTRL_INTEL_PLATFORM=m

A manual bind always works: 25 unbind/bind cycles at runtime gave 25
successes and 0 failures. The failure exists only in the early-boot window.

One hypothesis, tested and wrong
---------------------------------

Since both are modules, load order looked like the cause, so I tried

softdep soc_button_array pre: pinctrl-intel-platform

verified applied (modprobe --show-depends inserts pinctrl first), with the
rescue that normally binds it by hand disabled so nothing masked the result.
Five boots: 2 successes, 3 failures - the same rate as before.

pinctrl_intel_platform is a dependency of fifteen other modules and is
loaded long before either way. softdep orders modules; the race is against
the asynchronous probe of the individual INTC105D:0N devices, which register
their gpiochips at their own pace. Reporting this so nobody else spends the
evening on it.

Why no patch
------------

The comment says -EPROBE_DEFER is discarded because Intel uses "virtual
GPIOs" that never materialise, so deferring on them would hang the probe
forever. A fix has to tell that case apart from a controller that simply has
not probed yet, and I do not know which signal you would want to use for
that. Guessing would risk reintroducing the problem the workaround exists
for.

Happy to test whatever shape you would prefer - the machine is here and I
can build and boot kernels on it.

Related but probably not the same bug
--------------------------------------

https://github.com/linux-surface/linux-surface/issues/885

Open since 2022 on a Surface Pro 7+ and a Pro 6: same shape - driver loaded,
gpio-keys absent, rebind fixes it - but there the buttons are lost during a
session rather than never appearing at boot. Cross-referencing rather than
merging the two, since the triggers differ.

Machine: Surface Pro 11 for Business (Intel Core Ultra 7 268V)
DMI SKU: Surface_Pro_11th_Edition_With_Intel_For_Business_2103
Firmware: UEFI 17.100.143 (2025-11-19)
Kernel: 7.0.0-30-generic, Ubuntu 26.04.1

Thanks,
Sergey Lebedev