]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/libdrm.git/blobdiff - intel/intel_bufmgr_gem.c
intel: query for LLC support
[glsdk/libdrm.git] / intel / intel_bufmgr_gem.c
index ea76678271bc72de7eb806cd47af5b66e7648cf1..187e8ec9ca8684b5c99cbcb50f72fd095fbe2879 100644 (file)
@@ -39,6 +39,7 @@
 #endif
 
 #include <xf86drm.h>
+#include <xf86atomic.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <stdbool.h>
 
 #include "errno.h"
 #include "libdrm_lists.h"
-#include "intel_atomic.h"
 #include "intel_bufmgr.h"
 #include "intel_bufmgr_priv.h"
 #include "intel_chipset.h"
@@ -66,6 +67,8 @@
                fprintf(stderr, __VA_ARGS__);           \
 } while (0)
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
 typedef struct _drm_intel_bo_gem drm_intel_bo_gem;
 
 struct drm_intel_gem_bo_bucket {
@@ -73,10 +76,6 @@ struct drm_intel_gem_bo_bucket {
        unsigned long size;
 };
 
-/* Only cache objects up to 64MB.  Bigger than that, and the rounding of the
- * size makes many operations fail that wouldn't otherwise.
- */
-#define DRM_INTEL_GEM_BO_BUCKETS       14
 typedef struct _drm_intel_bufmgr_gem {
        drm_intel_bufmgr bufmgr;
 
@@ -93,14 +92,24 @@ typedef struct _drm_intel_bufmgr_gem {
        int exec_count;
 
        /** Array of lists of cached gem objects of power-of-two sizes */
-       struct drm_intel_gem_bo_bucket cache_bucket[DRM_INTEL_GEM_BO_BUCKETS];
+       struct drm_intel_gem_bo_bucket cache_bucket[14 * 4];
+       int num_buckets;
+       time_t time;
+
+       drmMMListHead named;
+       drmMMListHead vma_cache;
+       int vma_count, vma_open, vma_max;
 
        uint64_t gtt_size;
        int available_fences;
        int pci_device;
        int gen;
-       char bo_reuse;
-       char fenced_relocs;
+       unsigned int has_bsd : 1;
+       unsigned int has_blt : 1;
+       unsigned int has_relaxed_fencing : 1;
+       unsigned int has_llc : 1;
+       unsigned int bo_reuse : 1;
+       bool fenced_relocs;
 } drm_intel_bufmgr_gem;
 
 #define DRM_INTEL_RELOC_FENCE (1<<0)
@@ -121,6 +130,7 @@ struct _drm_intel_bo_gem {
         * Kenel-assigned global name for this object
         */
        unsigned int global_name;
+       drmMMListHead name_list;
 
        /**
         * Index of the buffer within the validation list while preparing a
@@ -133,6 +143,7 @@ struct _drm_intel_bo_gem {
         */
        uint32_t tiling_mode;
        uint32_t swizzle_mode;
+       unsigned long stride;
 
        time_t free_time;
 
@@ -148,6 +159,8 @@ struct _drm_intel_bo_gem {
        void *mem_virtual;
        /** GTT virtual address for the buffer, saved across map/unmap cycles */
        void *gtt_virtual;
+       int map_count;
+       drmMMListHead vma_list;
 
        /** BO cache list */
        drmMMListHead head;
@@ -156,24 +169,24 @@ struct _drm_intel_bo_gem {
         * Boolean of whether this BO and its children have been included in
         * the current drm_intel_bufmgr_check_aperture_space() total.
         */
-       char included_in_check_aperture;
+       bool included_in_check_aperture;
 
        /**
         * Boolean of whether this buffer has been used as a relocation
         * target and had its size accounted for, and thus can't have any
         * further relocations added to it.
         */
-       char used_as_reloc_target;
+       bool used_as_reloc_target;
 
        /**
         * Boolean of whether we have encountered an error whilst building the relocation tree.
         */
-       char has_error;
+       bool has_error;
 
        /**
         * Boolean of whether this buffer can be re-used
         */
-       char reusable;
+       bool reusable;
 
        /**
         * Size in bytes of this buffer and its relocation descendents.
@@ -188,6 +201,9 @@ struct _drm_intel_bo_gem {
         * relocations.
         */
        int reloc_tree_fences;
+
+       /** Flags that we may need to do the SW_FINSIH ioctl on unmap. */
+       bool mapped_cpu_write;
 };
 
 static unsigned int
@@ -201,8 +217,9 @@ drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
                            uint32_t * swizzle_mode);
 
 static int
-drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
-                           uint32_t stride);
+drm_intel_gem_bo_set_tiling_internal(drm_intel_bo *bo,
+                                    uint32_t tiling_mode,
+                                    uint32_t stride);
 
 static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo,
                                                      time_t time);
@@ -226,7 +243,7 @@ drm_intel_gem_bo_tile_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size,
                return ROUND_UP_TO(size, 4096);
 
        /* Older chips need powers of two, of at least 512k or 1M */
-       if (bufmgr_gem->gen == 2) {
+       if (bufmgr_gem->gen == 3) {
                min_size = 1024*1024;
                max_size = 128*1024*1024;
        } else {
@@ -239,6 +256,10 @@ drm_intel_gem_bo_tile_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size,
                return size;
        }
 
+       /* Do we need to allocate every page for the fence? */
+       if (bufmgr_gem->has_relaxed_fencing)
+               return ROUND_UP_TO(size, 4096);
+
        for (i = min_size; i < size; i <<= 1)
                ;
 
@@ -252,18 +273,36 @@ drm_intel_gem_bo_tile_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size,
  */
 static unsigned long
 drm_intel_gem_bo_tile_pitch(drm_intel_bufmgr_gem *bufmgr_gem,
-                           unsigned long pitch, uint32_t tiling_mode)
+                           unsigned long pitch, uint32_t *tiling_mode)
 {
-       unsigned long tile_width = 512;
+       unsigned long tile_width;
        unsigned long i;
 
-       if (tiling_mode == I915_TILING_NONE)
-               return ROUND_UP_TO(pitch, tile_width);
+       /* If untiled, then just align it so that we can do rendering
+        * to it with the 3D engine.
+        */
+       if (*tiling_mode == I915_TILING_NONE)
+               return ALIGN(pitch, 64);
+
+       if (*tiling_mode == I915_TILING_X
+                       || (IS_915(bufmgr_gem->pci_device)
+                           && *tiling_mode == I915_TILING_Y))
+               tile_width = 512;
+       else
+               tile_width = 128;
 
        /* 965 is flexible */
        if (bufmgr_gem->gen >= 4)
                return ROUND_UP_TO(pitch, tile_width);
 
+       /* The older hardware has a maximum pitch of 8192 with tiled
+        * surfaces, so fallback to untiled if it's too large.
+        */
+       if (pitch > 8192) {
+               *tiling_mode = I915_TILING_NONE;
+               return ALIGN(pitch, 64);
+       }
+
        /* Pre-965 needs power of two tile width */
        for (i = tile_width; i < pitch; i <<= 1)
                ;
@@ -277,7 +316,7 @@ drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem,
 {
        int i;
 
-       for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) {
+       for (i = 0; i < bufmgr_gem->num_buckets; i++) {
                struct drm_intel_gem_bo_bucket *bucket =
                    &bufmgr_gem->cache_bucket[i];
                if (bucket->size >= size) {
@@ -326,7 +365,6 @@ drm_intel_gem_bo_reference(drm_intel_bo *bo)
 {
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 
-       assert(atomic_read(&bo_gem->refcount) > 0);
        atomic_inc(&bo_gem->refcount);
 }
 
@@ -383,8 +421,12 @@ drm_intel_add_validate_buffer2(drm_intel_bo *bo, int need_fence)
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo;
        int index;
 
-       if (bo_gem->validate_index != -1)
+       if (bo_gem->validate_index != -1) {
+               if (need_fence)
+                       bufmgr_gem->exec2_objects[bo_gem->validate_index].flags |=
+                               EXEC_OBJECT_NEEDS_FENCE;
                return;
+       }
 
        /* Extend the array of validation entries as necessary. */
        if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) {
@@ -439,8 +481,23 @@ drm_intel_bo_gem_set_in_aperture_size(drm_intel_bufmgr_gem *bufmgr_gem,
         * aperture. Optimal packing is for wimps.
         */
        size = bo_gem->bo.size;
-       if (bufmgr_gem->gen < 4 && bo_gem->tiling_mode != I915_TILING_NONE)
-               size *= 2;
+       if (bufmgr_gem->gen < 4 && bo_gem->tiling_mode != I915_TILING_NONE) {
+               int min_size;
+
+               if (bufmgr_gem->has_relaxed_fencing) {
+                       if (bufmgr_gem->gen == 3)
+                               min_size = 1024*1024;
+                       else
+                               min_size = 512*1024;
+
+                       while (min_size < size)
+                               min_size *= 2;
+               } else
+                       min_size = size;
+
+               /* Account for worst-case alignment. */
+               size = 2 * min_size;
+       }
 
        bo_gem->reloc_tree_size = size;
 }
@@ -458,9 +515,9 @@ drm_intel_setup_reloc_list(drm_intel_bo *bo)
        bo_gem->relocs = malloc(max_relocs *
                                sizeof(struct drm_i915_gem_relocation_entry));
        bo_gem->reloc_target_info = malloc(max_relocs *
-                                          sizeof(drm_intel_reloc_target *));
+                                          sizeof(drm_intel_reloc_target));
        if (bo_gem->relocs == NULL || bo_gem->reloc_target_info == NULL) {
-               bo_gem->has_error = 1;
+               bo_gem->has_error = true;
 
                free (bo_gem->relocs);
                bo_gem->relocs = NULL;
@@ -485,9 +542,7 @@ drm_intel_gem_bo_busy(drm_intel_bo *bo)
        memset(&busy, 0, sizeof(busy));
        busy.handle = bo_gem->gem_handle;
 
-       do {
-               ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
-       } while (ret == -1 && errno == EINTR);
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
 
        return (ret == 0 && busy.busy);
 }
@@ -501,7 +556,7 @@ drm_intel_gem_bo_madvise_internal(drm_intel_bufmgr_gem *bufmgr_gem,
        madv.handle = bo_gem->gem_handle;
        madv.madv = state;
        madv.retained = 1;
-       ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
+       drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
 
        return madv.retained;
 }
@@ -538,19 +593,21 @@ static drm_intel_bo *
 drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr,
                                const char *name,
                                unsigned long size,
-                               unsigned long flags)
+                               unsigned long flags,
+                               uint32_t tiling_mode,
+                               unsigned long stride)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
        drm_intel_bo_gem *bo_gem;
        unsigned int page_size = getpagesize();
        int ret;
        struct drm_intel_gem_bo_bucket *bucket;
-       int alloc_from_cache;
+       bool alloc_from_cache;
        unsigned long bo_size;
-       int for_render = 0;
+       bool for_render = false;
 
        if (flags & BO_ALLOC_FOR_RENDER)
-               for_render = 1;
+               for_render = true;
 
        /* Round the allocated size up to a power of two number of pages. */
        bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size);
@@ -569,7 +626,7 @@ drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr,
        pthread_mutex_lock(&bufmgr_gem->lock);
        /* Get a buffer out of the cache if available */
 retry:
-       alloc_from_cache = 0;
+       alloc_from_cache = false;
        if (bucket != NULL && !DRMLISTEMPTY(&bucket->head)) {
                if (for_render) {
                        /* Allocate new render-target BOs from the tail (MRU)
@@ -579,7 +636,7 @@ retry:
                        bo_gem = DRMLISTENTRY(drm_intel_bo_gem,
                                              bucket->head.prev, head);
                        DRMLISTDEL(&bo_gem->head);
-                       alloc_from_cache = 1;
+                       alloc_from_cache = true;
                } else {
                        /* For non-render-target BOs (where we're probably
                         * going to map it first thing in order to fill it
@@ -591,7 +648,7 @@ retry:
                        bo_gem = DRMLISTENTRY(drm_intel_bo_gem,
                                              bucket->head.next, head);
                        if (!drm_intel_gem_bo_busy(&bo_gem->bo)) {
-                               alloc_from_cache = 1;
+                               alloc_from_cache = true;
                                DRMLISTDEL(&bo_gem->head);
                        }
                }
@@ -604,6 +661,13 @@ retry:
                                                                    bucket);
                                goto retry;
                        }
+
+                       if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
+                                                                tiling_mode,
+                                                                stride)) {
+                               drm_intel_gem_bo_free(&bo_gem->bo);
+                               goto retry;
+                       }
                }
        }
        pthread_mutex_unlock(&bufmgr_gem->lock);
@@ -619,11 +683,9 @@ retry:
                memset(&create, 0, sizeof(create));
                create.size = bo_size;
 
-               do {
-                       ret = ioctl(bufmgr_gem->fd,
-                                   DRM_IOCTL_I915_GEM_CREATE,
-                                   &create);
-               } while (ret == -1 && errno == EINTR);
+               ret = drmIoctl(bufmgr_gem->fd,
+                              DRM_IOCTL_I915_GEM_CREATE,
+                              &create);
                bo_gem->gem_handle = create.handle;
                bo_gem->bo.handle = bo_gem->gem_handle;
                if (ret != 0) {
@@ -631,17 +693,29 @@ retry:
                        return NULL;
                }
                bo_gem->bo.bufmgr = bufmgr;
+
+               bo_gem->tiling_mode = I915_TILING_NONE;
+               bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+               bo_gem->stride = 0;
+
+               if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
+                                                        tiling_mode,
+                                                        stride)) {
+                   drm_intel_gem_bo_free(&bo_gem->bo);
+                   return NULL;
+               }
+
+               DRMINITLISTHEAD(&bo_gem->name_list);
+               DRMINITLISTHEAD(&bo_gem->vma_list);
        }
 
        bo_gem->name = name;
        atomic_set(&bo_gem->refcount, 1);
        bo_gem->validate_index = -1;
        bo_gem->reloc_tree_fences = 0;
-       bo_gem->used_as_reloc_target = 0;
-       bo_gem->has_error = 0;
-       bo_gem->tiling_mode = I915_TILING_NONE;
-       bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
-       bo_gem->reusable = 1;
+       bo_gem->used_as_reloc_target = false;
+       bo_gem->has_error = false;
+       bo_gem->reusable = true;
 
        drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
 
@@ -658,7 +732,8 @@ drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
                                  unsigned int alignment)
 {
        return drm_intel_gem_bo_alloc_internal(bufmgr, name, size,
-                                              BO_ALLOC_FOR_RENDER);
+                                              BO_ALLOC_FOR_RENDER,
+                                              I915_TILING_NONE, 0);
 }
 
 static drm_intel_bo *
@@ -667,7 +742,8 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr,
                       unsigned long size,
                       unsigned int alignment)
 {
-       return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, 0);
+       return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, 0,
+                                              I915_TILING_NONE, 0);
 }
 
 static drm_intel_bo *
@@ -676,35 +752,50 @@ drm_intel_gem_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name,
                             unsigned long *pitch, unsigned long flags)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
-       drm_intel_bo *bo;
-       unsigned long size, stride, aligned_y = y;
-       int ret;
-
-       if (*tiling_mode == I915_TILING_NONE)
-               aligned_y = ALIGN(y, 2);
-       else if (*tiling_mode == I915_TILING_X)
-               aligned_y = ALIGN(y, 8);
-       else if (*tiling_mode == I915_TILING_Y)
-               aligned_y = ALIGN(y, 32);
-
-       stride = x * cpp;
-       stride = drm_intel_gem_bo_tile_pitch(bufmgr_gem, stride, *tiling_mode);
-       size = stride * aligned_y;
-       size = drm_intel_gem_bo_tile_size(bufmgr_gem, size, tiling_mode);
-
-       bo = drm_intel_gem_bo_alloc_internal(bufmgr, name, size, flags);
-       if (!bo)
-               return NULL;
-
-       ret = drm_intel_gem_bo_set_tiling(bo, tiling_mode, stride);
-       if (ret != 0) {
-               drm_intel_gem_bo_unreference(bo);
-               return NULL;
-       }
+       unsigned long size, stride;
+       uint32_t tiling;
 
+       do {
+               unsigned long aligned_y, height_alignment;
+
+               tiling = *tiling_mode;
+
+               /* If we're tiled, our allocations are in 8 or 32-row blocks,
+                * so failure to align our height means that we won't allocate
+                * enough pages.
+                *
+                * If we're untiled, we still have to align to 2 rows high
+                * because the data port accesses 2x2 blocks even if the
+                * bottom row isn't to be rendered, so failure to align means
+                * we could walk off the end of the GTT and fault.  This is
+                * documented on 965, and may be the case on older chipsets
+                * too so we try to be careful.
+                */
+               aligned_y = y;
+               height_alignment = 2;
+
+               if ((bufmgr_gem->gen == 2) && tiling != I915_TILING_NONE)
+                       height_alignment = 16;
+               else if (tiling == I915_TILING_X
+                       || (IS_915(bufmgr_gem->pci_device)
+                           && tiling == I915_TILING_Y))
+                       height_alignment = 8;
+               else if (tiling == I915_TILING_Y)
+                       height_alignment = 32;
+               aligned_y = ALIGN(y, height_alignment);
+
+               stride = x * cpp;
+               stride = drm_intel_gem_bo_tile_pitch(bufmgr_gem, stride, tiling_mode);
+               size = stride * aligned_y;
+               size = drm_intel_gem_bo_tile_size(bufmgr_gem, size, tiling_mode);
+       } while (*tiling_mode != tiling);
        *pitch = stride;
 
-       return bo;
+       if (tiling == I915_TILING_NONE)
+               stride = 0;
+
+       return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, flags,
+                                              tiling, stride);
 }
 
 /**
@@ -723,6 +814,23 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
        int ret;
        struct drm_gem_open open_arg;
        struct drm_i915_gem_get_tiling get_tiling;
+       drmMMListHead *list;
+
+       /* At the moment most applications only have a few named bo.
+        * For instance, in a DRI client only the render buffers passed
+        * between X and the client are named. And since X returns the
+        * alternating names for the front/back buffer a linear search
+        * provides a sufficiently fast match.
+        */
+       for (list = bufmgr_gem->named.next;
+            list != &bufmgr_gem->named;
+            list = list->next) {
+               bo_gem = DRMLISTENTRY(drm_intel_bo_gem, list, name_list);
+               if (bo_gem->global_name == handle) {
+                       drm_intel_gem_bo_reference(&bo_gem->bo);
+                       return &bo_gem->bo;
+               }
+       }
 
        bo_gem = calloc(1, sizeof(*bo_gem));
        if (!bo_gem)
