aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-11 18:35:33 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-01-20 16:17:15 -0500
commit7b24056be6db7ce907baffdd4cf142ab774ea60c (patch)
tree63ecb8c4bc549e90d0ddf7b937537a392b3060a1
parentb4d5e7d1dbdd6a758a4f7717beef7bd6b007bd66 (diff)
drm: don't hold crtc mutexes for connector ->detect callbacks
The coup de grace of the entire journey. No more dropped frames every 10s on my testbox! I've tried to audit all ->detect and ->get_modes callbacks, but things became a bit fuzzy after trying to piece together the umpteenth implemenation. Afaict most drivers just have bog-standard output register frobbing with a notch of i2c edid reading, nothing which could potentially race with the newly concurrent pageflip/set_cursor code. The big exception is load-detection code which requires a running pipe, but radeon/nouveau seem to to this without touching any state which can be observed from page_flip (e.g. disabled crtcs temporarily getting enabled and so a pageflip succeeding). The only special case I could find is the i915 load detect code. That uses the normal modeset interface to enable the load-detect crtc, and so userspace could try to squeeze in a pageflip on the load-detect pipe. So we need to grab the relevant crtc mutex in there, to avoid the temporary crtc enabling to sneak out and be visible to userspace. Note that the sysfs files already stopped grabbing the per-crtc locks, since I didn't want to bother with doing a interruptible modeset_lock_all. But since there's very little in-between breakage (essentially just the ability for userspace to pageflip on load-detect crtcs when it shouldn't on the i915 driver) I figured I don't need to bother. Reviewed-by: Rob Clark <rob@ti.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/drm_crtc.c5
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c8
-rw-r--r--drivers/gpu/drm/i915/intel_display.c10
3 files changed, 15 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index fd3e9a13b04f..9c797f6fea75 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1617,7 +1617,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
1617 1617
1618 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 1618 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
1619 1619
1620 drm_modeset_lock_all(dev); 1620 mutex_lock(&dev->mode_config.mutex);
1621 1621
1622 obj = drm_mode_object_find(dev, out_resp->connector_id, 1622 obj = drm_mode_object_find(dev, out_resp->connector_id,
1623 DRM_MODE_OBJECT_CONNECTOR); 1623 DRM_MODE_OBJECT_CONNECTOR);
@@ -1714,7 +1714,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
1714 out_resp->count_encoders = encoders_count; 1714 out_resp->count_encoders = encoders_count;
1715 1715
1716out: 1716out:
1717 drm_modeset_unlock_all(dev); 1717 mutex_unlock(&dev->mode_config.mutex);
1718
1718 return ret; 1719 return ret;
1719} 1720}
1720 1721
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 400ef86a2b43..7b2d378b2576 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -980,7 +980,7 @@ static void output_poll_execute(struct work_struct *work)
980 if (!drm_kms_helper_poll) 980 if (!drm_kms_helper_poll)
981 return; 981 return;
982 982
983 drm_modeset_lock_all(dev); 983 mutex_lock(&dev->mode_config.mutex);
984 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 984 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
985 985
986 /* Ignore forced connectors. */ 986 /* Ignore forced connectors. */
@@ -1010,7 +1010,7 @@ static void output_poll_execute(struct work_struct *work)
1010 changed = true; 1010 changed = true;
1011 } 1011 }
1012 1012
1013 drm_modeset_unlock_all(dev); 1013 mutex_unlock(&dev->mode_config.mutex);
1014 1014
1015 if (changed) 1015 if (changed)
1016 drm_kms_helper_hotplug_event(dev); 1016 drm_kms_helper_hotplug_event(dev);
@@ -1070,7 +1070,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
1070 if (!dev->mode_config.poll_enabled) 1070 if (!dev->mode_config.poll_enabled)
1071 return; 1071 return;
1072 1072
1073 drm_modeset_lock_all(dev); 1073 mutex_lock(&dev->mode_config.mutex);
1074 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1074 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1075 1075
1076 /* Only handle HPD capable connectors. */ 1076 /* Only handle HPD capable connectors. */
@@ -1088,7 +1088,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
1088 changed = true; 1088 changed = true;
1089 } 1089 }
1090 1090
1091 drm_modeset_unlock_all(dev); 1091 mutex_unlock(&dev->mode_config.mutex);
1092 1092
1093 if (changed) 1093 if (changed)
1094 drm_kms_helper_hotplug_event(dev); 1094 drm_kms_helper_hotplug_event(dev);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index df51203dcebd..c8f417b34d1a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6700,6 +6700,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
6700 if (encoder->crtc) { 6700 if (encoder->crtc) {
6701 crtc = encoder->crtc; 6701 crtc = encoder->crtc;
6702 6702
6703 mutex_lock(&crtc->mutex);
6704
6703 old->dpms_mode = connector->dpms; 6705 old->dpms_mode = connector->dpms;
6704 old->load_detect_temp = false; 6706 old->load_detect_temp = false;
6705 6707
@@ -6729,6 +6731,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
6729 return false; 6731 return false;
6730 } 6732 }
6731 6733
6734 mutex_lock(&crtc->mutex);
6732 intel_encoder->new_crtc = to_intel_crtc(crtc); 6735 intel_encoder->new_crtc = to_intel_crtc(crtc);
6733 to_intel_connector(connector)->new_encoder = intel_encoder; 6736 to_intel_connector(connector)->new_encoder = intel_encoder;
6734 6737
@@ -6756,6 +6759,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
6756 DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); 6759 DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
6757 if (IS_ERR(fb)) { 6760 if (IS_ERR(fb)) {
6758 DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); 6761 DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
6762 mutex_unlock(&crtc->mutex);
6759 return false; 6763 return false;
6760 } 6764 }
6761 6765
@@ -6763,6 +6767,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
6763 DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); 6767 DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
6764 if (old->release_fb) 6768 if (old->release_fb)
6765 old->release_fb->funcs->destroy(old->release_fb); 6769 old->release_fb->funcs->destroy(old->release_fb);
6770 mutex_unlock(&crtc->mutex);
6766 return false; 6771 return false;
6767 } 6772 }
6768 6773
@@ -6777,14 +6782,13 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
6777 struct intel_encoder *intel_encoder = 6782 struct intel_encoder *intel_encoder =
6778 intel_attached_encoder(connector); 6783 intel_attached_encoder(connector);
6779 struct drm_encoder *encoder = &intel_encoder->base; 6784 struct drm_encoder *encoder = &intel_encoder->base;
6785 struct drm_crtc *crtc = encoder->crtc;
6780 6786
6781 DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", 6787 DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
6782 connector->base.id, drm_get_connector_name(connector), 6788 connector->base.id, drm_get_connector_name(connector),
6783 encoder->base.id, drm_get_encoder_name(encoder)); 6789 encoder->base.id, drm_get_encoder_name(encoder));
6784 6790
6785 if (old->load_detect_temp) { 6791 if (old->load_detect_temp) {
6786 struct drm_crtc *crtc = encoder->crtc;
6787
6788 to_intel_connector(connector)->new_encoder = NULL; 6792 to_intel_connector(connector)->new_encoder = NULL;
6789 intel_encoder->new_crtc = NULL; 6793 intel_encoder->new_crtc = NULL;
6790 intel_set_mode(crtc, NULL, 0, 0, NULL); 6794 intel_set_mode(crtc, NULL, 0, 0, NULL);
@@ -6800,6 +6804,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
6800 /* Switch crtc and encoder back off if necessary */ 6804 /* Switch crtc and encoder back off if necessary */
6801 if (old->dpms_mode != DRM_MODE_DPMS_ON) 6805 if (old->dpms_mode != DRM_MODE_DPMS_ON)
6802 connector->funcs->dpms(connector, old->dpms_mode); 6806 connector->funcs->dpms(connector, old->dpms_mode);
6807
6808 mutex_unlock(&crtc->mutex);
6803} 6809}
6804 6810
6805/* Returns the clock of the currently programmed mode of the given pipe. */ 6811/* Returns the clock of the currently programmed mode of the given pipe. */