All of 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 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.