drm: create mode_config idr lock

Create a separate mode_config IDR lock for simplicity.  The core DRM
config structures (connector, mode, etc. lists) are still protected by
the mode_config mutex, but the CRTC IDR (used for the various identifier
IDs) is now protected by the mode_config idr_mutex.  Simplifies the
locking a bit and removes a warning.

All objects are protected by the config mutex, we may in the future,
split the object further to have reference counts.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5b2cbb7..bfce099 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -194,7 +194,6 @@
  * @type: object type
  *
  * LOCKING:
- * Caller must hold DRM mode_config lock.
  *
  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
  * for tracking modes, CRTCs and connectors.
@@ -209,15 +208,15 @@
 	int new_id = 0;
 	int ret;
 
-	WARN(!mutex_is_locked(&dev->mode_config.mutex),
-	     "%s called w/o mode_config lock\n", __func__);
 again:
 	if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
 		DRM_ERROR("Ran out memory getting a mode number\n");
 		return -EINVAL;
 	}
 
+	mutex_lock(&dev->mode_config.idr_mutex);
 	ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id);
+	mutex_unlock(&dev->mode_config.idr_mutex);
 	if (ret == -EAGAIN)
 		goto again;
 
@@ -239,16 +238,20 @@
 static void drm_mode_object_put(struct drm_device *dev,
 				struct drm_mode_object *object)
 {
+	mutex_lock(&dev->mode_config.idr_mutex);
 	idr_remove(&dev->mode_config.crtc_idr, object->id);
+	mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
 void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type)
 {
-	struct drm_mode_object *obj;
+	struct drm_mode_object *obj = NULL;
 
+	mutex_lock(&dev->mode_config.idr_mutex);
 	obj = idr_find(&dev->mode_config.crtc_idr, id);
 	if (!obj || (obj->type != type) || (obj->id != id))
-		return NULL;
+		obj = NULL;
+	mutex_unlock(&dev->mode_config.idr_mutex);
 
 	return obj;
 }
@@ -786,6 +789,7 @@
 void drm_mode_config_init(struct drm_device *dev)
 {
 	mutex_init(&dev->mode_config.mutex);
+	mutex_init(&dev->mode_config.idr_mutex);
 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
 	INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list);
 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 47809ac..d54de24 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -528,7 +528,8 @@
  *
  */
 struct drm_mode_config {
-	struct mutex mutex; /* protects configuration and IDR */
+	struct mutex mutex; /* 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 */
 	int num_fb;