Merge branch 'master' into modesetting-101

Conflicts:

	linux-core/Makefile.kernel
	linux-core/drm_bo.c
	linux-core/drm_objects.h
main
Thomas Hellstrom 2007-10-25 11:00:45 +02:00
commit 9adf8c0256
18 changed files with 567 additions and 526 deletions

View File

@ -2695,62 +2695,37 @@ int drmBOUnmap(int fd, drmBO *buf)
return 0; return 0;
} }
int drmBOValidate(int fd, drmBO *buf, uint32_t fence_class, int drmBOSetStatus(int fd, drmBO *buf,
uint64_t flags, uint64_t mask, uint64_t flags, uint64_t mask,
unsigned hint) unsigned int hint,
unsigned int desired_tile_stride,
unsigned int tile_info)
{ {
struct drm_bo_op_arg arg;
struct drm_bo_op_req *req = &arg.d.req; struct drm_bo_map_wait_idle_arg arg;
struct drm_bo_arg_rep *rep = &arg.d.rep; struct drm_bo_info_req *req = &arg.d.req;
struct drm_bo_info_rep *rep = &arg.d.rep;
int ret = 0; int ret = 0;
memset(&arg, 0, sizeof(arg)); memset(&arg, 0, sizeof(arg));
req->bo_req.handle = buf->handle; req->mask = mask;
req->bo_req.flags = flags; req->flags = flags;
req->bo_req.mask = mask; req->handle = buf->handle;
req->bo_req.hint = hint; req->hint = hint;
req->bo_req.fence_class = fence_class; req->desired_tile_stride = desired_tile_stride;
req->op = drm_bo_validate; req->tile_info = tile_info;
do{ do {
ret = ioctl(fd, DRM_IOCTL_BO_OP, &arg); ret = ioctl(fd, DRM_IOCTL_BO_SETSTATUS, &arg);
} while (ret && errno == EAGAIN); } while (ret && errno == EAGAIN);
if (ret) if (ret)
return -errno; return -errno;
if (!arg.handled)
return -EFAULT;
if (rep->ret)
return rep->ret;
drmBOCopyReply(&rep->bo_info, buf); drmBOCopyReply(rep, buf);
return 0;
} }
int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle)
{
struct drm_bo_op_arg arg;
struct drm_bo_op_req *req = &arg.d.req;
struct drm_bo_arg_rep *rep = &arg.d.rep;
int ret = 0;
memset(&arg, 0, sizeof(arg));
req->bo_req.handle = buf->handle;
req->bo_req.flags = flags;
req->arg_handle = fenceHandle;
req->op = drm_bo_fence;
ret = ioctl(fd, DRM_IOCTL_BO_OP, &arg);
if (ret)
return -errno;
if (!arg.handled)
return -EFAULT;
if (rep->ret)
return rep->ret;
return 0;
}
int drmBOInfo(int fd, drmBO *buf) int drmBOInfo(int fd, drmBO *buf)
{ {
struct drm_bo_reference_info_arg arg; struct drm_bo_reference_info_arg arg;
@ -2794,29 +2769,6 @@ int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint)
return 0; 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) int drmBOBusy(int fd, drmBO *buf, int *busy)
{ {
if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) && if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) &&
@ -2864,13 +2816,20 @@ int drmMMTakedown(int fd, unsigned memType)
return 0; return 0;
} }
int drmMMLock(int fd, unsigned memType) /*
* If this function returns an error, and lockBM was set to 1,
* the buffer manager is NOT locked.
*/
int drmMMLock(int fd, unsigned memType, int lockBM, int ignoreNoEvict)
{ {
struct drm_mm_type_arg arg; struct drm_mm_type_arg arg;
int ret; int ret;
memset(&arg, 0, sizeof(arg)); memset(&arg, 0, sizeof(arg));
arg.mem_type = memType; arg.mem_type = memType;
arg.lock_flags |= (lockBM) ? DRM_BO_LOCK_UNLOCK_BM : 0;
arg.lock_flags |= (ignoreNoEvict) ? DRM_BO_LOCK_IGNORE_NO_EVICT : 0;
do{ do{
ret = ioctl(fd, DRM_IOCTL_MM_LOCK, &arg); ret = ioctl(fd, DRM_IOCTL_MM_LOCK, &arg);
@ -2879,7 +2838,7 @@ int drmMMLock(int fd, unsigned memType)
return (ret) ? -errno : 0; return (ret) ? -errno : 0;
} }
int drmMMUnlock(int fd, unsigned memType) int drmMMUnlock(int fd, unsigned memType, int unlockBM)
{ {
struct drm_mm_type_arg arg; struct drm_mm_type_arg arg;
int ret; int ret;
@ -2887,6 +2846,7 @@ int drmMMUnlock(int fd, unsigned memType)
memset(&arg, 0, sizeof(arg)); memset(&arg, 0, sizeof(arg));
arg.mem_type = memType; arg.mem_type = memType;
arg.lock_flags |= (unlockBM) ? DRM_BO_LOCK_UNLOCK_BM : 0;
do{ do{
ret = ioctl(fd, DRM_IOCTL_MM_UNLOCK, &arg); ret = ioctl(fd, DRM_IOCTL_MM_UNLOCK, &arg);
@ -2895,6 +2855,30 @@ int drmMMUnlock(int fd, unsigned memType)
return (ret) ? -errno : 0; return (ret) ? -errno : 0;
} }
int drmBOVersion(int fd, unsigned int *major,
unsigned int *minor,
unsigned int *patchlevel)
{
struct drm_bo_version_arg arg;
int ret;
memset(&arg, 0, sizeof(arg));
ret = ioctl(fd, DRM_IOCTL_BO_VERSION, &arg);
if (ret)
return ret;
if (major)
*major = arg.major;
if (minor)
*minor = arg.minor;
if (patchlevel)
*patchlevel = arg.patchlevel;
return (ret) ? -errno : 0;
}
#define DRM_MAX_FDS 16 #define DRM_MAX_FDS 16
static struct { static struct {
char *BusID; char *BusID;

View File

@ -164,7 +164,6 @@ extern int drmBOInfo(int fd, drmBO *buf);
extern int drmBOBusy(int fd, drmBO *buf, int *busy); extern int drmBOBusy(int fd, drmBO *buf, int *busy);
extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint);
int drmBOSetPin(int fd, drmBO *buf, int pin);
/* /*
* Initialization functions. * Initialization functions.
@ -173,8 +172,16 @@ int drmBOSetPin(int fd, drmBO *buf, int pin);
extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize,
unsigned memType); unsigned memType);
extern int drmMMTakedown(int fd, unsigned memType); extern int drmMMTakedown(int fd, unsigned memType);
extern int drmMMLock(int fd, unsigned memType); extern int drmMMLock(int fd, unsigned memType, int lockBM, int ignoreNoEvict);
extern int drmMMUnlock(int fd, unsigned memType); extern int drmMMUnlock(int fd, unsigned memType, int unlockBM);
extern int drmBOSetStatus(int fd, drmBO *buf,
uint64_t flags, uint64_t mask,
unsigned int hint,
unsigned int desired_tile_stride,
unsigned int tile_info);
extern int drmBOVersion(int fd, unsigned int *major,
unsigned int *minor,
unsigned int *patchlevel);
#endif #endif

View File

@ -269,7 +269,6 @@ PAGE_AGP := $(shell cat $(LINUXDIR)/include/asm/agp.h 2>/dev/null | \
ifneq ($(PAGE_AGP),0) ifneq ($(PAGE_AGP),0)
EXTRA_CFLAGS += -DHAVE_PAGE_AGP EXTRA_CFLAGS += -DHAVE_PAGE_AGP
endif endif
EXTRA_CFLAGS += -g
# Start with all modules turned off. # Start with all modules turned off.
CONFIG_DRM_GAMMA := n CONFIG_DRM_GAMMA := n

View File

@ -14,7 +14,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \
drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \
drm_edid.o drm_modes.o drm_edid.o drm_modes.o drm_bo_lock.o
tdfx-objs := tdfx_drv.o tdfx-objs := tdfx_drv.o
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o

View File

@ -80,7 +80,8 @@ void drm_bo_add_to_lru(struct drm_buffer_object * bo)
DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); DRM_ASSERT_LOCKED(&bo->dev->struct_mutex);
if (!bo->pinned || bo->mem.mem_type != bo->pinned_mem_type) { if (!(bo->mem.mask & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT))
|| bo->mem.mem_type != bo->pinned_mem_type) {
man = &bo->dev->bm.man[bo->mem.mem_type]; man = &bo->dev->bm.man[bo->mem.mem_type];
list_add_tail(&bo->lru, &man->lru); list_add_tail(&bo->lru, &man->lru);
} else { } else {
@ -637,8 +638,7 @@ int drm_fence_buffer_objects(struct drm_device *dev,
mutex_lock(&entry->mutex); mutex_lock(&entry->mutex);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
list_del_init(l); list_del_init(l);
if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED && if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) {
entry->fence_class == fence_class) {
count++; count++;
if (entry->fence) if (entry->fence)
drm_fence_usage_deref_locked(&entry->fence); drm_fence_usage_deref_locked(&entry->fence);
@ -760,7 +760,7 @@ static int drm_bo_mem_force_space(struct drm_device * dev,
atomic_inc(&entry->usage); atomic_inc(&entry->usage);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_lock(&entry->mutex); mutex_lock(&entry->mutex);
BUG_ON(entry->pinned); BUG_ON(entry->mem.flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT));
ret = drm_bo_evict(entry, mem_type, no_wait); ret = drm_bo_evict(entry, mem_type, no_wait);
mutex_unlock(&entry->mutex); mutex_unlock(&entry->mutex);
@ -920,16 +920,29 @@ int drm_bo_mem_space(struct drm_buffer_object * bo,
EXPORT_SYMBOL(drm_bo_mem_space); EXPORT_SYMBOL(drm_bo_mem_space);
static int drm_bo_new_mask(struct drm_buffer_object * bo, static int drm_bo_new_mask(struct drm_buffer_object * bo,
uint64_t new_mask, uint32_t hint) uint64_t new_flags, uint64_t used_mask)
{ {
uint32_t new_props; uint32_t new_props;
if (bo->type == drm_bo_type_user) { if (bo->type == drm_bo_type_user) {
DRM_ERROR("User buffers are not supported yet\n"); DRM_ERROR("User buffers are not supported yet.\n");
return -EINVAL; return -EINVAL;
} }
new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | if ((used_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;
}
if ((new_flags & DRM_BO_FLAG_NO_MOVE)) {
DRM_ERROR
("DRM_BO_FLAG_NO_MOVE is not properly implemented yet.\n");
return -EPERM;
}
new_props = new_flags & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_READ); DRM_BO_FLAG_READ);
if (!new_props) { if (!new_props) {
@ -937,7 +950,7 @@ static int drm_bo_new_mask(struct drm_buffer_object * bo,
return -EINVAL; return -EINVAL;
} }
bo->mem.mask = new_mask; bo->mem.mask = new_flags;
return 0; return 0;
} }
@ -1058,13 +1071,6 @@ static int drm_bo_check_unfenced(struct drm_buffer_object * bo)
/* /*
* Wait until a buffer, scheduled to be fenced moves off the unfenced list. * Wait until a buffer, scheduled to be fenced moves off the unfenced list.
* Until then, we cannot really do anything with it except delete it. * Until then, we cannot really do anything with it except delete it.
* The unfenced list is a PITA, and the operations
* 1) validating
* 2) submitting commands
* 3) fencing
* Should really be an atomic operation.
* We now "solve" this problem by keeping
* the buffer "unfenced" after validating, but before fencing.
*/ */
static int drm_bo_wait_unfenced(struct drm_buffer_object * bo, int no_wait, static int drm_bo_wait_unfenced(struct drm_buffer_object * bo, int no_wait,
@ -1147,11 +1153,9 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle,
return -EINVAL; return -EINVAL;
mutex_lock(&bo->mutex); mutex_lock(&bo->mutex);
if (!(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) {
ret = drm_bo_wait_unfenced(bo, no_wait, 0); ret = drm_bo_wait_unfenced(bo, no_wait, 0);
if (ret) if (ret)
goto out; goto out;
}
/* /*
* If this returns true, we are currently unmapped. * If this returns true, we are currently unmapped.
@ -1294,10 +1298,7 @@ int drm_bo_move_buffer(struct drm_buffer_object * bo, uint32_t new_mem_flags,
mutex_lock(&bm->evict_mutex); mutex_lock(&bm->evict_mutex);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
list_del(&bo->lru); list_del_init(&bo->lru);
list_add_tail(&bo->lru, &bm->unfenced);
DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED,
_DRM_BO_FLAG_UNFENCED);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
/* /*
@ -1317,10 +1318,6 @@ int drm_bo_move_buffer(struct drm_buffer_object * bo, uint32_t new_mem_flags,
drm_mm_put_block(mem.mm_node); drm_mm_put_block(mem.mm_node);
mem.mm_node = NULL; mem.mm_node = NULL;
} }
DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
DRM_WAKEUP(&bo->event_queue);
list_del(&bo->lru);
drm_bo_add_to_lru(bo);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} }
@ -1371,12 +1368,6 @@ static int drm_buffer_object_validate(struct drm_buffer_object * bo,
return ret; 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, * We're switching command submission mechanism,
* or cannot simply rely on the hardware serializing for us. * or cannot simply rely on the hardware serializing for us.
@ -1417,6 +1408,37 @@ 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. * We might need to add a TTM.
*/ */
@ -1467,7 +1489,7 @@ int drm_bo_do_validate(struct drm_buffer_object *bo,
DRM_FLAG_MASKED(flags, bo->mem.mask, ~mask); DRM_FLAG_MASKED(flags, bo->mem.mask, ~mask);
ret = drm_bo_new_mask(bo, flags, hint); ret = drm_bo_new_mask(bo, flags, mask);
if (ret) if (ret)
goto out; goto out;
@ -1487,7 +1509,9 @@ EXPORT_SYMBOL(drm_bo_do_validate);
int drm_bo_handle_validate(struct drm_file * file_priv, uint32_t handle, int drm_bo_handle_validate(struct drm_file * file_priv, uint32_t handle,
uint32_t fence_class, uint32_t fence_class,
uint64_t flags, uint64_t mask, uint32_t hint, uint64_t flags, uint64_t mask,
uint32_t hint,
int use_old_fence_class,
struct drm_bo_info_rep * rep, struct drm_bo_info_rep * rep,
struct drm_buffer_object **bo_rep) struct drm_buffer_object **bo_rep)
{ {
@ -1500,9 +1524,19 @@ int drm_bo_handle_validate(struct drm_file * file_priv, uint32_t handle,
bo = drm_lookup_buffer_object(file_priv, handle, 1); bo = drm_lookup_buffer_object(file_priv, handle, 1);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
if (!bo) { if (!bo)
return -EINVAL; return -EINVAL;
}
if (use_old_fence_class)
fence_class = bo->fence_class;
/*
* Only allow creator to change shared buffer mask.
*/
if (bo->base.owner != file_priv)
mask &= ~(DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE);
ret = drm_bo_do_validate(bo, flags, mask, hint, fence_class, ret = drm_bo_do_validate(bo, flags, mask, hint, fence_class,
no_wait, rep); no_wait, rep);
@ -1516,10 +1550,6 @@ int drm_bo_handle_validate(struct drm_file * file_priv, uint32_t handle,
} }
EXPORT_SYMBOL(drm_bo_handle_validate); EXPORT_SYMBOL(drm_bo_handle_validate);
/**
* 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, static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle,
struct drm_bo_info_rep *rep) struct drm_bo_info_rep *rep)
{ {
@ -1586,7 +1616,6 @@ int drm_buffer_object_create(struct drm_device *dev,
{ {
struct drm_buffer_manager *bm = &dev->bm; struct drm_buffer_manager *bm = &dev->bm;
struct drm_buffer_object *bo; struct drm_buffer_object *bo;
struct drm_bo_driver *driver = dev->driver->bo_driver;
int ret = 0; int ret = 0;
unsigned long num_pages; unsigned long num_pages;
@ -1630,8 +1659,10 @@ int drm_buffer_object_create(struct drm_device *dev,
bo->mem.page_alignment = page_alignment; bo->mem.page_alignment = page_alignment;
bo->buffer_start = buffer_start; bo->buffer_start = buffer_start;
bo->priv_flags = 0; bo->priv_flags = 0;
bo->mem.flags = 0ULL; bo->mem.flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED |
bo->mem.mask = 0ULL; DRM_BO_FLAG_MAPPABLE;
bo->mem.mask = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED |
DRM_BO_FLAG_MAPPABLE;
atomic_inc(&bm->count); atomic_inc(&bm->count);
ret = drm_bo_new_mask(bo, mask, hint); ret = drm_bo_new_mask(bo, mask, hint);
@ -1646,21 +1677,10 @@ int drm_buffer_object_create(struct drm_device *dev,
goto out_err; goto out_err;
} }
bo->fence_class = 0; ret = drm_buffer_object_validate(bo, 0, 0, hint & DRM_BO_HINT_DONT_BLOCK);
ret = driver->fence_type(bo, &bo->fence_class, &bo->fence_type);
if (ret) {
DRM_ERROR("Driver did not support given buffer permissions\n");
goto out_err;
}
ret = drm_bo_add_ttm(bo);
if (ret) if (ret)
goto out_err; goto out_err;
mutex_lock(&dev->struct_mutex);
drm_bo_add_to_lru(bo);
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&bo->mutex); mutex_unlock(&bo->mutex);
*buf_obj = bo; *buf_obj = bo;
return 0; return 0;
@ -1673,6 +1693,7 @@ int drm_buffer_object_create(struct drm_device *dev,
} }
EXPORT_SYMBOL(drm_buffer_object_create); EXPORT_SYMBOL(drm_buffer_object_create);
static int drm_bo_add_user_object(struct drm_file *file_priv, static int drm_bo_add_user_object(struct drm_file *file_priv,
struct drm_buffer_object *bo, int shareable) struct drm_buffer_object *bo, int shareable)
{ {
@ -1694,88 +1715,6 @@ static int drm_bo_add_user_object(struct drm_file *file_priv,
return ret; return ret;
} }
static int drm_bo_lock_test(struct drm_device * dev, struct drm_file *file_priv)
{
LOCK_TEST_WITH_RETURN(dev, file_priv);
return 0;
}
int drm_bo_op_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_bo_op_arg curarg;
struct drm_bo_op_arg *arg = data;
struct drm_bo_op_req *req = &arg->d.req;
struct drm_bo_info_rep rep;
unsigned long next = 0;
void __user *curuserarg = NULL;
int ret;
DRM_DEBUG("drm_bo_op_ioctl\n");
if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL;
}
do {
if (next != 0) {
curuserarg = (void __user *)next;
if (copy_from_user(&curarg, curuserarg,
sizeof(curarg)) != 0)
return -EFAULT;
arg = &curarg;
}
if (arg->handled) {
next = arg->next;
continue;
}
req = &arg->d.req;
ret = 0;
switch (req->op) {
case drm_bo_validate:
ret = drm_bo_lock_test(dev, file_priv);
if (ret)
break;
ret = drm_bo_handle_validate(file_priv, req->bo_req.handle,
req->bo_req.fence_class,
req->bo_req.flags,
req->bo_req.mask,
req->bo_req.hint,
&rep, NULL);
break;
case drm_bo_fence:
ret = -EINVAL;
DRM_ERROR("Function is not implemented yet.\n");
break;
case drm_bo_ref_fence:
ret = -EINVAL;
DRM_ERROR("Function is not implemented yet.\n");
break;
default:
ret = -EINVAL;
}
next = arg->next;
/*
* A signal interrupted us. Make sure the ioctl is restartable.
*/
if (ret == -EAGAIN)
return -EAGAIN;
arg->handled = 1;
arg->d.rep.ret = ret;
arg->d.rep.bo_info = rep;
if (arg != data) {
if (copy_to_user(curuserarg, &curarg,
sizeof(curarg)) != 0)
return -EFAULT;
}
} while (next != 0);
return 0;
}
int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ {
struct drm_bo_create_arg *arg = data; struct drm_bo_create_arg *arg = data;
@ -1814,15 +1753,43 @@ out:
return ret; return ret;
} }
int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_bo_setstatus_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{ {
struct drm_bo_map_wait_idle_arg *arg = data; struct drm_bo_map_wait_idle_arg *arg = data;
struct drm_bo_info_req *req = &arg->d.req; struct drm_bo_info_req *req = &arg->d.req;
struct drm_bo_info_rep *rep = &arg->d.rep; struct drm_bo_info_rep *rep = &arg->d.rep;
int ret; int ret;
DRM_DEBUG("drm_bo_map_ioctl: buffer %d\n", req->handle); if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL;
}
ret = drm_bo_read_lock(&dev->bm.bm_lock);
if (ret)
return ret;
ret = drm_bo_handle_validate(file_priv, req->handle, req->fence_class,
req->flags,
req->mask,
req->hint | DRM_BO_HINT_DONT_FENCE,
1,
rep, NULL);
(void) drm_bo_read_unlock(&dev->bm.bm_lock);
if (ret)
return ret;
return 0;
}
int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_bo_map_wait_idle_arg *arg = data;
struct drm_bo_info_req *req = &arg->d.req;
struct drm_bo_info_rep *rep = &arg->d.rep;
int ret;
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n"); DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL; return -EINVAL;
@ -1840,9 +1807,6 @@ int drm_bo_unmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file
{ {
struct drm_bo_handle_arg *arg = data; struct drm_bo_handle_arg *arg = data;
int ret; int ret;
DRM_DEBUG("drm_bo_unmap_ioctl: buffer %d\n", arg->handle);
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n"); DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL; return -EINVAL;
@ -1861,8 +1825,6 @@ int drm_bo_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *
struct drm_user_object *uo; struct drm_user_object *uo;
int ret; int ret;
DRM_DEBUG("drm_bo_reference_ioctl: buffer %d\n", req->handle);
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n"); DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL; return -EINVAL;
@ -1885,8 +1847,6 @@ int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file
struct drm_bo_handle_arg *arg = data; struct drm_bo_handle_arg *arg = data;
int ret = 0; int ret = 0;
DRM_DEBUG("drm_bo_unreference_ioctl: buffer %d\n", arg->handle);
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n"); DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL; return -EINVAL;
@ -1903,8 +1863,6 @@ int drm_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
struct drm_bo_info_rep *rep = &arg->d.rep; struct drm_bo_info_rep *rep = &arg->d.rep;
int ret; int ret;
DRM_DEBUG("drm_bo_info_ioctl: buffer %d\n", req->handle);
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n"); DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL; return -EINVAL;
@ -1923,9 +1881,6 @@ int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *
struct drm_bo_info_req *req = &arg->d.req; struct drm_bo_info_req *req = &arg->d.req;
struct drm_bo_info_rep *rep = &arg->d.rep; struct drm_bo_info_rep *rep = &arg->d.rep;
int ret; int ret;
DRM_DEBUG("drm_bo_wait_idle_ioctl: buffer %d\n", req->handle);
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
DRM_ERROR("Buffer object manager is not initialized.\n"); DRM_ERROR("Buffer object manager is not initialized.\n");
return -EINVAL; return -EINVAL;
@ -1939,177 +1894,10 @@ int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *
return 0; 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.
*/
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, bo->fence_class, 0, 0);
if (ret) {
mutex_unlock(&bo->mutex);
return ret;
}
/* Pull the buffer off of the LRU and add it to the pinned
* list
*/
bo->pinned_mem_type = bo->mem.mem_type;
mutex_lock(&dev->struct_mutex);
list_del_init(&bo->lru);
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;
}
bo->pinned = pin;
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;
bo->pinned = pin;
mutex_unlock(&dev->struct_mutex);
}
mutex_unlock(&bo->mutex);
return 0;
}
EXPORT_SYMBOL(drm_bo_set_pin);
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;
DRM_DEBUG("drm_bo_set_pin_ioctl: buffer %d, pin %d\n",
req->handle, req->pin);
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;
}
/**
*Clean the unfenced list and put on regular LRU.
*This is part of the memory manager cleanup and should only be
*called with the DRI lock held.
*Call dev->struct_sem locked.
*/
static void drm_bo_clean_unfenced(struct drm_device *dev)
{
struct drm_buffer_manager *bm = &dev->bm;
struct list_head *head, *list;
struct drm_buffer_object *entry;
struct drm_fence_object *fence;
head = &bm->unfenced;
if (list_empty(head))
return;
DRM_ERROR("Clean unfenced\n");
if (drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence)) {
/*
* Fixme: Should really wait here.
*/
}
if (fence)
drm_fence_usage_deref_locked(&fence);
if (list_empty(head))
return;
DRM_ERROR("Really clean unfenced\n");
list = head->next;
while(list != head) {
prefetch(list->next);
entry = list_entry(list, struct drm_buffer_object, lru);
atomic_inc(&entry->usage);
mutex_unlock(&dev->struct_mutex);
mutex_lock(&entry->mutex);
mutex_lock(&dev->struct_mutex);
list_del(&entry->lru);
DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
drm_bo_add_to_lru(entry);
mutex_unlock(&entry->mutex);
list = head->next;
}
}
static int drm_bo_leave_list(struct drm_buffer_object * bo, static int drm_bo_leave_list(struct drm_buffer_object * bo,
uint32_t mem_type, uint32_t mem_type,
int free_pinned, int allow_errors) int free_pinned,
int allow_errors)
{ {
struct drm_device *dev = bo->dev; struct drm_device *dev = bo->dev;
int ret = 0; int ret = 0;
@ -2133,10 +1921,11 @@ static int drm_bo_leave_list(struct drm_buffer_object * bo,
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} }
if (bo->pinned) { if (bo->mem.flags & DRM_BO_FLAG_NO_EVICT) {
DRM_ERROR("A pinned buffer was present at " DRM_ERROR("A DRM_BO_NO_EVICT buffer present at "
"cleanup. Removing flag and evicting.\n"); "cleanup. Removing flag and evicting.\n");
bo->pinned = 0; bo->mem.flags &= ~DRM_BO_FLAG_NO_EVICT;
bo->mem.mask &= ~DRM_BO_FLAG_NO_EVICT;
} }
if (bo->mem.mem_type == mem_type) if (bo->mem.mem_type == mem_type)
@ -2256,8 +2045,7 @@ int drm_bo_clean_mm(struct drm_device * dev, unsigned mem_type)
ret = 0; ret = 0;
if (mem_type > 0) { if (mem_type > 0) {
BUG_ON(!list_empty(&bm->unfenced));
drm_bo_clean_unfenced(dev);
drm_bo_force_list_clean(dev, &man->lru, mem_type, 1, 0, 0); drm_bo_force_list_clean(dev, &man->lru, mem_type, 1, 0, 0);
drm_bo_force_list_clean(dev, &man->pinned, mem_type, 1, 0, 1); drm_bo_force_list_clean(dev, &man->pinned, mem_type, 1, 0, 1);
@ -2295,7 +2083,6 @@ static int drm_bo_lock_mm(struct drm_device * dev, unsigned mem_type)
return 0; return 0;
} }
drm_bo_clean_unfenced(dev);
ret = drm_bo_force_list_clean(dev, &man->lru, mem_type, 0, 1, 0); ret = drm_bo_force_list_clean(dev, &man->lru, mem_type, 0, 1, 0);
if (ret) if (ret)
return ret; return ret;
@ -2349,8 +2136,10 @@ int drm_bo_init_mm(struct drm_device * dev,
EXPORT_SYMBOL(drm_bo_init_mm); EXPORT_SYMBOL(drm_bo_init_mm);
/* /*
* This is called from lastclose, so we don't need to bother about * This function is intended to be called on drm driver unload.
* any clients still running when we set the initialized flag to zero. * If you decide to call it from lastclose, you must protect the call
* from a potentially racing drm_bo_driver_init in firstopen.
* (This may happen on X server restart).
*/ */
int drm_bo_driver_finish(struct drm_device * dev) int drm_bo_driver_finish(struct drm_device * dev)
@ -2360,7 +2149,6 @@ int drm_bo_driver_finish(struct drm_device * dev)
unsigned i = DRM_BO_MEM_TYPES; unsigned i = DRM_BO_MEM_TYPES;
struct drm_mem_type_manager *man; struct drm_mem_type_manager *man;
mutex_lock(&dev->bm.init_mutex);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (!bm->initialized) if (!bm->initialized)
@ -2400,18 +2188,24 @@ int drm_bo_driver_finish(struct drm_device * dev)
} }
out: out:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->bm.init_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL(drm_bo_driver_finish); EXPORT_SYMBOL(drm_bo_driver_finish);
/*
* This function is intended to be called on drm driver load.
* If you decide to call it from firstopen, you must protect the call
* from a potentially racing drm_bo_driver_finish in lastclose.
* (This may happen on X server restart).
*/
int drm_bo_driver_init(struct drm_device * dev) int drm_bo_driver_init(struct drm_device * dev)
{ {
struct drm_bo_driver *driver = dev->driver->bo_driver; struct drm_bo_driver *driver = dev->driver->bo_driver;
struct drm_buffer_manager *bm = &dev->bm; struct drm_buffer_manager *bm = &dev->bm;
int ret = -EINVAL; int ret = -EINVAL;
mutex_lock(&dev->bm.init_mutex); drm_bo_init_lock(&bm->bm_lock);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (!driver) if (!driver)
goto out_unlock; goto out_unlock;
@ -2437,7 +2231,6 @@ int drm_bo_driver_init(struct drm_device * dev)
INIT_LIST_HEAD(&bm->ddestroy); INIT_LIST_HEAD(&bm->ddestroy);
out_unlock: out_unlock:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->bm.init_mutex);
return ret; return ret;
} }
@ -2450,14 +2243,15 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
struct drm_bo_driver *driver = dev->driver->bo_driver; struct drm_bo_driver *driver = dev->driver->bo_driver;
int ret; int ret;
DRM_DEBUG("drm_mm_init_ioctl: type %d, 0x%08llx offset, %dkb\n",
arg->mem_type, arg->p_offset * PAGE_SIZE, (int)(arg->p_size * 4));
if (!driver) { if (!driver) {
DRM_ERROR("Buffer objects are not supported by this driver\n"); DRM_ERROR("Buffer objects are not supported by this driver\n");
return -EINVAL; return -EINVAL;
} }
ret = drm_bo_write_lock(&bm->bm_lock, file_priv);
if (ret)
return ret;
ret = -EINVAL; ret = -EINVAL;
if (arg->magic != DRM_BO_INIT_MAGIC) { if (arg->magic != DRM_BO_INIT_MAGIC) {
DRM_ERROR("You are using an old libdrm that is not compatible with\n" DRM_ERROR("You are using an old libdrm that is not compatible with\n"
@ -2466,19 +2260,11 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
} }
if (arg->major != DRM_BO_INIT_MAJOR) { if (arg->major != DRM_BO_INIT_MAJOR) {
DRM_ERROR("libdrm and kernel DRM buffer object interface major\n" DRM_ERROR("libdrm and kernel DRM buffer object interface major\n"
"\tversion don't match. Got %d, expected %d,\n", "\tversion don't match. Got %d, expected %d.\n",
arg->major, DRM_BO_INIT_MAJOR); arg->major, DRM_BO_INIT_MAJOR);
return -EINVAL; return -EINVAL;
} }
if (arg->minor > DRM_BO_INIT_MINOR) {
DRM_ERROR("libdrm expects a newer DRM buffer object interface.\n"
"\tlibdrm buffer object interface version is %d.%d.\n"
"\tkernel DRM buffer object interface version is %d.%d\n",
arg->major, arg->minor, DRM_BO_INIT_MAJOR, DRM_BO_INIT_MINOR);
return -EINVAL;
}
mutex_lock(&dev->bm.init_mutex);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (!bm->initialized) { if (!bm->initialized) {
DRM_ERROR("DRM memory manager was not initialized.\n"); DRM_ERROR("DRM memory manager was not initialized.\n");
@ -2493,7 +2279,8 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
out: out:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->bm.init_mutex); (void) drm_bo_write_unlock(&bm->bm_lock, file_priv);
if (ret) if (ret)
return ret; return ret;
@ -2507,15 +2294,15 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
struct drm_bo_driver *driver = dev->driver->bo_driver; struct drm_bo_driver *driver = dev->driver->bo_driver;
int ret; int ret;
DRM_DEBUG("drm_mm_takedown_ioctl: %d type\n", arg->mem_type);
if (!driver) { if (!driver) {
DRM_ERROR("Buffer objects are not supported by this driver\n"); DRM_ERROR("Buffer objects are not supported by this driver\n");
return -EINVAL; return -EINVAL;
} }
LOCK_TEST_WITH_RETURN(dev, file_priv); ret = drm_bo_write_lock(&bm->bm_lock, file_priv);
mutex_lock(&dev->bm.init_mutex); if (ret)
return ret;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
ret = -EINVAL; ret = -EINVAL;
if (!bm->initialized) { if (!bm->initialized) {
@ -2533,7 +2320,8 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
} }
out: out:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->bm.init_mutex); (void) drm_bo_write_unlock(&bm->bm_lock, file_priv);
if (ret) if (ret)
return ret; return ret;
@ -2546,46 +2334,51 @@ int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
struct drm_bo_driver *driver = dev->driver->bo_driver; struct drm_bo_driver *driver = dev->driver->bo_driver;
int ret; int ret;
DRM_DEBUG("drm_mm_lock_ioctl: %d type\n", arg->mem_type);
if (!driver) { if (!driver) {
DRM_ERROR("Buffer objects are not supported by this driver\n"); DRM_ERROR("Buffer objects are not supported by this driver\n");
return -EINVAL; return -EINVAL;
} }
LOCK_TEST_WITH_RETURN(dev, file_priv); if (arg->lock_flags & DRM_BO_LOCK_IGNORE_NO_EVICT) {
mutex_lock(&dev->bm.init_mutex); DRM_ERROR("Lock flag DRM_BO_LOCK_IGNORE_NO_EVICT not supported yet.\n");
return -EINVAL;
}
if (arg->lock_flags & DRM_BO_LOCK_UNLOCK_BM) {
ret = drm_bo_write_lock(&dev->bm.bm_lock, file_priv);
if (ret)
return ret;
}
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
ret = drm_bo_lock_mm(dev, arg->mem_type); ret = drm_bo_lock_mm(dev, arg->mem_type);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->bm.init_mutex); if (ret) {
if (ret) (void) drm_bo_write_unlock(&dev->bm.bm_lock, file_priv);
return ret; return ret;
}
return 0; return 0;
} }
int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_mm_unlock_ioctl(struct drm_device *dev,
void *data,
struct drm_file *file_priv)
{ {
struct drm_mm_type_arg *arg = data;
struct drm_bo_driver *driver = dev->driver->bo_driver; struct drm_bo_driver *driver = dev->driver->bo_driver;
int ret; int ret;
DRM_DEBUG("drm_mm_unlock_ioctl\n");
if (!driver) { if (!driver) {
DRM_ERROR("Buffer objects are not supported by this driver\n"); DRM_ERROR("Buffer objects are not supported by this driver\n");
return -EINVAL; return -EINVAL;
} }
LOCK_TEST_WITH_RETURN(dev, file_priv); if (arg->lock_flags & DRM_BO_LOCK_UNLOCK_BM) {
mutex_lock(&dev->bm.init_mutex); ret = drm_bo_write_unlock(&dev->bm.bm_lock, file_priv);
mutex_lock(&dev->struct_mutex);
ret = 0;
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->bm.init_mutex);
if (ret) if (ret)
return ret; return ret;
}
return 0; return 0;
} }
@ -2735,3 +2528,15 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object * bo)
return 0; return 0;
} }
int drm_bo_version_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_bo_version_arg *arg = (struct drm_bo_version_arg *)data;
arg->major = DRM_BO_INIT_MAJOR;
arg->minor = DRM_BO_INIT_MINOR;
arg->patchlevel = DRM_BO_INIT_PATCH;
return 0;
}

