From 53d804b134494be8a324781283faecb2968f6511 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Feb 2015 20:25:07 +0000 Subject: [PATCH] sna: Avoid asserting that a foreign bo is idle Once again we fall foul of a foreign bo that between consecutive calls to the busy ioctl may be used by another client. Relax the assertion that on the status of the bo being retired and double check afterwards. Reported-by: Jiri Slaby References: https://bugs.freedesktop.org/show_bug.cgi?id=70461#c101 Signed-off-by: Chris Wilson --- src/sna/kgem.c | 53 +++++++++++++++++++++++++++++++++++--------------- src/sna/kgem.h | 5 ++--- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 2cc2c74b..c5126450 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -2654,6 +2654,34 @@ static bool kgem_retire__flushing(struct kgem *kgem) return retired; } +static bool __kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo) +{ + struct drm_i915_gem_busy busy; + + if (!bo->needs_flush) + return false; + + bo->needs_flush = false; + + VG_CLEAR(busy); + busy.handle = bo->handle; + busy.busy = !kgem->wedged; + (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); + DBG(("%s: handle=%d, busy=%d, wedged=%d\n", + __FUNCTION__, bo->handle, busy.busy, kgem->wedged)); + + if (busy.busy == 0) + return false; + + DBG(("%s: moving %d to flushing\n", + __FUNCTION__, bo->handle)); + list_add(&bo->request, &kgem->flushing); + bo->rq = MAKE_REQUEST(kgem, !!(busy.busy & ~0x1ffff)); + bo->needs_flush = true; + kgem->need_retire = true; + return true; +} + static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq) { bool retired = false; @@ -2678,15 +2706,10 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq) list_del(&bo->request); - if (bo->needs_flush) - bo->needs_flush = __kgem_busy(kgem, bo->handle); - if (bo->needs_flush) { - DBG(("%s: moving %d to flushing\n", - __FUNCTION__, bo->handle)); + if (unlikely(__kgem_bo_flush(kgem, bo))) { assert(bo != rq->bo); - list_add(&bo->request, &kgem->flushing); - bo->rq = MAKE_REQUEST(kgem, RQ_RING(bo->rq)); - kgem->need_retire = true; + DBG(("%s: movied %d to flushing\n", + __FUNCTION__, bo->handle)); continue; } @@ -2844,20 +2867,18 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring) return true; } -void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo) +bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo) { struct kgem_request *rq = bo->rq, *tmp; struct list *requests = &kgem->requests[RQ_RING(rq) == KGEM_BLT]; DBG(("%s(handle=%d)\n", __FUNCTION__, bo->handle)); - assert(!__kgem_busy(kgem, bo->handle)); - bo->needs_flush = false; rq = RQ(rq); assert(rq != &kgem->static_request); if (rq == (struct kgem_request *)kgem) { __kgem_bo_clear_busy(bo); - return; + return false; } do { @@ -2866,10 +2887,10 @@ void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo) __kgem_retire_rq(kgem, tmp); } while (tmp != rq); - assert(bo->rq == NULL); - assert(list_is_empty(&bo->request)); - assert(!bo->needs_flush); - assert(bo->domain == DOMAIN_NONE); + assert(bo->needs_flush || bo->rq == NULL); + assert(bo->needs_flush || list_is_empty(&bo->request)); + assert(bo->needs_flush || bo->domain == DOMAIN_NONE); + return bo->rq; } #if 0 diff --git a/src/sna/kgem.h b/src/sna/kgem.h index 576aaa36..f98d3b6d 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -627,7 +627,7 @@ static inline bool kgem_bo_is_busy(struct kgem_bo *bo) return bo->rq; } -void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo); +bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo); static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo) { DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__, @@ -643,8 +643,7 @@ static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo) if (__kgem_busy(kgem, bo->handle)) return true; - __kgem_retire_requests_upto(kgem, bo); - return false; + return __kgem_retire_requests_upto(kgem, bo); } static inline bool kgem_bo_is_render(struct kgem_bo *bo)