Skip to content

Commit

Permalink
Merge tag 'drm-misc-fixes-2018-02-21' of git://anongit.freedesktop.or…
Browse files Browse the repository at this point in the history
…g/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
  • Loading branch information
airlied committed Feb 21, 2018
2 parents ccffc9e + 30a3317 commit dfe8db2
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 58 deletions.
2 changes: 1 addition & 1 deletion Documentation/gpu/tve200.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
==================================

.. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c
:doc: Faraday TV Encoder 200
:doc: Faraday TV Encoder TVE200 DRM Driver
58 changes: 38 additions & 20 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,9 +736,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected;
int r;

r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
}

if (encoder) {
struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
Expand All @@ -757,8 +759,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
/* check acpi lid status ??? */

amdgpu_connector_update_scratch_regs(connector, ret);
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);

if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
}

return ret;
}

Expand Down Expand Up @@ -868,9 +874,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected;
int r;

r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
}

encoder = amdgpu_connector_best_single_encoder(connector);
if (!encoder)
Expand Down Expand Up @@ -924,8 +932,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
amdgpu_connector_update_scratch_regs(connector, ret);

out:
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
}

return ret;
}
Expand Down Expand Up @@ -988,9 +998,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected;
bool dret = false, broken_edid = false;

r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
}

if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
ret = connector->status;
Expand Down Expand Up @@ -1115,8 +1127,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
amdgpu_connector_update_scratch_regs(connector, ret);

exit:
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
}

return ret;
}
Expand Down Expand Up @@ -1359,9 +1373,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
int r;

r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
if (!drm_kms_helper_is_poll_worker()) {
r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
}

if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
ret = connector->status;
Expand Down Expand Up @@ -1429,8 +1445,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)

amdgpu_connector_update_scratch_regs(connector, ret);
out:
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
}

return ret;
}
Expand Down
15 changes: 15 additions & 0 deletions drivers/gpu/drm/drm_atomic_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
new_crtc_state->event->base.completion = &commit->flip_done;
new_crtc_state->event->base.completion_release = release_crtc_commit;
drm_crtc_commit_get(commit);

commit->abort_completion = true;
}

for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
Expand Down Expand Up @@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
{
if (state->commit) {
/*
* In the event that a non-blocking commit returns
* -ERESTARTSYS before the commit_tail work is queued, we will
* have an extra reference to the commit object. Release it, if
* the event has not been consumed by the worker.
*
* state->event may be freed, so we can't directly look at
* state->event->base.completion.
*/
if (state->event && state->commit->abort_completion)
drm_crtc_commit_put(state->commit);

kfree(state->commit->event);
state->commit->event = NULL;

drm_crtc_commit_put(state->commit);
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ static const struct edid_quirk {
/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
{ "AEO", 0, EDID_QUIRK_FORCE_6BPC },

/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
{ "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },

/* Belinea 10 15 55 */
{ "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
{ "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
Expand Down
21 changes: 18 additions & 3 deletions drivers/gpu/drm/drm_mm.c
Original file line number Diff line number Diff line change
Expand Up @@ -836,9 +836,24 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)
if (!mm->color_adjust)
return NULL;

hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack);
hole_start = __drm_mm_hole_node_start(hole);
hole_end = hole_start + hole->hole_size;
/*
* The hole found during scanning should ideally be the first element
* in the hole_stack list, but due to side-effects in the driver it
* may not be.
*/
list_for_each_entry(hole, &mm->hole_stack, hole_stack) {
hole_start = __drm_mm_hole_node_start(hole);
hole_end = hole_start + hole->hole_size;

if (hole_start <= scan->hit_start &&
hole_end >= scan->hit_end)
break;
}

/* We should only be called after we found the hole previously */
DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack);
if (unlikely(&hole->hole_stack == &mm->hole_stack))
return NULL;

DRM_MM_BUG_ON(hole_start > scan->hit_start);
DRM_MM_BUG_ON(hole_end < scan->hit_end);
Expand Down
20 changes: 20 additions & 0 deletions drivers/gpu/drm/drm_probe_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,26 @@ static void output_poll_execute(struct work_struct *work)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
}

/**
* drm_kms_helper_is_poll_worker - is %current task an output poll worker?
*
* Determine if %current task is an output poll worker. This can be used
* to select distinct code paths for output polling versus other contexts.
*
* One use case is to avoid a deadlock between the output poll worker and
* the autosuspend worker wherein the latter waits for polling to finish
* upon calling drm_kms_helper_poll_disable(), while the former waits for
* runtime suspend to finish upon calling pm_runtime_get_sync() in a
* connector ->detect hook.
*/
bool drm_kms_helper_is_poll_worker(void)
{
struct work_struct *work = current_work();

return work && work->func == output_poll_execute;
}
EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);

/**
* drm_kms_helper_poll_disable - disable output polling
* @dev: drm_device
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/meson/meson_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "meson_venc.h"
#include "meson_vpp.h"
#include "meson_viu.h"
#include "meson_canvas.h"
#include "meson_registers.h"

/* CRTC definition */
Expand Down Expand Up @@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv)
} else
meson_vpp_disable_interlace_vscaler_osd1(priv);

meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
priv->viu.osd1_addr, priv->viu.osd1_stride,
priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
MESON_CANVAS_BLKMODE_LINEAR);

/* Enable OSD1 */
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
priv->io_base + _REG(VPP_MISC));
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/meson/meson_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ struct meson_drm {
bool osd1_commit;
uint32_t osd1_ctrl_stat;
uint32_t osd1_blk0_cfg[5];
uint32_t osd1_addr;
uint32_t osd1_stride;
uint32_t osd1_height;
} viu;

struct {
Expand Down
7 changes: 3 additions & 4 deletions drivers/gpu/drm/meson/meson_plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
/* Update Canvas with buffer address */
gem = drm_fb_cma_get_gem_obj(fb, 0);

meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
gem->paddr, fb->pitches[0],
fb->height, MESON_CANVAS_WRAP_NONE,
MESON_CANVAS_BLKMODE_LINEAR);
priv->viu.osd1_addr = gem->paddr;
priv->viu.osd1_stride = fb->pitches[0];
priv->viu.osd1_height = fb->height;

spin_unlock_irqrestore(&priv->drm->event_lock, flags);
}
Expand Down
18 changes: 13 additions & 5 deletions drivers/gpu/drm/nouveau/nouveau_connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
nv_connector->edid = NULL;
}

ret = pm_runtime_get_sync(connector->dev->dev);
if (ret < 0 && ret != -EACCES)
return conn_status;
/* Outputs are only polled while runtime active, so acquiring a
* runtime PM ref here is unnecessary (and would deadlock upon
* runtime suspend because it waits for polling to finish).
*/
if (!drm_kms_helper_is_poll_worker()) {
ret = pm_runtime_get_sync(connector->dev->dev);
if (ret < 0 && ret != -EACCES)
return conn_status;
}

nv_encoder = nouveau_connector_ddc_detect(connector);
if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
Expand Down Expand Up @@ -647,8 +653,10 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)

out:

pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
if (!drm_kms_helper_is_poll_worker()) {
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
}

return conn_status;
}
Expand Down
Loading

0 comments on commit dfe8db2

Please sign in to comment.