178
linux-core/drm_bo_lock.c Normal file
View File

@ -0,0 +1,178 @@
/**************************************************************************
*
* Copyright (c) 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
/*
* This file implements a simple replacement for the buffer manager use
* of the heavyweight hardware lock.
* The lock is a read-write lock. Taking it in read mode is fast, and
* intended for in-kernel use only.
* Taking it in write mode is slow.
*
* The write mode is used only when there is a need to block all
* user-space processes from allocating a
* new memory area.
* Typical use in write mode is X server VT switching, and it's allowed
* to leave kernel space with the write lock held. If a user-space process
* dies while having the write-lock, it will be released during the file
* descriptor release.
*
* The read lock is typically placed at the start of an IOCTL- or
* user-space callable function that may end up allocating a memory area.
* This includes setstatus, super-ioctls and no_pfn; the latter may move
* unmappable regions to mappable. It's a bug to leave kernel space with the
* read lock held.
*
* Both read- and write lock taking is interruptible for low signal-delivery
* latency. The locking functions will return -EAGAIN if interrupted by a
* signal.
*
* Locking order: The lock should be taken BEFORE any kernel mutexes
* or spinlocks.
*/
#include "drmP.h"
void drm_bo_init_lock(struct drm_bo_lock *lock)
{
DRM_INIT_WAITQUEUE(&lock->queue);
atomic_set(&lock->write_lock_pending, 0);
atomic_set(&lock->readers, 0);
}
void drm_bo_read_unlock(struct drm_bo_lock *lock)
{
if (unlikely(atomic_add_negative(-1, &lock->readers)))
BUG();
if (atomic_read(&lock->readers) == 0)
wake_up_interruptible(&lock->queue);
}
EXPORT_SYMBOL(drm_bo_read_unlock);
int drm_bo_read_lock(struct drm_bo_lock *lock)
{
while (unlikely(atomic_read(&lock->write_lock_pending) != 0)) {
int ret;
ret = wait_event_interruptible
(lock->queue, atomic_read(&lock->write_lock_pending) == 0);
if (ret)
return -EAGAIN;
}
while (unlikely(!atomic_add_unless(&lock->readers, 1, -1))) {
int ret;
ret = wait_event_interruptible
(lock->queue, atomic_add_unless(&lock->readers, 1, -1));
if (ret)
return -EAGAIN;
}
return 0;
}
EXPORT_SYMBOL(drm_bo_read_lock);
static int __drm_bo_write_unlock(struct drm_bo_lock *lock)
{
if (unlikely(atomic_cmpxchg(&lock->readers, -1, 0) != -1))
return -EINVAL;
if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 1, 0) != 1))
return -EINVAL;
wake_up_interruptible(&lock->queue);
return 0;
}
static void drm_bo_write_lock_remove(struct drm_file *file_priv,
struct drm_user_object *item)
{
struct drm_bo_lock *lock = container_of(item, struct drm_bo_lock, base);
int ret;
ret = __drm_bo_write_unlock(lock);
BUG_ON(ret);
}
int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv)
{
int ret = 0;
struct drm_device *dev;
if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 0, 1) != 0)) {
return -EINVAL;
}
while (unlikely(atomic_cmpxchg(&lock->readers, 0, -1) != 0)) {
ret = wait_event_interruptible
(lock->queue, atomic_cmpxchg(&lock->readers, 0, -1) == 0);
if (ret) {
atomic_set(&lock->write_lock_pending, 0);
wake_up_interruptible(&lock->queue);
return -EAGAIN;
}
}
/*
* Add a dummy user-object, the destructor of which will
* make sure the lock is released if the client dies
* while holding it.
*/
dev = file_priv->head->dev;
mutex_lock(&dev->struct_mutex);
ret = drm_add_user_object(file_priv, &lock->base, 0);
lock->base.remove = &drm_bo_write_lock_remove;
lock->base.type = drm_lock_type;
if (ret) {
(void)__drm_bo_write_unlock(lock);
}
mutex_unlock(&dev->struct_mutex);
return ret;
}
int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv)
{
struct drm_device *dev = file_priv->head->dev;
struct drm_ref_object *ro;
mutex_lock(&dev->struct_mutex);
if (lock->base.owner != file_priv) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
ro = drm_lookup_ref_object(file_priv, &lock->base, _DRM_REF_USE);
BUG_ON(!ro);
drm_remove_ref_object(file_priv, ro);
lock->base.owner = NULL;
mutex_unlock(&dev->struct_mutex);
return 0;
}

