diff options
| -rw-r--r-- | linux-core/drmP.h | 3 | ||||
| -rw-r--r-- | linux-core/drm_bo.c | 160 | ||||
| -rw-r--r-- | linux-core/drm_ttm.c | 56 | ||||
| -rw-r--r-- | linux-core/drm_ttm.h | 7 | ||||
| -rw-r--r-- | shared-core/drm.h | 14 | 
5 files changed, 215 insertions, 25 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f83b4b4b..07f3571b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -949,8 +949,9 @@ typedef struct drm_buffer_object{  	drm_device_t *dev;  	drm_user_object_t base;  	atomic_t usage; -	drm_map_list_t *ttm_maplist; +	drm_ttm_object_t *ttm_object;  	drm_ttm_backend_list_t *ttm_region; +        void __user *user_pages;  	atomic_t mapped; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0aa0b138..affee135 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -148,7 +148,7 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy)  } -void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo)  {  	drm_buffer_manager_t *bm = &dev->bm; @@ -189,6 +189,31 @@ void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo)  	drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ);  } + +void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +{ +	if (atomic_dec_and_test(&bo->usage)) { +		drm_bo_destroy_locked(dev, bo); +	} +} + +void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +{ +	if (atomic_dec_and_test(&bo->usage)) { +		mutex_lock(&dev->struct_mutex); +		if (atomic_read(&bo->usage) == 0) +			drm_bo_destroy_locked(dev, bo); +		mutex_unlock(&dev->struct_mutex); +	} +} + +static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +{ +	drm_bo_usage_deref_locked(priv->head->dev,  +				  drm_user_object_entry(uo, drm_buffer_object_t, base)); +} +				   +  static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint,  			    int init, uint32_t *n_flags)  { @@ -399,6 +424,9 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo)  /*   * Wait for buffer idle and register that we've mapped the buffer. + * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1,  + * so that if the client dies, the mapping is automatically  + * unregistered.   */ @@ -421,13 +449,15 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait)  		if ((atomic_read(&bo->mapped) == 0) &&   		    drm_bo_busy(dev, bo)) {  			mutex_unlock(&bo->mutex); -			return -EBUSY; +			ret = -EBUSY; +			goto out;  		}  	} else {  		ret = drm_bo_wait(dev, bo, 0);  		if (ret) {  			mutex_unlock(&bo->mutex); -			return -EBUSY; +			ret = -EBUSY; +			goto out;  		}  	}  	mutex_lock(&dev->struct_mutex); @@ -438,11 +468,132 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait)  	}  	mutex_unlock(&bo->mutex); + out: +	drm_bo_usage_deref_unlocked(dev,bo); +	return ret; +} + + +static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +{ +	drm_device_t *dev = priv->head->dev; +	drm_buffer_object_t *bo; +	drm_ref_object_t *ro; +	int ret = 0; + +	mutex_lock(&dev->struct_mutex); + +	bo = drm_lookup_buffer_object(priv, handle, 1); +	if (!bo) { +		ret = -EINVAL; +		goto out; +	} + +	ro = drm_lookup_ref_object(priv, &bo->base, _DRM_REF_TYPE1); +	if (!ro) { +		ret = -EINVAL; +		goto out; +	} + +	drm_remove_ref_object(priv, ro); +	drm_bo_usage_deref_locked(dev, bo); + out: +	mutex_unlock(&dev->struct_mutex);  	return ret;  } +/* + * Call struct-sem locked. + */ +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +{ +	drm_device_t *dev = priv->head->dev; +	drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + +	if (atomic_dec_and_test(&bo->mapped)) { +		mutex_unlock(&dev->struct_mutex); +		mutex_lock(&bo->mutex); +		if (atomic_read(&bo->mapped) == 0) { +			DRM_WAKEUP(&bo->validate_queue); +		} +		mutex_unlock(&bo->mutex); +		mutex_lock(&dev->struct_mutex); +	} +} + +static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +{ +	return 0; +} + +int drm_buffer_object_create(drm_file_t *priv, +			     int size, +			     drm_bo_type_t type, +			     uint32_t ttm_handle, +			     uint32_t mask, +			     uint32_t hint, +			     void __user *user_pages, +			     drm_buffer_object_t **buf_obj) +{ +	drm_device_t *dev = priv->head->dev; +	drm_buffer_object_t *bo; +	int ret = 0; +	uint32_t ttm_flags = 0; + +	bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + +	if (!bo) +		return -ENOMEM; + +	mutex_init(&bo->mutex); +	mutex_lock(&bo->mutex); + +	atomic_set(&bo->usage, 1); +	atomic_set(&bo->mapped, 0); +	DRM_INIT_WAITQUEUE(&bo->validate_queue); +	INIT_LIST_HEAD(&bo->head); +	INIT_LIST_HEAD(&bo->ddestroy); +	bo->dev = dev; + +	switch(type) { +	case drm_bo_type_dc: +		ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); +		if (ret)  +			goto out_err; +		break; +	case drm_bo_type_ttm: +		bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); +		if (ret)  +			goto out_err; +		break; +	case drm_bo_type_user: +		bo->user_pages = user_pages; +		break; +	default: +		ret = -EINVAL; +		goto out_err; +	} +				 +	bo->mask = mask; +	bo->mask_hint = hint; + +	ret = drm_buffer_object_validate(dev, bo); +	if (ret) +		goto out_err; + +	mutex_unlock(&bo->mutex); +	*buf_obj = bo; +	return 0; +	 + out_err: +	mutex_unlock(&bo->mutex); +	drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); +	return  ret; +} +	 +	  int drm_bo_ioctl(DRM_IOCTL_ARGS)  { @@ -459,6 +610,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)  		rep.ret = 0;  		rep.handled = 0;  		switch (req->op) { +		case drm_bo_unmap: +			rep.ret = drm_buffer_object_unmap(priv, req->handle); +			break;  		case drm_bo_map:  			rep.ret = drm_buffer_object_map(priv, req->handle,   							!(req->hint &  diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e76b41fb..cda3ec29 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -752,7 +752,6 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len,  /*   * dev->struct_mutex locked.   */ -  static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object)  {  	drm_map_list_t *list = &object->map_list; @@ -777,17 +776,24 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object)  	drm_free(object, sizeof(*object), DRM_MEM_TTM);  } + +void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +{ +	if (atomic_dec_and_test(&to->usage)) { +		drm_ttm_object_remove(dev, to); +	} +} + +  /*   * dev->struct_mutex locked.   */ -static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base)  { -	drm_ttm_object_t *object; -	drm_device_t *dev = priv->head->dev; - -	object = drm_user_object_entry(base, drm_ttm_object_t, base); -	if (atomic_dec_and_test(&object->usage))  -		drm_ttm_object_remove(dev, object); +	DRM_ERROR("User deref ttm\n"); +	drm_ttm_object_deref_locked(priv->head->dev, +				    drm_user_object_entry(base, drm_ttm_object_t,  +							  base));  } @@ -840,16 +846,33 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size,  	}  	list->user_token = list->hash.key; -	object->base.remove = drm_ttm_user_object_remove; -	object->base.type = drm_ttm_type; -	object->base.ref_struct_locked = NULL; -	object->base.unref = NULL;  	atomic_set(&object->usage, 1);  	*ttm_object = object;  	return 0;  } +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle,  +					int check_owner) +{ +	drm_user_object_t *uo; +	drm_ttm_object_t *to; + +	uo = drm_lookup_user_object(priv, handle); + +	if (!uo || (uo->type != drm_ttm_type))  +		return NULL; + +	if (check_owner && priv != uo->owner) { +		if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) +			return NULL; +	} + +	to = drm_user_object_entry(uo, drm_ttm_object_t, base); +	atomic_inc(&to->usage); +	return to; +} +  int drm_ttm_ioctl(DRM_IOCTL_ARGS)  { @@ -878,6 +901,10 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS)  			mutex_unlock(&dev->struct_mutex);  			return ret;  		} +		entry->base.remove = drm_ttm_user_deref_locked; +		entry->base.type = drm_ttm_type; +		entry->base.ref_struct_locked = NULL; +		entry->base.unref = NULL;  		atomic_inc(&entry->usage);  		break;  	case drm_ttm_reference: @@ -885,8 +912,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS)  		if (ret)  			return ret;  		mutex_lock(&dev->struct_mutex); -		uo = drm_lookup_user_object(priv, arg.handle); -		entry = drm_user_object_entry(uo, drm_ttm_object_t, base); +		entry = drm_lookup_ttm_object(priv, arg.handle , 0);  		break;  	case drm_ttm_unreference:  		return drm_user_object_unref(priv, arg.handle, drm_ttm_type); @@ -904,7 +930,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS)  	arg.handle = entry->base.hash.key;  	arg.user_token = entry->map_list.user_token;  	arg.size = drm_u64(entry->map_list.map->size); -	atomic_dec(&entry->usage); +	drm_ttm_object_deref_locked(dev, entry);  	mutex_unlock(&dev->struct_mutex);  	DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 6ebb1aa2..a87cf53e 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -108,6 +108,13 @@ typedef struct drm_ttm_object {  	drm_map_list_t map_list;  } drm_ttm_object_t; +extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size,  +				 uint32_t flags, drm_ttm_object_t **ttm_object); +extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); +extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle,  +					       int check_owner); + + diff --git a/shared-core/drm.h b/shared-core/drm.h index 7133eb8f..14b1741f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -695,18 +695,19 @@ typedef struct drm_ttm_arg {  #define DRM_BO_HINT_AVOID_LOCAL 0x00000002  #define DRM_BO_HINT_DONT_BLOCK  0x00000004 +typedef enum { +	drm_bo_type_ttm, +	drm_bo_type_dc, +	drm_bo_type_user +}drm_bo_type_t; +	  typedef struct drm_bo_arg_request {  	unsigned handle; /* User space handle */  	unsigned mask;  	unsigned hint;  	drm_u64_t size; - -	enum { -		drm_bo_type_ttm, -		drm_bo_type_dc, -		drm_bo_type_user -	}type; +	drm_bo_type_t type;  	unsigned arg_handle;  	drm_u64_t user_pointer;  	drm_u64_t next; @@ -714,6 +715,7 @@ typedef struct drm_bo_arg_request {  		drm_bo_create,  		drm_bo_validate,  		drm_bo_map, +		drm_bo_unmap,  		drm_bo_fence,  		drm_bo_destroy,  		drm_bo_reference,  | 
