Linux PCI subsystem development
 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 09/13] drm/amdgpu: Add Apple GMUX runtime PM support
Date: Sun, 25 Oct 2026 05:56:23 +0000	[thread overview]
Message-ID: <sashiko-outbox-184089@kernel.org> (raw)
In-Reply-To: <20261025040046.1602-10-atharvatiwarilinuxdev@gmail.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] drm/amdgpu: missing thunderbolt check in amdgpu_device_supports_gmux()
- [High] drm/amdgpu: NULL deref on GMUX runtime suspend if handler or iGPU not ready
- [High] drm/amdgpu: broken smart-suspend handling for GMUX in amdgpu_pci_probe()
- [Medium] drm/amdgpu: unconditional GMUX switcheroo runtime PM setup ignores runpm param
--

commit f1610061faecf7abbb15383a149d6591a343aafc
Author: Andre Eikmeyer <dev@deq.rocks>

drm/amdgpu: Add Apple GMUX runtime PM support

This commit adds runtime power management support for discrete GPUs on T2
MacBook Pro models controlled via Apple gmux using the vga_switcheroo power
domain. It also marks inactive gmux eDP panels as disconnected prior to
Display Core initialization so that disconnected internal panels do not hold
the discrete GPU runtime active.

> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 9269e780feb73..c1f1962425fee 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
[ ... ]
> @@ -570,6 +571,45 @@ bool amdgpu_device_supports_px(struct amdgpu_device *adev)
>  	return false;
>  }
>  
> +static const struct dmi_system_id amdgpu_gmux_runpm_dmi_table[] = {
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro15,3"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,1"),
> +		},
> +	},
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,4"),
> +		},
> +	},
> +	{ }
> +};
> +
> +bool amdgpu_device_supports_gmux(struct amdgpu_device *adev)
> +{
> +	return dmi_check_system(amdgpu_gmux_runpm_dmi_table) &&
> +	       !dev_is_removable(&adev->pdev->dev) &&

[Severity: High]
Should amdgpu_device_supports_gmux() also check
!pci_is_thunderbolt_attached(adev->pdev)?

On MacBook Pro systems, Intel Thunderbolt hierarchies are identified via
pci_is_thunderbolt_attached(adev->pdev) rather than the ExternalFacingPort
property that sets dev_is_removable() (as seen in commit 8587d48d694d and in
amdgpu_device_should_register_switcheroo()):

drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:amdgpu_device_should_register_switcheroo() {
	return !pci_is_thunderbolt_attached(adev->pdev) &&
	       (px || (!dev_is_removable(&adev->pdev->dev) &&
		       apple_gmux_detect(NULL, NULL)));
}

Because dmi_check_system() and apple_gmux_detect(NULL, NULL) are host-wide
checks, connecting a Thunderbolt external GPU to a MacBookPro15,1, 15,3,
16,1, or 16,4 causes amdgpu_device_supports_gmux() to return true for the
external GPU while amdgpu_device_should_register_switcheroo() returns false.

In amdgpu_device_init(), this skips vga_switcheroo_register_client() for the
Thunderbolt GPU, but still executes vga_switcheroo_init_domain_pm_ops()
because gmux is true, binding the external GPU to vga_switcheroo's power
domain without registering it as a switcheroo client. In addition,
amdgpu_device_has_gmux_edp() returns true for the external GPU on
MacBookPro15,3, 16,1, and 16,4, causing amdgpu_dm_init() to set
init_data.flags.edp_not_connected = true and
amdgpu_dm_initialize_drm_device() to skip eDP detection on the external GPU.

> +	       apple_gmux_detect(NULL, NULL);
> +}

[Severity: High]
Can this trigger a NULL pointer dereference when the 5-second runtime
autosuspend timer fires after amdgpu_pci_probe() if the apple-gmux handler or
the integrated GPU client has not been registered yet?

The inline helper apple_gmux_detect(NULL, NULL) only checks for hardware
presence in ACPI/PNP and returns true even if the apple-gmux driver
(CONFIG_APPLE_GMUX) has not probed or registered a vga_switcheroo handler.
Because amdgpu_pci_probe() does not call vga_switcheroo_client_probe_defer()
before enabling runtime autosuspend, two failure paths can occur when
vga_switcheroo_runtime_suspend() runs:

1. If apple-gmux has not probed yet (for instance, when built as a module and
not loaded in initramfs, or if its probe failed), vgasr_priv.handler is NULL
when vga_switcheroo_runtime_suspend() dereferences it:

drivers/gpu/vga/vga_switcheroo.c:vga_switcheroo_runtime_suspend() {
	...
	mutex_lock(&vgasr_mutex);
	if (vgasr_priv.handler->switchto) {
		mutex_lock(&vgasr_priv.mux_hw_lock);
		vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
		mutex_unlock(&vgasr_priv.mux_hw_lock);
	}
	pci_bus_set_current_state(pdev->bus, PCI_D3cold);
	vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
	mutex_unlock(&vgasr_mutex);
	...
}

2. Even if apple-gmux has registered its handler, vga_switcheroo_enable()
only runs and invokes gmux_get_client_id() (which is the only place that
populates gmux_data->discrete_pdev) once two vga_switcheroo clients have
registered. If i915 has not probed or is disabled when amdgpu autosuspends,
client->id remains VGA_SWITCHEROO_UNKNOWN_ID, and
vga_switcheroo_power_switch() -> gmux_set_power_state() ->
gmux_set_discrete_state() dereferences gmux_data->discrete_pdev while it is
NULL:

drivers/platform/x86/apple-gmux.c:gmux_set_discrete_state() {
	reinit_completion(&gmux_data->powerchange_done);
	acpi_handle discrete_handle = ACPI_HANDLE(&gmux_data->discrete_pdev->dev);
	...
}

[ ... ]
> @@ -4202,12 +4245,13 @@ int amdgpu_device_init(struct amdgpu_device *adev,
>  		vga_client_register(adev->pdev, amdgpu_device_vga_set_decode);
>  
>  	px = amdgpu_device_supports_px(adev);
> +	gmux = amdgpu_device_supports_gmux(adev);
>  
>  	if (amdgpu_device_should_register_switcheroo(adev, px))
>  		vga_switcheroo_register_client(adev->pdev,
> -					       &amdgpu_switcheroo_ops, px);
> +					       &amdgpu_switcheroo_ops, px || gmux);
>  
> -	if (px)
> +	if (px || gmux)
>  		vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);

[Severity: Medium]
What happens here when the module parameter amdgpu.runpm is set to 0, 1, or 2
on a supported MacBook Pro?

In amdgpu_driver_load_kms(), amdgpu_device_init() runs before
amdgpu_device_detect_runtime_pm_mode() evaluates amdgpu_runtime_pm:

drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c:amdgpu_driver_load_kms() {
	...
	r = amdgpu_device_init(adev, flags);
	if (r) {
		dev_err(dev->dev, "Fatal error during GPU init\n");
		goto out;
	}

	amdgpu_device_detect_runtime_pm_mode(adev);
	...
}

Because amdgpu_device_init() sets driver_power_control to true (px || gmux)
and attaches adev->vga_pm_domain unconditionally whenever
amdgpu_device_supports_gmux(adev) is true:

1. With amdgpu.runpm=0, amdgpu_device_detect_runtime_pm_mode() leaves
adev->pm.rpm_mode as AMDGPU_RUNPM_NONE, so amdgpu_pci_probe() does not enable
runtime power management. At the same time, vga_switchoff() and
vga_switchon() in drivers/gpu/vga/vga_switcheroo.c return early when
client->driver_power_control is true, disabling manual vga_switcheroo power
control as well.

2. With amdgpu.runpm=1 or amdgpu.runpm=2 on an ASIC that reports
BACO_SUPPORT or MACO_SUPPORT, amdgpu_device_detect_runtime_pm_mode() selects
AMDGPU_RUNPM_BACO or AMDGPU_RUNPM_BAMACO while vga_pm_domain remains attached
to adev->dev. On runtime suspend, amdgpu_pmops_runtime_suspend() enters BACO
without saving PCI state or disabling the PCI device, and
vga_switcheroo_runtime_suspend() then cuts power to the GPU and bridge via
gmux.