View File

@ -212,6 +212,8 @@ static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
unsigned long bus_offset; unsigned long bus_offset;
unsigned long bus_size; unsigned long bus_size;
dev = bo->dev;
while(drm_bo_read_lock(&dev->bm.bm_lock));
mutex_lock(&bo->mutex); mutex_lock(&bo->mutex);
@ -289,6 +291,7 @@ static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
data->type = VM_FAULT_OOM; data->type = VM_FAULT_OOM;
out_unlock: out_unlock:
mutex_unlock(&bo->mutex); mutex_unlock(&bo->mutex);
drm_bo_read_unlock(&dev->bm.bm_lock);
return NULL; return NULL;
} }

View File

@ -136,10 +136,14 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, DRM_AUTH), DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl,
DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl, DRM_AUTH), DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_FENCE_CREATE, drm_fence_create_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_FENCE_CREATE, drm_fence_create_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_FENCE_REFERENCE, drm_fence_reference_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_FENCE_REFERENCE, drm_fence_reference_ioctl, DRM_AUTH),
@ -155,10 +159,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_BO_UNMAP, drm_bo_unmap_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_UNMAP, drm_bo_unmap_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_BO_REFERENCE, drm_bo_reference_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_REFERENCE, drm_bo_reference_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_BO_UNREFERENCE, drm_bo_unreference_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_UNREFERENCE, drm_bo_unreference_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_BO_OP, drm_bo_op_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_SETSTATUS, drm_bo_setstatus_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_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_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), DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0),
}; };
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )

View File

@ -43,6 +43,7 @@ struct drm_bo_mem_reg;
enum drm_object_type { enum drm_object_type {
drm_fence_type, drm_fence_type,
drm_buffer_type, drm_buffer_type,
drm_lock_type,
/* /*
* Add other user space object types here. * Add other user space object types here.
*/ */
@ -377,7 +378,6 @@ struct drm_buffer_object {
unsigned long num_pages; unsigned long num_pages;
/* For pinned buffers */ /* For pinned buffers */
int pinned;
struct drm_mm_node *pinned_node; struct drm_mm_node *pinned_node;
uint32_t pinned_mem_type; uint32_t pinned_mem_type;
struct list_head pinned_lru; struct list_head pinned_lru;
@ -415,6 +415,13 @@ struct drm_mem_type_manager {
void *io_addr; void *io_addr;
}; };
struct drm_bo_lock {
struct drm_user_object base;
wait_queue_head_t queue;
atomic_t write_lock_pending;
atomic_t readers;
};
#define _DRM_FLAG_MEMTYPE_FIXED 0x00000001 /* Fixed (on-card) PCI memory */ #define _DRM_FLAG_MEMTYPE_FIXED 0x00000001 /* Fixed (on-card) PCI memory */
#define _DRM_FLAG_MEMTYPE_MAPPABLE 0x00000002 /* Memory mappable */ #define _DRM_FLAG_MEMTYPE_MAPPABLE 0x00000002 /* Memory mappable */
#define _DRM_FLAG_MEMTYPE_CACHED 0x00000004 /* Cached binding */ #define _DRM_FLAG_MEMTYPE_CACHED 0x00000004 /* Cached binding */
@ -424,7 +431,7 @@ struct drm_mem_type_manager {
#define _DRM_FLAG_MEMTYPE_CSELECT 0x00000020 /* Select caching */ #define _DRM_FLAG_MEMTYPE_CSELECT 0x00000020 /* Select caching */
struct drm_buffer_manager { struct drm_buffer_manager {
struct mutex init_mutex; struct drm_bo_lock bm_lock;
struct mutex evict_mutex; struct mutex evict_mutex;
int nice_mode; int nice_mode;
int initialized; int initialized;
@ -471,13 +478,12 @@ extern int drm_bo_set_pin(struct drm_device *dev, struct drm_buffer_object *bo,
extern int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 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_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); extern int drm_bo_setstatus_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_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); extern int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int drm_bo_version_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int drm_bo_driver_finish(struct drm_device *dev); extern int drm_bo_driver_finish(struct drm_device *dev);
extern int drm_bo_driver_init(struct drm_device *dev); extern int drm_bo_driver_init(struct drm_device *dev);
extern int drm_bo_pci_offset(struct drm_device *dev, extern int drm_bo_pci_offset(struct drm_device *dev,
@ -513,6 +519,7 @@ extern int drm_bo_init_mm(struct drm_device * dev, unsigned type,
extern int drm_bo_handle_validate(struct drm_file * file_priv, uint32_t handle, extern int drm_bo_handle_validate(struct drm_file * file_priv, uint32_t handle,
uint32_t fence_class, uint64_t flags, uint32_t fence_class, uint64_t flags,
uint64_t mask, uint32_t hint, uint64_t mask, uint32_t hint,
int use_old_fence_class,
struct drm_bo_info_rep * rep, struct drm_bo_info_rep * rep,
struct drm_buffer_object **bo_rep); struct drm_buffer_object **bo_rep);
extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file * file_priv, extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file * file_priv,
@ -609,6 +616,21 @@ extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * m
void **virtual); void **virtual);
extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem, extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem,
void *virtual); void *virtual);
/*
* drm_bo_lock.c
* Simple replacement for the hardware lock on buffer manager init and clean.
*/
extern void drm_bo_init_lock(struct drm_bo_lock *lock);
extern void drm_bo_read_unlock(struct drm_bo_lock *lock);
extern int drm_bo_read_lock(struct drm_bo_lock *lock);
extern int drm_bo_write_lock(struct drm_bo_lock *lock,
struct drm_file *file_priv);
extern int drm_bo_write_unlock(struct drm_bo_lock *lock,
struct drm_file *file_priv);
#ifdef CONFIG_DEBUG_MUTEXES #ifdef CONFIG_DEBUG_MUTEXES
#define DRM_ASSERT_LOCKED(_mutex) \ #define DRM_ASSERT_LOCKED(_mutex) \
BUG_ON(!mutex_is_locked(_mutex) || \ BUG_ON(!mutex_is_locked(_mutex) || \

View File

@ -72,7 +72,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
init_timer(&dev->timer); init_timer(&dev->timer);
mutex_init(&dev->struct_mutex); mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex); mutex_init(&dev->ctxlist_mutex);
mutex_init(&dev->bm.init_mutex);
mutex_init(&dev->bm.evict_mutex); mutex_init(&dev->bm.evict_mutex);
idr_init(&dev->drw_idr); idr_init(&dev->drw_idr);

View File

@ -728,10 +728,17 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
if (address > vma->vm_end) if (address > vma->vm_end)
return NOPFN_SIGBUS; return NOPFN_SIGBUS;
err = mutex_lock_interruptible(&bo->mutex); dev = bo->dev;
err = drm_bo_read_lock(&dev->bm.bm_lock);
if (err) if (err)
return NOPFN_REFAULT; return NOPFN_REFAULT;
err = mutex_lock_interruptible(&bo->mutex);
if (err) {
drm_bo_read_unlock(&dev->bm.bm_lock);
return NOPFN_REFAULT;
}
err = drm_bo_wait(bo, 0, 0, 0); err = drm_bo_wait(bo, 0, 0, 0);
if (err) { if (err) {
ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
@ -754,7 +761,6 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
} }
} }
dev = bo->dev;
err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset, err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset,
&bus_size); &bus_size);
@ -792,6 +798,7 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
} }
out_unlock: out_unlock:
mutex_unlock(&bo->mutex); mutex_unlock(&bo->mutex);
drm_bo_read_unlock(&dev->bm.bm_lock);
return ret; return ret;
} }
#endif #endif

