Skip to content

Input: soc_button_array: defer MSHW0040 probe until GPIO is ready - #172

Open
zR-JB wants to merge 1 commit into
linux-surface:v6.19-surface-develfrom
zR-JB:mshw0040-buttons-defer
Open

Input: soc_button_array: defer MSHW0040 probe until GPIO is ready#172
zR-JB wants to merge 1 commit into
linux-surface:v6.19-surface-develfrom
zR-JB:mshw0040-buttons-defer

Conversation

@zR-JB

@zR-JB zR-JB commented Aug 12, 2026

Copy link
Copy Markdown

Summary

Fix a probe-order race in the MSHW0040 path of soc_button_array.

Surface Pro 12 for Business Intel is a reliable reproducer: during affected clean boots, soc_button_array probes before the Panther Lake GPIO provider is ready and the GPIO lookups for all three physical buttons return -EPROBE_DEFER.

The existing button definitions themselves are already correct:

  • GPIO index 0 -> KEY_POWER
  • GPIO index 2 -> KEY_VOLUMEUP
  • GPIO index 4 -> KEY_VOLUMEDOWN

Reloading the unchanged soc_button_array module later, after the GPIO provider has initialized, makes the driver bind immediately and all three buttons work.

This appears to be a probe-order/dependency issue, not a new Surface Pro 12 button mapping.

Existing linux-surface MSHW0040 patch

v6.19-surface-devel already carries the linux-surface surface-button patch which changes soc_device_check_MSHW0040() to use acpi_check_dsm().

That change solves: AMD Surface variants also use MSHW0040, but can report an OEM platform revision of zero. Checking for the existence of the OEM Platform Revision DSM function allows soc_button_array and surfacepro3_button to select the correct devices.

This PR preserves that logic.

The current check is effectively:

exists = acpi_check_dsm(...);
return exists ? 0 : -ENODEV;

It does not check whether the GPIO provider needed by soc_button_array is ready.

This PR changes the MSHW0040-specific check so that, after passing the existing DSM check, it also attempts to resolve GPIO index 0, which is the known physical power-button GPIO.

Only -EPROBE_DEFER is propagated.

Why do this in the MSHW0040-specific check?

The generic soc_button_array child-creation path deliberately ignores -EPROBE_DEFER.

That behavior is intentional. Some Intel systems expose virtual GPIO resources which are not backed by a real GPIO provider. Such resources may return -EPROBE_DEFER indefinitely.

Generic propagation of GPIO lookup errors was previously tried as part of the original newer-Surface support and had to be partially reverted because it could cause repeated deferred probes, repeated child-device creation/removal, a CPU core at 100%, and udev hangs.

Relevant upstream revert:

torvalds/linux@bcf0595

For MSHW0040, however, GPIO index 0 is the physical power-button GPIO.

Checking that GPIO in soc_device_check_MSHW0040() has two useful properties:

  1. it is restricted to devices which already pass the MSHW0040-specific DSM check; and
  2. it happens before any gpio-keys child devices are created.

The generic virtual-GPIO behavior should be left untouched.

The proposed logic is intentionally narrow:

error = soc_button_lookup_gpio(dev, 0, &gpio, &irq);
if (error == -EPROBE_DEFER)
        return error;

Other lookup errors continue to follow the existing behavior.

Surface Pro 12 reproducer

On the Surface Pro for Business 13in 12th Ed Intel, an instrumentation-only kernel showed all three lookups returning:

-517 = -EPROBE_DEFER

on affected clean boots:

button volume_up:   GPIO index 2 lookup failed: error=-517
button volume_down: GPIO index 4 lookup failed: error=-517
button power:       GPIO index 0 lookup failed: error=-517

The relevant configuration was:

CONFIG_INPUT_SOC_BUTTON_ARRAY=m
CONFIG_PINCTRL_INTEL_PLATFORM=m

Reloading the unchanged driver after boot:

modprobe -r soc_button_array
modprobe soc_button_array

made it bind immediately and all three buttons worked.

Adding the MSHW0040-specific readiness check fixed the issue across repeated clean reboots without a manual reload.

Full investigation and test results are documented here:

linux-surface/linux-surface#2144 (comment)

Why this can still matter with linux-surface

linux-surface has historically reduced similar probe-order problems by building a number of Intel pinctrl drivers into the kernel.

However, Panther Lake uses the newer CONFIG_PINCTRL_INTEL_PLATFORM driver. In the current linux-surface Arch configuration that driver remains a module.

