From: sashiko-bot@kernel.org
To: "Atharva Tiwari" <atharvatiwarilinuxdev@gmail.com>
Cc: "open list:PCI SUBSYSTEM" <linux-pci@vger.kernel.org>,
"open list:DRM DRIVERS" <dri-devel@lists.freedesktop.org>
Subject: Re: [PATCH 08/13] platform/apple-gmux: Add documentation about iMacs
Date: Sun, 25 Oct 2026 04:37:40 +0000 [thread overview]
Message-ID: <sashiko-outbox-184072@kernel.org> (raw)
In-Reply-To: <20261025040046.1602-9-atharvatiwarilinuxdev@gmail.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] platform/x86: apple-gmux: lock leak and uninit return in gmux_mmio_read8/32()
- [High] platform/x86: apple-gmux: NULL discrete_pdev deref in gmux_set_discrete_state()
- [High] platform/x86: apple-gmux: workqueue teardown bugs in gmux_probe/remove()
- [High] PCI: uninitialized output in pci_read_config_*() when access is ignored
- [High] platform/x86: apple-gmux: PCI state corruption in gmux_set_discrete_state()
--
commit 60c5ee5c904bb8e5a78842b541c5dc5de1769e8f
Author: Atharva Tiwari <atharvatiwarilinuxdev@gmail.com>
platform/apple-gmux: Add documentation about iMacs
This series updates the apple-gmux driver and PCI access layer to support MMIO
gmux power management, interrupts, boot GPU selection, FSS detection, and iMac
documentation.
> diff --git a/drivers/pci/access.c b/drivers/pci/access.c
> index b123da16b63ba..5e95130671767 100644
> --- a/drivers/pci/access.c
> +++ b/drivers/pci/access.c
> @@ -559,6 +559,9 @@ EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
>
> int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
> {
> + if (pci_dev_ignore_access(dev))
> + return PCIBIOS_SUCCESSFUL;
> +
> if (pci_dev_is_disconnected(dev)) {
> PCI_SET_ERROR_RESPONSE(val);
> return PCIBIOS_DEVICE_NOT_FOUND;
> @@ -569,6 +572,9 @@ EXPORT_SYMBOL(pci_read_config_byte);
>
> int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
> {
> + if (pci_dev_ignore_access(dev))
> + return PCIBIOS_SUCCESSFUL;
> +
> if (pci_dev_is_disconnected(dev)) {
> PCI_SET_ERROR_RESPONSE(val);
> return PCIBIOS_DEVICE_NOT_FOUND;
> @@ -580,6 +586,9 @@ EXPORT_SYMBOL(pci_read_config_word);
> int pci_read_config_dword(const struct pci_dev *dev, int where,
> u32 *val)
> {
> + if (pci_dev_ignore_access(dev))
> + return PCIBIOS_SUCCESSFUL;
[Severity: High]
Does returning PCIBIOS_SUCCESSFUL without setting *val in
pci_read_config_byte(), pci_read_config_word(), and pci_read_config_dword()
leave caller stack variables uninitialized when pci_dev_ignore_access(dev) is
true?
Callers such as pci_update_current_state() and pci_clear_and_set_config_dword()
pass an uninitialized stack variable to pci_read_config_word() or
pci_read_config_dword() expecting *val to be populated on return:
pci_update_current_state()
u16 pmcsr;
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
When dev->ignore_access_d3 is set and dev->current_state is PCI_D3cold, leaving
pmcsr uninitialized can overwrite dev->current_state and clear PCI_D3cold while
the upstream bridge is still powered down by PWRD(1), allowing subsequent
config accesses to hit the powered-off bridge.
> diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
> index 9c728ac4e045a..9f0e9ecbf9b97 100644
> --- a/drivers/platform/x86/apple-gmux.c
> +++ b/drivers/platform/x86/apple-gmux.c
[ ... ]
> @@ -244,12 +264,14 @@ static u8 gmux_mmio_read8(struct apple_gmux_data *gmux_data, int port)
> u8 val;
>
> mutex_lock(&gmux_data->index_lock);
> - gmux_mmio_wait(gmux_data);
> - iowrite8((port & 0xff), gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT);
> - iowrite8(GMUX_MMIO_READ | sizeof(val),
> - gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND);
> - gmux_mmio_wait(gmux_data);
> - val = ioread8(gmux_data->iomem_base);
> + if (gmux_mmio_wait(gmux_data)) {
> + iowrite8((port & 0xff), gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT);
> + iowrite8(GMUX_MMIO_READ | sizeof(val),
> + gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND);
> + if (!gmux_mmio_wait(gmux_data))
> + return 0;
> + val = ioread8(gmux_data->iomem_base);
> + }
> mutex_unlock(&gmux_data->index_lock);
>
> return val;
[ ... ]
> @@ -275,12 +300,16 @@ static u32 gmux_mmio_read32(struct apple_gmux_data *gmux_data, int port)
> u32 val;
>
> mutex_lock(&gmux_data->index_lock);
> - gmux_mmio_wait(gmux_data);
> - iowrite8((port & 0xff), gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT);
> - iowrite8(GMUX_MMIO_READ | sizeof(val),
> - gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND);
> - gmux_mmio_wait(gmux_data);
> - val = ioread32be(gmux_data->iomem_base);
> +
> + if (gmux_mmio_wait(gmux_data)) {
> + iowrite8((port & 0xff), gmux_data->iomem_base + GMUX_MMIO_PORT_SELECT);
> + iowrite8(GMUX_MMIO_READ | sizeof(val),
> + gmux_data->iomem_base + GMUX_MMIO_COMMAND_SEND);
> + if (!gmux_mmio_wait(gmux_data))
> + return 0;
> +
> + val = ioread32be(gmux_data->iomem_base);
> + }
> mutex_unlock(&gmux_data->index_lock);
>
> return val;
[Severity: High]
In gmux_mmio_read8() and gmux_mmio_read32(), if the second gmux_mmio_wait()
times out and returns 0, won't returning 0 directly leak gmux_data->index_lock
and deadlock subsequent gmux MMIO accesses?
Also, if the first gmux_mmio_wait() call returns 0, the if block is skipped and
both functions return the uninitialized local variable val (which can also be
read from userspace via debugfs in gmux_selected_port_data_read()). Should val
be initialized to 0 and the early return paths unlock gmux_data->index_lock
before returning?
[ ... ]
> @@ -502,23 +565,171 @@ static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
[ ... ]
> static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
> enum vga_switcheroo_state state)
> {
> reinit_completion(&gmux_data->powerchange_done);
> + acpi_handle discrete_handle = ACPI_HANDLE(&gmux_data->discrete_pdev->dev);
> + acpi_status status;
> + unsigned long long result;
> +
> + if (!discrete_handle)
> + return -ENODEV;
[Severity: High]
Can gmux_set_discrete_state() dereference a NULL gmux_data->discrete_pdev here?
gmux_data->discrete_pdev is only assigned in gmux_get_client_id() when
vga_switcheroo_enable() runs after both GPU clients have registered. If the
discrete GPU registers and enters runtime suspend before a second client
registers:
vga_switcheroo_runtime_suspend()
-> vga_switcheroo_power_switch()
-> gmux_set_power_state()
-> gmux_set_discrete_state()
gmux_data->discrete_pdev is still NULL when evaluating
ACPI_HANDLE(&gmux_data->discrete_pdev->dev). In addition, checking
!discrete_handle unconditionally at the start of gmux_set_discrete_state()
will abort with -ENODEV on non-MMIO systems (APPLE_GMUX_TYPE_PIO and
APPLE_GMUX_TYPE_INDEXED) that do not use discrete_handle.
> if (state == VGA_SWITCHEROO_ON) {
[ ... ]
> pr_debug("Discrete card powered up\n");
> } else {
> - gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
> - gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
> + if (gmux_data->type == APPLE_GMUX_TYPE_MMIO) {
> + if (gmux_data->uses_pwrd) {
> + acpi_handle parent_handle = discrete_handle;
> + bool saved_hda = false;
> +
> + while (ACPI_SUCCESS(acpi_get_parent(parent_handle,
> + &parent_handle))) {
> + if (!saved_hda) {
> + if (!gmux_save_restore_pci(parent_handle,
> + "HDAU", true, NULL)) {
> + saved_hda = true;
> + pci_save_state(gmux_data->discrete_pdev);
> + gmux_data->discrete_pdev->current_state =
> + PCI_D3cold;
> + }
> + }
> + if (gmux_save_restore_pci(parent_handle, NULL, true, NULL))
> + break;
> + }
> + status = acpi_execute_simple_method(discrete_handle, "PWRD", 1);
> + if (ACPI_FAILURE(status))
> + return -EIO;
> + }
[Severity: High]
What happens on MacBookPro16,1 and MacBookPro16,4 (where gmux_data->uses_pwrd
is true) when the system suspends and resumes while gmux_data->power_state is
already VGA_SWITCHEROO_OFF?
On system resume, gmux_resume() calls:
gmux_resume()
-> gmux_set_discrete_state(gmux_data, VGA_SWITCHEROO_OFF)
When the discrete GPU and upstream bridges are already powered off in
PCI_D3cold, calling pci_save_state() and gmux_save_restore_pci(..., true, NULL)
again will overwrite the previously saved PCI configuration state of HDAU,
gmux_data->discrete_pdev, and the upstream bridges with readings from the
powered-down devices before a subsequent VGA_SWITCHEROO_ON can restore them.
[ ... ]
> @@ -823,6 +1101,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
> pr_err("couldn't remap gmux mmio region");
> goto err_release;
> }
> + INIT_WORK(&gmux_data->interrupt_work, gmux_notify_work);
> goto get_version;
> case APPLE_GMUX_TYPE_INDEXED:
> gmux_data->config = &apple_gmux_index;
[ ... ]
> @@ -977,6 +1263,8 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
> err_unmap:
> if (gmux_data->iomem_base)
> iounmap(gmux_data->iomem_base);
> + if (gmux_data->type == APPLE_GMUX_TYPE_MMIO)
> + cancel_work_sync(&gmux_data->interrupt_work);
> err_release:
> if (gmux_data->config->resource_type == IORESOURCE_MEM)
> release_mem_region(gmux_data->iostart, gmux_data->iolen);
> @@ -993,7 +1281,9 @@ static void gmux_remove(struct pnp_dev *pnp)
>
> gmux_fini_debugfs(gmux_data);
> vga_switcheroo_unregister_handler();
> + pci_dev_put(gmux_data->discrete_pdev);
> gmux_disable_interrupts(gmux_data);
> + cancel_work_sync(&gmux_data->interrupt_work);
> if (gmux_data->gpe >= 0) {
> acpi_disable_gpe(NULL, gmux_data->gpe);
> acpi_remove_notify_handler(gmux_data->dhandle,
[Severity: High]
Are there a few teardown ordering issues with gmux_data->interrupt_work in
gmux_probe() and gmux_remove()?
First, INIT_WORK(&gmux_data->interrupt_work, gmux_notify_work) is only called
in gmux_probe() when type is APPLE_GMUX_TYPE_MMIO, but gmux_remove() calls
cancel_work_sync(&gmux_data->interrupt_work) unconditionally, which triggers
WARN_ON(!work->func) in __flush_work() on PIO and indexed gmux devices.
Second, in the err_unmap path of gmux_probe(), iounmap(gmux_data->iomem_base)
is called before cancel_work_sync(&gmux_data->interrupt_work), so a running
gmux_notify_work() can access gmux_data->iomem_base after it has been unmapped.
Third, in gmux_remove(), pci_dev_put(gmux_data->discrete_pdev) and
cancel_work_sync(&gmux_data->interrupt_work) are called before
acpi_disable_gpe() and acpi_remove_notify_handler(). Can gmux_notify_handler()
reschedule interrupt_work after cancel_work_sync(), or can a running
gmux_notify_work() dereference gmux_data->discrete_pdev after pci_dev_put()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261025040046.1602-1-atharvatiwarilinuxdev@gmail.com?part=8
next prev parent reply other threads:[~2026-10-25 4:37 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-25 3:59 [PATCH 00/13] Fixes for apple-gmux and runtime support Atharva Tiwari
2026-10-25 3:59 ` [PATCH 01/13] platform/apple-gmux: Fix power for MMIO systems Atharva Tiwari
2026-10-25 4:49 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 02/13] PCI: Disable pcie port and access on D3 on specific amd devices Atharva Tiwari
2026-10-25 4:34 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 03/13] platform/apple-gmux: Fix MMIO interface Atharva Tiwari
2026-10-25 4:27 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 04/13] platform/apple-gmux: Fix Interrupts for MMIO systems Atharva Tiwari
2026-10-25 4:39 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 05/13] platform/apple-gmux: Write switch state to EFI on MMIO devices Atharva Tiwari
2026-10-25 4:36 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 06/13] platform/apple-gmux: Add parameter to configure boot gpu Atharva Tiwari
2026-10-25 4:33 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 07/13] platform/apple-gmux: Add check to detect FSS Atharva Tiwari
2026-10-25 3:59 ` [PATCH 08/13] platform/apple-gmux: Add documentation about iMacs Atharva Tiwari
2026-10-25 4:37 ` sashiko-bot [this message]
2026-10-25 3:59 ` [PATCH 09/13] drm/amdgpu: Add Apple GMUX runtime PM support Atharva Tiwari
2026-10-25 5:56 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 10/13] drm/amdgpu: Catch register access while GMUX keeps the GPU off Atharva Tiwari
2026-10-25 4:40 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 11/13] drm/amd/display: Refuse DP AUX " Atharva Tiwari
2026-10-25 4:41 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 12/13] drm/amdgpu: Skip AC/DC notification while the GPU is runtime suspended Atharva Tiwari
2026-10-25 4:43 ` sashiko-bot
2026-10-25 3:59 ` [PATCH 13/13] drm/amd/display: Skip panel power savings on eDP links without a panel Atharva Tiwari
2026-10-25 4:30 ` 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-184072@kernel.org \
--to=sashiko-bot@kernel.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