Some bugfixes.

Change the fence object interface somewhat to allow some more flexibility.
Make list IOCTLS really restartable.
Try to avoid busy-waits in the kernel using immediate return to user-space with an -EAGAIN.
main
Thomas Hellstrom 2006-09-15 11:18:35 +02:00
parent 7223b4e264
commit 49fbeb339c
10 changed files with 150 additions and 120 deletions

View File

@ -2240,16 +2240,20 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
#ifdef __linux__
int drmFenceCreate(int fd, int shareable, int class,unsigned type,
int emit,
/*
* Valid flags are
* DRM_FENCE_FLAG_EMIT
* DRM_FENCE_FLAG_SHAREABLE
* DRM_FENCE_MASK_DRIVER
*/
int drmFenceCreate(int fd, unsigned flags, int class,unsigned type,
drmFence *fence)
{
drm_fence_arg_t arg;
arg.type = type;
arg.class = class;
arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0;
arg.flags |= (emit) ? DRM_FENCE_FLAG_EMIT : 0;
arg.op = drm_fence_create;
if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
return -errno;
@ -2261,11 +2265,17 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type,
return 0;
}
int drmFenceBuffers(int fd, int shareable, drmFence *fence)
/*
* Valid flags are
* DRM_FENCE_FLAG_SHAREABLE
* DRM_FENCE_MASK_DRIVER
*/
int drmFenceBuffers(int fd, unsigned flags, drmFence *fence)
{
drm_fence_arg_t arg;
arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0;
arg.flags = flags;
arg.op = drm_fence_buffers;
if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
return -errno;
@ -2299,7 +2309,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence)
fence->handle = arg.handle;
fence->class = arg.class;
fence->type = arg.type;
fence->flags = 0;
fence->flags = arg.flags;
fence->signaled = arg.signaled;
return 0;
}
@ -2363,12 +2373,18 @@ int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType,
return 0;
}
/*
* Valid flags are
* DRM_FENCE_FLAG_SHAREABLE
* DRM_FENCE_MASK_DRIVER
*/
int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type)
int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type)
{
drm_fence_arg_t arg;
arg.flags = flags;
arg.handle = fence->handle;
arg.type = emit_type;
arg.op = drm_fence_emit;
@ -2379,23 +2395,27 @@ int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type)
fence->signaled = arg.signaled;
return 0;
}
/*
* Valid flags are
* DRM_FENCE_FLAG_WAIT_LAZY
* DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS
*/
int drmFenceWait(int fd, drmFence *fence, unsigned flush_type,
int lazy, int ignore_signals)
int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type)
{
drm_fence_arg_t arg;
int ret;
if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) {
if (flush_type & fence->signaled == flush_type) {
if ((flush_type & fence->signaled) == flush_type) {
return 0;
}
}
arg.handle = fence->handle;
arg.type = flush_type;
arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0;
arg.flags |= (ignore_signals) ? DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS : 0;
arg.flags = flags;
arg.op = drm_fence_wait;
do {
ret = ioctl(fd, DRM_IOCTL_FENCE, &arg);
@ -2666,7 +2686,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size,
return -EINVAL;
}
req->op = drm_bo_create;
req->next = 0;
arg.next = 0;
if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg))
return -errno;
@ -2700,7 +2720,7 @@ int drmBODestroy(int fd, drmBO *buf)
arg.handled = 0;
req->handle = buf->handle;
req->op = drm_bo_destroy;
req->next = 0;
arg.next = 0;
if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg))
return -errno;
@ -2725,7 +2745,7 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf)
arg.handled = 0;
req->handle = handle;
req->op = drm_bo_reference;
req->next = 0;
arg.next = 0;
if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg))
return -errno;
@ -2761,7 +2781,7 @@ int drmBOUnReference(int fd, drmBO *buf)
arg.handled = 0;
req->handle = buf->handle;
req->op = drm_bo_unreference;
req->next = 0;
arg.next = 0;
if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg))
return -errno;
@ -2813,7 +2833,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint,
req->mask = mapFlags;
req->hint = mapHint;
req->op = drm_bo_map;
req->next = 0;
arg.next = 0;
/*
* May hang if the buffer object is busy.
@ -2849,7 +2869,7 @@ int drmBOUnmap(int fd, drmBO *buf)
arg.handled = 0;
req->handle = buf->handle;
req->op = drm_bo_unmap;
req->next = 0;
arg.next = 0;
if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) {
return -errno;
@ -2876,12 +2896,12 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask,
req->hint = hint;
req->arg_handle = mask; /* Encode mask in the arg_handle field :/ */
req->op = drm_bo_validate;
req->next = 0;
arg.next = 0;
do{
ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg);
} while (ret && errno == -EAGAIN);
} while (ret && errno == EAGAIN);
if (ret)
@ -2908,7 +2928,7 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle)
req->mask = flags;
req->arg_handle = fenceHandle;
req->op = drm_bo_validate;
req->next = 0;
arg.next = 0;
ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg);
@ -2931,7 +2951,7 @@ int drmBOInfo(int fd, drmBO *buf)
arg.handled = 0;
req->handle = buf->handle;
req->op = drm_bo_info;
req->next = 0;
arg.next = 0;
ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg);
@ -3044,20 +3064,14 @@ int drmBOValidateList(int fd, drmBOList *list)
if (prevNext)
*prevNext = (unsigned long) arg;
req->next = 0;
prevNext = &req->next;
arg->next = 0;
prevNext = &arg->next;
arg->handled = 0;
req->handle = node->buf->handle;
req->op = drm_bo_validate;
req->mask = node->arg0;
req->hint = 0;
req->arg_handle = node->arg1 | DRM_BO_MASK_MEM;
#ifdef BODEBUG
fprintf(stderr, "Offset 0x%08x, Handle 0x%08x, "
"mask 0x%08x flags 0x%08x\n",
node->buf->offset,
req->handle, req->arg_handle, req->mask);
#endif
req->arg_handle = node->arg1;
}
if (!first)
@ -3065,7 +3079,7 @@ int drmBOValidateList(int fd, drmBOList *list)
do{
ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first);
} while (ret && errno == -EAGAIN);
} while (ret && errno == EAGAIN);
if (ret)
@ -3076,17 +3090,15 @@ int drmBOValidateList(int fd, drmBOList *list)
arg = &node->bo_arg;
rep = &arg->d.rep;
if (!arg->handled)
if (!arg->handled) {
drmMsg("Unhandled request\n");
return -EFAULT;
}
if (rep->ret)
return rep->ret;
buf = node->buf;
drmBOCopyReply(rep, buf);
#ifdef BODEBUG
fprintf(stderr,"Offset 0x%08x, Flags 0x%08x\n",
buf->offset, buf->flags);
#endif
}
return 0;
@ -3120,8 +3132,8 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle)
if (prevNext)
*prevNext = (unsigned long) arg;
req->next = 0;
prevNext = &req->next;
arg->next = 0;
prevNext = &arg->next;
arg->handled = 0;
req->handle = node->buf->handle;
req->op = drm_bo_fence;

