[PATCH] drm/kms: Convert mode_config's mutex to an rwsem

Adam Jackson ajax at redhat.com
Thu Jun 21 11:51:33 PDT 2012


This is a start at pushing down the locking a bit further.  Ideally
things like i2c shouldn't affect pageflipping.  I've made some attempt
to only take read locks where possible, but there's certainly more work
to be done.

Signed-off-by: Adam Jackson <ajax at redhat.com>
---
 drivers/gpu/drm/ast/ast_drv.c             |    4 +-
 drivers/gpu/drm/drm_crtc.c                |  133 +++++++++++++++--------------
 drivers/gpu/drm/drm_crtc_helper.c         |    5 +-
 drivers/gpu/drm/drm_fb_helper.c           |   20 ++--
 drivers/gpu/drm/drm_sysfs.c               |    8 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c |    4 +-
 drivers/gpu/drm/gma500/psb_device.c       |    8 +-
 drivers/gpu/drm/gma500/psb_drv.c          |    4 +-
 drivers/gpu/drm/i915/i915_debugfs.c       |   25 ++----
 drivers/gpu/drm/i915/i915_drv.c           |    4 +-
 drivers/gpu/drm/i915/i915_irq.c           |    4 +-
 drivers/gpu/drm/i915/intel_dp.c           |    4 +-
 drivers/gpu/drm/i915/intel_fb.c           |    4 +-
 drivers/gpu/drm/i915/intel_lvds.c         |    4 +-
 drivers/gpu/drm/i915/intel_overlay.c      |   20 +++--
 drivers/gpu/drm/i915/intel_sprite.c       |    8 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c     |   12 ++--
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c       |   15 ++--
 include/drm/drm_crtc.h                    |    4 +-
 19 files changed, 143 insertions(+), 147 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index d0c4574..cea85a9 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -96,9 +96,9 @@ static int ast_drm_thaw(struct drm_device *dev)
 	ast_post_gpu(dev);
 
 	drm_mode_config_reset(dev);
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	drm_helper_resume_force_mode(dev);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	console_lock();
 	ast_fbdev_set_suspend(dev, 0);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 08a7aa7..6f57547 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -378,7 +378,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	crtc->dev = dev;
 	crtc->funcs = funcs;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
 	if (ret)
