From 757fffcfdffb6c0dd46c1b264091c36b4e5a86ae Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Nov 2017 15:36:22 +0200 Subject: [PATCH] drm/i915: Put all non-blocking modesets onto an ordered wq MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit We have plenty of global registers and whatnot programmed without any further locking by the modeset code. Currently non-bocking modesets are allowed to execute in parallel which could corrupt said registers. To avoid the problem let's run all non-blocking modesets on an ordered workqueue. We still put page flips etc. to system_unbound_wq allowing page flips on one pipe to execute in parallel with page flips or a modeset on a another pipe (assuming no known state is shared between them, at which point they would have been added to the same atomic commit and serialized that way). Blocking modesets are already serialized with each other by connection_mutex, and thus are safe. To serialize them with non-blocking modesets we just flush the workqueue before executing blocking modesets. Cc: Daniel Vetter Cc: Maarten Lankhorst Fixes: 94f050246b42 ("drm/i915: nonblocking commit") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171113133622.8593-1-ville.syrjala@linux.intel.com Acked-by: Daniel Vetter Reviewed-by: Maarten Lankhorst --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4b943cd..19df7b72 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1960,6 +1960,9 @@ struct drm_i915_private { */ struct workqueue_struct *wq; + /* ordered wq for modesets */ + struct workqueue_struct *modeset_wq; + /* Display functions */ struct drm_i915_display_funcs display; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b3bde22..0cd3559 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12483,11 +12483,15 @@ static int intel_atomic_commit(struct drm_device *dev, INIT_WORK(&state->commit_work, intel_atomic_commit_work); i915_sw_fence_commit(&intel_state->commit_ready); - if (nonblock) + if (nonblock && intel_state->modeset) { + queue_work(dev_priv->modeset_wq, &state->commit_work); + } else if (nonblock) { queue_work(system_unbound_wq, &state->commit_work); - else + } else { + if (intel_state->modeset) + flush_workqueue(dev_priv->modeset_wq); intel_atomic_commit_tail(state); - + } return 0; } @@ -14450,6 +14454,8 @@ int intel_modeset_init(struct drm_device *dev) enum pipe pipe; struct intel_crtc *crtc; + dev_priv->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0); + drm_mode_config_init(dev); dev->mode_config.min_width = 0; @@ -15254,6 +15260,8 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_cleanup_gt_powersave(dev_priv); intel_teardown_gmbus(dev_priv); + + destroy_workqueue(dev_priv->modeset_wq); } void intel_connector_attach_encoder(struct intel_connector *connector, -- 2.7.4