@@ -730,14 +838,12 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
 
        memset(&open_arg, 0, sizeof(open_arg));
        open_arg.name = handle;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_GEM_OPEN,
-                           &open_arg);
-       } while (ret == -1 && errno == EINTR);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_GEM_OPEN,
+                      &open_arg);
        if (ret != 0) {
-               fprintf(stderr, "Couldn't reference %s handle 0x%08x: %s\n",
-                       name, handle, strerror(errno));
+               DBG("Couldn't reference %s handle 0x%08x: %s\n",
+                   name, handle, strerror(errno));
                free(bo_gem);
                return NULL;
        }
@@ -749,20 +855,26 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
        atomic_set(&bo_gem->refcount, 1);
        bo_gem->validate_index = -1;
        bo_gem->gem_handle = open_arg.handle;
+       bo_gem->bo.handle = open_arg.handle;
        bo_gem->global_name = handle;
-       bo_gem->reusable = 0;
+       bo_gem->reusable = false;
 
        memset(&get_tiling, 0, sizeof(get_tiling));
        get_tiling.handle = bo_gem->gem_handle;
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_GET_TILING,
+                      &get_tiling);
        if (ret != 0) {
                drm_intel_gem_bo_unreference(&bo_gem->bo);
                return NULL;
        }
        bo_gem->tiling_mode = get_tiling.tiling_mode;
        bo_gem->swizzle_mode = get_tiling.swizzle_mode;