[ ... ]
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index d9d794a7db964..5ad7b6dd8b2b5 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -2494,11 +2494,12 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
>  		DRM_ERROR("Creating debugfs files failed (%d).\n", ret);
>  
>  	if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) {
> -		/* only need to skip on ATPX */
> +		/* ATPX requires a full system-sleep transition. */
>  		if (amdgpu_device_supports_px(adev))
>  			dev_pm_set_driver_flags(ddev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
> -		/* we want direct complete for BOCO */
> -		if (amdgpu_device_supports_boco(adev))
> +		/* BOCO and GMUX can remain runtime suspended across system sleep. */
> +		if (amdgpu_device_supports_boco(adev) ||
> +		    adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX)
>  			dev_pm_set_driver_flags(ddev->dev, DPM_FLAG_SMART_PREPARE |
>  						DPM_FLAG_SMART_SUSPEND |
>  						DPM_FLAG_MAY_SKIP_RESUME);
> @@ -2610,7 +2611,9 @@ static int amdgpu_pmops_prepare(struct device *dev)
>  	/* Return a positive number here so
>  	 * DPM_FLAG_SMART_SUSPEND works properly
>  	 */
> -	if (amdgpu_device_supports_boco(adev) && pm_runtime_suspended(dev))
> +	if ((amdgpu_device_supports_boco(adev) ||
> +	     adev->pm.rpm_mode == AMDGPU_RUNPM_GMUX) &&
> +	    pm_runtime_suspended(dev))
>  		return 1;

[Severity: High]
Is setting DPM_FLAG_SMART_PREPARE, DPM_FLAG_SMART_SUSPEND, and
DPM_FLAG_MAY_SKIP_RESUME safe for AMDGPU_RUNPM_GMUX when direct_complete is
not used during system sleep or hibernation?

When a gmux discrete GPU is runtime-suspended, amdgpu_pmops_runtime_suspend()
caches PCI state (setting pdev->state_saved = true), sets pdev->current_state
to PCI_D3cold, and sets drm_dev->switch_power_state to
DRM_SWITCH_POWER_DYNAMIC_OFF, while vga_switcheroo_runtime_suspend() cuts
power via apple-gmux (and powers down the PCIe bridge on MacBookPro16,1 and
16,4).

During system sleep or hibernation, direct_complete can be cleared in two
ways, neither of which is handled by vga_pm_domain or the amdgpu system sleep
callbacks:

1. When the companion HDA audio device (linked as a consumer to the discrete
GPU with DL_FLAG_PM_RUNTIME by quirk_gpu_hda()) is bound to snd_hda_intel,
its child PCM devices have .prepare = NULL and .suspend = do_pcm_suspend,
which clears direct_complete up to the HDA PCI device via
dpm_clear_superiors_direct_complete(). In pci_pm_suspend(), because
snd_hda_intel does not set DPM_FLAG_SMART_SUSPEND, pm_runtime_resume() is
called on the HDA device, which via rpm_get_suppliers() runtime-resumes the
gmux GPU during dpm_suspend() after amdgpu_pmops_prepare() already returned 1
and skipped amdgpu_device_prepare(). Then dpm_clear_superiors_direct_complete()
clears direct_complete on the GPU, so amdgpu_pmops_suspend() calls
amdgpu_device_suspend() without amdgpu_device_prepare() having run, and
because vga_pm_domain only implements runtime PM callbacks, gmux never cuts
power to the GPU for system sleep.

2. If direct_complete is false while the gmux GPU stays runtime-suspended
(for example, during hibernation in pci_pm_poweroff(), when
device_may_wakeup() is enabled, when a child amdgpu_bl backlight device whose
class PM ops have .prepare = NULL clears direct_complete, or when
snd_hda_intel is unbound), pci_pm_suspend() and pci_pm_poweroff() evaluate
(!dev_pm_smart_suspend(dev) || pci_dev_need_resume(pci_dev)) as false because
DPM_FLAG_SMART_SUSPEND is set and pci_dev_need_resume() is false for a
non-ACPI PCI device already in PCI_D3cold. They therefore skip
pm_runtime_resume() and invoke amdgpu_pmops_suspend() or
amdgpu_pmops_poweroff() -> amdgpu_device_suspend() while the GPU is powered
off:

drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:amdgpu_device_suspend() {
	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
		return 0;
	...
}

Because amdgpu_device_suspend() only checks for DRM_SWITCH_POWER_OFF (and not
DRM_SWITCH_POWER_DYNAMIC_OFF or pm_runtime_suspended(dev)), it proceeds to
access registers on the powered-off GPU. On the subsequent resume path,
pci_pm_resume() (which does not check dev_pm_skip_resume()) sees
pci_dev->state_saved == true from runtime suspend, attempts
pci_restore_standard_config() on the powered-off device, and calls
amdgpu_pmops_resume(), where pci_device_is_present() reads 0xffff, sets
adev->no_hw_access = true, and runs amdgpu_device_resume() while gmux still
has power cut.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261025040046.1602-1-atharvatiwarilinuxdev@gmail.com?part=9

  reply	other threads:[~2026-10-25  5:56 UTC|newest]

Thread overview: 36+ 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-27 23:00   ` Bjorn Helgaas
2026-10-28  0:08     ` Atharva Tiwari
2026-10-28  1:19       ` Atharva Tiwari
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 22:10   ` kernel test robot
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  4:30   ` sashiko-bot
2026-10-25  3:59 ` [PATCH 08/13] platform/apple-gmux: Add documentation about iMacs Atharva Tiwari
2026-10-25  4:37   ` sashiko-bot
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 [this message]
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-26 18:25   ` Alex Deucher
2026-10-27  8:29     ` Atharva Tiwari
2026-10-27 15:22       ` Alex Deucher
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-26 18:25   ` Alex Deucher
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-26 18:18   ` Alex Deucher
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-184089@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