[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180716235936.11268-2-lyude@redhat.com>
Date: Mon, 16 Jul 2018 19:59:25 -0400
From: Lyude Paul <lyude@...hat.com>
To: nouveau@...ts.freedesktop.org
Cc: Karol Herbst <karolherbst@...il.com>, stable@...r.kernel.org,
Ben Skeggs <bskeggs@...hat.com>,
David Airlie <airlied@...ux.ie>,
dri-devel@...ts.freedesktop.org, linux-kernel@...r.kernel.org
Subject: [PATCH 1/5] drm/nouveau: Prevent RPM callback recursion in suspend/resume paths
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@...hat.com>
Cc: Karol Herbst <karolherbst@...il.com>
Cc: stable@...r.kernel.org
---
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
Powered by blists - more mailing lists