+       /* XXX stride is unknown */
        drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
 
+       DRMINITLISTHEAD(&bo_gem->vma_list);
+       DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
        DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
 
        return &bo_gem->bo;
@@ -776,19 +888,23 @@ drm_intel_gem_bo_free(drm_intel_bo *bo)
        struct drm_gem_close close;
        int ret;
 
-       if (bo_gem->mem_virtual)
+       DRMLISTDEL(&bo_gem->vma_list);
+       if (bo_gem->mem_virtual) {
                munmap(bo_gem->mem_virtual, bo_gem->bo.size);
-       if (bo_gem->gtt_virtual)
+               bufmgr_gem->vma_count--;
+       }
+       if (bo_gem->gtt_virtual) {
                munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
+               bufmgr_gem->vma_count--;
+       }
 
        /* Close this object */
        memset(&close, 0, sizeof(close));
        close.handle = bo_gem->gem_handle;
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close);
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close);
        if (ret != 0) {
-               fprintf(stderr,
-                       "DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",
-                       bo_gem->gem_handle, bo_gem->name, strerror(errno));
+               DBG("DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",
+                   bo_gem->gem_handle, bo_gem->name, strerror(errno));
        }
        free(bo);
 }
@@ -799,7 +915,10 @@ drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time)
 {
        int i;
 
-       for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) {
+       if (bufmgr_gem->time == time)
+               return;
+
+       for (i = 0; i < bufmgr_gem->num_buckets; i++) {
                struct drm_intel_gem_bo_bucket *bucket =
                    &bufmgr_gem->cache_bucket[i];
 
@@ -816,6 +935,69 @@ drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time)
                        drm_intel_gem_bo_free(&bo_gem->bo);
                }
        }
+
+       bufmgr_gem->time = time;
+}
+
+static void drm_intel_gem_bo_purge_vma_cache(drm_intel_bufmgr_gem *bufmgr_gem)
+{
+       int limit;
+
+       DBG("%s: cached=%d, open=%d, limit=%d\n", __FUNCTION__,
+           bufmgr_gem->vma_count, bufmgr_gem->vma_open, bufmgr_gem->vma_max);
+
+       if (bufmgr_gem->vma_max < 0)
+               return;
+
+       /* We may need to evict a few entries in order to create new mmaps */
+       limit = bufmgr_gem->vma_max - 2*bufmgr_gem->vma_open;
+       if (limit < 0)
+               limit = 0;
+
+       while (bufmgr_gem->vma_count > limit) {
+               drm_intel_bo_gem *bo_gem;
+
+               bo_gem = DRMLISTENTRY(drm_intel_bo_gem,
+                                     bufmgr_gem->vma_cache.next,
+                                     vma_list);
+               assert(bo_gem->map_count == 0);
+               DRMLISTDELINIT(&bo_gem->vma_list);
+
+               if (bo_gem->mem_virtual) {
+                       munmap(bo_gem->mem_virtual, bo_gem->bo.size);
+                       bo_gem->mem_virtual = NULL;
+                       bufmgr_gem->vma_count--;
+               }
+               if (bo_gem->gtt_virtual) {
+                       munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
+                       bo_gem->gtt_virtual = NULL;
+                       bufmgr_gem->vma_count--;
+               }
+       }
+}
+
+static void drm_intel_gem_bo_close_vma(drm_intel_bufmgr_gem *bufmgr_gem,
+                                      drm_intel_bo_gem *bo_gem)
+{
+       bufmgr_gem->vma_open--;
+       DRMLISTADDTAIL(&bo_gem->vma_list, &bufmgr_gem->vma_cache);
+       if (bo_gem->mem_virtual)
+               bufmgr_gem->vma_count++;
+       if (bo_gem->gtt_virtual)
+               bufmgr_gem->vma_count++;
+       drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
+}
+
+static void drm_intel_gem_bo_open_vma(drm_intel_bufmgr_gem *bufmgr_gem,
+                                     drm_intel_bo_gem *bo_gem)
+{
+       bufmgr_gem->vma_open++;
+       DRMLISTDEL(&bo_gem->vma_list);
+       if (bo_gem->mem_virtual)
+               bufmgr_gem->vma_count--;
+       if (bo_gem->gtt_virtual)
+               bufmgr_gem->vma_count--;
+       drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
 }
 
 static void
