From: sashiko-bot@kernel.org
To: "Atharva Tiwari" <atharvatiwarilinuxdev@gmail.com>
Cc: "open list:PCI SUBSYSTEM" <linux-pci@vger.kernel.org>,
"open list:RADEON and AMDGPU DRM DRIVERS"
<amd-gfx@lists.freedesktop.org>,
"open list:DRM DRIVERS" <dri-devel@lists.freedesktop.org>
Subject: Re: [PATCH v2 04/12] platform/apple-gmux: Fix Interrupts for MMIO systems
Date: Sat, 14 Nov 2026 16:27:41 +0000 [thread overview]
Message-ID: <sashiko-outbox-214749@kernel.org> (raw)
In-Reply-To: <20261114160731.3756-5-atharvatiwarilinuxdev@gmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential
issues to consider:
- [Medium] platform/apple-gmux: uninitialized interrupt_work in
gmux_probe() and remove
- [Medium] platform/apple-gmux: gmux_notify_work() races with suspend
and teardown
- [Medium] platform/apple-gmux: lost interrupt bits and unbounded loop
in gmux_notify_work()
- [Medium] platform/apple-gmux: early GPE enable in gmux_probe() and
unhandled status=0 GPEs
--
commit 77837b33a80099f01ff89538d43f85130095f9ea
Author: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
platform/apple-gmux: Fix Interrupts for MMIO systems
This commit moves MMIO gmux interrupt handling to a workqueue, checks for
failed interrupt status bits, and requests a runtime resume of the discrete
GPU on display hotplug interrupts.
> diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
> index 9625551e54bfa..37ba207793a2e 100644
> --- a/drivers/platform/x86/apple-gmux.c
> +++ b/drivers/platform/x86/apple-gmux.c
[ ... ]
> @@ -806,23 +819,78 @@ static void gmux_clear_interrupts(struct apple_gmux_data *gmux_data)
> /* to clear interrupts write back current status */
> status = gmux_interrupt_get_status(gmux_data);
> gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_STATUS, status);
> - /* Prevent flood of status=0 interrupts */
> - if (gmux_data->config == &apple_gmux_mmio)
> - acpi_execute_simple_method(gmux_data->dhandle, "GMSP", 0);
> }
>
> +static void gmux_notify_work(struct work_struct *work)
> +{
> + struct apple_gmux_data *gmux_data =
> + container_of(work, struct apple_gmux_data, interrupt_work);
> + u8 status;
> + bool turn_on_gpu = false;
> +
> + status = gmux_interrupt_get_status(gmux_data);
> + if (!status)
> + return;
> +
> + gmux_disable_interrupts(gmux_data);
> + pr_debug("Notify handler called: status %d\n", status);
> + acpi_execute_simple_method(gmux_data->dhandle, "GMSP", 0);
[Severity: Medium]
Does returning early when status is 0 leave status=0 GPE floods uncleared on
MMIO systems?
Previously, gmux_clear_interrupts() called GMSP(0) unconditionally, even when
status was 0. Now, if a GPE fires while GMUX_PORT_INTERRUPT_STATUS reads 0
(for example, during system resume before gmux_resume() runs, or in
gmux_probe() between acpi_enable_gpe() and gmux_enable_interrupts(gmux_data,
1)), gmux_notify_work() returns before calling GMSP(0) to reset the GPIO
polarity.
In addition, gmux_probe() enables the notify handler and GPE before
initializing gmux_data->external_switchable and gmux_data->powerchange_done:
drivers/platform/x86/apple-gmux.c:gmux_probe() {
...
status = acpi_enable_gpe(NULL, gmux_data->gpe);
...
gmux_data->external_switchable =
!bus_for_each_dev(&pci_bus_type, NULL, NULL, is_thunderbolt);
if (!gmux_data->external_switchable)
gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
apple_gmux_data = gmux_data;
init_completion(&gmux_data->powerchange_done);
gmux_enable_interrupts(gmux_data, 1);
}
If a GPE fires in that window, gmux_notify_handler() or gmux_notify_work() can
call complete(&gmux_data->powerchange_done) before init_completion() runs,
causing a NULL pointer dereference in swake_up_locked(), or read
gmux_data->external_switchable before it is set.
> +
> + status = gmux_interrupt_get_status(gmux_data);
> + while (status) {
> + gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_STATUS, status);
> + if (status & GMUX_INTERRUPT_STATUS_FAILED) {
> + pr_warn_ratelimited("interrupt failed: status: 0x%x\n", status);
> + status = gmux_interrupt_get_status(gmux_data);
> + continue;
> + }
[Severity: Medium]
Can this drop GMUX_INTERRUPT_STATUS_POWER or GMUX_INTERRUPT_STATUS_HOTPLUG
events when GMUX_INTERRUPT_STATUS_FAILED is set at the same time?
Writing status to GMUX_PORT_INTERRUPT_STATUS clears all set bits in hardware,
so jumping to the next iteration with continue skips the POWER and HOTPLUG
checks for bits that were just cleared, causing gmux_set_discrete_state() to
time out waiting on powerchange_done or missing a hotplug wakeup.
Also, while (status) has no retry limit; if a status bit fails to clear in
hardware, gmux_notify_work() spins forever on system_percpu_wq and hangs
cancel_work_sync() on teardown.
> + if (status & GMUX_INTERRUPT_STATUS_POWER)
> + complete(&gmux_data->powerchange_done);
> +
> + if (status & GMUX_INTERRUPT_STATUS_HOTPLUG) {
> + /*
> + * We get an interrupt every time a display connects or disconnects, but
> + * the GET_DISPLAY port only tells us if a display is connected or not,
> + * so we resume every time a display is connected or disconnected.
> + */
> + u8 external_state = gmux_read8(gmux_data,
> + GMUX_PORT_SWITCH_GET_DISPLAY);
> + if (external_state != gmux_data->external_state) {
> + gmux_data->external_state = external_state;
> + if (external_state)
> + pr_debug("A display has been connected\n");
> + else
> + pr_debug("All displays has been disconnected\n");
> + }
> + turn_on_gpu = true;
> + }
> + status = gmux_interrupt_get_status(gmux_data);
> + }
> +
> + gmux_enable_interrupts(gmux_data, 0);
> +
> + if (turn_on_gpu && !gmux_data->external_switchable && gmux_data->discrete_pdev &&
> + pm_runtime_enabled(&gmux_data->discrete_pdev->dev))
> + pm_request_resume(&gmux_data->discrete_pdev->dev);
> +
> +}
[Severity: Medium]
Can gmux_notify_work() race with gmux_suspend() and driver teardown to
re-enable interrupts and wake the discrete GPU after interrupts were disabled?
CPU0 CPU1 (kworker)
gmux_notify_handler()
schedule_work(&interrupt_work)
gmux_suspend()
gmux_disable_interrupts()
gmux_notify_work()
...
gmux_enable_interrupts(gmux_data, 0)
pm_request_resume(&discrete_pdev->dev)
gmux_suspend() does not cancel or flush gmux_data->interrupt_work, so a queued
work item can re-enable gmux interrupts and request a runtime resume of
discrete_pdev during system suspend. Similarly, gmux_remove() and the
err_register_handler path in gmux_probe() call gmux_disable_interrupts()
before disabling the GPE, removing the notify handler, and calling
cancel_work_sync(), so an in-flight gmux_notify_work() will re-enable hardware
interrupts before cancel_work_sync() returns.
[ ... ]
> @@ -1072,6 +1140,8 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
> goto err_notify;
> }
>
> + if (type == APPLE_GMUX_TYPE_MMIO)
> + INIT_WORK(&gmux_data->interrupt_work, gmux_notify_work);
> status = acpi_enable_gpe(NULL, gmux_data->gpe);
> if (ACPI_FAILURE(status)) {
> pr_err("Cannot enable gpe: %s\n",
[ ... ]
> @@ -1124,6 +1194,9 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
> acpi_remove_notify_handler(gmux_data->dhandle,
> ACPI_DEVICE_NOTIFY,
> &gmux_notify_handler);
> +
> + if (gmux_data->type == APPLE_GMUX_TYPE_MMIO)
> + cancel_work_sync(&gmux_data->interrupt_work);
[Severity: Medium]
Can cancel_work_sync() and schedule_work() be called on an uninitialized
gmux_data->interrupt_work?
INIT_WORK(&gmux_data->interrupt_work, gmux_notify_work) is only called inside
the if (ACPI_SUCCESS(status)) branch for GMGP, and after
acpi_install_notify_handler() has already registered gmux_notify_handler().
If evaluating GMGP fails on an MMIO system, gmux_probe() sets gmux_data->gpe =
-1 and continues without initializing interrupt_work, but both gmux_remove()
and the err_enable_gpe path in gmux_probe() unconditionally call
cancel_work_sync(&gmux_data->interrupt_work), triggering WARN_ON(!work->func)
in __flush_work(). In addition, if an ACPI notification arrives between
acpi_install_notify_handler() and INIT_WORK(), gmux_notify_handler() schedules
interrupt_work while its func pointer is still NULL.
Initializing interrupt_work before evaluating GMGP in gmux_probe() would
avoid both issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261114160731.3756-1-atharvatiwarilinuxdev@gmail.com?part=4
next prev parent reply other threads:[~2026-11-14 16:27 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-14 16:06 [PATCH v2 00/12] Fixes for apple-gmux and runtime support Atharva Tiwari
2026-11-14 16:06 ` [PATCH v2 01/12] platform/apple-gmux: Fix power for MMIO systems Atharva Tiwari
2026-11-14 16:42 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 02/12] PCI: Disable pcie port on specific amd devices Atharva Tiwari
2026-11-14 16:34 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 03/12] platform/apple-gmux: Fix MMIO interface Atharva Tiwari
2026-11-14 16:17 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 04/12] platform/apple-gmux: Fix Interrupts for MMIO systems Atharva Tiwari
2026-11-14 16:27 ` sashiko-bot [this message]
2026-11-14 16:06 ` [PATCH v2 05/12] platform/apple-gmux: Write switch state to EFI on MMIO devices Atharva Tiwari
2026-11-14 16:25 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 06/12] platform/apple-gmux: Add check to detect FSS Atharva Tiwari
2026-11-14 16:17 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 07/12] platform/apple-gmux: Add documentation about iMacs Atharva Tiwari
2026-11-14 16:40 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 08/12] drm/amdgpu: Add Apple GMUX runtime PM support Atharva Tiwari
2026-11-14 16:44 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 09/12] drm/amdgpu: Catch register access while GMUX keeps the GPU off Atharva Tiwari
2026-11-14 16:33 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 10/12] drm/amd/display: Refuse DP AUX " Atharva Tiwari
2026-11-14 16:34 ` sashiko-bot
2026-11-14 16:06 ` [PATCH v2 11/12] drm/amdgpu: Skip AC/DC notification while the GPU is runtime suspended Atharva Tiwari
2026-11-14 16:06 ` [PATCH v2 12/12] drm/amd/display: Skip panel power savings on eDP links without a panel Atharva Tiwari
2026-11-14 16:37 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-214749@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=amd-gfx@lists.freedesktop.org \
--cc=atharvatiwarilinuxdev@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-pci@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox