diff options
author | Dave Airlie <airlied@redhat.com> | 2018-02-21 17:39:26 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-02-21 17:39:26 -0500 |
commit | dfe8db22372873d205c78a9fd5370b1b088a2b87 (patch) | |
tree | a2d0d68121caad20e1cd01ca9707c03d92d8adb9 | |
parent | ccffc9ebfa66e3f2cc5e17b2579202786050b32e (diff) | |
parent | 30a3317ddc2427d173d8bcffaa3f41a61eb66560 (diff) |
Merge tag 'drm-misc-fixes-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes
Fixes for 4.16. I contains fixes for deadlock on runtime suspend on few
drivers, a memory leak on non-blocking commits, a crash on color-eviction.
The is also meson and edid fixes, plus a fix for a doc warning.
* tag 'drm-misc-fixes-2018-02-21' of git://anongit.freedesktop.org/drm/drm-misc:
drm/tve200: fix kernel-doc documentation comment include
drm/meson: fix vsync buffer update
drm: Handle unexpected holes in color-eviction
drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA
drm/amdgpu: Fix deadlock on runtime suspend
drm/radeon: Fix deadlock on runtime suspend
drm/nouveau: Fix deadlock on runtime suspend
drm: Allow determining if current task is output poll worker
workqueue: Allow retrieval of current task's work struct
drm/atomic: Fix memleak on ERESTARTSYS during non-blocking commits
-rw-r--r-- | Documentation/gpu/tve200.rst | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 58 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_mm.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_probe_helper.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/meson/meson_crtc.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/meson/meson_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/meson/meson_plane.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 74 | ||||
-rw-r--r-- | include/drm/drm_atomic.h | 9 | ||||
-rw-r--r-- | include/drm/drm_crtc_helper.h | 1 | ||||
-rw-r--r-- | include/linux/workqueue.h | 1 | ||||
-rw-r--r-- | kernel/workqueue.c | 16 |
15 files changed, 196 insertions, 58 deletions
diff --git a/Documentation/gpu/tve200.rst b/Documentation/gpu/tve200.rst index 69b17b324e12..152ea9398f7e 100644 --- a/Documentation/gpu/tve200.rst +++ b/Documentation/gpu/tve200.rst | |||
@@ -3,4 +3,4 @@ | |||
3 | ================================== | 3 | ================================== |
4 | 4 | ||
5 | .. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c | 5 | .. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c |
6 | :doc: Faraday TV Encoder 200 | 6 | :doc: Faraday TV Encoder TVE200 DRM Driver |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 8ca3783f2deb..74d2efaec52f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | |||
@@ -736,9 +736,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) | |||
736 | enum drm_connector_status ret = connector_status_disconnected; | 736 | enum drm_connector_status ret = connector_status_disconnected; |
737 | int r; | 737 | int r; |
738 | 738 | ||
739 | r = pm_runtime_get_sync(connector->dev->dev); | 739 | if (!drm_kms_helper_is_poll_worker()) { |
740 | if (r < 0) | 740 | r = pm_runtime_get_sync(connector->dev->dev); |
741 | return connector_status_disconnected; | 741 | if (r < 0) |
742 | return connector_status_disconnected; | ||
743 | } | ||
742 | 744 | ||
743 | if (encoder) { | 745 | if (encoder) { |
744 | struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); | 746 | struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); |
@@ -757,8 +759,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) | |||
757 | /* check acpi lid status ??? */ | 759 | /* check acpi lid status ??? */ |
758 | 760 | ||
759 | amdgpu_connector_update_scratch_regs(connector, ret); | 761 | amdgpu_connector_update_scratch_regs(connector, ret); |
760 | pm_runtime_mark_last_busy(connector->dev->dev); | 762 | |
761 | pm_runtime_put_autosuspend(connector->dev->dev); | 763 | if (!drm_kms_helper_is_poll_worker()) { |
764 | pm_runtime_mark_last_busy(connector->dev->dev); | ||
765 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
766 | } | ||
767 | |||
762 | return ret; | 768 | return ret; |
763 | } | 769 | } |
764 | 770 | ||
@@ -868,9 +874,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) | |||
868 | enum drm_connector_status ret = connector_status_disconnected; | 874 | enum drm_connector_status ret = connector_status_disconnected; |
869 | int r; | 875 | int r; |
870 | 876 | ||
871 | r = pm_runtime_get_sync(connector->dev->dev); | 877 | if (!drm_kms_helper_is_poll_worker()) { |
872 | if (r < 0) | 878 | r = pm_runtime_get_sync(connector->dev->dev); |
873 | return connector_status_disconnected; | 879 | if (r < 0) |
880 | return connector_status_disconnected; | ||
881 | } | ||
874 | 882 | ||
875 | encoder = amdgpu_connector_best_single_encoder(connector); | 883 | encoder = amdgpu_connector_best_single_encoder(connector); |
876 | if (!encoder) | 884 | if (!encoder) |
@@ -924,8 +932,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) | |||
924 | amdgpu_connector_update_scratch_regs(connector, ret); | 932 | amdgpu_connector_update_scratch_regs(connector, ret); |
925 | 933 | ||
926 | out: | 934 | out: |
927 | pm_runtime_mark_last_busy(connector->dev->dev); | 935 | if (!drm_kms_helper_is_poll_worker()) { |
928 | pm_runtime_put_autosuspend(connector->dev->dev); | 936 | pm_runtime_mark_last_busy(connector->dev->dev); |
937 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
938 | } | ||
929 | 939 | ||
930 | return ret; | 940 | return ret; |
931 | } | 941 | } |
@@ -988,9 +998,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) | |||
988 | enum drm_connector_status ret = connector_status_disconnected; | 998 | enum drm_connector_status ret = connector_status_disconnected; |
989 | bool dret = false, broken_edid = false; | 999 | bool dret = false, broken_edid = false; |
990 | 1000 | ||
991 | r = pm_runtime_get_sync(connector->dev->dev); | 1001 | if (!drm_kms_helper_is_poll_worker()) { |
992 | if (r < 0) | 1002 | r = pm_runtime_get_sync(connector->dev->dev); |
993 | return connector_status_disconnected; | 1003 | if (r < 0) |
1004 | return connector_status_disconnected; | ||
1005 | } | ||
994 | 1006 | ||
995 | if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { | 1007 | if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { |
996 | ret = connector->status; | 1008 | ret = connector->status; |
@@ -1115,8 +1127,10 @@ out: | |||
1115 | amdgpu_connector_update_scratch_regs(connector, ret); | 1127 | amdgpu_connector_update_scratch_regs(connector, ret); |
1116 | 1128 | ||
1117 | exit: | 1129 | exit: |
1118 | pm_runtime_mark_last_busy(connector->dev->dev); | 1130 | if (!drm_kms_helper_is_poll_worker()) { |
1119 | pm_runtime_put_autosuspend(connector->dev->dev); | 1131 | pm_runtime_mark_last_busy(connector->dev->dev); |
1132 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
1133 | } | ||
1120 | 1134 | ||
1121 | return ret; | 1135 | return ret; |
1122 | } | 1136 | } |
@@ -1359,9 +1373,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) | |||
1359 | struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); | 1373 | struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); |
1360 | int r; | 1374 | int r; |
1361 | 1375 | ||
1362 | r = pm_runtime_get_sync(connector->dev->dev); | 1376 | if (!drm_kms_helper_is_poll_worker()) { |
1363 | if (r < 0) | 1377 | r = pm_runtime_get_sync(connector->dev->dev); |
1364 | return connector_status_disconnected; | 1378 | if (r < 0) |
1379 | return connector_status_disconnected; | ||
1380 | } | ||
1365 | 1381 | ||
1366 | if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { | 1382 | if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { |
1367 | ret = connector->status; | 1383 | ret = connector->status; |
@@ -1429,8 +1445,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) | |||
1429 | 1445 | ||
1430 | amdgpu_connector_update_scratch_regs(connector, ret); | 1446 | amdgpu_connector_update_scratch_regs(connector, ret); |
1431 | out: | 1447 | out: |
1432 | pm_runtime_mark_last_busy(connector->dev->dev); | 1448 | if (!drm_kms_helper_is_poll_worker()) { |
1433 | pm_runtime_put_autosuspend(connector->dev->dev); | 1449 | pm_runtime_mark_last_busy(connector->dev->dev); |
1450 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
1451 | } | ||
1434 | 1452 | ||
1435 | return ret; | 1453 | return ret; |
1436 | } | 1454 | } |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ab4032167094..ae3cbfe9e01c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, | |||
1878 | new_crtc_state->event->base.completion = &commit->flip_done; | 1878 | new_crtc_state->event->base.completion = &commit->flip_done; |
1879 | new_crtc_state->event->base.completion_release = release_crtc_commit; | 1879 | new_crtc_state->event->base.completion_release = release_crtc_commit; |
1880 | drm_crtc_commit_get(commit); | 1880 | drm_crtc_commit_get(commit); |
1881 | |||
1882 | commit->abort_completion = true; | ||
1881 | } | 1883 | } |
1882 | 1884 | ||
1883 | for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { | 1885 | for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { |
@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); | |||
3421 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) | 3423 | void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) |
3422 | { | 3424 | { |
3423 | if (state->commit) { | 3425 | if (state->commit) { |
3426 | /* | ||
3427 | * In the event that a non-blocking commit returns | ||
3428 | * -ERESTARTSYS before the commit_tail work is queued, we will | ||
3429 | * have an extra reference to the commit object. Release it, if | ||
3430 | * the event has not been consumed by the worker. | ||
3431 | * | ||
3432 | * state->event may be freed, so we can't directly look at | ||
3433 | * state->event->base.completion. | ||
3434 | */ | ||
3435 | if (state->event && state->commit->abort_completion) | ||
3436 | drm_crtc_commit_put(state->commit); | ||
3437 | |||
3424 | kfree(state->commit->event); | 3438 | kfree(state->commit->event); |
3425 | state->commit->event = NULL; | 3439 | state->commit->event = NULL; |
3440 | |||
3426 | drm_crtc_commit_put(state->commit); | 3441 | drm_crtc_commit_put(state->commit); |
3427 | } | 3442 | } |
3428 | 3443 | ||
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9796c29dc004..4f751a9d71a3 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -113,6 +113,9 @@ static const struct edid_quirk { | |||
113 | /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ | 113 | /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ |
114 | { "AEO", 0, EDID_QUIRK_FORCE_6BPC }, | 114 | { "AEO", 0, EDID_QUIRK_FORCE_6BPC }, |
115 | 115 | ||
116 | /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ | ||
117 | { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, | ||
118 | |||
116 | /* Belinea 10 15 55 */ | 119 | /* Belinea 10 15 55 */ |
117 | { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, | 120 | { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, |
118 | { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, | 121 | { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, |
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 186c4e90cc1c..89eef1bb4ddc 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
@@ -836,9 +836,24 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan) | |||
836 | if (!mm->color_adjust) | 836 | if (!mm->color_adjust) |
837 | return NULL; | 837 | return NULL; |
838 | 838 | ||
839 | hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack); | 839 | /* |
840 | hole_start = __drm_mm_hole_node_start(hole); | 840 | * The hole found during scanning should ideally be the first element |
841 | hole_end = hole_start + hole->hole_size; | 841 | * in the hole_stack list, but due to side-effects in the driver it |
842 | * may not be. | ||
843 | */ | ||
844 | list_for_each_entry(hole, &mm->hole_stack, hole_stack) { | ||
845 | hole_start = __drm_mm_hole_node_start(hole); | ||
846 | hole_end = hole_start + hole->hole_size; | ||
847 | |||
848 | if (hole_start <= scan->hit_start && | ||
849 | hole_end >= scan->hit_end) | ||
850 | break; | ||
851 | } | ||
852 | |||
853 | /* We should only be called after we found the hole previously */ | ||
854 | DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack); | ||
855 | if (unlikely(&hole->hole_stack == &mm->hole_stack)) | ||
856 | return NULL; | ||
842 | 857 | ||
843 | DRM_MM_BUG_ON(hole_start > scan->hit_start); | 858 | DRM_MM_BUG_ON(hole_start > scan->hit_start); |
844 | DRM_MM_BUG_ON(hole_end < scan->hit_end); | 859 | DRM_MM_BUG_ON(hole_end < scan->hit_end); |
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 555fbe54d6e2..00b8445ba819 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c | |||
@@ -654,6 +654,26 @@ out: | |||
654 | } | 654 | } |
655 | 655 | ||
656 | /** | 656 | /** |
657 | * drm_kms_helper_is_poll_worker - is %current task an output poll worker? | ||
658 | * | ||
659 | * Determine if %current task is an output poll worker. This can be used | ||
660 | * to select distinct code paths for output polling versus other contexts. | ||
661 | * | ||
662 | * One use case is to avoid a deadlock between the output poll worker and | ||
663 | * the autosuspend worker wherein the latter waits for polling to finish | ||
664 | * upon calling drm_kms_helper_poll_disable(), while the former waits for | ||
665 | * runtime suspend to finish upon calling pm_runtime_get_sync() in a | ||
666 | * connector ->detect hook. | ||
667 | */ | ||
668 | bool drm_kms_helper_is_poll_worker(void) | ||
669 | { | ||
670 | struct work_struct *work = current_work(); | ||
671 | |||
672 | return work && work->func == output_poll_execute; | ||
673 | } | ||
674 | EXPORT_SYMBOL(drm_kms_helper_is_poll_worker); | ||
675 | |||
676 | /** | ||
657 | * drm_kms_helper_poll_disable - disable output polling | 677 | * drm_kms_helper_poll_disable - disable output polling |
658 | * @dev: drm_device | 678 | * @dev: drm_device |
659 | * | 679 | * |
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 5155f0179b61..05520202c967 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "meson_venc.h" | 36 | #include "meson_venc.h" |
37 | #include "meson_vpp.h" | 37 | #include "meson_vpp.h" |
38 | #include "meson_viu.h" | 38 | #include "meson_viu.h" |
39 | #include "meson_canvas.h" | ||
39 | #include "meson_registers.h" | 40 | #include "meson_registers.h" |
40 | 41 | ||
41 | /* CRTC definition */ | 42 | /* CRTC definition */ |
@@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv) | |||
192 | } else | 193 | } else |
193 | meson_vpp_disable_interlace_vscaler_osd1(priv); | 194 | meson_vpp_disable_interlace_vscaler_osd1(priv); |
194 | 195 | ||
196 | meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, | ||
197 | priv->viu.osd1_addr, priv->viu.osd1_stride, | ||
198 | priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, | ||
199 | MESON_CANVAS_BLKMODE_LINEAR); | ||
200 | |||
195 | /* Enable OSD1 */ | 201 | /* Enable OSD1 */ |
196 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, | 202 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, |
197 | priv->io_base + _REG(VPP_MISC)); | 203 | priv->io_base + _REG(VPP_MISC)); |
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 5e8b392b9d1f..8450d6ac8c9b 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h | |||
@@ -43,6 +43,9 @@ struct meson_drm { | |||
43 | bool osd1_commit; | 43 | bool osd1_commit; |
44 | uint32_t osd1_ctrl_stat; | 44 | uint32_t osd1_ctrl_stat; |
45 | uint32_t osd1_blk0_cfg[5]; | 45 | uint32_t osd1_blk0_cfg[5]; |
46 | uint32_t osd1_addr; | ||
47 | uint32_t osd1_stride; | ||
48 | uint32_t osd1_height; | ||
46 | } viu; | 49 | } viu; |
47 | 50 | ||
48 | struct { | 51 | struct { |
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index d0a6ac8390f3..27bd3503e1e4 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c | |||
@@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane, | |||
164 | /* Update Canvas with buffer address */ | 164 | /* Update Canvas with buffer address */ |
165 | gem = drm_fb_cma_get_gem_obj(fb, 0); | 165 | gem = drm_fb_cma_get_gem_obj(fb, 0); |
166 | 166 | ||
167 | meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, | 167 | priv->viu.osd1_addr = gem->paddr; |
168 | gem->paddr, fb->pitches[0], | 168 | priv->viu.osd1_stride = fb->pitches[0]; |
169 | fb->height, MESON_CANVAS_WRAP_NONE, | 169 | priv->viu.osd1_height = fb->height; |
170 | MESON_CANVAS_BLKMODE_LINEAR); | ||
171 | 170 | ||
172 | spin_unlock_irqrestore(&priv->drm->event_lock, flags); | 171 | spin_unlock_irqrestore(&priv->drm->event_lock, flags); |
173 | } | 172 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 69d6e61a01ec..6ed9cb053dfa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
@@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) | |||
570 | nv_connector->edid = NULL; | 570 | nv_connector->edid = NULL; |
571 | } | 571 | } |
572 | 572 | ||
573 | ret = pm_runtime_get_sync(connector->dev->dev); | 573 | /* Outputs are only polled while runtime active, so acquiring a |
574 | if (ret < 0 && ret != -EACCES) | 574 | * runtime PM ref here is unnecessary (and would deadlock upon |
575 | return conn_status; | 575 | * runtime suspend because it waits for polling to finish). |
576 | */ | ||
577 | if (!drm_kms_helper_is_poll_worker()) { | ||
578 | ret = pm_runtime_get_sync(connector->dev->dev); | ||
579 | if (ret < 0 && ret != -EACCES) | ||
580 | return conn_status; | ||
581 | } | ||
576 | 582 | ||
577 | nv_encoder = nouveau_connector_ddc_detect(connector); | 583 | nv_encoder = nouveau_connector_ddc_detect(connector); |
578 | if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { | 584 | if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { |
@@ -647,8 +653,10 @@ detect_analog: | |||
647 | 653 | ||
648 | out: | 654 | out: |
649 | 655 | ||
650 | pm_runtime_mark_last_busy(connector->dev->dev); | 656 | if (!drm_kms_helper_is_poll_worker()) { |
651 | pm_runtime_put_autosuspend(connector->dev->dev); | 657 | pm_runtime_mark_last_busy(connector->dev->dev); |
658 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
659 | } | ||
652 | 660 | ||
653 | return conn_status; | 661 | return conn_status; |
654 | } | 662 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 5012f5e47a1e..2e2ca3c6b47d 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -899,9 +899,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) | |||
899 | enum drm_connector_status ret = connector_status_disconnected; | 899 | enum drm_connector_status ret = connector_status_disconnected; |
900 | int r; | 900 | int r; |
901 | 901 | ||
902 | r = pm_runtime_get_sync(connector->dev->dev); | 902 | if (!drm_kms_helper_is_poll_worker()) { |
903 | if (r < 0) | 903 | r = pm_runtime_get_sync(connector->dev->dev); |
904 | return connector_status_disconnected; | 904 | if (r < 0) |
905 | return connector_status_disconnected; | ||
906 | } | ||
905 | 907 | ||
906 | if (encoder) { | 908 | if (encoder) { |
907 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 909 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
@@ -924,8 +926,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) | |||
924 | /* check acpi lid status ??? */ | 926 | /* check acpi lid status ??? */ |
925 | 927 | ||
926 | radeon_connector_update_scratch_regs(connector, ret); | 928 | radeon_connector_update_scratch_regs(connector, ret); |
927 | pm_runtime_mark_last_busy(connector->dev->dev); | 929 | |
928 | pm_runtime_put_autosuspend(connector->dev->dev); | 930 | if (!drm_kms_helper_is_poll_worker()) { |
931 | pm_runtime_mark_last_busy(connector->dev->dev); | ||
932 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
933 | } | ||
934 | |||
929 | return ret; | 935 | return ret; |
930 | } | 936 | } |
931 | 937 | ||
@@ -1039,9 +1045,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force) | |||
1039 | enum drm_connector_status ret = connector_status_disconnected; | 1045 | enum drm_connector_status ret = connector_status_disconnected; |
1040 | int r; | 1046 | int r; |
1041 | 1047 | ||
1042 | r = pm_runtime_get_sync(connector->dev->dev); | 1048 | if (!drm_kms_helper_is_poll_worker()) { |
1043 | if (r < 0) | 1049 | r = pm_runtime_get_sync(connector->dev->dev); |
1044 | return connector_status_disconnected; | 1050 | if (r < 0) |
1051 | return connector_status_disconnected; | ||
1052 | } | ||
1045 | 1053 | ||
1046 | encoder = radeon_best_single_encoder(connector); | 1054 | encoder = radeon_best_single_encoder(connector); |
1047 | if (!encoder) | 1055 | if (!encoder) |
@@ -1108,8 +1116,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force) | |||
1108 | radeon_connector_update_scratch_regs(connector, ret); | 1116 | radeon_connector_update_scratch_regs(connector, ret); |
1109 | 1117 | ||
1110 | out: | 1118 | out: |
1111 | pm_runtime_mark_last_busy(connector->dev->dev); | 1119 | if (!drm_kms_helper_is_poll_worker()) { |
1112 | pm_runtime_put_autosuspend(connector->dev->dev); | 1120 | pm_runtime_mark_last_busy(connector->dev->dev); |
1121 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
1122 | } | ||
1113 | 1123 | ||
1114 | return ret; | 1124 | return ret; |
1115 | } | 1125 | } |
@@ -1173,9 +1183,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force) | |||
1173 | if (!radeon_connector->dac_load_detect) | 1183 | if (!radeon_connector->dac_load_detect) |
1174 | return ret; | 1184 | return ret; |
1175 | 1185 | ||
1176 | r = pm_runtime_get_sync(connector->dev->dev); | 1186 | if (!drm_kms_helper_is_poll_worker()) { |
1177 | if (r < 0) | 1187 | r = pm_runtime_get_sync(connector->dev->dev); |
1178 | return connector_status_disconnected; | 1188 | if (r < 0) |
1189 | return connector_status_disconnected; | ||
1190 | } | ||
1179 | 1191 | ||
1180 | encoder = radeon_best_single_encoder(connector); | 1192 | encoder = radeon_best_single_encoder(connector); |
1181 | if (!encoder) | 1193 | if (!encoder) |
@@ -1187,8 +1199,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force) | |||
1187 | if (ret == connector_status_connected) | 1199 | if (ret == connector_status_connected) |
1188 | ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); | 1200 | ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); |
1189 | radeon_connector_update_scratch_regs(connector, ret); | 1201 | radeon_connector_update_scratch_regs(connector, ret); |
1190 | pm_runtime_mark_last_busy(connector->dev->dev); | 1202 | |
1191 | pm_runtime_put_autosuspend(connector->dev->dev); | 1203 | if (!drm_kms_helper_is_poll_worker()) { |
1204 | pm_runtime_mark_last_busy(connector->dev->dev); | ||
1205 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
1206 | } | ||
1207 | |||
1192 | return ret; | 1208 | return ret; |
1193 | } | 1209 | } |
1194 | 1210 | ||
@@ -1251,9 +1267,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) | |||
1251 | enum drm_connector_status ret = connector_status_disconnected; | 1267 | enum drm_connector_status ret = connector_status_disconnected; |
1252 | bool dret = false, broken_edid = false; | 1268 | bool dret = false, broken_edid = false; |
1253 | 1269 | ||
1254 | r = pm_runtime_get_sync(connector->dev->dev); | 1270 | if (!drm_kms_helper_is_poll_worker()) { |
1255 | if (r < 0) | 1271 | r = pm_runtime_get_sync(connector->dev->dev); |
1256 | return connector_status_disconnected; | 1272 | if (r < 0) |
1273 | return connector_status_disconnected; | ||
1274 | } | ||
1257 | 1275 | ||
1258 | if (radeon_connector->detected_hpd_without_ddc) { | 1276 | if (radeon_connector->detected_hpd_without_ddc) { |
1259 | force = true; | 1277 | force = true; |
@@ -1436,8 +1454,10 @@ out: | |||
1436 | } | 1454 | } |
1437 | 1455 | ||
1438 | exit: | 1456 | exit: |
1439 | pm_runtime_mark_last_busy(connector->dev->dev); | 1457 | if (!drm_kms_helper_is_poll_worker()) { |
1440 | pm_runtime_put_autosuspend(connector->dev->dev); | 1458 | pm_runtime_mark_last_busy(connector->dev->dev); |
1459 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
1460 | } | ||
1441 | 1461 | ||
1442 | return ret; | 1462 | return ret; |
1443 | } | 1463 | } |
@@ -1688,9 +1708,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) | |||
1688 | if (radeon_dig_connector->is_mst) | 1708 | if (radeon_dig_connector->is_mst) |
1689 | return connector_status_disconnected; | 1709 | return connector_status_disconnected; |
1690 | 1710 | ||
1691 | r = pm_runtime_get_sync(connector->dev->dev); | 1711 | if (!drm_kms_helper_is_poll_worker()) { |
1692 | if (r < 0) | 1712 | r = pm_runtime_get_sync(connector->dev->dev); |
1693 | return connector_status_disconnected; | 1713 | if (r < 0) |
1714 | return connector_status_disconnected; | ||
1715 | } | ||
1694 | 1716 | ||
1695 | if (!force && radeon_check_hpd_status_unchanged(connector)) { | 1717 | if (!force && radeon_check_hpd_status_unchanged(connector)) { |
1696 | ret = connector->status; | 1718 | ret = connector->status; |
@@ -1777,8 +1799,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) | |||
1777 | } | 1799 | } |
1778 | 1800 | ||
1779 | out: | 1801 | out: |
1780 | pm_runtime_mark_last_busy(connector->dev->dev); | 1802 | if (!drm_kms_helper_is_poll_worker()) { |
1781 | pm_runtime_put_autosuspend(connector->dev->dev); | 1803 | pm_runtime_mark_last_busy(connector->dev->dev); |
1804 | pm_runtime_put_autosuspend(connector->dev->dev); | ||
1805 | } | ||
1782 | 1806 | ||
1783 | return ret; | 1807 | return ret; |
1784 | } | 1808 | } |
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 1c27526c499e..cf13842a6dbd 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
@@ -134,6 +134,15 @@ struct drm_crtc_commit { | |||
134 | * &drm_pending_vblank_event pointer to clean up private events. | 134 | * &drm_pending_vblank_event pointer to clean up private events. |
135 | */ | 135 | */ |
136 | struct drm_pending_vblank_event *event; | 136 | struct drm_pending_vblank_event *event; |
137 | |||
138 | /** | ||
139 | * @abort_completion: | ||
140 | * | ||
141 | * A flag that's set after drm_atomic_helper_setup_commit takes a second | ||
142 | * reference for the completion of $drm_crtc_state.event. It's used by | ||
143 | * the free code to remove the second reference if commit fails. | ||
144 | */ | ||
145 | bool abort_completion; | ||
137 | }; | 146 | }; |
138 | 147 | ||
139 | struct __drm_planes_state { | 148 | struct __drm_planes_state { |
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 76e237bd989b..6914633037a5 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h | |||
@@ -77,5 +77,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev); | |||
77 | 77 | ||
78 | void drm_kms_helper_poll_disable(struct drm_device *dev); | 78 | void drm_kms_helper_poll_disable(struct drm_device *dev); |
79 | void drm_kms_helper_poll_enable(struct drm_device *dev); | 79 | void drm_kms_helper_poll_enable(struct drm_device *dev); |
80 | bool drm_kms_helper_is_poll_worker(void); | ||
80 | 81 | ||
81 | #endif | 82 | #endif |
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 4a54ef96aff5..bc0cda180c8b 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h | |||
@@ -465,6 +465,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork); | |||
465 | 465 | ||
466 | extern void workqueue_set_max_active(struct workqueue_struct *wq, | 466 | extern void workqueue_set_max_active(struct workqueue_struct *wq, |
467 | int max_active); | 467 | int max_active); |
468 | extern struct work_struct *current_work(void); | ||
468 | extern bool current_is_workqueue_rescuer(void); | 469 | extern bool current_is_workqueue_rescuer(void); |
469 | extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); | 470 | extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); |
470 | extern unsigned int work_busy(struct work_struct *work); | 471 | extern unsigned int work_busy(struct work_struct *work); |
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 017044c26233..bb9a519cbf50 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -4180,6 +4180,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) | |||
4180 | EXPORT_SYMBOL_GPL(workqueue_set_max_active); | 4180 | EXPORT_SYMBOL_GPL(workqueue_set_max_active); |
4181 | 4181 | ||
4182 | /** | 4182 | /** |
4183 | * current_work - retrieve %current task's work struct | ||
4184 | * | ||
4185 | * Determine if %current task is a workqueue worker and what it's working on. | ||
4186 | * Useful to find out the context that the %current task is running in. | ||
4187 | * | ||
4188 | * Return: work struct if %current task is a workqueue worker, %NULL otherwise. | ||
4189 | */ | ||
4190 | struct work_struct *current_work(void) | ||
4191 | { | ||
4192 | struct worker *worker = current_wq_worker(); | ||
4193 | |||
4194 | return worker ? worker->current_work : NULL; | ||
4195 | } | ||
4196 | EXPORT_SYMBOL(current_work); | ||
4197 | |||
4198 | /** | ||
4183 | * current_is_workqueue_rescuer - is %current workqueue rescuer? | 4199 | * current_is_workqueue_rescuer - is %current workqueue rescuer? |
4184 | * | 4200 | * |
4185 | * Determine whether %current is a workqueue rescuer. Can be used from | 4201 | * Determine whether %current is a workqueue rescuer. Can be used from |