@@ -824,17 +1006,18 @@ drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time)
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
        struct drm_intel_gem_bo_bucket *bucket;
-       uint32_t tiling_mode;
        int i;
 
        /* Unreference all the target buffers */
        for (i = 0; i < bo_gem->reloc_count; i++) {
-               drm_intel_gem_bo_unreference_locked_timed(bo_gem->
-                                                         reloc_target_info[i].bo,
-                                                         time);
+               if (bo_gem->reloc_target_info[i].bo != bo) {
+                       drm_intel_gem_bo_unreference_locked_timed(bo_gem->
+                                                                 reloc_target_info[i].bo,
+                                                                 time);
+               }
        }
        bo_gem->reloc_count = 0;
-       bo_gem->used_as_reloc_target = 0;
+       bo_gem->used_as_reloc_target = false;
 
        DBG("bo_unreference final: %d (%s)\n",
            bo_gem->gem_handle, bo_gem->name);
@@ -849,11 +1032,18 @@ drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time)
                bo_gem->relocs = NULL;
        }
 
+       /* Clear any left-over mappings */
+       if (bo_gem->map_count) {
+               DBG("bo freed with non-zero map-count %d\n", bo_gem->map_count);
+               bo_gem->map_count = 0;
+               drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+       }
+
+       DRMLISTDEL(&bo_gem->name_list);
+
        bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size);
        /* Put the buffer into our internal cache for reuse if we can. */
-       tiling_mode = I915_TILING_NONE;
        if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL &&
-           drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0 &&
            drm_intel_gem_bo_madvise_internal(bufmgr_gem, bo_gem,
                                              I915_MADV_DONTNEED)) {
                bo_gem->free_time = time;
@@ -862,8 +1052,6 @@ drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time)
                bo_gem->validate_index = -1;
 
                DRMLISTADDTAIL(&bo_gem->head, &bucket->head);
-
-               drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time);
        } else {
                drm_intel_gem_bo_free(bo);
        }
@@ -893,6 +1081,7 @@ static void drm_intel_gem_bo_unreference(drm_intel_bo *bo)
 
                pthread_mutex_lock(&bufmgr_gem->lock);
                drm_intel_gem_bo_unreference_final(bo, time.tv_sec);
+               drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec);
                pthread_mutex_unlock(&bufmgr_gem->lock);
        }
 }
@@ -906,29 +1095,29 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable)
 
        pthread_mutex_lock(&bufmgr_gem->lock);
 
-       /* Allow recursive mapping. Mesa may recursively map buffers with
-        * nested display loops.
-        */
+       if (bo_gem->map_count++ == 0)
+               drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
        if (!bo_gem->mem_virtual) {
                struct drm_i915_gem_mmap mmap_arg;
 
-               DBG("bo_map: %d (%s)\n", bo_gem->gem_handle, bo_gem->name);
+               DBG("bo_map: %d (%s), map_count=%d\n",
+                   bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
 
                memset(&mmap_arg, 0, sizeof(mmap_arg));
                mmap_arg.handle = bo_gem->gem_handle;
                mmap_arg.offset = 0;
                mmap_arg.size = bo->size;
-               do {
-                       ret = ioctl(bufmgr_gem->fd,
-                                   DRM_IOCTL_I915_GEM_MMAP,
-                                   &mmap_arg);
-               } while (ret == -1 && errno == EINTR);
+               ret = drmIoctl(bufmgr_gem->fd,
+                              DRM_IOCTL_I915_GEM_MMAP,
+                              &mmap_arg);
                if (ret != 0) {
                        ret = -errno;
-                       fprintf(stderr,
-                               "%s:%d: Error mapping buffer %d (%s): %s .\n",
-                               __FILE__, __LINE__, bo_gem->gem_handle,
-                               bo_gem->name, strerror(errno));
+                       DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",
+                           __FILE__, __LINE__, bo_gem->gem_handle,
+                           bo_gem->name, strerror(errno));
+                       if (--bo_gem->map_count == 0)
+                               drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
                        pthread_mutex_unlock(&bufmgr_gem->lock);
                        return ret;
                }
@@ -944,20 +1133,18 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable)
                set_domain.write_domain = I915_GEM_DOMAIN_CPU;
        else
                set_domain.write_domain = 0;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_SET_DOMAIN,
-                           &set_domain);
-       } while (ret == -1 && errno == EINTR);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_SET_DOMAIN,
+                      &set_domain);
        if (ret != 0) {
-               ret = -errno;
-               fprintf(stderr, "%s:%d: Error setting to CPU domain %d: %s\n",
-                       __FILE__, __LINE__, bo_gem->gem_handle,
-                       strerror(errno));
-               pthread_mutex_unlock(&bufmgr_gem->lock);
-               return ret;
+               DBG("%s:%d: Error setting to CPU domain %d: %s\n",
+                   __FILE__, __LINE__, bo_gem->gem_handle,
+                   strerror(errno));
        }
 
+       if (write_enable)
+               bo_gem->mapped_cpu_write = true;
+
        pthread_mutex_unlock(&bufmgr_gem->lock);
 
        return 0;
@@ -972,29 +1159,31 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
 
        pthread_mutex_lock(&bufmgr_gem->lock);
 
+       if (bo_gem->map_count++ == 0)
+               drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
        /* Get a mapping of the buffer if we haven't before. */
        if (bo_gem->gtt_virtual == NULL) {
                struct drm_i915_gem_mmap_gtt mmap_arg;
 
-               DBG("bo_map_gtt: mmap %d (%s)\n", bo_gem->gem_handle,
-                   bo_gem->name);
+               DBG("bo_map_gtt: mmap %d (%s), map_count=%d\n",
+                   bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
 
                memset(&mmap_arg, 0, sizeof(mmap_arg));
                mmap_arg.handle = bo_gem->gem_handle;
 
                /* Get the fake offset back... */
-               do {
-                       ret = ioctl(bufmgr_gem->fd,
-                                   DRM_IOCTL_I915_GEM_MMAP_GTT,
-                                   &mmap_arg);
-               } while (ret == -1 && errno == EINTR);
+               ret = drmIoctl(bufmgr_gem->fd,
+                              DRM_IOCTL_I915_GEM_MMAP_GTT,
+                              &mmap_arg);
                if (ret != 0) {
                        ret = -errno;
-                       fprintf(stderr,
-                               "%s:%d: Error preparing buffer map %d (%s): %s .\n",
-                               __FILE__, __LINE__,
-                               bo_gem->gem_handle, bo_gem->name,
-                               strerror(errno));
+                       DBG("%s:%d: Error preparing buffer map %d (%s): %s .\n",
+                           __FILE__, __LINE__,
+                           bo_gem->gem_handle, bo_gem->name,
+                           strerror(errno));
+                       if (--bo_gem->map_count == 0)
+                               drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
                        pthread_mutex_unlock(&bufmgr_gem->lock);
                        return ret;
                }
@@ -1006,11 +1195,12 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
                if (bo_gem->gtt_virtual == MAP_FAILED) {
                        bo_gem->gtt_virtual = NULL;
                        ret = -errno;
-                       fprintf(stderr,
-                               "%s:%d: Error mapping buffer %d (%s): %s .\n",
-                               __FILE__, __LINE__,
-                               bo_gem->gem_handle, bo_gem->name,
-                               strerror(errno));
+                       DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",
+                           __FILE__, __LINE__,
+                           bo_gem->gem_handle, bo_gem->name,
+                           strerror(errno));
+                       if (--bo_gem->map_count == 0)
+                               drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
                        pthread_mutex_unlock(&bufmgr_gem->lock);
                        return ret;
                }
@@ -1025,69 +1215,72 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
        set_domain.handle = bo_gem->gem_handle;
        set_domain.read_domains = I915_GEM_DOMAIN_GTT;
        set_domain.write_domain = I915_GEM_DOMAIN_GTT;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_SET_DOMAIN,
-                           &set_domain);
-       } while (ret == -1 && errno == EINTR);
-
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_SET_DOMAIN,
+                      &set_domain);
        if (ret != 0) {
-               ret = -errno;
-               fprintf(stderr, "%s:%d: Error setting domain %d: %s\n",
-                       __FILE__, __LINE__, bo_gem->gem_handle,
-                       strerror(errno));
+               DBG("%s:%d: Error setting domain %d: %s\n",
+                   __FILE__, __LINE__, bo_gem->gem_handle,
+                   strerror(errno));
        }
 
        pthread_mutex_unlock(&bufmgr_gem->lock);
 