View File

@ -280,23 +280,6 @@ typedef struct _drmSetVersion {
int drm_dd_minor;
} drmSetVersion, *drmSetVersionPtr;
typedef struct _drmFence{
unsigned handle;
int class;
unsigned type;
unsigned flags;
unsigned signaled;
} drmFence;
typedef struct _drmTTM{
unsigned handle;
drm_handle_t user_token;
unsigned flags;
unsigned long size;
void *virtual;
int mapCount;
} drmTTM;
#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock)
#define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */
@ -614,31 +597,6 @@ extern int drmScatterGatherFree(int fd, drm_handle_t handle);
extern int drmWaitVBlank(int fd, drmVBlankPtr vbl);
/* Fencing */
extern int drmFenceCreate(int fd, int shareable, int class,
unsigned type, int emit,
drmFence *fence);
extern int drmFenceDestroy(int fd, const drmFence *fence);
extern int drmFenceReference(int fd, unsigned handle, drmFence *fence);
extern int drmFenceUnreference(int fd, const drmFence *fence);
extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type);
extern int drmFenceSignaled(int fd, drmFence *fence,
unsigned fenceType, int *signaled);
extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type,
int lazy, int ignore_signals);
extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type);
extern int drmFenceBuffers(int fd, int shareable, drmFence *fence);
/* TTMS */
extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size,
unsigned flags);
extern int drmTTMDestroy(int fd, const drmTTM *ttm);
extern int drmTTMReference(int fd, unsigned handle, drmTTM *ttm);
extern int drmTTMUnreference(int fd, const drmTTM *ttm);
extern drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm);
/* Support routines */
extern int drmError(int err, const char *label);
extern void *drmMalloc(int size);