View File

@ -124,6 +124,8 @@ uint32_t i915_evict_mask(struct drm_buffer_object *bo)
} }
} }
#if 0 /* See comment below */
static void i915_emit_copy_blit(struct drm_device * dev, static void i915_emit_copy_blit(struct drm_device * dev,
uint32_t src_offset, uint32_t src_offset,
uint32_t dst_offset, uint32_t dst_offset,
@ -224,6 +226,16 @@ out_cleanup:
return ret; return ret;
} }
#endif
/*
* Disable i915_move_flip for now, since we can't guarantee that the hardware lock
* is held here. To re-enable we need to make sure either
* a) The X server is using DRM to submit commands to the ring, or
* b) DRM can use the HP ring for these blits. This means i915 needs to implement
* a new ring submission mechanism and fence class.
*/
int i915_move(struct drm_buffer_object * bo, int i915_move(struct drm_buffer_object * bo,
int evict, int no_wait, struct drm_bo_mem_reg * new_mem) int evict, int no_wait, struct drm_bo_mem_reg * new_mem)
{ {
@ -232,10 +244,10 @@ int i915_move(struct drm_buffer_object * bo,
if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { if (old_mem->mem_type == DRM_BO_MEM_LOCAL) {
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
} else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) {
if (i915_move_flip(bo, evict, no_wait, new_mem)) if (0 /*i915_move_flip(bo, evict, no_wait, new_mem)*/)
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
} else { } else {
if (i915_move_blit(bo, evict, no_wait, new_mem)) if (0 /*i915_move_blit(bo, evict, no_wait, new_mem)*/)
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
} }
return 0; return 0;

View File

@ -500,8 +500,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
DRM_BO_FLAG_READ | DRM_BO_FLAG_READ |
DRM_BO_FLAG_WRITE | DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_TT |
DRM_BO_FLAG_MEM_VRAM, DRM_BO_FLAG_MEM_VRAM |
0, 0, 0, DRM_BO_FLAG_NO_EVICT,
DRM_BO_HINT_DONT_FENCE, 0, 0,
&fbo); &fbo);
if (ret || !fbo) { if (ret || !fbo) {
printk(KERN_ERR "failed to allocate framebuffer\n"); printk(KERN_ERR "failed to allocate framebuffer\n");
@ -510,14 +511,6 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
return -EINVAL; return -EINVAL;
} }
ret = drm_bo_set_pin(dev, fbo, 1);
if (ret) {
printk(KERN_ERR "failed to pin framebuffer, aborting\n");
drm_framebuffer_destroy(fb);
framebuffer_release(info);
return -EINVAL;
}
fb->offset = fbo->offset; fb->offset = fbo->offset;
fb->bo = fbo; fb->bo = fbo;
printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,