-       return ret;
+       return 0;
 }
 
-int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo)
+static int drm_intel_gem_bo_unmap(drm_intel_bo *bo)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+       struct drm_i915_gem_sw_finish sw_finish;
        int ret = 0;
 
        if (bo == NULL)
                return 0;
 
-       assert(bo_gem->gtt_virtual != NULL);
-
        pthread_mutex_lock(&bufmgr_gem->lock);
-       bo->virtual = NULL;
-       pthread_mutex_unlock(&bufmgr_gem->lock);
-
-       return ret;
-}
-
-static int drm_intel_gem_bo_unmap(drm_intel_bo *bo)
-{
-       drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
-       drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
-       struct drm_i915_gem_sw_finish sw_finish;
-       int ret;
 
-       if (bo == NULL)
+       if (bo_gem->map_count <= 0) {
+               DBG("attempted to unmap an unmapped bo\n");
+               pthread_mutex_unlock(&bufmgr_gem->lock);
+               /* Preserve the old behaviour of just treating this as a
+                * no-op rather than reporting the error.
+                */
                return 0;
+       }
 
-       assert(bo_gem->mem_virtual != NULL);
+       if (bo_gem->mapped_cpu_write) {
+               /* Cause a flush to happen if the buffer's pinned for
+                * scanout, so the results show up in a timely manner.
+                * Unlike GTT set domains, this only does work if the
+                * buffer should be scanout-related.
+                */
+               sw_finish.handle = bo_gem->gem_handle;
+               ret = drmIoctl(bufmgr_gem->fd,
+                              DRM_IOCTL_I915_GEM_SW_FINISH,
+                              &sw_finish);
+               ret = ret == -1 ? -errno : 0;
 
-       pthread_mutex_lock(&bufmgr_gem->lock);
+               bo_gem->mapped_cpu_write = false;
+       }
 
-       /* Cause a flush to happen if the buffer's pinned for scanout, so the
-        * results show up in a timely manner.
+       /* We need to unmap after every innovation as we cannot track
+        * an open vma for every bo as that will exhaasut the system
+        * limits and cause later failures.
         */
-       sw_finish.handle = bo_gem->gem_handle;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_SW_FINISH,
-                           &sw_finish);
-       } while (ret == -1 && errno == EINTR);
-
-       bo->virtual = NULL;
+       if (--bo_gem->map_count == 0) {
+               drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+               bo->virtual = NULL;
+       }
        pthread_mutex_unlock(&bufmgr_gem->lock);
-       return 0;
+
+       return ret;
+}
+
+int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo)
+{
+       return drm_intel_gem_bo_unmap(bo);
 }
 
 static int
@@ -1104,18 +1297,17 @@ drm_intel_gem_bo_subdata(drm_intel_bo *bo, unsigned long offset,
        pwrite.offset = offset;
        pwrite.size = size;
        pwrite.data_ptr = (uint64_t) (uintptr_t) data;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_PWRITE,
-                           &pwrite);
-       } while (ret == -1 && errno == EINTR);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_PWRITE,
+                      &pwrite);
        if (ret != 0) {
-               fprintf(stderr,
-                       "%s:%d: Error writing data to buffer %d: (%d %d) %s .\n",
-                       __FILE__, __LINE__, bo_gem->gem_handle, (int)offset,
-                       (int)size, strerror(errno));
+               ret = -errno;
+               DBG("%s:%d: Error writing data to buffer %d: (%d %d) %s .\n",
+                   __FILE__, __LINE__, bo_gem->gem_handle, (int)offset,
+                   (int)size, strerror(errno));
        }
-       return 0;
+
+       return ret;
 }
 
 static int
@@ -1126,8 +1318,9 @@ drm_intel_gem_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id)
        int ret;
 
        get_pipe_from_crtc_id.crtc_id = crtc_id;
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID,
-                   &get_pipe_from_crtc_id);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID,
+                      &get_pipe_from_crtc_id);
        if (ret != 0) {
                /* We return -1 here to signal that we don't
                 * know which pipe is associated with this crtc.
@@ -1155,26 +1348,24 @@ drm_intel_gem_bo_get_subdata(drm_intel_bo *bo, unsigned long offset,
        pread.offset = offset;
        pread.size = size;
        pread.data_ptr = (uint64_t) (uintptr_t) data;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_PREAD,
-                           &pread);
-       } while (ret == -1 && errno == EINTR);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_PREAD,
+                      &pread);
        if (ret != 0) {
                ret = -errno;
-               fprintf(stderr,
-                       "%s:%d: Error reading data from buffer %d: (%d %d) %s .\n",
-                       __FILE__, __LINE__, bo_gem->gem_handle, (int)offset,
-                       (int)size, strerror(errno));
+               DBG("%s:%d: Error reading data from buffer %d: (%d %d) %s .\n",
+                   __FILE__, __LINE__, bo_gem->gem_handle, (int)offset,
+                   (int)size, strerror(errno));
        }
+
        return ret;
 }
 
-/** Waits for all GPU rendering to the object to have completed. */
+/** Waits for all GPU rendering with the object to have completed. */
 static void
 drm_intel_gem_bo_wait_rendering(drm_intel_bo *bo)
 {
-       drm_intel_gem_bo_start_gtt_access(bo, 0);
+       drm_intel_gem_bo_start_gtt_access(bo, 1);
 }
 
 /**
@@ -1195,17 +1386,14 @@ drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable)
        set_domain.handle = bo_gem->gem_handle;
        set_domain.read_domains = I915_GEM_DOMAIN_GTT;
        set_domain.write_domain = write_enable ? I915_GEM_DOMAIN_GTT : 0;
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_SET_DOMAIN,
-                           &set_domain);
-       } while (ret == -1 && errno == EINTR);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_SET_DOMAIN,
+                      &set_domain);
        if (ret != 0) {
-               fprintf(stderr,
-                       "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n",
-                       __FILE__, __LINE__, bo_gem->gem_handle,
-                       set_domain.read_domains, set_domain.write_domain,
-                       strerror(errno));
+               DBG("%s:%d: Error setting memory domains %d (%08x %08x): %s .\n",
+                   __FILE__, __LINE__, bo_gem->gem_handle,
+                   set_domain.read_domains, set_domain.write_domain,
+                   strerror(errno));
        }
 }
 
@@ -1222,7 +1410,7 @@ drm_intel_bufmgr_gem_destroy(drm_intel_bufmgr *bufmgr)
        pthread_mutex_destroy(&bufmgr_gem->lock);
 
        /* Free any cached buffer objects we were going to reuse */
-       for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) {
+       for (i = 0; i < bufmgr_gem->num_buckets; i++) {
                struct drm_intel_gem_bo_bucket *bucket =
                    &bufmgr_gem->cache_bucket[i];
                drm_intel_bo_gem *bo_gem;
@@ -1252,26 +1440,28 @@ static int
 do_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
                 drm_intel_bo *target_bo, uint32_t target_offset,
                 uint32_t read_domains, uint32_t write_domain,
-                int need_fence)
+                bool need_fence)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
        drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo;
