diff options
| author | Eric Anholt <eric@anholt.net> | 2007-07-26 10:14:17 -0700 | 
|---|---|---|
| committer | Eric Anholt <eric@anholt.net> | 2007-07-26 10:15:11 -0700 | 
| commit | cf2d569daca6954d11a796f4d110148ae2e0c827 (patch) | |
| tree | a90aa9eed7d107671af12a0c4d3886e4f51c0fc3 /linux-core | |
| parent | 03e932e32be6ae3de6994c6893c813a34623ad7d (diff) | |
Replace NO_MOVE/NO_EVICT flags to buffer objects with an ioctl to set pinning.
This cleans up the create/validate interfaces for this very uncommon path, and
makes pinned object creation much easier to use for the X Server.
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/drm_bo.c | 169 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 1 | ||||
| -rw-r--r-- | linux-core/drm_objects.h | 3 | 
3 files changed, 122 insertions, 51 deletions
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 75d89e46..53885a3e 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -80,8 +80,7 @@ void drm_bo_add_to_lru(struct drm_buffer_object * bo)  	DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); -	if (!(bo->mem.mask & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)) -	    || bo->mem.mem_type != bo->pinned_mem_type) { +	if (!bo->pinned || bo->mem.mem_type != bo->pinned_mem_type) {  		man = &bo->dev->bm.man[bo->mem.mem_type];  		list_add_tail(&bo->lru, &man->lru);  	} else { @@ -733,7 +732,7 @@ static int drm_bo_mem_force_space(struct drm_device * dev,  		atomic_inc(&entry->usage);  		mutex_unlock(&dev->struct_mutex);  		mutex_lock(&entry->mutex); -		BUG_ON(entry->mem.flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)); +		BUG_ON(entry->pinned);  		ret = drm_bo_evict(entry, mem_type, no_wait);  		mutex_unlock(&entry->mutex); @@ -893,18 +892,6 @@ static int drm_bo_new_mask(struct drm_buffer_object * bo,  		DRM_ERROR("User buffers are not supported yet\n");  		return -EINVAL;  	} -	if (bo->type == drm_bo_type_fake && -	    !(new_mask & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT))) { -		DRM_ERROR("Fake buffers must be pinned.\n"); -		return -EINVAL; -	} - -	if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { -		DRM_ERROR -		    ("DRM_BO_FLAG_NO_EVICT is only available to priviliged " -		     "processes\n"); -		return -EPERM; -	}  	new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE |  				DRM_BO_FLAG_READ); @@ -1382,6 +1369,12 @@ static int drm_buffer_object_validate(struct drm_buffer_object * bo,  		return ret;  	} +	if (bo->pinned && bo->pinned_mem_type != bo->mem.mem_type) { +		DRM_ERROR("Attempt to validate pinned buffer into different memory " +		    "type\n"); +		return -EINVAL; +	} +  	/*  	 * We're switching command submission mechanism,  	 * or cannot simply rely on the hardware serializing for us. @@ -1426,37 +1419,6 @@ static int drm_buffer_object_validate(struct drm_buffer_object * bo,  	}  	/* -	 * Pinned buffers. -	 */ - -	if (bo->mem.mask & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { -		bo->pinned_mem_type = bo->mem.mem_type; -		mutex_lock(&dev->struct_mutex); -		list_del_init(&bo->pinned_lru); -		drm_bo_add_to_pinned_lru(bo); - -		if (bo->pinned_node != bo->mem.mm_node) { -			if (bo->pinned_node != NULL) -				drm_mm_put_block(bo->pinned_node); -			bo->pinned_node = bo->mem.mm_node; -		} - -		mutex_unlock(&dev->struct_mutex); - -	} else if (bo->pinned_node != NULL) { - -		mutex_lock(&dev->struct_mutex); - -		if (bo->pinned_node != bo->mem.mm_node) -			drm_mm_put_block(bo->pinned_node); - -		list_del_init(&bo->pinned_lru); -		bo->pinned_node = NULL; -		mutex_unlock(&dev->struct_mutex); - -	} - -	/*  	 * We might need to add a TTM.  	 */ @@ -1533,6 +1495,10 @@ static int drm_bo_handle_validate(struct drm_file *file_priv,  	return ret;  } +/** + * Fills out the generic buffer object ioctl reply with the information for + * the BO with id of handle. + */  static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle,  			      struct drm_bo_info_rep *rep)  { @@ -1948,6 +1914,110 @@ int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *  	return 0;  } +/** + * Pins or unpins the given buffer object in the given memory area. + * + * Pinned buffers will not be evicted from or move within their memory area. + * Must be called with the hardware lock held for pinning. + */ +static int +drm_bo_set_pin(struct drm_device *dev, struct drm_buffer_object *bo, +    int pin) +{ +	int ret = 0; + +	mutex_lock(&bo->mutex); +	if (bo->pinned == pin) { +		mutex_unlock(&bo->mutex); +		return 0; +	} + +	if (pin) { +		ret = drm_bo_wait_unfenced(bo, 0, 0); +		if (ret) { +			mutex_unlock(&bo->mutex); +			return ret; +		} + +		/* Validate the buffer into its pinned location, with no pending +		 * fence. +		 */ +		ret = drm_buffer_object_validate(bo, 0, 0, 0); +		if (ret) { +			mutex_unlock(&bo->mutex); +			return ret; +		} + +		/* Add our buffer to the pinned list */ +		bo->pinned_mem_type = bo->mem.mem_type; +		mutex_lock(&dev->struct_mutex); +		list_del_init(&bo->pinned_lru); +		drm_bo_add_to_pinned_lru(bo); + +		if (bo->pinned_node != bo->mem.mm_node) { +			if (bo->pinned_node != NULL) +				drm_mm_put_block(bo->pinned_node); +			bo->pinned_node = bo->mem.mm_node; +		} + +		mutex_unlock(&dev->struct_mutex); + +	} else { +		mutex_lock(&dev->struct_mutex); + +		/* Remove our buffer from the pinned list */ +		if (bo->pinned_node != bo->mem.mm_node) +			drm_mm_put_block(bo->pinned_node); + +		list_del_init(&bo->pinned_lru); +		bo->pinned_node = NULL; +		mutex_unlock(&dev->struct_mutex); +	} +	bo->pinned = pin; +	mutex_unlock(&bo->mutex); +	return 0; +} + +int drm_bo_set_pin_ioctl(struct drm_device *dev, void *data, +			 struct drm_file *file_priv) +{ +	struct drm_bo_set_pin_arg *arg = data; +	struct drm_bo_set_pin_req *req = &arg->d.req; +	struct drm_bo_info_rep *rep = &arg->d.rep; +	struct drm_buffer_object *bo; +	int ret; + +	if (!dev->bm.initialized) { +		DRM_ERROR("Buffer object manager is not initialized.\n"); +		return -EINVAL; +	} + +	if (req->pin < 0 || req->pin > 1) { +		DRM_ERROR("Bad arguments to set_pin\n"); +		return -EINVAL; +	} + +	if (req->pin) +		LOCK_TEST_WITH_RETURN(dev, file_priv); + +	mutex_lock(&dev->struct_mutex); +	bo = drm_lookup_buffer_object(file_priv, req->handle, 1); +	mutex_unlock(&dev->struct_mutex); +	if (!bo) { +		return -EINVAL; +	} + +	ret = drm_bo_set_pin(dev, bo, req->pin); +	if (ret) { +		drm_bo_usage_deref_unlocked(&bo); +		return ret; +	} + +	drm_bo_fill_rep_arg(bo, rep); +	drm_bo_usage_deref_unlocked(&bo); + +	return 0; +}  /** @@ -2009,11 +2079,10 @@ static int drm_bo_leave_list(struct drm_buffer_object * bo,  		mutex_unlock(&dev->struct_mutex);  	} -	if (bo->mem.flags & DRM_BO_FLAG_NO_EVICT) { -		DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " +	if (bo->pinned) { +		DRM_ERROR("A pinned buffer was present at "  			  "cleanup. Removing flag and evicting.\n"); -		bo->mem.flags &= ~DRM_BO_FLAG_NO_EVICT; -		bo->mem.mask &= ~DRM_BO_FLAG_NO_EVICT; +		bo->pinned = 0;  	}  	if (bo->mem.mem_type == mem_type) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index cc676bda..93dfcdb5 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -147,6 +147,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {  	DRM_IOCTL_DEF(DRM_IOCTL_BO_OP, drm_bo_op_ioctl, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_ioctl, DRM_AUTH),  	DRM_IOCTL_DEF(DRM_IOCTL_BO_WAIT_IDLE, drm_bo_wait_idle_ioctl, DRM_AUTH), +	DRM_IOCTL_DEF(DRM_IOCTL_BO_SET_PIN, drm_bo_set_pin_ioctl, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),  };  #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index e5f2b69c..64f71651 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -362,6 +362,7 @@ struct drm_buffer_object {  	struct mutex mutex;  	/* For pinned buffers */ +	int pinned;  	struct drm_mm_node *pinned_node;  	uint32_t pinned_mem_type;  	struct list_head pinned_lru; @@ -455,7 +456,7 @@ extern int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct d  extern int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_bo_op_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); - +int drm_bo_set_pin_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  extern int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);  | 
