diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-12-12 19:43:19 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-12-12 20:49:46 +0000 |
commit | c7f7dd61fd07dbf938fc6ba711de07986d35ce1f (patch) | |
tree | a3cfe46b2b3533144eb4e6ab1b68f4171662e6c8 /src/sna/kgem.c | |
parent | b154d0dc404a152e1283a013a78be06b8d734867 (diff) |
sna: Pin some batches to avoid CS incoherence on 830/845
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=26345
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/kgem.c')
-rw-r--r-- | src/sna/kgem.c | 162 |
1 files changed, 140 insertions, 22 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c index a730e960..52474c90 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -832,6 +832,58 @@ static int kgem_get_screen_index(struct kgem *kgem) return sna->scrn->scrnIndex; } +static bool kgem_init_pinned_batches(struct kgem *kgem) +{ + int count[2] = { 16, 4 }; + int size[2] = { 1, 4 }; + int n, i; + + if (kgem->wedged) + return true; + + for (n = 0; n < ARRAY_SIZE(count); n++) { + for (i = 0; i < count[n]; i++) { + struct drm_i915_gem_pin pin; + struct kgem_bo *bo; + + pin.handle = gem_create(kgem->fd, size[n]); + if (pin.handle == 0) + goto err; + + DBG(("%s: new handle=%d, num_pages=%d\n", + __FUNCTION__, pin.handle, size[n])); + + bo = __kgem_bo_alloc(pin.handle, size[n]); + if (bo == NULL) { + gem_close(kgem->fd, pin.handle); + goto err; + } + + pin.alignment = 0; + if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin)) { + gem_close(kgem->fd, pin.handle); + goto err; + } + bo->presumed_offset = pin.offset; + debug_alloc__bo(kgem, bo); + list_add(&bo->list, &kgem->pinned_batches[n]); + bo->refcnt = 1; + } + } + + return true; + +err: + for (n = 0; n < ARRAY_SIZE(kgem->pinned_batches); n++) { + while (!list_is_empty(&kgem->pinned_batches[i])) { + kgem_bo_destroy(kgem, + list_first_entry(&kgem->pinned_batches[i], + struct kgem_bo, list)); + } + } + return false; +} + void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) { struct drm_i915_gem_get_aperture aperture; @@ -846,6 +898,30 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) kgem->fd = fd; kgem->gen = gen; + list_init(&kgem->requests[0]); + list_init(&kgem->requests[1]); + list_init(&kgem->batch_buffers); + list_init(&kgem->active_buffers); + list_init(&kgem->flushing); + list_init(&kgem->large); + list_init(&kgem->large_inactive); + list_init(&kgem->snoop); + for (i = 0; i < ARRAY_SIZE(kgem->pinned_batches); i++) + list_init(&kgem->pinned_batches[i]); + for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) + list_init(&kgem->inactive[i]); + for (i = 0; i < ARRAY_SIZE(kgem->active); i++) { + for (j = 0; j < ARRAY_SIZE(kgem->active[i]); j++) + list_init(&kgem->active[i][j]); + } + for (i = 0; i < ARRAY_SIZE(kgem->vma); i++) { + for (j = 0; j < ARRAY_SIZE(kgem->vma[i].inactive); j++) + list_init(&kgem->vma[i].inactive[j]); + } + kgem->vma[MAP_GTT].count = -MAX_GTT_VMA_CACHE; + kgem->vma[MAP_CPU].count = -MAX_CPU_VMA_CACHE; + + kgem->has_blt = gem_param(kgem, I915_PARAM_HAS_BLT) > 0; DBG(("%s: has BLT ring? %d\n", __FUNCTION__, kgem->has_blt)); @@ -904,6 +980,9 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) } kgem->batch_size = ARRAY_SIZE(kgem->batch); + if (gen == 020) + /* Limited to what we can pin */ + kgem->batch_size = 4*1024; if (gen == 022) /* 865g cannot handle a batch spanning multiple pages */ kgem->batch_size = PAGE_SIZE / sizeof(uint32_t); @@ -912,6 +991,12 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) if (!kgem->has_relaxed_delta && kgem->batch_size > 4*1024) kgem->batch_size = 4*1024; + if (!kgem_init_pinned_batches(kgem) && gen == 020) { + xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, + "Unable to reserve memory for GPU, disabling acceleration.\n"); + kgem->wedged = 1; + } + DBG(("%s: maximum batch size? %d\n", __FUNCTION__, kgem->batch_size)); @@ -923,27 +1008,6 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) DBG(("%s: half cpu cache %d pages\n", __FUNCTION__, kgem->half_cpu_cache_pages)); - list_init(&kgem->requests[0]); - list_init(&kgem->requests[1]); - list_init(&kgem->batch_buffers); - list_init(&kgem->active_buffers); - list_init(&kgem->flushing); - list_init(&kgem->large); - list_init(&kgem->large_inactive); - list_init(&kgem->snoop); - for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) - list_init(&kgem->inactive[i]); - for (i = 0; i < ARRAY_SIZE(kgem->active); i++) { - for (j = 0; j < ARRAY_SIZE(kgem->active[i]); j++) - list_init(&kgem->active[i][j]); - } - for (i = 0; i < ARRAY_SIZE(kgem->vma); i++) { - for (j = 0; j < ARRAY_SIZE(kgem->vma[i].inactive); j++) - list_init(&kgem->vma[i].inactive[j]); - } - kgem->vma[MAP_GTT].count = -MAX_GTT_VMA_CACHE; - kgem->vma[MAP_CPU].count = -MAX_CPU_VMA_CACHE; - kgem->next_request = __kgem_request_alloc(); DBG(("%s: cpu bo enabled %d: llc? %d, set-cache-level? %d, userptr? %d\n", __FUNCTION__, @@ -2258,6 +2322,60 @@ static int compact_batch_surface(struct kgem *kgem) return size * sizeof(uint32_t); } +static struct kgem_bo * +kgem_create_batch(struct kgem *kgem, int size) +{ + struct drm_i915_gem_set_domain set_domain; + struct kgem_bo *bo; + + if (size <= 4096) { + bo = list_first_entry(&kgem->pinned_batches[0], + struct kgem_bo, + list); + if (!bo->rq) { + list_move_tail(&bo->list, &kgem->pinned_batches[0]); + return kgem_bo_reference(bo); + } + } + + if (size <= 16384) { + bo = list_first_entry(&kgem->pinned_batches[1], + struct kgem_bo, + list); + if (!bo->rq) { + list_move_tail(&bo->list, &kgem->pinned_batches[1]); + return kgem_bo_reference(bo); + } + } + + if (kgem->gen == 20) { + assert(size <= 16384); + + bo = list_first_entry(&kgem->pinned_batches[size > 4096], + struct kgem_bo, + list); + list_move_tail(&bo->list, &kgem->pinned_batches[size > 4096]); + + DBG(("%s: syncing due to busy batches\n", __FUNCTION__)); + + VG_CLEAR(set_domain); + set_domain.handle = bo->handle; + set_domain.read_domains = I915_GEM_DOMAIN_GTT; + set_domain.write_domain = I915_GEM_DOMAIN_GTT; + if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { + DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); + kgem_throttle(kgem); + return NULL; + } + + kgem_retire(kgem); + assert(bo->rq == NULL); + return kgem_bo_reference(bo); + } + + return kgem_create_linear(kgem, size, CREATE_NO_THROTTLE); +} + void _kgem_submit(struct kgem *kgem) { struct kgem_request *rq; @@ -2295,7 +2413,7 @@ void _kgem_submit(struct kgem *kgem) size = compact_batch_surface(kgem); else size = kgem->nbatch * sizeof(kgem->batch[0]); - rq->bo = kgem_create_linear(kgem, size, CREATE_NO_THROTTLE); + rq->bo = kgem_create_batch(kgem, size); if (rq->bo) { uint32_t handle = rq->bo->handle; int i; |