+       bool fenced_command;
 
        if (bo_gem->has_error)
                return -ENOMEM;
 
        if (target_bo_gem->has_error) {
-               bo_gem->has_error = 1;
+               bo_gem->has_error = true;
                return -ENOMEM;
        }
 
-       if (target_bo_gem->tiling_mode == I915_TILING_NONE)
-               need_fence = 0;
-
        /* We never use HW fences for rendering on 965+ */
        if (bufmgr_gem->gen >= 4)
-               need_fence = 0;
+               need_fence = false;
+
+       fenced_command = need_fence;
+       if (target_bo_gem->tiling_mode == I915_TILING_NONE)
+               need_fence = false;
 
        /* Create a new relocation list if needed */
        if (bo_gem->relocs == NULL && drm_intel_setup_reloc_list(bo))
@@ -1288,7 +1478,10 @@ do_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
         * already been accounted for.
         */
        assert(!bo_gem->used_as_reloc_target);
-       bo_gem->reloc_tree_size += target_bo_gem->reloc_tree_size;
+       if (target_bo_gem != bo_gem) {
+               target_bo_gem->used_as_reloc_target = true;
+               bo_gem->reloc_tree_size += target_bo_gem->reloc_tree_size;
+       }
        /* An object needing a fence is a tiled buffer, so it won't have
         * relocs to other buffers.
         */
@@ -1296,9 +1489,6 @@ do_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
                target_bo_gem->reloc_tree_fences = 1;
        bo_gem->reloc_tree_fences += target_bo_gem->reloc_tree_fences;
 
-       /* Flag the target to disallow further relocations in it. */
-       target_bo_gem->used_as_reloc_target = 1;
-
        bo_gem->relocs[bo_gem->reloc_count].offset = offset;
        bo_gem->relocs[bo_gem->reloc_count].delta = target_offset;
        bo_gem->relocs[bo_gem->reloc_count].target_handle =
@@ -1308,8 +1498,9 @@ do_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
        bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset;
 
        bo_gem->reloc_target_info[bo_gem->reloc_count].bo = target_bo;
-       drm_intel_gem_bo_reference(target_bo);
-       if (need_fence)
+       if (target_bo != bo)
+               drm_intel_gem_bo_reference(target_bo);
+       if (fenced_command)
                bo_gem->reloc_target_info[bo_gem->reloc_count].flags =
                        DRM_INTEL_RELOC_FENCE;
        else
@@ -1339,7 +1530,49 @@ drm_intel_gem_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset,
                                  uint32_t read_domains, uint32_t write_domain)
 {
        return do_bo_emit_reloc(bo, offset, target_bo, target_offset,
-                               read_domains, write_domain, 1);
+                               read_domains, write_domain, true);
+}
+
+int
+drm_intel_gem_bo_get_reloc_count(drm_intel_bo *bo)
+{
+       drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+       return bo_gem->reloc_count;
+}
+
+/**
+ * Removes existing relocation entries in the BO after "start".
+ *
+ * This allows a user to avoid a two-step process for state setup with
+ * counting up all the buffer objects and doing a
+ * drm_intel_bufmgr_check_aperture_space() before emitting any of the
+ * relocations for the state setup.  Instead, save the state of the
+ * batchbuffer including drm_intel_gem_get_reloc_count(), emit all the
+ * state, and then check if it still fits in the aperture.
+ *
+ * Any further drm_intel_bufmgr_check_aperture_space() queries
+ * involving this buffer in the tree are undefined after this call.
+ */
+void
+drm_intel_gem_bo_clear_relocs(drm_intel_bo *bo, int start)
+{
+       drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+       int i;
+       struct timespec time;
+
+       clock_gettime(CLOCK_MONOTONIC, &time);
+
+       assert(bo_gem->reloc_count >= start);
+       /* Unreference the cleared target buffers */
+       for (i = start; i < bo_gem->reloc_count; i++) {
+               if (bo_gem->reloc_target_info[i].bo != bo) {
+                       drm_intel_gem_bo_unreference_locked_timed(bo_gem->
+                                                                 reloc_target_info[i].bo,
+                                                                 time.tv_sec);
+               }
+       }
+       bo_gem->reloc_count = start;
 }
 
 /**
@@ -1359,6 +1592,9 @@ drm_intel_gem_bo_process_reloc(drm_intel_bo *bo)
        for (i = 0; i < bo_gem->reloc_count; i++) {
                drm_intel_bo *target_bo = bo_gem->reloc_target_info[i].bo;
 
+               if (target_bo == bo)
+                       continue;
+
                /* Continue walking the tree depth-first. */
                drm_intel_gem_bo_process_reloc(target_bo);
 
@@ -1380,6 +1616,9 @@ drm_intel_gem_bo_process_reloc2(drm_intel_bo *bo)
                drm_intel_bo *target_bo = bo_gem->reloc_target_info[i].bo;
                int need_fence;
 
+               if (target_bo == bo)
+                       continue;
+
                /* Continue walking the tree depth-first. */
                drm_intel_gem_bo_process_reloc2(target_bo);
 
@@ -1461,25 +1700,21 @@ drm_intel_gem_bo_exec(drm_intel_bo *bo, int used,
        execbuf.DR1 = 0;
        execbuf.DR4 = DR4;
 
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_EXECBUFFER,
-                           &execbuf);
-       } while (ret != 0 && errno == EINTR);
-
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_EXECBUFFER,
+                      &execbuf);
        if (ret != 0) {
                ret = -errno;
                if (errno == ENOSPC) {
-                       fprintf(stderr,
-                               "Execbuffer fails to pin. "
-                               "Estimate: %u. Actual: %u. Available: %u\n",
-                               drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos,
-                                                                  bufmgr_gem->
-                                                                  exec_count),
-                               drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos,
-                                                                 bufmgr_gem->
-                                                                 exec_count),
-                               (unsigned int)bufmgr_gem->gtt_size);
+                       DBG("Execbuffer fails to pin. "
+                           "Estimate: %u. Actual: %u. Available: %u\n",
+                           drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos,
+                                                              bufmgr_gem->
+                                                              exec_count),
+                           drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos,
+                                                             bufmgr_gem->
+                                                             exec_count),
+                           (unsigned int)bufmgr_gem->gtt_size);
                }
        }
        drm_intel_update_buffer_offsets(bufmgr_gem);
@@ -1502,14 +1737,30 @@ drm_intel_gem_bo_exec(drm_intel_bo *bo, int used,
 }
 
 static int
-drm_intel_gem_bo_exec2(drm_intel_bo *bo, int used,
-                      drm_clip_rect_t *cliprects, int num_cliprects,
-                      int DR4)
+drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used,
+                       drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
+                       unsigned int flags)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
        struct drm_i915_gem_execbuffer2 execbuf;
        int ret, i;
 
+       switch (flags & 0x7) {
+       default:
+               return -EINVAL;
+       case I915_EXEC_BLT:
+               if (!bufmgr_gem->has_blt)
+                       return -EINVAL;
+               break;
+       case I915_EXEC_BSD:
+               if (!bufmgr_gem->has_bsd)
+                       return -EINVAL;
+               break;
+       case I915_EXEC_RENDER:
+       case I915_EXEC_DEFAULT:
+               break;
+       }
+
        pthread_mutex_lock(&bufmgr_gem->lock);
        /* Update indices and set up the validate list. */
        drm_intel_gem_bo_process_reloc2(bo);
