dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
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

  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