A particular initramfs may load the provider early enough to mask the race, so this PR is not claiming that every linux-surface boot on every configuration will visibly fail. The underlying MSHW0040 driver path, however, currently has no way to defer when its real GPIO provider is not ready.

Prior work / history

This change is based on both the SP12 diagnostics and prior work around MSHW0040 / soc_button_array. I do not want to imply that the idea of deferring for the Surface GPIO provider is new to the SP12 work.

Relevant history:

Original MSHW0040 Surface support

The original 2019 MSHW0040 support was developed by Maximilian Luz:

https://lore.kernel.org/all/20190516142523.117978-3-luzmaximilian@gmail.com/

The original discussion already considered an MSHW0040-specific GPIO readiness check, with the rationale that these devices are expected to have real GPIOs and probing should be retried if their provider has not loaded yet.

Review:

https://lore.kernel.org/all/CAHp75VfoVO+QqTnGadfc4eNxTYL2pNkH446aPmOwOVEpqQ1RTg@mail.gmail.com/

2019 generic EPROBE_DEFER regression

Generic propagation of GPIO lookup failures later caused regressions on systems with virtual GPIO resources and was reverted:

https://lore.kernel.org/all/65b265d2-f7a8-bcd7-e63f-f8efb7349324@gmail.com/

Follow-up:

https://lore.kernel.org/all/ef31abf6-b3f2-f3aa-1536-3ecd5fc819e1@redhat.com/

Upstream revert:

torvalds/linux@bcf0595

This PR deliberately does not restore that generic behavior.

Previous linux-surface reproducer

linux-surface/linux-surface#61 documents essentially the same symptom on a Surface Pro 5: three GPIO lookups returning -517 during boot and reloading soc_button_array later making the buttons work.

Related linux-surface deferred-probe discussion

There has also been later discussion in linux-surface about correctly using EPROBE_DEFER when Surface drivers race their dependencies. During #152, missing pinctrl dependencies and reports of soc-button-array failing on Arch were specifically mentioned.

Testing

Runtime behavior of this MSHW0040-specific GPIO readiness check has already been tested on:

Surface Pro for Business 13in 12th Ed Intel
MSHW0743 / Panther Lake

The original SP12 test showed reliable power, volume-up and volume-down binding across repeated clean reboots, without manual module reloads.

The version in this PR has been adapted to preserve linux-surface's existing acpi_check_dsm() MSHW0040 device-selection logic and has been compile-tested against v6.19-surface-devel with the linux-surface Arch configuration.

Because MSHW0040 is shared by multiple Surface generations, additional testing would be particularly useful on older MSHW0040 devices and AMD Surface variants.

Surface Pro 12 enablement

This is one part of my broader Surface Pro 12 Intel enablement work:

linux-surface/linux-surface#2144

Related Surface Pro 12 work

MSHW0040 Surface devices use GPIO index 0 for the physical power
button. On the Surface Pro 12 for Business Intel, soc_button_array
can probe before the Panther Lake GPIO provider is ready. On affected
boots, the GPIO lookups for the power and volume buttons return
-EPROBE_DEFER.

Reloading the unchanged soc_button_array driver after the GPIO provider
has initialized makes the driver bind and all three buttons work.

The generic button creation path deliberately ignores -EPROBE_DEFER
because some Intel platforms expose virtual GPIO resources which never
acquire a GPIO provider. Propagating that error from the generic path
has previously caused severe deferred-probe loops on such systems.

Instead, check the known real MSHW0040 power-button GPIO before
creating any child devices and propagate only -EPROBE_DEFER. Keep all
other lookup errors and the generic virtual-GPIO handling unchanged.

This follows the direction already considered during the original
MSHW0040 Surface button support discussion, while avoiding the generic
error propagation that was later reverted.

The Surface Pro 12 Intel provides a reliable reproducer with both
CONFIG_INPUT_SOC_BUTTON_ARRAY and CONFIG_PINCTRL_INTEL_PLATFORM built
as modules.

Link: linux-surface/linux-surface#2144 (comment)
Link: linux-surface/linux-surface#61
Link: https://lore.kernel.org/all/20190516142523.117978-3-luzmaximilian@gmail.com/
Link: https://lore.kernel.org/all/65b265d2-f7a8-bcd7-e63f-f8efb7349324@gmail.com/
Signed-off-by: Jan Baisch <jan.baisch@protonmail.com>
Link: linux-surface#172
Patchset: surface-button
@zR-JB
zR-JB force-pushed the mshw0040-buttons-defer branch from 7febef5 to 7afe011 Compare August 12, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant