In order to fix all of the spots that need to have runtime PM get/puts() added, we need to ensure that it's possible for us to call pm_runtime_get/put() in any context, regardless of how deep, since almost all of the spots that are currently missing refs can potentially get called in the runtime suspend/resume path. Otherwise, we'll try to resume the GPU as we're trying to resume the GPU (and vice-versa) and cause the kernel to deadlock. With this, it should be safe to call the pm runtime functions in any context in nouveau with one condition: any point in the driver that calls pm_runtime_get*() cannot hold any locks owned by nouveau that would be acquired anywhere inside nouveau_pmops_runtime_resume(). This includes modesetting locks, i2c bus locks, etc. Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx> Cc: Karol Herbst <karolherbst@xxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- drivers/gpu/drm/nouveau/nouveau_drm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index c7ec86d6c3c9..e851ef7b6373 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -835,6 +835,8 @@ nouveau_pmops_runtime_suspend(struct device *dev) return -EBUSY; } + dev->power.disable_depth++; + drm_kms_helper_poll_disable(drm_dev); nouveau_switcheroo_optimus_dsm(); ret = nouveau_do_suspend(drm_dev, true); @@ -843,6 +845,8 @@ nouveau_pmops_runtime_suspend(struct device *dev) pci_ignore_hotplug(pdev); pci_set_power_state(pdev, PCI_D3cold); drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + + dev->power.disable_depth--; return ret; } @@ -859,11 +863,13 @@ nouveau_pmops_runtime_resume(struct device *dev) return -EBUSY; } + dev->power.disable_depth++; + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); ret = pci_enable_device(pdev); if (ret) - return ret; + goto out; pci_set_master(pdev); ret = nouveau_do_resume(drm_dev, true); @@ -875,6 +881,8 @@ nouveau_pmops_runtime_resume(struct device *dev) /* Monitors may have been connected / disconnected during suspend */ schedule_work(&nouveau_drm(drm_dev)->hpd_work); +out: + dev->power.disable_depth--; return ret; } -- 2.17.1