aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <groeck@chromium.org>2017-02-05 02:54:58 -0500
committerMark Yao <mark.yao@rock-chips.com>2017-02-05 03:29:46 -0500
commit5eb2e6ee97b5e9a8587143db339bc71b28a3e1ca (patch)
tree07aad5ee1fc248292ee4513687f9082c0c5995e9
parent83c132ed46a7e9c8ac17be436ef3892850df8695 (diff)
drm/rockchip: cdn-dp: Do not run worker while suspended
If the driver is in suspended mode, the dp block may be disabled, and chip registers may not be accessible. Yet, the worker may be triggered in this situation by an extcon event. If that happens, the following crash will be seen. cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work] *ERROR* Enable dp failed -19 cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work] Connected, not enabled. Enabling cdn Bad mode in Error handler detected, code 0xbf000002 -- SError CPU: 1 PID: 10357 Comm: kworker/1:2 Not tainted 4.4.21-05903-ge0514ea #1 Hardware name: Google Kevin (DT) Workqueue: events cdn_dp_pd_event_work task: ffffffc0cda67080 ti: ffffffc0b9b80000 task.ti: ffffffc0b9b80000 PC is at cdn_dp_clock_reset+0x30/0xa8 LR is at cdn_dp_enable+0x1e0/0x69c ... Call trace: [<ffffffc0005a7e24>] cdn_dp_pd_event_work+0x58/0x3f4 [<ffffffc0002397f0>] process_one_work+0x240/0x424 [<ffffffc00023a28c>] worker_thread+0x2fc/0x424 [<ffffffc00023f5fc>] kthread+0x10c/0x114 [<ffffffc000203dd0>] ret_from_fork+0x10/0x40 Problem is two-fold: The worker should not run while suspended, and the suspend function should not call cdn_dp_disable() while the worker is running. Signed-off-by: Guenter Roeck <groeck@chromium.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Chris Zhong <zyw@rock-chips.com>
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.c15
-rw-r--r--drivers/gpu/drm/rockchip/cdn-dp-core.h1
2 files changed, 14 insertions, 2 deletions
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index b8d0dd7abc61..a70eedc88e1a 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -939,6 +939,10 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
939 u8 sink_count; 939 u8 sink_count;
940 940
941 mutex_lock(&dp->lock); 941 mutex_lock(&dp->lock);
942
943 if (dp->suspended)
944 goto out;
945
942 ret = cdn_dp_request_firmware(dp); 946 ret = cdn_dp_request_firmware(dp);
943 if (ret) 947 if (ret)
944 goto out; 948 goto out;
@@ -1123,19 +1127,26 @@ static const struct component_ops cdn_dp_component_ops = {
1123int cdn_dp_suspend(struct device *dev) 1127int cdn_dp_suspend(struct device *dev)
1124{ 1128{
1125 struct cdn_dp_device *dp = dev_get_drvdata(dev); 1129 struct cdn_dp_device *dp = dev_get_drvdata(dev);
1130 int ret = 0;
1126 1131
1132 mutex_lock(&dp->lock);
1127 if (dp->active) 1133 if (dp->active)
1128 return cdn_dp_disable(dp); 1134 ret = cdn_dp_disable(dp);
1135 dp->suspended = true;
1136 mutex_unlock(&dp->lock);
1129 1137
1130 return 0; 1138 return ret;
1131} 1139}
1132 1140
1133int cdn_dp_resume(struct device *dev) 1141int cdn_dp_resume(struct device *dev)
1134{ 1142{
1135 struct cdn_dp_device *dp = dev_get_drvdata(dev); 1143 struct cdn_dp_device *dp = dev_get_drvdata(dev);
1136 1144
1145 mutex_lock(&dp->lock);
1146 dp->suspended = false;
1137 if (dp->fw_loaded) 1147 if (dp->fw_loaded)
1138 schedule_work(&dp->event_work); 1148 schedule_work(&dp->event_work);
1149 mutex_unlock(&dp->lock);
1139 1150
1140 return 0; 1151 return 0;
1141} 1152}
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index 3bea4b8d265f..7d48661362c8 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -82,6 +82,7 @@ struct cdn_dp_device {
82 struct mutex lock; 82 struct mutex lock;
83 bool connected; 83 bool connected;
84 bool active; 84 bool active;
85 bool suspended;
85 86
86 const struct firmware *fw; /* cdn dp firmware */ 87 const struct firmware *fw; /* cdn dp firmware */
87 unsigned int fw_version; /* cdn fw version */ 88 unsigned int fw_version; /* cdn fw version */