@@ -1527,24 +1778,24 @@ drm_intel_gem_bo_exec2(drm_intel_bo *bo, int used,
        execbuf.num_cliprects = num_cliprects;
        execbuf.DR1 = 0;
        execbuf.DR4 = DR4;
-       execbuf.flags = 0;
+       execbuf.flags = flags;
        execbuf.rsvd1 = 0;
        execbuf.rsvd2 = 0;
 
-       do {
-               ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2,
-                           &execbuf);
-       } while (ret != 0 && errno == EAGAIN);
-
-       if (ret != 0 && errno == ENOMEM) {
-               fprintf(stderr,
-                       "Execbuffer fails to pin. "
-                       "Estimate: %u. Actual: %u. Available: %u\n",
-                       drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos,
-                                                          bufmgr_gem->exec_count),
-                       drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos,
-                                                         bufmgr_gem->exec_count),
-                       (unsigned int) bufmgr_gem->gtt_size);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_EXECBUFFER2,
+                      &execbuf);
+       if (ret != 0) {
+               ret = -errno;
+               if (ret == -ENOSPC) {
+                       DBG("Execbuffer fails to pin. "
+                           "Estimate: %u. Actual: %u. Available: %u\n",
+                           drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos,
+                                                              bufmgr_gem->exec_count),
+                           drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos,
+                                                             bufmgr_gem->exec_count),
+                           (unsigned int) bufmgr_gem->gtt_size);
+               }
        }
        drm_intel_update_buffer_offsets2(bufmgr_gem);
 
@@ -1562,7 +1813,17 @@ drm_intel_gem_bo_exec2(drm_intel_bo *bo, int used,
        bufmgr_gem->exec_count = 0;
        pthread_mutex_unlock(&bufmgr_gem->lock);
 
-       return 0;
+       return ret;
+}
+
+static int
+drm_intel_gem_bo_exec2(drm_intel_bo *bo, int used,
+                      drm_clip_rect_t *cliprects, int num_cliprects,
+                      int DR4)
+{
+       return drm_intel_gem_bo_mrb_exec2(bo, used,
+                                       cliprects, num_cliprects, DR4,
+                                       I915_EXEC_RENDER);
 }
 
 static int
@@ -1577,12 +1838,9 @@ drm_intel_gem_bo_pin(drm_intel_bo *bo, uint32_t alignment)
        pin.handle = bo_gem->gem_handle;
        pin.alignment = alignment;
 
-       do {
-               ret = ioctl(bufmgr_gem->fd,
-                           DRM_IOCTL_I915_GEM_PIN,
-                           &pin);
-       } while (ret == -1 && errno == EINTR);
-
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_PIN,
+                      &pin);
        if (ret != 0)
                return -errno;
 
@@ -1601,7 +1859,7 @@ drm_intel_gem_bo_unpin(drm_intel_bo *bo)
        memset(&unpin, 0, sizeof(unpin));
        unpin.handle = bo_gem->gem_handle;
 
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_UNPIN, &unpin);
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_UNPIN, &unpin);
        if (ret != 0)
                return -errno;
 
@@ -1609,35 +1867,63 @@ drm_intel_gem_bo_unpin(drm_intel_bo *bo)
 }
 
 static int
-drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
-                           uint32_t stride)
+drm_intel_gem_bo_set_tiling_internal(drm_intel_bo *bo,
+                                    uint32_t tiling_mode,
+                                    uint32_t stride)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
        struct drm_i915_gem_set_tiling set_tiling;
        int ret;
 
-       if (bo_gem->global_name == 0 && *tiling_mode == bo_gem->tiling_mode)
+       if (bo_gem->global_name == 0 &&
+           tiling_mode == bo_gem->tiling_mode &&
+           stride == bo_gem->stride)
                return 0;
 
        memset(&set_tiling, 0, sizeof(set_tiling));
-       set_tiling.handle = bo_gem->gem_handle;
-
        do {
-               set_tiling.tiling_mode = *tiling_mode;
+               /* set_tiling is slightly broken and overwrites the
+                * input on the error path, so we have to open code
+                * rmIoctl.
+                */
+               set_tiling.handle = bo_gem->gem_handle;
+               set_tiling.tiling_mode = tiling_mode;
                set_tiling.stride = stride;
 
                ret = ioctl(bufmgr_gem->fd,
                            DRM_IOCTL_I915_GEM_SET_TILING,
                            &set_tiling);
-       } while (ret == -1 && errno == EINTR);
+       } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+       if (ret == -1)
+               return -errno;
+
        bo_gem->tiling_mode = set_tiling.tiling_mode;
        bo_gem->swizzle_mode = set_tiling.swizzle_mode;
+       bo_gem->stride = set_tiling.stride;
+       return 0;
+}
 
-       drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
+static int
+drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
+                           uint32_t stride)
+{
+       drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+       drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+       int ret;
+
+       /* Linear buffers have no stride. By ensuring that we only ever use
+        * stride 0 with linear buffers, we simplify our code.
+        */
+       if (*tiling_mode == I915_TILING_NONE)
+               stride = 0;
+
+       ret = drm_intel_gem_bo_set_tiling_internal(bo, *tiling_mode, stride);
+       if (ret == 0)
+               drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
 
        *tiling_mode = bo_gem->tiling_mode;
-       return ret == 0 ? 0 : -errno;
+       return ret;
 }
 
 static int
@@ -1663,11 +1949,13 @@ drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t * name)
                memset(&flink, 0, sizeof(flink));
                flink.handle = bo_gem->gem_handle;
 
-               ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink);
+               ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink);
                if (ret != 0)
                        return -errno;
                bo_gem->global_name = flink.name;
-               bo_gem->reusable = 0;
+               bo_gem->reusable = false;
+
+               DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
        }
 
        *name = bo_gem->global_name;
