Skip to content

Commit 56eac98

Browse files
committed
Merge tag 'exynos-drm-fixes-for-v4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-fixes
- fix suspend/resume issues. - fix memory corruption detected by kasan. - fix build error on x86. * tag 'exynos-drm-fixes-for-v4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos/hdmi: Fix unsafe list iteration drm: exynos: include linux/irq.h drm/exynos: Fix suspend/resume support drm/exynos: Fix locking in the suspend/resume paths
2 parents c106c7a + 04fc52f commit 56eac98

File tree

6 files changed

+55
-27
lines changed

6 files changed

+55
-27
lines changed

drivers/gpu/drm/exynos/exynos5433_drm_decon.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/clk.h>
1515
#include <linux/component.h>
1616
#include <linux/iopoll.h>
17+
#include <linux/irq.h>
1718
#include <linux/mfd/syscon.h>
1819
#include <linux/of_device.h>
1920
#include <linux/of_gpio.h>

drivers/gpu/drm/exynos/exynos_drm_drv.c

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -168,46 +168,34 @@ static struct drm_driver exynos_drm_driver = {
168168
static int exynos_drm_suspend(struct device *dev)
169169
{
170170
struct drm_device *drm_dev = dev_get_drvdata(dev);
171-
struct drm_connector *connector;
172-
struct drm_connector_list_iter conn_iter;
171+
struct exynos_drm_private *private = drm_dev->dev_private;
173172

174173
if (pm_runtime_suspended(dev) || !drm_dev)
175174
return 0;
176175

177-
drm_connector_list_iter_begin(drm_dev, &conn_iter);
178-
drm_for_each_connector_iter(connector, &conn_iter) {
179-
int old_dpms = connector->dpms;
180-
181-
if (connector->funcs->dpms)
182-
connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
183-
184-
/* Set the old mode back to the connector for resume */
185-
connector->dpms = old_dpms;
176+
drm_kms_helper_poll_disable(drm_dev);
177+
exynos_drm_fbdev_suspend(drm_dev);
178+
private->suspend_state = drm_atomic_helper_suspend(drm_dev);
179+
if (IS_ERR(private->suspend_state)) {
180+
exynos_drm_fbdev_resume(drm_dev);
181+
drm_kms_helper_poll_enable(drm_dev);
182+
return PTR_ERR(private->suspend_state);
186183
}
187-
drm_connector_list_iter_end(&conn_iter);
188184

189185
return 0;
190186
}
191187

192188
static int exynos_drm_resume(struct device *dev)
193189
{
194190
struct drm_device *drm_dev = dev_get_drvdata(dev);
195-
struct drm_connector *connector;
196-
struct drm_connector_list_iter conn_iter;
191+
struct exynos_drm_private *private = drm_dev->dev_private;
197192

198193
if (pm_runtime_suspended(dev) || !drm_dev)
199194
return 0;
200195

201-
drm_connector_list_iter_begin(drm_dev, &conn_iter);
202-
drm_for_each_connector_iter(connector, &conn_iter) {
203-
if (connector->funcs->dpms) {
204-
int dpms = connector->dpms;
205-
206-
connector->dpms = DRM_MODE_DPMS_OFF;
207-
connector->funcs->dpms(connector, dpms);
208-
}
209-
}
210-
drm_connector_list_iter_end(&conn_iter);
196+
drm_atomic_helper_resume(drm_dev, private->suspend_state);
197+
exynos_drm_fbdev_resume(drm_dev);
198+
drm_kms_helper_poll_enable(drm_dev);
211199

212200
return 0;
213201
}

drivers/gpu/drm/exynos/exynos_drm_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ struct drm_exynos_file_private {
202202
*/
203203
struct exynos_drm_private {
204204
struct drm_fb_helper *fb_helper;
205+
struct drm_atomic_state *suspend_state;
205206

206207
struct device *dma_dev;
207208
void *mapping;

drivers/gpu/drm/exynos/exynos_drm_fbdev.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <drm/drm_crtc_helper.h>
1919
#include <drm/exynos_drm.h>
2020

21+
#include <linux/console.h>
22+
2123
#include "exynos_drm_drv.h"
2224
#include "exynos_drm_fb.h"
2325
#include "exynos_drm_fbdev.h"
@@ -285,3 +287,21 @@ void exynos_drm_output_poll_changed(struct drm_device *dev)
285287

286288
drm_fb_helper_hotplug_event(fb_helper);
287289
}
290+
291+
void exynos_drm_fbdev_suspend(struct drm_device *dev)
292+
{
293+
struct exynos_drm_private *private = dev->dev_private;
294+
295+
console_lock();
296+
drm_fb_helper_set_suspend(private->fb_helper, 1);
297+
console_unlock();
298+
}
299+
300+
void exynos_drm_fbdev_resume(struct drm_device *dev)
301+
{
302+
struct exynos_drm_private *private = dev->dev_private;
303+
304+
console_lock();
305+
drm_fb_helper_set_suspend(private->fb_helper, 0);
306+
console_unlock();
307+
}

drivers/gpu/drm/exynos/exynos_drm_fbdev.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev);
2121
void exynos_drm_fbdev_fini(struct drm_device *dev);
2222
void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
2323
void exynos_drm_output_poll_changed(struct drm_device *dev);
24+
void exynos_drm_fbdev_suspend(struct drm_device *drm);
25+
void exynos_drm_fbdev_resume(struct drm_device *drm);
2426

2527
#else
2628

@@ -39,6 +41,14 @@ static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
3941

4042
#define exynos_drm_output_poll_changed (NULL)
4143

44+
static inline void exynos_drm_fbdev_suspend(struct drm_device *drm)
45+
{
46+
}
47+
48+
static inline void exynos_drm_fbdev_resume(struct drm_device *drm)
49+
{
50+
}
51+
4252
#endif
4353

4454
#endif

drivers/gpu/drm/exynos/exynos_hdmi.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -944,22 +944,27 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
944944
struct drm_device *dev = encoder->dev;
945945
struct drm_connector *connector;
946946
struct drm_display_mode *m;
947+
struct drm_connector_list_iter conn_iter;
947948
int mode_ok;
948949

949950
drm_mode_set_crtcinfo(adjusted_mode, 0);
950951

951-
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
952+
drm_connector_list_iter_begin(dev, &conn_iter);
953+
drm_for_each_connector_iter(connector, &conn_iter) {
952954
if (connector->encoder == encoder)
953955
break;
954956
}
957+
if (connector)
958+
drm_connector_get(connector);
959+
drm_connector_list_iter_end(&conn_iter);
955960

956-
if (connector->encoder != encoder)
961+
if (!connector)
957962
return true;
958963

959964
mode_ok = hdmi_mode_valid(connector, adjusted_mode);
960965

961966
if (mode_ok == MODE_OK)
962-
return true;
967+
goto cleanup;
963968

964969
/*
965970
* Find the most suitable mode and copy it to adjusted_mode.
@@ -979,6 +984,9 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
979984
}
980985
}
981986

987+
cleanup:
988+
drm_connector_put(connector);
989+
982990
return true;
983991
}
984992

0 commit comments

Comments
 (0)