@@ -54,6 +54,8 @@ void drm_modeset_lock_all(struct drm_device *dev)
mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev->mode_config.connection_mutex);
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
}
@@ -72,6 +74,8 @@ void drm_modeset_unlock_all(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
mutex_unlock(&crtc->mutex);
+ mutex_unlock(&dev->mode_config.connection_mutex);
+
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_modeset_unlock_all);
@@ -93,6 +97,7 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!mutex_is_locked(&crtc->mutex));
+ WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
}
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
@@ -1799,6 +1804,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
mutex_lock(&dev->mode_config.mutex);
+ mutex_lock(&dev->mode_config.connection_mutex);
connector = drm_connector_find(dev, out_resp->connector_id);
if (!connector) {
@@ -1897,6 +1903,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out_resp->count_encoders = encoders_count;
out:
+ mutex_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);
return ret;
@@ -4637,6 +4644,7 @@ EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
void drm_mode_config_init(struct drm_device *dev)
{
mutex_init(&dev->mode_config.mutex);
+ mutex_init(&dev->mode_config.connection_mutex);
mutex_init(&dev->mode_config.idr_mutex);
mutex_init(&dev->mode_config.fb_lock);
INIT_LIST_HEAD(&dev->mode_config.fb_list);
@@ -89,6 +89,8 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+ WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex));
+
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
if (connector->encoder == encoder)
return true;
@@ -3299,6 +3299,8 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
struct drm_connector *connector;
struct drm_device *dev = encoder->dev;
+ WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
if (connector->encoder == encoder && connector->eld[0])
return connector;
@@ -54,6 +54,13 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
struct drm_connector *connector;
int count = 0;
+ /*
+ * Note: Once we change the plane hooks to more fine-grained locking we
+ * need to grab the connection_mutex here to be able to make these
+ * checks.
+ */
+ WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex));
+
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
if (connector->encoder && connector->encoder->crtc == crtc) {
if (connector_list != NULL && count < num_connectors)
@@ -7988,6 +7988,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
connector->base.id, drm_get_connector_name(connector),
encoder->base.id, drm_get_encoder_name(encoder));
+ mutex_lock(&dev->mode_config.connection_mutex);
+
/*
* Algorithm gets a little messy:
*
@@ -8030,7 +8032,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
*/
if (!crtc) {
DRM_DEBUG_KMS("no pipe available for load-detect\n");
- return false;
+ goto fail_unlock_connector;
}
mutex_lock(&crtc->mutex);
@@ -8084,6 +8086,9 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
else
intel_crtc->new_config = NULL;
mutex_unlock(&crtc->mutex);
+fail_unlock_connector:
+ mutex_unlock(&dev->mode_config.connection_mutex);
+
return false;
}
@@ -8113,6 +8118,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
}
mutex_unlock(&crtc->mutex);
+ mutex_unlock(&connector->dev->mode_config.connection_mutex);
return;
}
@@ -8121,6 +8127,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
connector->funcs->dpms(connector, old->dpms_mode);
mutex_unlock(&crtc->mutex);
+ mutex_unlock(&connector->dev->mode_config.connection_mutex);
}
static int i9xx_pll_refclk(struct drm_device *dev,
@@ -2953,6 +2953,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
u8 sink_irq_vector;
u8 link_status[DP_LINK_STATUS_SIZE];
+ /* FIXME: This access isn't protected by any locks. */
if (!intel_encoder->connectors_active)
return;
@@ -346,6 +346,7 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb,
VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb);
+ /* FIXME: This is racy - no protection against modeset config changes. */
while ((connector = omap_framebuffer_get_next_connector(fb, connector))) {
/* only consider connectors that are part of a chain */
if (connector->encoder && connector->encoder->crtc) {
@@ -48,6 +48,7 @@ void radeon_connector_hotplug(struct drm_connector *connector)
radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
/* if the connector is already off, don't turn it back on */
+ /* FIXME: This access isn't protected by any locks. */
if (connector->dpms != DRM_MODE_DPMS_ON)
return;
@@ -738,6 +738,7 @@ struct drm_mode_group {
*/
struct drm_mode_config {
struct mutex mutex; /* protects configuration (mode lists etc.) */
+ struct mutex connection_mutex; /* protects connector->encoder and encoder->crtc links */
struct mutex idr_mutex; /* for IDR management */
struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
/* this is limited to one for now */