View File

@ -93,7 +93,22 @@ typedef struct _drmMMListHead
#define DRMLISTENTRY(__type, __item, __field) \
((__type *)(((char *) (__item)) - offsetof(__type, __field)))
typedef struct _drmFence{
unsigned handle;
int class;
unsigned type;
unsigned flags;
unsigned signaled;
} drmFence;
typedef struct _drmTTM{
unsigned handle;
drm_handle_t user_token;
unsigned flags;
unsigned long size;
void *virtual;
int mapCount;
} drmTTM;
typedef struct _drmBO{
drm_bo_type_t type;
@ -130,6 +145,23 @@ typedef struct _drmBOList {
drmMMListHead free;
} drmBOList;
/* Fencing */
extern int drmFenceCreate(int fd, unsigned flags, int class,
unsigned type,
drmFence *fence);
extern int drmFenceDestroy(int fd, const drmFence *fence);
extern int drmFenceReference(int fd, unsigned handle, drmFence *fence);
extern int drmFenceUnreference(int fd, const drmFence *fence);
extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type);
extern int drmFenceSignaled(int fd, drmFence *fence,
unsigned fenceType, int *signaled);
extern int drmFenceWait(int fd, unsigned flags, drmFence *fence,
unsigned flush_type);
extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence,
unsigned emit_type);
extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence);
/*
* TTM functions.

View File

@ -655,6 +655,7 @@ typedef struct drm_ref_object {
typedef struct drm_bo_driver{
int cached_tt;
int cached_vram;
drm_local_map_t *vram_map;
drm_ttm_backend_t *(*create_ttm_backend_entry)
(struct drm_device *dev, int cached);
int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type);

View File

@ -322,15 +322,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals,
bo->fence = NULL;
return 0;
}
if (no_wait)
if (no_wait) {
return -EBUSY;
}
ret =
drm_fence_object_wait(dev, fence, lazy, ignore_signals,
bo->fence_flags);
if (ret)
return ret;
if (ret)
return ret;
drm_fence_usage_deref_unlocked(dev, fence);
bo->fence = NULL;
@ -360,9 +360,14 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait)
if (!tt && !bo->vram)
goto out;
ret = drm_bo_wait(bo, 0, 0, no_wait);
if (ret)
if (ret) {
if (ret != -EAGAIN)
DRM_ERROR("Failed to expire fence before "
"buffer eviction.\n");
goto out;
}
if (tt) {
ret = drm_move_tt_to_local(bo);
@ -420,7 +425,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait)
} while (1);
if (!node) {
DRM_ERROR("Out of aperture space\n");
DRM_ERROR("Out of videoram / aperture space\n");
mutex_unlock(&dev->struct_mutex);
return -ENOMEM;
}
@ -646,7 +651,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo)
bo->fence = NULL;
return 0;
}
drm_fence_object_flush(dev, fence, DRM_FENCE_EXE);
drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE);
if (drm_fence_object_signaled(fence, bo->fence_flags)) {
drm_fence_usage_deref_unlocked(dev, fence);
bo->fence = NULL;
@ -981,11 +986,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo,
DRM_ERROR("Vram support not implemented yet\n");
return -EINVAL;
}
if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) &&
(new_flags & DRM_BO_FLAG_CACHED)) {
DRM_ERROR("Cached binding not implemented yet\n");
return -EINVAL;
}
DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags);
ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags);
if (ret) {
@ -1003,8 +1004,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo,
return -EINVAL;
}
ret = drm_bo_move_buffer(bo, new_flags, no_wait);
if (ret)
if (ret) {
if (ret != -EAGAIN)
DRM_ERROR("Failed moving buffer.\n");
return ret;
}
}
if (move_unfenced) {
@ -1304,7 +1308,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg));
if (arg.handled) {
data = req->next;
data = arg.next;
continue;
}
@ -1404,7 +1408,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS)
default:
rep.ret = -EINVAL;
}
next = req->next;
next = arg.next;
/*
* A signal interrupted us. Make sure the ioctl is restartable.

View File

@ -283,10 +283,10 @@ int drm_fence_object_flush(drm_device_t * dev,
write_lock_irqsave(&fm->lock, flags);
fence->flush_mask |= type;
if (fence->submitted_flush == fence->signaled) {
if ((fence->type & DRM_FENCE_EXE) &&
!(fence->submitted_flush & DRM_FENCE_EXE)) {
if ((fence->type & DRM_FENCE_TYPE_EXE) &&
!(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) {
drm_fence_flush_exe(fm, driver, fence->sequence);
fence->submitted_flush |= DRM_FENCE_EXE;
fence->submitted_flush |= DRM_FENCE_TYPE_EXE;
} else {
fm->pending_flush |= (fence->flush_mask &
~fence->submitted_flush);
@ -362,7 +362,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence,
if (ret)
return ((ret == -EINTR) ? -EAGAIN : ret);
} else if ((fence->class == 0) && (mask & DRM_FENCE_EXE) &&
} else if ((fence->class == 0) && (mask & DRM_FENCE_TYPE_EXE) &&
driver->lazy_capable) {
/*
@ -372,7 +372,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence,
do {
DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ,
fence_signaled(dev, fence, DRM_FENCE_EXE,
fence_signaled(dev, fence, DRM_FENCE_TYPE_EXE,
1));
if (time_after_eq(jiffies, _end))
break;
@ -386,7 +386,15 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence,
if (fence_signaled(dev, fence, mask, 0))
return 0;
do {
/*
* Avoid kernel-space busy-waits.
*/
#if 1
if (!ignore_signals)
return -EAGAIN;
#endif
do {
schedule();
signaled = fence_signaled(dev, fence, mask, 1);
} while (!signaled && !time_after_eq(jiffies, _end));