@@ -1686,7 +1974,7 @@ drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr)
 {
        drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
 
-       bufmgr_gem->bo_reuse = 1;
+       bufmgr_gem->bo_reuse = true;
 }
 
 /**
@@ -1699,9 +1987,10 @@ drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr)
 void
 drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr)
 {
-    drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
+       drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
 
-    bufmgr_gem->fenced_relocs = 1;
+       if (bufmgr_gem->bufmgr.bo_exec == drm_intel_gem_bo_exec2)
+               bufmgr_gem->fenced_relocs = true;
 }
 
 /**
@@ -1719,7 +2008,7 @@ drm_intel_gem_bo_get_aperture_space(drm_intel_bo *bo)
                return 0;
 
        total += bo->size;
-       bo_gem->included_in_check_aperture = 1;
+       bo_gem->included_in_check_aperture = true;
 
        for (i = 0; i < bo_gem->reloc_count; i++)
                total +=
@@ -1767,7 +2056,7 @@ drm_intel_gem_bo_clear_aperture_space_flag(drm_intel_bo *bo)
        if (bo == NULL || !bo_gem->included_in_check_aperture)
                return;
 
-       bo_gem->included_in_check_aperture = 0;
+       bo_gem->included_in_check_aperture = false;
 
        for (i = 0; i < bo_gem->reloc_count; i++)
                drm_intel_gem_bo_clear_aperture_space_flag(bo_gem->
@@ -1884,10 +2173,18 @@ drm_intel_gem_bo_disable_reuse(drm_intel_bo *bo)
 {
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 
-       bo_gem->reusable = 0;
+       bo_gem->reusable = false;
        return 0;
 }
 
+static int
+drm_intel_gem_bo_is_reusable(drm_intel_bo *bo)
+{
+       drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+       return bo_gem->reusable;
+}
+
 static int
 _drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo)
 {
@@ -1897,6 +2194,8 @@ _drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo)
        for (i = 0; i < bo_gem->reloc_count; i++) {
                if (bo_gem->reloc_target_info[i].bo == target_bo)
                        return 1;
+               if (bo == bo_gem->reloc_target_info[i].bo)
+                       continue;
                if (_drm_intel_gem_bo_references(bo_gem->reloc_target_info[i].bo,
                                                target_bo))
                        return 1;
@@ -1918,6 +2217,55 @@ drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo)
        return 0;
 }
 
+static void
+add_bucket(drm_intel_bufmgr_gem *bufmgr_gem, int size)
+{
+       unsigned int i = bufmgr_gem->num_buckets;
+
+       assert(i < ARRAY_SIZE(bufmgr_gem->cache_bucket));
+
+       DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head);
+       bufmgr_gem->cache_bucket[i].size = size;
+       bufmgr_gem->num_buckets++;
+}
+
+static void
+init_cache_buckets(drm_intel_bufmgr_gem *bufmgr_gem)
+{
+       unsigned long size, cache_max_size = 64 * 1024 * 1024;
+
+       /* OK, so power of two buckets was too wasteful of memory.
+        * Give 3 other sizes between each power of two, to hopefully
+        * cover things accurately enough.  (The alternative is
+        * probably to just go for exact matching of sizes, and assume
+        * that for things like composited window resize the tiled
+        * width/height alignment and rounding of sizes to pages will
+        * get us useful cache hit rates anyway)
+        */
+       add_bucket(bufmgr_gem, 4096);
+       add_bucket(bufmgr_gem, 4096 * 2);
+       add_bucket(bufmgr_gem, 4096 * 3);
+
+       /* Initialize the linked lists for BO reuse cache. */
+       for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
+               add_bucket(bufmgr_gem, size);
+
+               add_bucket(bufmgr_gem, size + size * 1 / 4);
+               add_bucket(bufmgr_gem, size + size * 2 / 4);
+               add_bucket(bufmgr_gem, size + size * 3 / 4);
+       }
+}
+
+void
+drm_intel_bufmgr_gem_set_vma_cache_size(drm_intel_bufmgr *bufmgr, int limit)
+{
+       drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
+
+       bufmgr_gem->vma_max = limit;
+
+       drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
+}
+
 /**
  * Initializes the GEM buffer manager, which uses the kernel to allocate, map,
  * and manage map buffer objections.
@@ -1930,9 +2278,8 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
        drm_intel_bufmgr_gem *bufmgr_gem;
        struct drm_i915_gem_get_aperture aperture;
        drm_i915_getparam_t gp;
-       int ret, i;
-       unsigned long size;
-       int exec2 = 0;
+       int ret, tmp;
+       bool exec2 = false;
 
        bufmgr_gem = calloc(1, sizeof(*bufmgr_gem));
        if (bufmgr_gem == NULL)
@@ -1945,7 +2292,9 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
                return NULL;
        }
 
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
+       ret = drmIoctl(bufmgr_gem->fd,
+                      DRM_IOCTL_I915_GEM_GET_APERTURE,
+                      &aperture);
 
        if (ret == 0)
                bufmgr_gem->gtt_size = aperture.aper_available_size;
@@ -1961,30 +2310,70 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
 
        gp.param = I915_PARAM_CHIPSET_ID;
        gp.value = &bufmgr_gem->pci_device;
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
        if (ret) {
                fprintf(stderr, "get chip id failed: %d [%d]\n", ret, errno);
                fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value);
        }
 
-       if (IS_GEN2(bufmgr_gem))
+       if (IS_GEN2(bufmgr_gem->pci_device))
                bufmgr_gem->gen = 2;
-       else if (IS_GEN3(bufmgr_gem))
+       else if (IS_GEN3(bufmgr_gem->pci_device))
                bufmgr_gem->gen = 3;
-       else if (IS_GEN4(bufmgr_gem))
+       else if (IS_GEN4(bufmgr_gem->pci_device))
                bufmgr_gem->gen = 4;
-       else
+       else if (IS_GEN5(bufmgr_gem->pci_device))
+               bufmgr_gem->gen = 5;
+       else if (IS_GEN6(bufmgr_gem->pci_device))
                bufmgr_gem->gen = 6;
+       else if (IS_GEN7(bufmgr_gem->pci_device))
+               bufmgr_gem->gen = 7;
+       else
+               assert(0);
+
+       if (IS_GEN3(bufmgr_gem->pci_device) &&
+           bufmgr_gem->gtt_size > 256*1024*1024) {
+               /* The unmappable part of gtt on gen 3 (i.e. above 256MB) can't
+                * be used for tiled blits. To simplify the accounting, just
+                * substract the unmappable part (fixed to 256MB on all known
+                * gen3 devices) if the kernel advertises it. */
+               bufmgr_gem->gtt_size -= 256*1024*1024;
+       }
+
+       gp.value = &tmp;
 
        gp.param = I915_PARAM_HAS_EXECBUF2;
-       ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
        if (!ret)
-               exec2 = 1;
+               exec2 = true;
+
+       gp.param = I915_PARAM_HAS_BSD;
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+       bufmgr_gem->has_bsd = ret == 0;
+
+       gp.param = I915_PARAM_HAS_BLT;
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+       bufmgr_gem->has_blt = ret == 0;
+
+       gp.param = I915_PARAM_HAS_RELAXED_FENCING;
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+       bufmgr_gem->has_relaxed_fencing = ret == 0;
+
+       gp.param = I915_PARAM_HAS_LLC;
+       ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+       if (ret == -EINVAL) {
+               /* Kernel does not supports HAS_LLC query, fallback to GPU
+                * generation detection and assume that we have LLC on GEN6/7
+                */
+               bufmgr_gem->has_llc = (IS_GEN6(bufmgr_gem->pci_device) |
+                               IS_GEN7(bufmgr_gem->pci_device));
+       } else
+               bufmgr_gem->has_llc = ret == 0;
 
        if (bufmgr_gem->gen < 4) {
                gp.param = I915_PARAM_NUM_FENCES_AVAIL;
                gp.value = &bufmgr_gem->available_fences;
-               ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+               ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
                if (ret) {
                        fprintf(stderr, "get fences failed: %d [%d]\n", ret,
                                errno);
@@ -2034,9 +2423,10 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
        bufmgr_gem->bufmgr.bo_set_tiling = drm_intel_gem_bo_set_tiling;
        bufmgr_gem->bufmgr.bo_flink = drm_intel_gem_bo_flink;
        /* Use the new one if available */
-       if (exec2)
+       if (exec2) {
                bufmgr_gem->bufmgr.bo_exec = drm_intel_gem_bo_exec2;
-       else
+               bufmgr_gem->bufmgr.bo_mrb_exec = drm_intel_gem_bo_mrb_exec2;
+       } else
                bufmgr_gem->bufmgr.bo_exec = drm_intel_gem_bo_exec;
        bufmgr_gem->bufmgr.bo_busy = drm_intel_gem_bo_busy;
        bufmgr_gem->bufmgr.bo_madvise = drm_intel_gem_bo_madvise;
@@ -2045,15 +2435,16 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
        bufmgr_gem->bufmgr.check_aperture_space =
            drm_intel_gem_check_aperture_space;
        bufmgr_gem->bufmgr.bo_disable_reuse = drm_intel_gem_bo_disable_reuse;
+       bufmgr_gem->bufmgr.bo_is_reusable = drm_intel_gem_bo_is_reusable;
        bufmgr_gem->bufmgr.get_pipe_from_crtc_id =
            drm_intel_gem_get_pipe_from_crtc_id;
        bufmgr_gem->bufmgr.bo_references = drm_intel_gem_bo_references;
 
-       /* Initialize the linked lists for BO reuse cache. */
-       for (i = 0, size = 4096; i < DRM_INTEL_GEM_BO_BUCKETS; i++, size *= 2) {
-               DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head);
-               bufmgr_gem->cache_bucket[i].size = size;
-       }
+       DRMINITLISTHEAD(&bufmgr_gem->named);
+       init_cache_buckets(bufmgr_gem);
+
+       DRMINITLISTHEAD(&bufmgr_gem->vma_cache);
+       bufmgr_gem->vma_max = -1; /* unlimited by default */
 
        return &bufmgr_gem->bufmgr;
 }