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.
main
Eric Anholt 2007-07-26 10:14:17 -07:00
parent 03e932e32b
commit cf2d569dac
6 changed files with 165 additions and 61 deletions

View File

@ -2975,7 +2975,30 @@ int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint)
}
return 0;
}
int drmBOSetPin(int fd, drmBO *buf, int pin)
{
struct drm_bo_set_pin_arg arg;
struct drm_bo_set_pin_req *req = &arg.d.req;
struct drm_bo_info_rep *rep = &arg.d.rep;
int ret = 0;
memset(&arg, 0, sizeof(arg));
req->handle = buf->handle;
req->pin = pin;
do {
ret = ioctl(fd, DRM_IOCTL_BO_SET_PIN, &arg);
} while (ret && errno == EAGAIN);
if (ret)
return -errno;
drmBOCopyReply(rep, buf);
return 0;
}
int drmBOBusy(int fd, drmBO *buf, int *busy)
{
if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) &&

View File

@ -201,6 +201,7 @@ extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags,
extern int drmBOValidateList(int fd, drmBOList *list);
extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle);
extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint);
int drmBOSetPin(int fd, drmBO *buf, int pin);
/*
* Initialization functions.

View File

@ -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.
@ -1425,37 +1418,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)

View File

@ -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 )

View File

@ -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);

View File

@ -688,14 +688,6 @@ struct drm_fence_arg {
* Can also be set in the buffer mask before validation.
*/
/*
* Mask: Never evict this buffer. Not even with force. This type of buffer is only
* available to root and must be manually removed before buffer manager shutdown
* or lock.
* Flags: Acknowledge
*/
#define DRM_BO_FLAG_NO_EVICT (1ULL << 4)
/*
* Mask: Require that the buffer is placed in mappable memory when validated.
* If not set the buffer may or may not be in mappable memory when validated.
@ -813,6 +805,16 @@ struct drm_bo_op_req {
struct drm_bo_info_req bo_req;
};
struct drm_bo_set_pin_req {
/** Buffer object ID */
unsigned int handle;
/**
* - 0: Unpin the given buffer object.
* - 1: Pin the given buffer object.
*/
unsigned int pin;
};
/*
* Reply flags
*/
@ -878,6 +880,13 @@ struct drm_bo_op_arg {
unsigned int pad64;
};
struct drm_bo_set_pin_arg {
union {
struct drm_bo_set_pin_req req;
struct drm_bo_info_rep rep;
} d;
};
#define DRM_BO_MEM_LOCAL 0
#define DRM_BO_MEM_TT 1
#define DRM_BO_MEM_VRAM 2
@ -993,7 +1002,7 @@ struct drm_mm_init_arg {
#define DRM_IOCTL_BO_OP DRM_IOWR(0xd3, struct drm_bo_op_arg)
#define DRM_IOCTL_BO_INFO DRM_IOWR(0xd4, struct drm_bo_reference_info_arg)
#define DRM_IOCTL_BO_WAIT_IDLE DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg)
#define DRM_IOCTL_BO_SET_PIN DRM_IOWR(0xd6, struct drm_bo_set_pin_arg)
/*@}*/