View File

@ -49,6 +49,7 @@ static drm_fence_driver_t i915_fence_driver = {
};
static drm_bo_driver_t i915_bo_driver = {
.vram_map = NULL,
.cached_vram = 0,
.cached_tt = 1,
.create_ttm_backend_entry = i915_create_ttm_backend_entry,

View File

@ -43,7 +43,6 @@ static void i915_perform_flush(drm_device_t * dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
drm_fence_manager_t *fm = &dev->fm;
drm_fence_driver_t *driver = dev->driver->fence_driver;
int flush_completed = 0;
uint32_t flush_flags = 0;
uint32_t flush_sequence = 0;
uint32_t i_status;
@ -52,9 +51,14 @@ static void i915_perform_flush(drm_device_t * dev)
if (fm->pending_exe_flush) {
sequence = READ_BREADCRUMB(dev_priv);
/*
* First update fences with the current breadcrumb.
*/
diff = sequence - fm->last_exe_flush;
if (diff < driver->wrap_diff && diff != 0) {
drm_fence_handler(dev, sequence, DRM_FENCE_EXE);
drm_fence_handler(dev, sequence, DRM_FENCE_TYPE_EXE);
}
diff = sequence - fm->exe_flush_sequence;
@ -69,20 +73,18 @@ static void i915_perform_flush(drm_device_t * dev)
dev_priv->fence_irq_on = 1;
}
}
if (dev_priv->flush_pending) {
i_status = READ_HWSP(dev_priv, 0);
if ((i_status & (1 << 12)) !=
(dev_priv->saved_flush_status & (1 << 12))) {
flush_completed = 1;
flush_flags = dev_priv->flush_flags;
flush_sequence = dev_priv->flush_sequence;
dev_priv->flush_pending = 0;
} else {
}
}
if (flush_completed) {
drm_fence_handler(dev, flush_sequence, flush_flags);
drm_fence_handler(dev, flush_sequence, flush_flags);
}
}
if (fm->pending_flush && !dev_priv->flush_pending) {
dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv);
dev_priv->flush_flags = fm->pending_flush;
@ -91,6 +93,18 @@ static void i915_perform_flush(drm_device_t * dev)
dev_priv->flush_pending = 1;
fm->pending_flush = 0;
}
if (dev_priv->flush_pending) {
i_status = READ_HWSP(dev_priv, 0);
if ((i_status & (1 << 12)) !=
(dev_priv->saved_flush_status & (1 << 12))) {
flush_flags = dev_priv->flush_flags;
flush_sequence = dev_priv->flush_sequence;
dev_priv->flush_pending = 0;
drm_fence_handler(dev, flush_sequence, flush_flags);
}
}
}
void i915_poke_flush(drm_device_t * dev)
@ -117,7 +131,6 @@ void i915_fence_handler(drm_device_t * dev)
write_lock(&fm->lock);
i915_perform_flush(dev);
i915_perform_flush(dev);
write_unlock(&fm->lock);
}

