From 154199c682f4c1069bfad2d46e2b279e04435507 Mon Sep 17 00:00:00 2001 From: ElXreno Date: Sat, 6 Jun 2026 18:03:01 +0300 Subject: [PATCH] nvidia: don't wake a runtime-suspended GPU to service NVPCF/GPS ACPI notifies On RTD3 laptops the dGPU is runtime-suspended (D3cold) while idle. Some platforms still deliver ACPI Notify() events for the NVPCF device and for GPS status changes while the GPU is suspended (for example around battery/AC transitions, or when the SBIOS pushes a thermal or power-limit hint). rm_acpi_nvpcf_notify() and RmHandleGPSStatusChange() both call os_ref_dynamic_power() unconditionally, resuming the GPU only to deliver an event that is meaningless while it is powered down. The GPU then re-suspends, and where the next notify arrives immediately it never settles in D3cold, cycling D0/D3cold and draining the battery (see #860, where users work around it by patching the ACPI tables to drop the Notify(NPCF, 0xC0)). Skip the work when the GPU is already runtime-suspended (NV_DYNAMIC_POWER_STATE_IDLE_INDICATED), the same guard that rm_pmu_perfmon_get_load() already uses. The NVPCF event is only consumed while the GPU is active, and GPS/SBIOS state is re-read on the next StateLoad, so no state is lost. --- src/nvidia/arch/nvalloc/unix/src/osapi.c | 31 ++++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/nvidia/arch/nvalloc/unix/src/osapi.c b/src/nvidia/arch/nvalloc/unix/src/osapi.c index 894cd6638..91bd795af 100644 --- a/src/nvidia/arch/nvalloc/unix/src/osapi.c +++ b/src/nvidia/arch/nvalloc/unix/src/osapi.c @@ -2023,6 +2023,17 @@ static void RmHandleGPSStatusChange RM_API *pRmApi; THREAD_STATE_NODE threadState; NV0000_CTRL_SYSTEM_GPS_CONTROL_PARAMS gpsControl = { 0 }; + nv_priv_t *nvp = NV_GET_NV_PRIV(pNv); + + // + // Don't wake a runtime-suspended GPU just to handle a GPS status + // change; service it only when the GPU is already awake. + // + if (nvp != NULL && + nvp->dynamic_power.state == NV_DYNAMIC_POWER_STATE_IDLE_INDICATED) + { + return; + } pRmApi = RmUnixRmApiPrologue(pNv, &threadState, RM_LOCK_MODULES_ACPI); if (pRmApi == NULL) @@ -6066,13 +6077,23 @@ void NV_API_CALL rm_acpi_nvpcf_notify( if (pGpu != NULL) { nv_state_t *nv = NV_GET_NV_STATE(pGpu); - if ((rmStatus = os_ref_dynamic_power(nv, NV_DYNAMIC_PM_FINE)) == - NV_OK) + nv_priv_t *nvp = NV_GET_NV_PRIV(nv); + + // + // Don't wake a runtime-suspended GPU just to deliver an NVPCF + // event; service it only when the GPU is already awake. + // + if (nvp == NULL || + nvp->dynamic_power.state != NV_DYNAMIC_POWER_STATE_IDLE_INDICATED) { - gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_NVPCF_EVENTS, - NULL, 0, 0, 0); + if ((rmStatus = os_ref_dynamic_power(nv, NV_DYNAMIC_PM_FINE)) == + NV_OK) + { + gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_NVPCF_EVENTS, + NULL, 0, 0, 0); + } + os_unref_dynamic_power(nv, NV_DYNAMIC_PM_FINE); } - os_unref_dynamic_power(nv, NV_DYNAMIC_PM_FINE); } rmapiLockRelease(); }