From 738e36acbce24df0ccadb499c5cf62ccb74f56df Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 5 Sep 2008 10:35:32 +0100 Subject: Move intel libdrm stuff to libdrm_intel.so dri_bufmgr.h is replaced by intel_bufmgr.h, and several functions are renamed, though the structures and many functions remain dri_bufmgr_* and dri_bo_* --- libdrm/intel/intel_bufmgr_fake.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index e2dd9dc7..8e581aed 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -37,8 +37,9 @@ #include #include #include -#include "dri_bufmgr.h" +#include #include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" #include "drm.h" #include "i915_drm.h" #include "mm.h" @@ -105,7 +106,6 @@ struct block { typedef struct _bufmgr_fake { dri_bufmgr bufmgr; - struct intel_bufmgr intel_bufmgr; unsigned long low_offset; unsigned long size; @@ -1216,12 +1216,12 @@ intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, bufmgr_fake->bufmgr.bo_map = dri_fake_bo_map; bufmgr_fake->bufmgr.bo_unmap = dri_fake_bo_unmap; bufmgr_fake->bufmgr.bo_wait_rendering = dri_fake_bo_wait_rendering; + bufmgr_fake->bufmgr.bo_emit_reloc = dri_fake_emit_reloc; bufmgr_fake->bufmgr.destroy = dri_fake_destroy; bufmgr_fake->bufmgr.process_relocs = dri_fake_process_relocs; bufmgr_fake->bufmgr.post_submit = dri_fake_post_submit; bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space; bufmgr_fake->bufmgr.debug = 0; - bufmgr_fake->intel_bufmgr.emit_reloc = dri_fake_emit_reloc; bufmgr_fake->fence_emit = fence_emit; bufmgr_fake->fence_wait = fence_wait; -- cgit v1.2.3 From 869d8bebedddf2075c59d6bffea8ee640cb80353 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 6 Sep 2008 03:07:41 +0100 Subject: intel: Move IRQ emit/wait from callbacks into the bufmgr. In the process, work around the glaring bugs of the kernel irq wait function. --- libdrm/intel/intel_bufmgr_fake.c | 89 ++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 22 deletions(-) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 8e581aed..47629033 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "intel_bufmgr.h" #include "intel_bufmgr_priv.h" @@ -135,17 +136,10 @@ typedef struct _bufmgr_fake { unsigned need_fence:1; int thrashing; - /** - * Driver callback to emit a fence, returning the cookie. - * - * Currently, this also requires that a write flush be emitted before - * emitting the fence, but this should change. - */ - unsigned int (*fence_emit)(void *private); - /** Driver callback to wait for a fence cookie to have passed. */ - int (*fence_wait)(void *private, unsigned int fence_cookie); - /** Driver-supplied argument to driver callbacks */ - void *driver_priv; + /* Pointer to kernel-updated sarea data for the last completed user irq */ + volatile unsigned int *last_dispatch; + + int fd; int debug; @@ -214,18 +208,64 @@ static int FENCE_LTE( unsigned a, unsigned b ) static unsigned int _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake) { - bufmgr_fake->last_fence = bufmgr_fake->fence_emit(bufmgr_fake->driver_priv); + struct drm_i915_irq_emit ie; + int ret, seq = 1; + + ie.irq_seq = &seq; + ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT, + &ie, sizeof(ie)); + if (ret) { + drmMsg("%s: drm_i915_irq_emit: %d\n", __FUNCTION__, ret); + abort(); + } + + /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has + * been since it was first introduced. It only checks for + * completed_seq >= seq, and thus returns success early for wrapped irq + * values if the CPU wins a race. + * + * We have to do it up front at emit when we discover wrap, so that another + * client can't race (after we drop the lock) to emit and wait and fail. + */ + if (seq == 0 || seq == 1) { + drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_FLUSH, &ie, sizeof(ie)); + } + + DBG("emit 0x%08x\n", seq); + bufmgr_fake->last_fence = seq; return bufmgr_fake->last_fence; } static void _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie) { + struct drm_i915_irq_wait iw; + unsigned int last_dispatch; int ret; - ret = bufmgr_fake->fence_wait(bufmgr_fake->driver_priv, cookie); + DBG("wait 0x%08x\n", iw.irq_seq); + + /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has + * been since it was first introduced. It only checks for + * completed_seq >= seq, and thus never returns for pre-wrapped irq values + * if the GPU wins the race. + * + * So, check if it looks like a pre-wrapped value and just return success. + */ + if (*bufmgr_fake->last_dispatch - cookie > 0x4000000) + return; + + iw.irq_seq = cookie; + + do { + last_dispatch = *bufmgr_fake->last_dispatch; + ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, + &iw, sizeof(iw)); + } while (ret == -EAGAIN || ret == -EINTR || + (ret == -EBUSY && last_dispatch != *bufmgr_fake->last_dispatch)); + if (ret != 0) { - drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__); + drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret); abort(); } clear_fenced(bufmgr_fake, cookie); @@ -540,7 +580,7 @@ dri_bufmgr_fake_wait_idle(dri_bufmgr_fake *bufmgr_fake) { unsigned int cookie; - cookie = bufmgr_fake->fence_emit(bufmgr_fake->driver_priv); + cookie = _fence_emit_internal(bufmgr_fake); _fence_wait_internal(bufmgr_fake, cookie); } @@ -1187,13 +1227,19 @@ intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr) free_block(bufmgr_fake, block); } } +void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, + volatile unsigned int *last_dispatch) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + + bufmgr_fake->last_dispatch = last_dispatch; +} dri_bufmgr * -intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, +intel_bufmgr_fake_init(int fd, + unsigned long low_offset, void *low_virtual, unsigned long size, - unsigned int (*fence_emit)(void *private), - int (*fence_wait)(void *private, unsigned int cookie), - void *driver_priv) + volatile unsigned int *last_dispatch) { dri_bufmgr_fake *bufmgr_fake; @@ -1223,9 +1269,8 @@ intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space; bufmgr_fake->bufmgr.debug = 0; - bufmgr_fake->fence_emit = fence_emit; - bufmgr_fake->fence_wait = fence_wait; - bufmgr_fake->driver_priv = driver_priv; + bufmgr_fake->fd = fd; + bufmgr_fake->last_dispatch = last_dispatch; return &bufmgr_fake->bufmgr; } -- cgit v1.2.3 From f9d98beefc9e7b8d06a29f5b69a19f10fd3c435f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 8 Sep 2008 08:51:40 -0700 Subject: intel: move drm calls to exec buffers to libdrm_intel. This avoids duplicating the effort in 3 places. Also, added emit/wait fence callbacks back in bufmgr_fake since we need it for non-drm 2d. Sigh. --- libdrm/intel/intel_bufmgr_fake.c | 151 +++++++++++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 38 deletions(-) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 47629033..f9e1cd12 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -136,6 +136,31 @@ typedef struct _bufmgr_fake { unsigned need_fence:1; int thrashing; + /** + * Driver callback to emit a fence, returning the cookie. + * + * This allows the driver to hook in a replacement for the DRM usage in + * bufmgr_fake. + * + * Currently, this also requires that a write flush be emitted before + * emitting the fence, but this should change. + */ + unsigned int (*fence_emit)(void *private); + /** Driver callback to wait for a fence cookie to have passed. */ + void (*fence_wait)(unsigned int fence, void *private); + void *fence_priv; + + /** + * Driver callback to execute a buffer. + * + * This allows the driver to hook in a replacement for the DRM usage in + * bufmgr_fake. + */ + int (*exec)(dri_bo *bo, unsigned int used, void *priv); + void *exec_priv; + + /** Driver-supplied argument to driver callbacks */ + void *driver_priv; /* Pointer to kernel-updated sarea data for the last completed user irq */ volatile unsigned int *last_dispatch; @@ -205,12 +230,28 @@ static int FENCE_LTE( unsigned a, unsigned b ) return 0; } +void intel_bufmgr_fake_set_fence_callback(dri_bufmgr *bufmgr, + unsigned int (*emit)(void *priv), + void (*wait)(unsigned int fence, + void *priv), + void *priv) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + + bufmgr_fake->fence_emit = emit; + bufmgr_fake->fence_wait = wait; + bufmgr_fake->fence_priv = priv; +} + static unsigned int _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake) { struct drm_i915_irq_emit ie; int ret, seq = 1; + if (bufmgr_fake->fence_emit != NULL) + return bufmgr_fake->fence_emit(bufmgr_fake->fence_priv); + ie.irq_seq = &seq; ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT, &ie, sizeof(ie)); @@ -243,6 +284,11 @@ _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie) unsigned int last_dispatch; int ret; + if (bufmgr_fake->fence_wait != NULL) { + bufmgr_fake->fence_wait(cookie, bufmgr_fake->fence_priv); + return; + } + DBG("wait 0x%08x\n", iw.irq_seq); /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has @@ -1092,38 +1138,6 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo) return dri_fake_bo_validate(bo); } -static void * -dri_fake_process_relocs(dri_bo *batch_buf) -{ - dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr; - dri_bo_fake *batch_fake = (dri_bo_fake *)batch_buf; - int ret; - int retry_count = 0; - - bufmgr_fake->performed_rendering = 0; - - dri_fake_calculate_domains(batch_buf); - - batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; - - /* we've ran out of RAM so blow the whole lot away and retry */ - restart: - ret = dri_fake_reloc_and_validate_buffer(batch_buf); - if (bufmgr_fake->fail == 1) { - if (retry_count == 0) { - retry_count++; - dri_fake_kick_all(bufmgr_fake); - bufmgr_fake->fail = 0; - goto restart; - } else /* dump out the memory here */ - mmDumpMemInfo(bufmgr_fake->heap); - } - - assert(ret == 0); - - return NULL; -} - static void dri_bo_fake_post_submit(dri_bo *bo) { @@ -1150,12 +1164,74 @@ dri_bo_fake_post_submit(dri_bo *bo) } -static void -dri_fake_post_submit(dri_bo *batch_buf) +void intel_bufmgr_fake_set_exec_callback(dri_bufmgr *bufmgr, + int (*exec)(dri_bo *bo, + unsigned int used, + void *priv), + void *priv) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + + bufmgr_fake->exec = exec; + bufmgr_fake->exec_priv = exec; +} + +static int +dri_fake_bo_exec(dri_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4) { - dri_fake_fence_validated(batch_buf->bufmgr); + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; + dri_bo_fake *batch_fake = (dri_bo_fake *)bo; + struct drm_i915_batchbuffer batch; + int ret; + int retry_count = 0; + + bufmgr_fake->performed_rendering = 0; + + dri_fake_calculate_domains(bo); - dri_bo_fake_post_submit(batch_buf); + batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; + + /* we've ran out of RAM so blow the whole lot away and retry */ + restart: + ret = dri_fake_reloc_and_validate_buffer(bo); + if (bufmgr_fake->fail == 1) { + if (retry_count == 0) { + retry_count++; + dri_fake_kick_all(bufmgr_fake); + bufmgr_fake->fail = 0; + goto restart; + } else /* dump out the memory here */ + mmDumpMemInfo(bufmgr_fake->heap); + } + + assert(ret == 0); + + if (bufmgr_fake->exec != NULL) { + int ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv); + if (ret != 0) + return ret; + } else { + batch.start = bo->offset; + batch.used = used; + batch.cliprects = cliprects; + batch.num_cliprects = num_cliprects; + batch.DR1 = 0; + batch.DR4 = DR4; + + if (drmCommandWrite(bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch, + sizeof(batch))) { + drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno); + return -errno; + } + } + + dri_fake_fence_validated(bo->bufmgr); + + dri_bo_fake_post_submit(bo); + + return 0; } /** @@ -1264,8 +1340,7 @@ intel_bufmgr_fake_init(int fd, bufmgr_fake->bufmgr.bo_wait_rendering = dri_fake_bo_wait_rendering; bufmgr_fake->bufmgr.bo_emit_reloc = dri_fake_emit_reloc; bufmgr_fake->bufmgr.destroy = dri_fake_destroy; - bufmgr_fake->bufmgr.process_relocs = dri_fake_process_relocs; - bufmgr_fake->bufmgr.post_submit = dri_fake_post_submit; + bufmgr_fake->bufmgr.bo_exec = dri_fake_bo_exec; bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space; bufmgr_fake->bufmgr.debug = 0; -- cgit v1.2.3 From 368b392e6dcd19cb75675c0c18d02f70257af1df Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 10 Sep 2008 13:54:34 -0700 Subject: intel: don't forget to include config.h in bufmgr code. Thanks to airlied for catching this. --- libdrm/intel/intel_bufmgr_fake.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index f9e1cd12..4b4c2a1b 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -34,6 +34,10 @@ * the bugs in the old texture manager. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include -- cgit v1.2.3 From 3949f3c9eaad9547fe046ca4d469fa7cc8f12304 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Mon, 22 Sep 2008 10:16:19 +0800 Subject: intel: Fix driver-supplied argument to exec function (fd.o bug #17653). --- libdrm/intel/intel_bufmgr_fake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 4b4c2a1b..28c7f6b3 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -1177,7 +1177,7 @@ void intel_bufmgr_fake_set_exec_callback(dri_bufmgr *bufmgr, dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; bufmgr_fake->exec = exec; - bufmgr_fake->exec_priv = exec; + bufmgr_fake->exec_priv = priv; } static int -- cgit v1.2.3 From 0dccf017ab629d69fce91e18b013882ecb45f55d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 23 Sep 2008 10:48:39 -0700 Subject: intel: Replace wraparound test logic in bufmgr_fake. Again. I'd swapped the operands, so if we weren't in lockstep with the hardware we said the sequence was always passed. Additionally, a race was available that we might have failed at recovering from. Instead, I've replaced the logic with new stuff that should be more robust and not rely on all the parties in userland following the same IRQ_EMIT() == 1 protocol. Also, in a radical departure from past efforts, include a long comment describing the failure modes and how we're working around them. Thanks to haihao for catching the original issue. --- libdrm/intel/intel_bufmgr_fake.c | 115 ++++++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 31 deletions(-) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 28c7f6b3..e26d46c1 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -166,7 +166,7 @@ typedef struct _bufmgr_fake { /** Driver-supplied argument to driver callbacks */ void *driver_priv; /* Pointer to kernel-updated sarea data for the last completed user irq */ - volatile unsigned int *last_dispatch; + volatile int *last_dispatch; int fd; @@ -264,61 +264,114 @@ _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake) abort(); } - /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has - * been since it was first introduced. It only checks for - * completed_seq >= seq, and thus returns success early for wrapped irq - * values if the CPU wins a race. - * - * We have to do it up front at emit when we discover wrap, so that another - * client can't race (after we drop the lock) to emit and wait and fail. - */ - if (seq == 0 || seq == 1) { - drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_FLUSH, &ie, sizeof(ie)); - } - DBG("emit 0x%08x\n", seq); bufmgr_fake->last_fence = seq; return bufmgr_fake->last_fence; } static void -_fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie) +_fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) { struct drm_i915_irq_wait iw; - unsigned int last_dispatch; + int hw_seq; int ret; + int kernel_lied; if (bufmgr_fake->fence_wait != NULL) { - bufmgr_fake->fence_wait(cookie, bufmgr_fake->fence_priv); + bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv); return; } DBG("wait 0x%08x\n", iw.irq_seq); - /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has - * been since it was first introduced. It only checks for - * completed_seq >= seq, and thus never returns for pre-wrapped irq values - * if the GPU wins the race. + iw.irq_seq = seq; + + /* The kernel IRQ_WAIT implementation is all sorts of broken. + * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit unsigned + * range. + * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit + * signed range. + * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit + * signed range. + * 4) It returns -EBUSY in 3 seconds even if the hardware is still + * successfully chewing through buffers. + * + * Assume that in userland we treat sequence numbers as ints, which makes + * some of the comparisons convenient, since the sequence numbers are + * all postive signed integers. + * + * From this we get several cases we need to handle. Here's a timeline. + * 0x2 0x7 0x7ffffff8 0x7ffffffd + * | | | | + * ------------------------------------------------------------------- + * + * A) Normal wait for hw to catch up + * hw_seq seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = 5. If we call IRQ_WAIT, it will wait for hw to catch up. + * + * B) Normal wait for a sequence number that's already passed. + * seq hw_seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = -5. If we call IRQ_WAIT, it returns 0 quickly. * - * So, check if it looks like a pre-wrapped value and just return success. + * C) Hardware has already wrapped around ahead of us + * hw_seq seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = 0x80000000 - 5. If we called IRQ_WAIT, it would wait + * for hw_seq >= seq, which may never occur. Thus, we want to catch this + * in userland and return 0. + * + * D) We've wrapped around ahead of the hardware. + * seq hw_seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = -(0x80000000 - 5). If we called IRQ_WAIT, it would return + * 0 quickly because hw_seq >= seq, even though the hardware isn't caught up. + * Thus, we need to catch this early return in userland and bother the + * kernel until the hardware really does catch up. + * + * E) Hardware might wrap after we test in userland. + * hw_seq seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = 5. If we call IRQ_WAIT, it will likely see seq >= hw_seq + * and wait. However, suppose hw_seq wraps before we make it into the + * kernel. The kernel sees hw_seq >= seq and waits for 3 seconds then + * returns -EBUSY. This is case C). We should catch this and then return + * successfully. */ - if (*bufmgr_fake->last_dispatch - cookie > 0x4000000) - return; + do { + /* Keep a copy of last_dispatch so that if the wait -EBUSYs because the + * hardware didn't catch up in 3 seconds, we can see if it at least made + * progress and retry. + */ + hw_seq = *bufmgr_fake->last_dispatch; - iw.irq_seq = cookie; + /* Catch case C */ + if (seq - hw_seq > 0x40000000) + return; - do { - last_dispatch = *bufmgr_fake->last_dispatch; ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, &iw, sizeof(iw)); - } while (ret == -EAGAIN || ret == -EINTR || - (ret == -EBUSY && last_dispatch != *bufmgr_fake->last_dispatch)); + /* Catch case D */ + kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch < + -0x40000000); + + /* Catch case E */ + if (ret == -EBUSY && (seq - *bufmgr_fake->last_dispatch > 0x40000000)) + ret = 0; + } while (kernel_lied || ret == -EAGAIN || ret == -EINTR || + (ret == -EBUSY && hw_seq != *bufmgr_fake->last_dispatch)); if (ret != 0) { drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret); abort(); } - clear_fenced(bufmgr_fake, cookie); + clear_fenced(bufmgr_fake, seq); } static int @@ -1312,7 +1365,7 @@ void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, { dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; - bufmgr_fake->last_dispatch = last_dispatch; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; } dri_bufmgr * @@ -1349,7 +1402,7 @@ intel_bufmgr_fake_init(int fd, bufmgr_fake->bufmgr.debug = 0; bufmgr_fake->fd = fd; - bufmgr_fake->last_dispatch = last_dispatch; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; return &bufmgr_fake->bufmgr; } -- cgit v1.2.3 From 2db8e0c8ef8c7a66460fceda129533b364f6418c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 23 Sep 2008 17:06:01 -0700 Subject: intel: Allow up to 15 seconds chewing on one buffer before acknowledging -EBUSY. The gltestperf demo in some cases took over seven seconds to make it through one batchbuffer on a GM965. Bug #17004. --- libdrm/intel/intel_bufmgr_fake.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'libdrm/intel/intel_bufmgr_fake.c') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index e26d46c1..a5b183aa 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -273,7 +273,7 @@ static void _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) { struct drm_i915_irq_wait iw; - int hw_seq; + int hw_seq, busy_count = 0; int ret; int kernel_lied; @@ -343,7 +343,17 @@ _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) * kernel. The kernel sees hw_seq >= seq and waits for 3 seconds then * returns -EBUSY. This is case C). We should catch this and then return * successfully. + * + * F) Hardware might take a long time on a buffer. + * hw_seq seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = 5. If we call IRQ_WAIT, if sequence 2 through 5 take too + * long, it will return -EBUSY. Batchbuffers in the gltestperf demo were + * seen to take up to 7 seconds. We should catch early -EBUSY return + * and keep trying. */ + do { /* Keep a copy of last_dispatch so that if the wait -EBUSYs because the * hardware didn't catch up in 3 seconds, we can see if it at least made @@ -364,11 +374,18 @@ _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) /* Catch case E */ if (ret == -EBUSY && (seq - *bufmgr_fake->last_dispatch > 0x40000000)) ret = 0; + + /* Catch case F: Allow up to 15 seconds chewing on one buffer. */ + if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch)) + busy_count = 0; + else + busy_count++; } while (kernel_lied || ret == -EAGAIN || ret == -EINTR || - (ret == -EBUSY && hw_seq != *bufmgr_fake->last_dispatch)); + (ret == -EBUSY && busy_count < 5)); if (ret != 0) { - drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret); + drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__, __LINE__, + strerror(-ret)); abort(); } clear_fenced(bufmgr_fake, seq); -- cgit v1.2.3