aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-04-22 16:10:30 -0400
committerDave Airlie <airlied@redhat.com>2016-04-26 19:58:05 -0400
commit152ef5fa9e14e93e7efc43adad7dbcf35d7780f5 (patch)
tree4ddd6c930c01b6199526623d260ffead4c13da32 /drivers/gpu/drm/drm_crtc.c
parentb0b5511bdff86244da09665f4eb4968842199322 (diff)
drm: Switch blobs to the new generic modeset obj refcounting
Need to move the free function around a bit, but otherwise mostly just removing code. Specifically we can nuke all the _locked variants since the weak idr reference is now protected by the idr_mutex, which we never hold anywhere expect in the lookup/reg/unreg functions. And those never call anything else. Another benefit of this is that this patch switches the weak reference logic from kref_put_mutex to kref_get_unless_zero. And the later is in general more flexible wrt accomodating multiple weak references protected by different locks, which might or might not come handy eventually. But one consequence of that switch is that we need to acquire the blob_lock from the free function for the list_del calls. That's a bit tricky to pull off, but works well if we pick the exact same scheme as is already used for framebuffers. Most important changes: - filp list is maintainer by create/destroy_blob ioctls directly (already the case, so we can just remove the redundant list_del from the free function). - filp close handler walks the filp-private list lockless - works because we know no one else can access it. I copied the same comment from the fb code over to explain this. - Otherwise we need to sufficiently restrict blob_lock critical sections to avoid all the unreference calls. Easy to do once the blob_lock only protects the list, and no longer the weak reference. Cc: Dave Airlie <airlied@gmail.com> Cc: Daniel Stone <daniels@collabora.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c164
1 files changed, 45 insertions, 119 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 2c761afbcecd..4e5b015a5e3a 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -360,10 +360,6 @@ static struct drm_mode_object *_object_find(struct drm_device *dev,
360 obj = NULL; 360 obj = NULL;
361 if (obj && obj->id != id) 361 if (obj && obj->id != id)
362 obj = NULL; 362 obj = NULL;
363 /* don't leak out unref'd fb's */
364 if (obj &&
365 obj->type == DRM_MODE_OBJECT_BLOB)
366 obj = NULL;
367 363
368 if (obj && obj->free_cb) { 364 if (obj && obj->free_cb) {
369 if (!kref_get_unless_zero(&obj->refcount)) 365 if (!kref_get_unless_zero(&obj->refcount))
@@ -389,7 +385,6 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
389{ 385{
390 struct drm_mode_object *obj = NULL; 386 struct drm_mode_object *obj = NULL;
391 387
392 WARN_ON(type == DRM_MODE_OBJECT_BLOB);
393 obj = _object_find(dev, id, type); 388 obj = _object_find(dev, id, type);
394 return obj; 389 return obj;
395} 390}
@@ -4259,6 +4254,20 @@ done:
4259 return ret; 4254 return ret;
4260} 4255}
4261 4256
4257static void drm_property_free_blob(struct kref *kref)
4258{
4259 struct drm_property_blob *blob =
4260 container_of(kref, struct drm_property_blob, base.refcount);
4261
4262 mutex_lock(&blob->dev->mode_config.blob_lock);
4263 list_del(&blob->head_global);
4264 mutex_unlock(&blob->dev->mode_config.blob_lock);
4265
4266 drm_mode_object_unregister(blob->dev, &blob->base);
4267
4268 kfree(blob);
4269}
4270
4262/** 4271/**
4263 * drm_property_create_blob - Create new blob property 4272 * drm_property_create_blob - Create new blob property
4264 * 4273 *
@@ -4296,20 +4305,16 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
4296 if (data) 4305 if (data)
4297 memcpy(blob->data, data, length); 4306 memcpy(blob->data, data, length);
4298 4307
4299 mutex_lock(&dev->mode_config.blob_lock); 4308 ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
4300 4309 true, drm_property_free_blob);
4301 ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
4302 if (ret) { 4310 if (ret) {
4303 kfree(blob); 4311 kfree(blob);
4304 mutex_unlock(&dev->mode_config.blob_lock);
4305 return ERR_PTR(-EINVAL); 4312 return ERR_PTR(-EINVAL);
4306 } 4313 }
4307 4314
4308 kref_init(&blob->refcount); 4315 mutex_lock(&dev->mode_config.blob_lock);
4309
4310 list_add_tail(&blob->head_global, 4316 list_add_tail(&blob->head_global,
4311 &dev->mode_config.property_blob_list); 4317 &dev->mode_config.property_blob_list);
4312
4313 mutex_unlock(&dev->mode_config.blob_lock); 4318 mutex_unlock(&dev->mode_config.blob_lock);
4314 4319
4315 return blob; 4320 return blob;
@@ -4317,27 +4322,6 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
4317EXPORT_SYMBOL(drm_property_create_blob); 4322EXPORT_SYMBOL(drm_property_create_blob);
4318 4323
4319/** 4324/**
4320 * drm_property_free_blob - Blob property destructor
4321 *
4322 * Internal free function for blob properties; must not be used directly.
4323 *
4324 * @kref: Reference
4325 */
4326static void drm_property_free_blob(struct kref *kref)
4327{
4328 struct drm_property_blob *blob =
4329 container_of(kref, struct drm_property_blob, refcount);
4330
4331 WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock));
4332
4333 list_del(&blob->head_global);
4334 list_del(&blob->head_file);
4335 drm_mode_object_unregister(blob->dev, &blob->base);
4336
4337 kfree(blob);
4338}
4339
4340/**
4341 * drm_property_unreference_blob - Unreference a blob property 4325 * drm_property_unreference_blob - Unreference a blob property
4342 * 4326 *
4343 * Drop a reference on a blob property. May free the object. 4327 * Drop a reference on a blob property. May free the object.
@@ -4346,42 +4330,14 @@ static void drm_property_free_blob(struct kref *kref)
4346 */ 4330 */
4347void drm_property_unreference_blob(struct drm_property_blob *blob) 4331void drm_property_unreference_blob(struct drm_property_blob *blob)
4348{ 4332{
4349 struct drm_device *dev;
4350
4351 if (!blob) 4333 if (!blob)
4352 return; 4334 return;
4353 4335
4354 dev = blob->dev; 4336 drm_mode_object_unreference(&blob->base);
4355
4356 DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
4357
4358 if (kref_put_mutex(&blob->refcount, drm_property_free_blob,
4359 &dev->mode_config.blob_lock))
4360 mutex_unlock(&dev->mode_config.blob_lock);
4361 else
4362 might_lock(&dev->mode_config.blob_lock);
4363} 4337}
4364EXPORT_SYMBOL(drm_property_unreference_blob); 4338EXPORT_SYMBOL(drm_property_unreference_blob);
4365 4339
4366/** 4340/**
4367 * drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held
4368 *
4369 * Drop a reference on a blob property. May free the object. This must be
4370 * called with blob_lock held.
4371 *
4372 * @blob: Pointer to blob property
4373 */
4374static void drm_property_unreference_blob_locked(struct drm_property_blob *blob)
4375{
4376 if (!blob)
4377 return;
4378
4379 DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
4380
4381 kref_put(&blob->refcount, drm_property_free_blob);
4382}
4383
4384/**
4385 * drm_property_destroy_user_blobs - destroy all blobs created by this client 4341 * drm_property_destroy_user_blobs - destroy all blobs created by this client
4386 * @dev: DRM device 4342 * @dev: DRM device
4387 * @file_priv: destroy all blobs owned by this file handle 4343 * @file_priv: destroy all blobs owned by this file handle
@@ -4391,14 +4347,14 @@ void drm_property_destroy_user_blobs(struct drm_device *dev,
4391{ 4347{
4392 struct drm_property_blob *blob, *bt; 4348 struct drm_property_blob *blob, *bt;
4393 4349
4394 mutex_lock(&dev->mode_config.blob_lock); 4350 /*
4395 4351 * When the file gets released that means no one else can access the
4352 * blob list any more, so no need to grab dev->blob_lock.
4353 */
4396 list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4354 list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
4397 list_del_init(&blob->head_file); 4355 list_del_init(&blob->head_file);
4398 drm_property_unreference_blob_locked(blob); 4356 drm_property_unreference_blob(blob);
4399 } 4357 }
4400
4401 mutex_unlock(&dev->mode_config.blob_lock);
4402} 4358}
4403 4359
4404/** 4360/**
@@ -4410,35 +4366,11 @@ void drm_property_destroy_user_blobs(struct drm_device *dev,
4410 */ 4366 */
4411struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 4367struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob)
4412{ 4368{
4413 DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 4369 drm_mode_object_reference(&blob->base);
4414 kref_get(&blob->refcount);
4415 return blob; 4370 return blob;
4416} 4371}
4417EXPORT_SYMBOL(drm_property_reference_blob); 4372EXPORT_SYMBOL(drm_property_reference_blob);
4418 4373
4419/*
4420 * Like drm_property_lookup_blob, but does not return an additional reference.
4421 * Must be called with blob_lock held.
4422 */
4423static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev,
4424 uint32_t id)
4425{
4426 struct drm_mode_object *obj = NULL;
4427 struct drm_property_blob *blob;
4428
4429 WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock));
4430
4431 mutex_lock(&dev->mode_config.idr_mutex);
4432 obj = idr_find(&dev->mode_config.crtc_idr, id);
4433 if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id))
4434 blob = NULL;
4435 else
4436 blob = obj_to_blob(obj);
4437 mutex_unlock(&dev->mode_config.idr_mutex);
4438
4439 return blob;
4440}
4441
4442/** 4374/**
4443 * drm_property_lookup_blob - look up a blob property and take a reference 4375 * drm_property_lookup_blob - look up a blob property and take a reference
4444 * @dev: drm device 4376 * @dev: drm device
@@ -4451,16 +4383,12 @@ static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *d
4451struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 4383struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
4452 uint32_t id) 4384 uint32_t id)
4453{ 4385{
4454 struct drm_property_blob *blob; 4386 struct drm_mode_object *obj;
4455 4387 struct drm_property_blob *blob = NULL;
4456 mutex_lock(&dev->mode_config.blob_lock);
4457 blob = __drm_property_lookup_blob(dev, id);
4458 if (blob) {
4459 if (!kref_get_unless_zero(&blob->refcount))
4460 blob = NULL;
4461 }
4462 mutex_unlock(&dev->mode_config.blob_lock);
4463 4388
4389 obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB);
4390 if (obj)
4391 blob = obj_to_blob(obj);
4464 return blob; 4392 return blob;
4465} 4393}
4466EXPORT_SYMBOL(drm_property_lookup_blob); 4394EXPORT_SYMBOL(drm_property_lookup_blob);
@@ -4565,26 +4493,21 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
4565 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4493 if (!drm_core_check_feature(dev, DRIVER_MODESET))
4566 return -EINVAL; 4494 return -EINVAL;
4567 4495
4568 drm_modeset_lock_all(dev); 4496 blob = drm_property_lookup_blob(dev, out_resp->blob_id);
4569 mutex_lock(&dev->mode_config.blob_lock); 4497 if (!blob)
4570 blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4498 return -ENOENT;
4571 if (!blob) {
4572 ret = -ENOENT;
4573 goto done;
4574 }
4575 4499
4576 if (out_resp->length == blob->length) { 4500 if (out_resp->length == blob->length) {
4577 blob_ptr = (void __user *)(unsigned long)out_resp->data; 4501 blob_ptr = (void __user *)(unsigned long)out_resp->data;
4578 if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4502 if (copy_to_user(blob_ptr, blob->data, blob->length)) {
4579 ret = -EFAULT; 4503 ret = -EFAULT;
4580 goto done; 4504 goto unref;
4581 } 4505 }
4582 } 4506 }
4583 out_resp->length = blob->length; 4507 out_resp->length = blob->length;
4508unref:
4509 drm_property_unreference_blob(blob);
4584 4510
4585done:
4586 mutex_unlock(&dev->mode_config.blob_lock);
4587 drm_modeset_unlock_all(dev);
4588 return ret; 4511 return ret;
4589} 4512}
4590 4513
@@ -4663,13 +4586,11 @@ int drm_mode_destroyblob_ioctl(struct drm_device *dev,
4663 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4586 if (!drm_core_check_feature(dev, DRIVER_MODESET))
4664 return -EINVAL; 4587 return -EINVAL;
4665 4588
4666 mutex_lock(&dev->mode_config.blob_lock); 4589 blob = drm_property_lookup_blob(dev, out_resp->blob_id);
4667 blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4590 if (!blob)
4668 if (!blob) { 4591 return -ENOENT;
4669 ret = -ENOENT;
4670 goto err;
4671 }
4672 4592
4593 mutex_lock(&dev->mode_config.blob_lock);
4673 /* Ensure the property was actually created by this user. */ 4594 /* Ensure the property was actually created by this user. */
4674 list_for_each_entry(bt, &file_priv->blobs, head_file) { 4595 list_for_each_entry(bt, &file_priv->blobs, head_file) {
4675 if (bt == blob) { 4596 if (bt == blob) {
@@ -4686,13 +4607,18 @@ int drm_mode_destroyblob_ioctl(struct drm_device *dev,
4686 /* We must drop head_file here, because we may not be the last 4607 /* We must drop head_file here, because we may not be the last
4687 * reference on the blob. */ 4608 * reference on the blob. */
4688 list_del_init(&blob->head_file); 4609 list_del_init(&blob->head_file);
4689 drm_property_unreference_blob_locked(blob);
4690 mutex_unlock(&dev->mode_config.blob_lock); 4610 mutex_unlock(&dev->mode_config.blob_lock);
4691 4611
4612 /* One reference from lookup, and one from the filp. */
4613 drm_property_unreference_blob(blob);
4614 drm_property_unreference_blob(blob);
4615
4692 return 0; 4616 return 0;
4693 4617
4694err: 4618err:
4695 mutex_unlock(&dev->mode_config.blob_lock); 4619 mutex_unlock(&dev->mode_config.blob_lock);
4620 drm_property_unreference_blob(blob);
4621
4696 return ret; 4622 return ret;
4697} 4623}
4698 4624