View File

@ -133,6 +133,7 @@ static int sis_drm_alloc(struct drm_device * dev, struct drm_file *file_priv,
dev_priv->agp_initialized)) { dev_priv->agp_initialized)) {
DRM_ERROR DRM_ERROR
("Attempt to allocate from uninitialized memory manager.\n"); ("Attempt to allocate from uninitialized memory manager.\n");
mutex_unlock(&dev->struct_mutex);
return -EINVAL; return -EINVAL;
} }

View File

@ -674,6 +674,14 @@ struct drm_fence_arg {
* Can also be set in the buffer mask before validation. * 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. * 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. * If not set the buffer may or may not be in mappable memory when validated.
@ -716,6 +724,7 @@ struct drm_fence_arg {
* Flags: Acknowledge. * Flags: Acknowledge.
*/ */
#define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14) #define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14)
#define DRM_BO_FLAG_TILE (1ULL << 15)
/* /*
* Memory type flags that can be or'ed together in the mask, but only * Memory type flags that can be or'ed together in the mask, but only
@ -748,11 +757,11 @@ struct drm_fence_arg {
/* Don't place this buffer on the unfenced list.*/ /* Don't place this buffer on the unfenced list.*/
#define DRM_BO_HINT_DONT_FENCE 0x00000004 #define DRM_BO_HINT_DONT_FENCE 0x00000004
#define DRM_BO_HINT_WAIT_LAZY 0x00000008 #define DRM_BO_HINT_WAIT_LAZY 0x00000008
#define DRM_BO_HINT_ALLOW_UNFENCED_MAP 0x00000010
#define DRM_BO_INIT_MAGIC 0xfe769812 #define DRM_BO_INIT_MAGIC 0xfe769812
#define DRM_BO_INIT_MAJOR 0 #define DRM_BO_INIT_MAJOR 1
#define DRM_BO_INIT_MINOR 1 #define DRM_BO_INIT_MINOR 0
#define DRM_BO_INIT_PATCH 0
struct drm_bo_info_req { struct drm_bo_info_req {
@ -761,6 +770,8 @@ struct drm_bo_info_req {
unsigned int handle; unsigned int handle;
unsigned int hint; unsigned int hint;
unsigned int fence_class; unsigned int fence_class;
unsigned int desired_tile_stride;
unsigned int tile_info;
unsigned int pad64; unsigned int pad64;
}; };
@ -772,27 +783,6 @@ struct drm_bo_create_req {
unsigned int page_alignment; unsigned int page_alignment;
}; };
struct drm_bo_op_req {
enum {
drm_bo_validate,
drm_bo_fence,
drm_bo_ref_fence,
} op;
unsigned int arg_handle;
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, requiring that its offset and
* memory area stay constant until unpin. The intended use is for
* scanout buffers.
*/
unsigned int pin;
};
/* /*
* Reply flags * Reply flags
@ -849,6 +839,17 @@ struct drm_bo_map_wait_idle_arg {
} d; } d;
}; };
struct drm_bo_op_req {
enum {
drm_bo_validate,
drm_bo_fence,
drm_bo_ref_fence,
} op;
unsigned int arg_handle;
struct drm_bo_info_req bo_req;
};
struct drm_bo_op_arg { struct drm_bo_op_arg {
uint64_t next; uint64_t next;
union { union {
@ -859,12 +860,6 @@ struct drm_bo_op_arg {
unsigned int pad64; 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_LOCAL 0
#define DRM_BO_MEM_TT 1 #define DRM_BO_MEM_TT 1
@ -877,8 +872,18 @@ struct drm_bo_set_pin_arg {
#define DRM_BO_MEM_TYPES 8 /* For now. */ #define DRM_BO_MEM_TYPES 8 /* For now. */
#define DRM_BO_LOCK_UNLOCK_BM (1 << 0)
#define DRM_BO_LOCK_IGNORE_NO_EVICT (1 << 1)
struct drm_bo_version_arg {
uint32_t major;
uint32_t minor;
uint32_t patchlevel;
};
struct drm_mm_type_arg { struct drm_mm_type_arg {
unsigned int mem_type; unsigned int mem_type;
unsigned int lock_flags;
}; };
struct drm_mm_init_arg { struct drm_mm_init_arg {
@ -1069,10 +1074,11 @@ struct drm_mode_mode_cmd {
#define DRM_IOCTL_BO_UNMAP DRM_IOWR(0xd0, struct drm_bo_handle_arg) #define DRM_IOCTL_BO_UNMAP DRM_IOWR(0xd0, struct drm_bo_handle_arg)
#define DRM_IOCTL_BO_REFERENCE DRM_IOWR(0xd1, struct drm_bo_reference_info_arg) #define DRM_IOCTL_BO_REFERENCE DRM_IOWR(0xd1, struct drm_bo_reference_info_arg)
#define DRM_IOCTL_BO_UNREFERENCE DRM_IOWR(0xd2, struct drm_bo_handle_arg) #define DRM_IOCTL_BO_UNREFERENCE DRM_IOWR(0xd2, struct drm_bo_handle_arg)
#define DRM_IOCTL_BO_OP DRM_IOWR(0xd3, struct drm_bo_op_arg) #define DRM_IOCTL_BO_SETSTATUS DRM_IOWR(0xd3, struct drm_bo_map_wait_idle_arg)
#define DRM_IOCTL_BO_INFO DRM_IOWR(0xd4, struct drm_bo_reference_info_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_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) #define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg)
#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res)
#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc)

View File

@ -180,6 +180,7 @@ static int i915_initialize(struct drm_device * dev,
} }
DRM_DEBUG("Enabled hardware status page\n"); DRM_DEBUG("Enabled hardware status page\n");
dev->dev_private = (void *)dev_priv; dev->dev_private = (void *)dev_priv;
mutex_init(&dev_priv->cmdbuf_mutex);
return 0; return 0;
} }
@ -461,7 +462,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
int i = 0, count, ret; int i = 0, count, ret;
if (cmd->sz & 0x3) { if (cmd->sz & 0x3) {
DRM_ERROR("alignment"); DRM_ERROR("alignment\n");
return -EINVAL; return -EINVAL;
} }
@ -499,7 +500,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
RING_LOCALS; RING_LOCALS;
if ((batch->start | batch->used) & 0x7) { if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment"); DRM_ERROR("alignment\n");
return -EINVAL; return -EINVAL;
} }
@ -831,6 +832,9 @@ int i915_process_relocs(struct drm_file *file_priv,
} while (reloc_offset != reloc_end); } while (reloc_offset != reloc_end);
out: out:
drm_bo_kunmap(&relocatee->kmap);
relocatee->data_page = NULL;
drm_bo_kunmap(&reloc_kmap); drm_bo_kunmap(&reloc_kmap);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
@ -868,7 +872,6 @@ static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle,
} }
} }
drm_bo_kunmap(&relocatee.kmap);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
drm_bo_usage_deref_locked(&relocatee.buf); drm_bo_usage_deref_locked(&relocatee.buf);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
@ -929,11 +932,19 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
buf_handle = req->bo_req.handle; buf_handle = req->bo_req.handle;
buf_reloc_handle = arg.reloc_handle; buf_reloc_handle = arg.reloc_handle;
if (buf_reloc_handle) {
ret = i915_exec_reloc(file_priv, buf_handle, buf_reloc_handle, buffers, buf_count);
if (ret)
goto out_err;
DRM_MEMORYBARRIER();
}
rep.ret = drm_bo_handle_validate(file_priv, req->bo_req.handle, rep.ret = drm_bo_handle_validate(file_priv, req->bo_req.handle,
req->bo_req.fence_class, req->bo_req.fence_class,
req->bo_req.flags, req->bo_req.flags,
req->bo_req.mask, req->bo_req.mask,
req->bo_req.hint, req->bo_req.hint,
0,
&rep.bo_info, &rep.bo_info,
&buffers[buf_count]); &buffers[buf_count]);
@ -953,11 +964,6 @@ int i915_validate_buffer_list(struct drm_file *file_priv,
data = next; data = next;
buf_count++; buf_count++;
if (buf_reloc_handle) {
ret = i915_exec_reloc(file_priv, buf_handle, buf_reloc_handle, buffers, buf_count);
if (ret)
goto out_err;
}
} while (next != 0); } while (next != 0);
*num_buffers = buf_count; *num_buffers = buf_count;
return 0; return 0;
@ -989,8 +995,6 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
} }
LOCK_TEST_WITH_RETURN(dev, file_priv);
if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
batch->num_cliprects * batch->num_cliprects *
sizeof(struct drm_clip_rect))) sizeof(struct drm_clip_rect)))
@ -999,11 +1003,30 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
if (exec_buf->num_buffers > dev_priv->max_validate_buffers) if (exec_buf->num_buffers > dev_priv->max_validate_buffers)
return -EINVAL; return -EINVAL;
ret = drm_bo_read_lock(&dev->bm.bm_lock);
if (ret)
return ret;
/*
* The cmdbuf_mutex makes sure the validate-submit-fence
* operation is atomic.
*/
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
if (ret) {
drm_bo_read_unlock(&dev->bm.bm_lock);
return -EAGAIN;
}
num_buffers = exec_buf->num_buffers; num_buffers = exec_buf->num_buffers;
buffers = drm_calloc(num_buffers, sizeof(struct drm_buffer_object *), DRM_MEM_DRIVER); buffers = drm_calloc(num_buffers, sizeof(struct drm_buffer_object *), DRM_MEM_DRIVER);
if (!buffers) if (!buffers) {
drm_bo_read_unlock(&dev->bm.bm_lock);
mutex_unlock(&dev_priv->cmdbuf_mutex);
return -ENOMEM; return -ENOMEM;
}
/* validate buffer list + fixup relocations */ /* validate buffer list + fixup relocations */
ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list, ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list,
@ -1012,7 +1035,7 @@ static int i915_execbuffer(struct drm_device *dev, void *data,
goto out_free; goto out_free;
/* make sure all previous memory operations have passed */ /* make sure all previous memory operations have passed */
asm volatile("mfence":::"memory"); DRM_MEMORYBARRIER();
/* submit buffer */ /* submit buffer */
batch->start = buffers[num_buffers-1]->offset; batch->start = buffers[num_buffers-1]->offset;
@ -1051,6 +1074,8 @@ out_err0:
out_free: out_free:
drm_free(buffers, (exec_buf->num_buffers * sizeof(struct drm_buffer_object *)), DRM_MEM_DRIVER); drm_free(buffers, (exec_buf->num_buffers * sizeof(struct drm_buffer_object *)), DRM_MEM_DRIVER);
mutex_unlock(&dev_priv->cmdbuf_mutex);
drm_bo_read_unlock(&dev->bm.bm_lock);
return ret; return ret;
} }
#endif #endif

View File

@ -143,6 +143,7 @@ struct drm_i915_private {
#ifdef I915_HAVE_BUFFER #ifdef I915_HAVE_BUFFER
void *agp_iomap; void *agp_iomap;
unsigned int max_validate_buffers; unsigned int max_validate_buffers;
struct mutex cmdbuf_mutex;
#endif #endif
DRM_SPINTYPE swaps_lock; DRM_SPINTYPE swaps_lock;

View File

@ -188,16 +188,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_VRAM |
DRM_BO_FLAG_NO_EVICT |
DRM_BO_HINT_DONT_FENCE, 0, 0x1, 0, DRM_BO_HINT_DONT_FENCE, 0, 0x1, 0,
&dev_priv->ring_buffer); &dev_priv->ring_buffer);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("Unable to allocate ring buffer\n"); DRM_ERROR("Unable to allocate or pin ring buffer\n");
return -EINVAL;
}
ret = drm_bo_set_pin(dev, dev_priv->ring_buffer, 1);
if (ret < 0) {
DRM_ERROR("Unable to pin ring buffer\n");
return -EINVAL; return -EINVAL;
} }