diff options
Diffstat (limited to 'drivers/gpu/drm/drm_gem.c')
| -rw-r--r-- | drivers/gpu/drm/drm_gem.c | 147 | 
1 files changed, 89 insertions, 58 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index c6240bab3fa5..6a44351e58b7 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -26,6 +26,7 @@   */  #include <linux/dma-buf.h> +#include <linux/export.h>  #include <linux/file.h>  #include <linux/fs.h>  #include <linux/iosys-map.h> @@ -212,6 +213,46 @@ void drm_gem_private_object_fini(struct drm_gem_object *obj)  }  EXPORT_SYMBOL(drm_gem_private_object_fini); +static void drm_gem_object_handle_get(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; + +	drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock)); + +	if (obj->handle_count++ == 0) +		drm_gem_object_get(obj); +} + +/** + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any + * @obj: GEM object + * + * Acquires a reference on the GEM buffer object's handle. Required to keep + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked() + * to release the reference. Does nothing if the buffer object has no handle. + * + * Returns: + * True if a handle exists, or false otherwise + */ +bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj) +{ +	struct drm_device *dev = obj->dev; + +	guard(mutex)(&dev->object_name_lock); + +	/* +	 * First ref taken during GEM object creation, if any. Some +	 * drivers set up internal framebuffers with GEM objects that +	 * do not have a GEM handle. Hence, this counter can be zero. +	 */ +	if (!obj->handle_count) +		return false; + +	drm_gem_object_handle_get(obj); + +	return true; +} +  /**   * drm_gem_object_handle_free - release resources bound to userspace handles   * @obj: GEM object to clean up. @@ -242,20 +283,26 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)  	}  } -static void -drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj) +/** + * drm_gem_object_handle_put_unlocked - releases reference on user-space handle + * @obj: GEM object + * + * Releases a reference on the GEM buffer object's handle. Possibly releases + * the GEM buffer object and associated dma-buf objects. + */ +void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)  {  	struct drm_device *dev = obj->dev;  	bool final = false; -	if (WARN_ON(READ_ONCE(obj->handle_count) == 0)) +	if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))  		return;  	/* -	* Must bump handle count first as this may be the last -	* ref, in which case the object would disappear before we -	* checked for a name -	*/ +	 * Must bump handle count first as this may be the last +	 * ref, in which case the object would disappear before +	 * we checked for a name. +	 */  	mutex_lock(&dev->object_name_lock);  	if (--obj->handle_count == 0) { @@ -279,6 +326,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)  	struct drm_file *file_priv = data;  	struct drm_gem_object *obj = ptr; +	if (drm_WARN_ON(obj->dev, !data)) +		return 0; +  	if (obj->funcs->close)  		obj->funcs->close(obj, file_priv); @@ -389,8 +439,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,  	int ret;  	WARN_ON(!mutex_is_locked(&dev->object_name_lock)); -	if (obj->handle_count++ == 0) -		drm_gem_object_get(obj); + +	drm_gem_object_handle_get(obj);  	/*  	 * Get the user-visible handle using idr.  Preload and perform @@ -399,7 +449,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,  	idr_preload(GFP_KERNEL);  	spin_lock(&file_priv->table_lock); -	ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT); +	ret = idr_alloc(&file_priv->object_idr, NULL, 1, 0, GFP_NOWAIT);  	spin_unlock(&file_priv->table_lock);  	idr_preload_end(); @@ -420,6 +470,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,  			goto err_revoke;  	} +	/* mirrors drm_gem_handle_delete to avoid races */ +	spin_lock(&file_priv->table_lock); +	obj = idr_replace(&file_priv->object_idr, obj, handle); +	WARN_ON(obj != NULL); +	spin_unlock(&file_priv->table_lock);  	*handlep = handle;  	return 0; @@ -1184,39 +1239,7 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,  		obj->funcs->print_info(p, indent, obj);  } -int drm_gem_pin_locked(struct drm_gem_object *obj) -{ -	if (obj->funcs->pin) -		return obj->funcs->pin(obj); - -	return 0; -} - -void drm_gem_unpin_locked(struct drm_gem_object *obj) -{ -	if (obj->funcs->unpin) -		obj->funcs->unpin(obj); -} - -int drm_gem_pin(struct drm_gem_object *obj) -{ -	int ret; - -	dma_resv_lock(obj->resv, NULL); -	ret = drm_gem_pin_locked(obj); -	dma_resv_unlock(obj->resv); - -	return ret; -} - -void drm_gem_unpin(struct drm_gem_object *obj) -{ -	dma_resv_lock(obj->resv, NULL); -	drm_gem_unpin_locked(obj); -	dma_resv_unlock(obj->resv); -} - -int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) +int drm_gem_vmap_locked(struct drm_gem_object *obj, struct iosys_map *map)  {  	int ret; @@ -1233,9 +1256,9 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)  	return 0;  } -EXPORT_SYMBOL(drm_gem_vmap); +EXPORT_SYMBOL(drm_gem_vmap_locked); -void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) +void drm_gem_vunmap_locked(struct drm_gem_object *obj, struct iosys_map *map)  {  	dma_resv_assert_held(obj->resv); @@ -1248,7 +1271,7 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)  	/* Always set the mapping to NULL. Callers may rely on this. */  	iosys_map_clear(map);  } -EXPORT_SYMBOL(drm_gem_vunmap); +EXPORT_SYMBOL(drm_gem_vunmap_locked);  void drm_gem_lock(struct drm_gem_object *obj)  { @@ -1262,25 +1285,25 @@ void drm_gem_unlock(struct drm_gem_object *obj)  }  EXPORT_SYMBOL(drm_gem_unlock); -int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) +int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)  {  	int ret;  	dma_resv_lock(obj->resv, NULL); -	ret = drm_gem_vmap(obj, map); +	ret = drm_gem_vmap_locked(obj, map);  	dma_resv_unlock(obj->resv);  	return ret;  } -EXPORT_SYMBOL(drm_gem_vmap_unlocked); +EXPORT_SYMBOL(drm_gem_vmap); -void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) +void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)  {  	dma_resv_lock(obj->resv, NULL); -	drm_gem_vunmap(obj, map); +	drm_gem_vunmap_locked(obj, map);  	dma_resv_unlock(obj->resv);  } -EXPORT_SYMBOL(drm_gem_vunmap_unlocked); +EXPORT_SYMBOL(drm_gem_vunmap);  /**   * drm_gem_lock_reservations - Sets up the ww context and acquires @@ -1460,12 +1483,14 @@ EXPORT_SYMBOL(drm_gem_lru_move_tail);   * @nr_to_scan: The number of pages to try to reclaim   * @remaining: The number of pages left to reclaim, should be initialized by caller   * @shrink: Callback to try to shrink/reclaim the object. + * @ticket: Optional ww_acquire_ctx context to use for locking   */  unsigned long  drm_gem_lru_scan(struct drm_gem_lru *lru,  		 unsigned int nr_to_scan,  		 unsigned long *remaining, -		 bool (*shrink)(struct drm_gem_object *obj)) +		 bool (*shrink)(struct drm_gem_object *obj, struct ww_acquire_ctx *ticket), +		 struct ww_acquire_ctx *ticket)  {  	struct drm_gem_lru still_in_lru;  	struct drm_gem_object *obj; @@ -1498,17 +1523,20 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,  		 */  		mutex_unlock(lru->lock); +		if (ticket) +			ww_acquire_init(ticket, &reservation_ww_class); +  		/*  		 * Note that this still needs to be trylock, since we can  		 * hit shrinker in response to trying to get backing pages  		 * for this obj (ie. while it's lock is already held)  		 */ -		if (!dma_resv_trylock(obj->resv)) { +		if (!ww_mutex_trylock(&obj->resv->lock, ticket)) {  			*remaining += obj->size >> PAGE_SHIFT;  			goto tail;  		} -		if (shrink(obj)) { +		if (shrink(obj, ticket)) {  			freed += obj->size >> PAGE_SHIFT;  			/* @@ -1522,6 +1550,9 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,  		dma_resv_unlock(obj->resv); +		if (ticket) +			ww_acquire_fini(ticket); +  tail:  		drm_gem_object_put(obj);  		mutex_lock(lru->lock); @@ -1543,10 +1574,10 @@ tail:  EXPORT_SYMBOL(drm_gem_lru_scan);  /** - * drm_gem_evict - helper to evict backing pages for a GEM object + * drm_gem_evict_locked - helper to evict backing pages for a GEM object   * @obj: obj in question   */ -int drm_gem_evict(struct drm_gem_object *obj) +int drm_gem_evict_locked(struct drm_gem_object *obj)  {  	dma_resv_assert_held(obj->resv); @@ -1558,4 +1589,4 @@ int drm_gem_evict(struct drm_gem_object *obj)  	return 0;  } -EXPORT_SYMBOL(drm_gem_evict); +EXPORT_SYMBOL(drm_gem_evict_locked);  | 