@@ -390,7 +390,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	dev->mode_config.num_crtc++;
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
@@ -479,7 +479,7 @@ int drm_connector_init(struct drm_device *dev,
 {
 	int ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
 	if (ret)
@@ -508,7 +508,7 @@ int drm_connector_init(struct drm_device *dev,
 				      dev->mode_config.dpms_property, 0);
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
@@ -537,11 +537,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
 	list_for_each_entry_safe(mode, t, &connector->user_modes, head)
 		drm_mode_remove(connector, mode);
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	drm_mode_object_put(dev, &connector->base);
 	list_del(&connector->head);
 	dev->mode_config.num_connector--;
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
@@ -563,7 +563,7 @@ int drm_encoder_init(struct drm_device *dev,
 {
 	int ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
 	if (ret)
@@ -577,7 +577,7 @@ int drm_encoder_init(struct drm_device *dev,
 	dev->mode_config.num_encoder++;
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
@@ -586,11 +586,11 @@ EXPORT_SYMBOL(drm_encoder_init);
 void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
 	struct drm_device *dev = encoder->dev;
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	drm_mode_object_put(dev, &encoder->base);
 	list_del(&encoder->head);
 	dev->mode_config.num_encoder--;
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 EXPORT_SYMBOL(drm_encoder_cleanup);
 
@@ -602,7 +602,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 {
 	int ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
 	if (ret)
@@ -636,7 +636,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	}
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
@@ -646,7 +646,7 @@ void drm_plane_cleanup(struct drm_plane *plane)
 {
 	struct drm_device *dev = plane->dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	kfree(plane->format_types);
 	drm_mode_object_put(dev, &plane->base);
 	/* if not added to a list, it must be a private plane */
@@ -654,7 +654,7 @@ void drm_plane_cleanup(struct drm_plane *plane)
 		list_del(&plane->head);
 		dev->mode_config.num_plane--;
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
@@ -927,7 +927,7 @@ EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
  */
 void drm_mode_config_init(struct drm_device *dev)
 {
-	mutex_init(&dev->mode_config.mutex);
+	init_rwsem(&dev->mode_config.sem);
 	mutex_init(&dev->mode_config.idr_mutex);
 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
@@ -938,9 +938,9 @@ void drm_mode_config_init(struct drm_device *dev)
 	INIT_LIST_HEAD(&dev->mode_config.plane_list);
 	idr_init(&dev->mode_config.crtc_idr);
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	drm_mode_create_standard_connector_properties(dev);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	/* Just to be sure */
 	dev->mode_config.num_fb = 0;
@@ -1169,7 +1169,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 
 	/*
 	 * For the non-control nodes we need to limit the list of resources
@@ -1311,7 +1311,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 		  card_res->count_connectors, card_res->count_encoders);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1343,7 +1343,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
 				   DRM_MODE_OBJECT_CRTC);
@@ -1371,7 +1371,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1418,7 +1418,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);
+	down_write(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, out_resp->connector_id,
 				   DRM_MODE_OBJECT_CONNECTOR);
@@ -1442,6 +1442,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 					     dev->mode_config.max_height);
 	}
 
+	downgrade_write(&dev->mode_config.sem);
+
 	/* delayed so we get modes regardless of pre-fill_modes state */
 	list_for_each_entry(mode, &connector->modes, head)
 		mode_count++;
@@ -1515,7 +1517,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	out_resp->count_encoders = encoders_count;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1530,7 +1532,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, enc_resp->encoder_id,
 				   DRM_MODE_OBJECT_ENCODER);
 	if (!obj) {
@@ -1549,7 +1551,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 	enc_resp->possible_clones = encoder->possible_clones;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1576,7 +1578,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	config = &dev->mode_config;
 
 	/*
@@ -1598,7 +1600,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	plane_resp->count_planes = config->num_plane;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1626,7 +1628,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, plane_resp->plane_id,
 				   DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -1666,7 +1668,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	plane_resp->count_format_types = plane->format_count;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1697,7 +1699,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	/*
 	 * First, find the plane, crtc, and fb objects.  If not available,
@@ -1796,7 +1798,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
@@ -1840,7 +1842,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
 		return -ERANGE;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
 				   DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
@@ -1966,7 +1968,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 out:
 	kfree(connector_set);
 	drm_mode_destroy(dev, mode);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -1984,7 +1986,8 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 	if (!req->flags)
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	/* XXX should probaby be down_read */
+	down_write(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
@@ -2012,7 +2015,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 		}
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2095,7 +2098,7 @@ int drm_mode_addfb(struct drm_device *dev,
 	if ((config->min_height > r.height) || (r.height > config->max_height))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	/* TODO check buffer is sufficiently large */
 	/* TODO setup destructor callback */
@@ -2112,7 +2115,7 @@ int drm_mode_addfb(struct drm_device *dev,
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2269,7 +2272,7 @@ int drm_mode_addfb2(struct drm_device *dev,
 	if (ret)
 		return ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
 	if (IS_ERR(fb)) {
@@ -2283,7 +2286,7 @@ int drm_mode_addfb2(struct drm_device *dev,
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2317,7 +2320,7 @@ int drm_mode_rmfb(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
 	/* TODO check that we really get a framebuffer back. */
 	if (!obj) {
@@ -2342,7 +2345,7 @@ int drm_mode_rmfb(struct drm_device *dev,
 	fb->funcs->destroy(fb);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2374,7 +2377,7 @@ int drm_mode_getfb(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
 	if (!obj) {
 		ret = -EINVAL;
@@ -2390,7 +2393,7 @@ int drm_mode_getfb(struct drm_device *dev,
 	fb->funcs->create_handle(fb, file_priv, &r->handle);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2409,7 +2412,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
 	if (!obj) {
 		ret = -EINVAL;
@@ -2463,7 +2466,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 out_err2:
 	kfree(clips);
 out_err1:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2487,12 +2490,12 @@ void drm_fb_release(struct drm_file *priv)
 	struct drm_device *dev = priv->minor->dev;
 	struct drm_framebuffer *fb, *tfb;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
 		list_del(&fb->filp_head);
 		fb->funcs->destroy(fb);
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 
 /**
@@ -2608,7 +2611,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
 	if (!obj) {
@@ -2632,7 +2635,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
 
 	drm_mode_attachmode(dev, connector, mode);
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2662,7 +2665,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
 	if (!obj) {
@@ -2679,7 +2682,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
 
 	ret = drm_mode_detachmode(dev, connector, &mode);
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -2946,7 +2949,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3024,7 +3027,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 		out_resp->count_enum_blobs = blob_count;
 	}
 done:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -3075,7 +3078,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3093,7 +3096,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 	out_resp->length = blob->length;
 
 done:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -3230,7 +3233,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
 	if (!obj) {
@@ -3267,7 +3270,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 	}
 	arg->count_props = props_count;
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -3284,7 +3287,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
 	if (!arg_obj)
@@ -3322,7 +3325,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -3384,7 +3387,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3425,7 +3428,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 
 }
@@ -3443,7 +3446,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3476,7 +3479,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 		goto out;
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -3495,7 +3498,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	    page_flip->reserved != 0)
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj)
 		goto out;
@@ -3568,7 +3571,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 3252e70..69cbf88 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -930,7 +930,8 @@ static void output_poll_execute(struct work_struct *work)
 	if (!drm_kms_helper_poll)
 		return;
 
-	mutex_lock(&dev->mode_config.mutex);
+	/* XXX need to sort this so it can be down_read */
+	down_write(&dev->mode_config.sem);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* if this is HPD or polled don't check it -
@@ -958,7 +959,7 @@ static void output_poll_execute(struct work_struct *work)
 			changed = true;
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	if (changed) {
 		/* send a uevent + call fbdev */
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 5683b7f..d173c27 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -320,7 +320,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 	/*
 	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
@@ -335,7 +335,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 				dev->mode_config.dpms_property, dpms_mode);
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 
 int drm_fb_helper_blank(int blank, struct fb_info *info)
@@ -655,16 +655,16 @@ int drm_fb_helper_set_par(struct fb_info *info)
 		return -EINVAL;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 		ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
 		if (ret) {
-			mutex_unlock(&dev->mode_config.mutex);
+			up_write(&dev->mode_config.sem);
 			return ret;
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	if (fb_helper->delayed_hotplug) {
 		fb_helper->delayed_hotplug = false;
@@ -684,7 +684,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 	int ret = 0;
 	int i;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
@@ -701,7 +701,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 			}
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 EXPORT_SYMBOL(drm_fb_helper_pan_display);
@@ -1359,7 +1359,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	if (!fb_helper->fb)
 		return 0;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (crtc->fb)
 			crtcs_bound = true;
@@ -1369,7 +1369,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
 	if (!bound && crtcs_bound) {
 		fb_helper->delayed_hotplug = true;
-		mutex_unlock(&dev->mode_config.mutex);
+		up_write(&dev->mode_config.sem);
 		return 0;
 	}
 	DRM_DEBUG_KMS("\n");
@@ -1381,7 +1381,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
 						    max_height);
 	drm_setup_crtcs(fb_helper);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 }
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 45cf1dd..4947d86 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -159,14 +159,12 @@ static ssize_t status_show(struct device *device,
 {
 	struct drm_connector *connector = to_drm_connector(device);
 	enum drm_connector_status status;
-	int ret;
 
-	ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
-	if (ret)
-		return ret;
+	if (!down_write_trylock(&connector->dev->mode_config.sem))
+		return -EINTR;
 
 	status = connector->funcs->detect(connector, true);
-	mutex_unlock(&connector->dev->mode_config.mutex);
+	up_write(&connector->dev->mode_config.sem);
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 			drm_get_connector_status_name(status));
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index c4c6525..e083309 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -149,7 +149,7 @@ int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
 		}
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, zpos_req->plane_id,
 			DRM_MODE_OBJECT_PLANE);
@@ -166,6 +166,6 @@ int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
 	exynos_plane->overlay.zpos = zpos_req->zpos;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index eff039b..549407c 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -190,7 +190,7 @@ static int psb_save_display_registers(struct drm_device *dev)
 	regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
 
 	/* Save crtc and output state */
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (drm_helper_crtc_in_use(crtc))
 			crtc->funcs->save(crtc);
@@ -200,7 +200,7 @@ static int psb_save_display_registers(struct drm_device *dev)
 		if (connector->funcs->save)
 			connector->funcs->save(connector);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return 0;
 }
 
@@ -230,7 +230,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
 	/*make sure VGA plane is off. it initializes to on after reset!*/
 	PSB_WVDC32(0x80000000, VGACNTRL);
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
 		if (drm_helper_crtc_in_use(crtc))
 			crtc->funcs->restore(crtc);
@@ -239,7 +239,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
 		if (connector->funcs->restore)
 			connector->funcs->restore(connector);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index caba6e0..ca04805 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -475,7 +475,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
 	case PSB_MODE_OPERATION_MODE_VALID:
 		umode = &arg->mode;
 
-		mutex_lock(&dev->mode_config.mutex);
+		down_write(&dev->mode_config.sem);
 
 		obj = drm_mode_object_find(dev, obj_id,
 					DRM_MODE_OBJECT_CONNECTOR);
@@ -524,7 +524,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
 		if (mode)
 			drm_mode_destroy(dev, mode);
 mode_op_out:
-		mutex_unlock(&dev->mode_config.mutex);
+		up_write(&dev->mode_config.sem);
 		return ret;
 
 	default:
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 5363e9c..4a1c145 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1362,11 +1362,9 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_fbdev *ifbdev;
 	struct intel_framebuffer *fb;
-	int ret;
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (ret)
-		return ret;
+	if (!down_read_trylock(&dev->mode_config.sem))
+		return -EINTR;
 
 	ifbdev = dev_priv->fbdev;
 	fb = to_intel_framebuffer(ifbdev->helper.fb);
@@ -1392,7 +1390,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 		seq_printf(m, "\n");
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return 0;
 }
@@ -1402,11 +1400,9 @@ static int i915_context_status(struct seq_file *m, void *unused)
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int ret;
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (ret)
-		return ret;
+	if (!down_read_trylock(&dev->mode_config.sem))
+		return -EINTR;
 
 	if (dev_priv->pwrctx) {
 		seq_printf(m, "power context ");
@@ -1420,7 +1416,7 @@ static int i915_context_status(struct seq_file *m, void *unused)
 		seq_printf(m, "\n");
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return 0;
 }
@@ -1545,17 +1541,14 @@ static int i915_dpio_info(struct seq_file *m, void *data)
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int ret;
-
 
 	if (!IS_VALLEYVIEW(dev)) {
 		seq_printf(m, "unsupported\n");
 		return 0;
 	}
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (ret)
-		return ret;
+	if (!down_read_trylock(&dev->mode_config.sem))
+		return -EINTR;
 
 	seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
 
@@ -1582,7 +1575,7 @@ static int i915_dpio_info(struct seq_file *m, void *data)
 	seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
 		   intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 9fe9ebe..a632117 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -651,9 +651,9 @@ static int i915_drm_thaw(struct drm_device *dev)
 		drm_irq_install(dev);
 
 		/* Resume the modeset for every activated CRTC */
-		mutex_lock(&dev->mode_config.mutex);
+		down_write(&dev->mode_config.sem);
 		drm_helper_resume_force_mode(dev);
-		mutex_unlock(&dev->mode_config.mutex);
+		up_write(&dev->mode_config.sem);
 	}
 
 	intel_opregion_init(dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b1fe0ed..2e589b2 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -283,14 +283,14 @@ static void i915_hotplug_work_func(struct work_struct *work)
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct intel_encoder *encoder;
 
-	mutex_lock(&mode_config->mutex);
+	down_write(&mode_config->sem);
 	DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
 	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
 		if (encoder->hot_plug)
 			encoder->hot_plug(encoder);
 
-	mutex_unlock(&mode_config->mutex);
+	up_write(&mode_config->sem);
 
 	/* Just fire off a uevent and let userspace tell us what to do */
 	drm_helper_hpd_irq_event(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c044932..f2c8a93 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1087,9 +1087,9 @@ static void ironlake_panel_vdd_work(struct work_struct *__work)
 						 struct intel_dp, panel_vdd_work);
 	struct drm_device *dev = intel_dp->base.base.dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	ironlake_panel_vdd_off_sync(intel_dp);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 
 static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index bf86907..bacbbd4 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -279,7 +279,7 @@ void intel_fb_restore_mode(struct drm_device *dev)
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_plane *plane;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
 	if (ret)
@@ -289,5 +289,5 @@ void intel_fb_restore_mode(struct drm_device *dev)
 	list_for_each_entry(plane, &config->plane_list, head)
 		plane->funcs->disable_plane(plane);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 08eb04c..5e900d9 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -539,9 +539,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
 
 	dev_priv->modeset_on_lid = 0;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	drm_helper_resume_force_mode(dev);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return NOTIFY_OK;
 }
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 458743d..3856757 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -779,7 +779,6 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
 	u32 swidth, swidthsw, sheight, ostride;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
 	BUG_ON(!overlay);
 
 	ret = intel_overlay_release_old_vid(overlay);
@@ -884,7 +883,6 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
 	int ret;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
 	ret = intel_overlay_recover_from_interrupt(overlay);
 	if (ret != 0)
@@ -1136,13 +1134,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 	}
 
 	if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
-		mutex_lock(&dev->mode_config.mutex);
+		down_write(&dev->mode_config.sem);
 		mutex_lock(&dev->struct_mutex);
 
 		ret = intel_overlay_switch_off(overlay);
 
 		mutex_unlock(&dev->struct_mutex);
-		mutex_unlock(&dev->mode_config.mutex);
+		up_write(&dev->mode_config.sem);
 
 		return ret;
 	}
@@ -1166,7 +1164,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 		goto out_free;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	mutex_lock(&dev->struct_mutex);
 
 	if (new_bo->tiling_mode) {
@@ -1248,7 +1246,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 		goto out_unlock;
 
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	kfree(params);
 
@@ -1256,7 +1254,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	drm_gem_object_unreference_unlocked(&new_bo->base);
 out_free:
 	kfree(params);
@@ -1324,6 +1322,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 	struct intel_overlay *overlay;
 	struct overlay_registers __iomem *regs;
 	int ret;
+	bool write = !!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS);
 
 	/* No need to check for DRIVER_MODESET - we don't set it up then. */
 	overlay = dev_priv->overlay;
@@ -1332,7 +1331,10 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 		return -ENODEV;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	if (write)
+		down_write(&dev->mode_config.sem);
+	else
+		down_read(&dev->mode_config.sem);
 	mutex_lock(&dev->struct_mutex);
 
 	ret = -EINVAL;
@@ -1398,7 +1400,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 	ret = 0;
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 2a20fb0..b7226d8 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -570,7 +570,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -583,7 +583,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 	ret = intel_plane->update_colorkey(plane, set);
 
 out_unlock:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
@@ -599,7 +599,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -ENODEV;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_read(&dev->mode_config.sem);
 
 	obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -612,7 +612,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
 	intel_plane->get_colorkey(plane, get);
 
 out_unlock:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 66917c6..820e694 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -160,8 +160,8 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 		goto out_no_copy;
 	}
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (unlikely(ret != 0)) {
+	ret = down_write_trylock(&dev->mode_config.sem);
+	if (unlikely(ret == 0)) {
 		ret = -ERESTARTSYS;
 		goto out_no_mode_mutex;
 	}
@@ -195,7 +195,7 @@ out_no_surface:
 	ttm_read_unlock(&vmaster->lock);
 out_no_ttm_lock:
 out_no_fb:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 out_no_mode_mutex:
 out_no_copy:
 	kfree(clips);
@@ -246,8 +246,8 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 		goto out_no_copy;
 	}
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (unlikely(ret != 0)) {
+	ret = down_write_trylock(&dev->mode_config.sem);
+	if (unlikely(ret == 0)) {
 		ret = -ERESTARTSYS;
 		goto out_no_mode_mutex;
 	}
@@ -277,7 +277,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 	ttm_read_unlock(&vmaster->lock);
 out_no_ttm_lock:
 out_no_fb:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 out_no_mode_mutex:
 out_no_copy:
 	kfree(clips);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 6b0078f..b053b3b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -352,7 +352,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
 	struct vmw_display_unit *du;
 	struct drm_crtc *crtc;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		du = vmw_crtc_to_du(crtc);
@@ -366,7 +366,7 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
 					64, 64, du->hotspot_x, du->hotspot_y);
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 }
 
 /*
@@ -1469,8 +1469,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
 	struct drm_crtc *crtc;
 	int ret = 0;
 
-
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 	if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) {
 
 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -1479,7 +1478,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
 			du->hotspot_y = arg->yhot;
 		}
 
-		mutex_unlock(&dev->mode_config.mutex);
+		up_write(&dev->mode_config.sem);
 		return 0;
 	}
 
@@ -1496,7 +1495,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
 	du->hotspot_y = arg->yhot;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return ret;
 }
@@ -1646,7 +1645,7 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
 	struct vmw_display_unit *du;
 	struct drm_connector *con;
 
-	mutex_lock(&dev->mode_config.mutex);
+	down_write(&dev->mode_config.sem);
 
 #if 0
 	{
@@ -1676,7 +1675,7 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
 		con->status = vmw_du_connector_detect(con, true);
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	up_write(&dev->mode_config.sem);
 
 	return 0;
 }
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index bac55c2..84763f5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -728,7 +728,7 @@ struct drm_mode_group {
 
 /**
  * drm_mode_config - Mode configuration control structure
- * @mutex: mutex protecting KMS related lists and structures
+ * @sem: r/w semaphore protecting KMS related lists and structures
  * @idr_mutex: mutex for KMS ID allocation and management
  * @crtc_idr: main KMS ID tracking object
  * @num_fb: number of fbs available
@@ -754,7 +754,7 @@ struct drm_mode_group {
  * global restrictions are also here, e.g. dimension restrictions.
  */
 struct drm_mode_config {
-	struct mutex mutex; /* protects configuration (mode lists etc.) */
+	struct rw_semaphore sem; /* protects configuration (mode lists etc.) */
 	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 */
-- 
1.7.7.6



More information about the dri-devel mailing list