View File

@ -643,7 +643,10 @@ typedef struct drm_set_version {
#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004
#define DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS 0x00000008
#define DRM_FENCE_EXE 0x00000001
/* Reserved for driver use */
#define DRM_FENCE_MASK_DRIVER 0xFF000000
#define DRM_FENCE_TYPE_EXE 0x00000001
typedef struct drm_fence_arg {
unsigned handle;
@ -750,7 +753,6 @@ typedef struct drm_bo_arg_request {
drm_bo_type_t type;
unsigned arg_handle;
drm_u64_t buffer_start;
drm_u64_t next;
enum {
drm_bo_create,
drm_bo_validate,
@ -789,6 +791,7 @@ typedef struct drm_bo_arg_reply {
typedef struct drm_bo_arg{
int handled;
drm_u64_t next;
union {
drm_bo_arg_request_t req;
drm_bo_arg_reply_t rep;

View File

@ -45,7 +45,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
temp = I915_READ16(I915REG_INT_IDENTITY_R);
temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
#if 0
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
@ -105,7 +105,6 @@ int i915_emit_irq(drm_device_t * dev)
void i915_user_irq_on(drm_i915_private_t *dev_priv)
{
return;
spin_lock(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
dev_priv->irq_enable_reg |= USER_INT_FLAG;
@ -117,11 +116,10 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv)
void i915_user_irq_off(drm_i915_private_t *dev_priv)
{
return;
spin_lock(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
// I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
}
spin_unlock(&dev_priv->user_irq_lock);
}
@ -241,7 +239,7 @@ static int i915_enable_interrupt (drm_device_t *dev)
dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED;
dev_priv->user_irq_refcount = 0;
dev_priv->irq_enable_reg = flag;
I915_WRITE16(I915REG_INT_ENABLE_R, flag | USER_INT_FLAG);
I915_WRITE16(I915REG_INT_ENABLE_R, flag);
dev_priv->irq_enabled = 1;
return 0;
}