aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Wunner <lukas@wunner.de>2018-02-11 04:38:28 -0500
committerLukas Wunner <lukas@wunner.de>2018-02-16 16:40:23 -0500
commitaa0aad57909eb321746325951d66af88a83bc956 (patch)
tree45a20e39488e683cddf0aa23939717dacf3851f4
parent15734feff2bdac24aa3266c437cffa42851990e3 (diff)
drm/amdgpu: Fix deadlock on runtime suspend
amdgpu's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in amdgpu's ->detect hooks, which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if the ->detect hooks are called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Fixes: d38ceaf99ed0 ("drm/amdgpu: add core driver (v4)") Cc: stable@vger.kernel.org # v4.2+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v4.2+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Alex Deucher <alexander.deucher@amd.com> Tested-by: Mike Lothian <mike@fireburn.co.uk> Reviewed-by: Lyude Paul <lyude@redhat.com> Signed-off-by: Lukas Wunner <lukas@wunner.de> Link: https://patchwork.freedesktop.org/patch/msgid/4c9bf72aacae1eef062bd134cd112e0770a7f121.1518338789.git.lukas@wunner.de
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c58
1 files changed, 38 insertions, 20 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index df9cbc78e168..21e7ae159dff 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -737,9 +737,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
737 enum drm_connector_status ret = connector_status_disconnected; 737 enum drm_connector_status ret = connector_status_disconnected;
738 int r; 738 int r;
739 739
740 r = pm_runtime_get_sync(connector->dev->dev); 740 if (!drm_kms_helper_is_poll_worker()) {
741 if (r < 0) 741 r = pm_runtime_get_sync(connector->dev->dev);
742 return connector_status_disconnected; 742 if (r < 0)
743 return connector_status_disconnected;
744 }
743 745
744 if (encoder) { 746 if (encoder) {
745 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 747 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
@@ -758,8 +760,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
758 /* check acpi lid status ??? */ 760 /* check acpi lid status ??? */
759 761
760 amdgpu_connector_update_scratch_regs(connector, ret); 762 amdgpu_connector_update_scratch_regs(connector, ret);
761 pm_runtime_mark_last_busy(connector->dev->dev); 763
762 pm_runtime_put_autosuspend(connector->dev->dev); 764 if (!drm_kms_helper_is_poll_worker()) {
765 pm_runtime_mark_last_busy(connector->dev->dev);
766 pm_runtime_put_autosuspend(connector->dev->dev);
767 }
768
763 return ret; 769 return ret;
764} 770}
765 771
@@ -869,9 +875,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
869 enum drm_connector_status ret = connector_status_disconnected; 875 enum drm_connector_status ret = connector_status_disconnected;
870 int r; 876 int r;
871 877
872 r = pm_runtime_get_sync(connector->dev->dev); 878 if (!drm_kms_helper_is_poll_worker()) {
873 if (r < 0) 879 r = pm_runtime_get_sync(connector->dev->dev);
874 return connector_status_disconnected; 880 if (r < 0)
881 return connector_status_disconnected;
882 }
875 883
876 encoder = amdgpu_connector_best_single_encoder(connector); 884 encoder = amdgpu_connector_best_single_encoder(connector);
877 if (!encoder) 885 if (!encoder)
@@ -925,8 +933,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
925 amdgpu_connector_update_scratch_regs(connector, ret); 933 amdgpu_connector_update_scratch_regs(connector, ret);
926 934
927out: 935out:
928 pm_runtime_mark_last_busy(connector->dev->dev); 936 if (!drm_kms_helper_is_poll_worker()) {
929 pm_runtime_put_autosuspend(connector->dev->dev); 937 pm_runtime_mark_last_busy(connector->dev->dev);
938 pm_runtime_put_autosuspend(connector->dev->dev);
939 }
930 940
931 return ret; 941 return ret;
932} 942}
@@ -989,9 +999,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
989 enum drm_connector_status ret = connector_status_disconnected; 999 enum drm_connector_status ret = connector_status_disconnected;
990 bool dret = false, broken_edid = false; 1000 bool dret = false, broken_edid = false;
991 1001
992 r = pm_runtime_get_sync(connector->dev->dev); 1002 if (!drm_kms_helper_is_poll_worker()) {
993 if (r < 0) 1003 r = pm_runtime_get_sync(connector->dev->dev);
994 return connector_status_disconnected; 1004 if (r < 0)
1005 return connector_status_disconnected;
1006 }
995 1007
996 if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { 1008 if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
997 ret = connector->status; 1009 ret = connector->status;
@@ -1116,8 +1128,10 @@ out:
1116 amdgpu_connector_update_scratch_regs(connector, ret); 1128 amdgpu_connector_update_scratch_regs(connector, ret);
1117 1129
1118exit: 1130exit:
1119 pm_runtime_mark_last_busy(connector->dev->dev); 1131 if (!drm_kms_helper_is_poll_worker()) {
1120 pm_runtime_put_autosuspend(connector->dev->dev); 1132 pm_runtime_mark_last_busy(connector->dev->dev);
1133 pm_runtime_put_autosuspend(connector->dev->dev);
1134 }
1121 1135
1122 return ret; 1136 return ret;
1123} 1137}
@@ -1360,9 +1374,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
1360 struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 1374 struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
1361 int r; 1375 int r;
1362 1376
1363 r = pm_runtime_get_sync(connector->dev->dev); 1377 if (!drm_kms_helper_is_poll_worker()) {
1364 if (r < 0) 1378 r = pm_runtime_get_sync(connector->dev->dev);
1365 return connector_status_disconnected; 1379 if (r < 0)
1380 return connector_status_disconnected;
1381 }
1366 1382
1367 if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { 1383 if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
1368 ret = connector->status; 1384 ret = connector->status;
@@ -1430,8 +1446,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
1430 1446
1431 amdgpu_connector_update_scratch_regs(connector, ret); 1447 amdgpu_connector_update_scratch_regs(connector, ret);
1432out: 1448out:
1433 pm_runtime_mark_last_busy(connector->dev->dev); 1449 if (!drm_kms_helper_is_poll_worker()) {
1434 pm_runtime_put_autosuspend(connector->dev->dev); 1450 pm_runtime_mark_last_busy(connector->dev->dev);
1451 pm_runtime_put_autosuspend(connector->dev->dev);
1452 }
1435 1453
1436 return ret; 1454 return ret;
1437} 1455}