}
 
        /* Now pin it into the GTT if needed */
-       ret = i915_gem_object_ggtt_pin(obj, &view, 0, PIN_MAPPABLE);
+       ret = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
        if (ret)
                goto unlock;
 
  * @obj: object to bind
  * @vm: address space to bind into
  * @ggtt_view: global gtt view if applicable
+ * @size: requested size in bytes (can be larger than the VMA)
  * @alignment: requested alignment
  * @flags: mask of PIN_* flags to use
  */
 i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
                           const struct i915_ggtt_view *ggtt_view,
+                          u64 size,
                           u64 alignment,
                           u64 flags)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       u32 fence_alignment, unfenced_alignment;
-       u32 search_flag, alloc_flag;
        u64 start, end;
-       u64 size, fence_size;
+       u32 search_flag, alloc_flag;
        struct i915_vma *vma;
        int ret;
 
        if (i915_is_ggtt(vm)) {
-               u32 view_size;
+               u32 fence_size, fence_alignment, unfenced_alignment;
+               u64 view_size;
 
                if (WARN_ON(!ggtt_view))
                        return ERR_PTR(-EINVAL);
                                                                view_size,
                                                                obj->tiling_mode,
                                                                false);
-               size = flags & PIN_MAPPABLE ? fence_size : view_size;
+               size = max(size, view_size);
+               if (flags & PIN_MAPPABLE)
+                       size = max_t(u64, size, fence_size);
+
+               if (alignment == 0)
+                       alignment = flags & PIN_MAPPABLE ? fence_alignment :
+                               unfenced_alignment;
+               if (flags & PIN_MAPPABLE && alignment & (fence_alignment - 1)) {
+                       DRM_DEBUG("Invalid object (view type=%u) alignment requested %llx\n",
+                                 ggtt_view ? ggtt_view->type : 0,
+                                 alignment);
+                       return ERR_PTR(-EINVAL);
+               }
        } else {
-               fence_size = i915_gem_get_gtt_size(dev,
-                                                  obj->base.size,
-                                                  obj->tiling_mode);
-               fence_alignment = i915_gem_get_gtt_alignment(dev,
-                                                            obj->base.size,
-                                                            obj->tiling_mode,
-                                                            true);
-               unfenced_alignment =
-                       i915_gem_get_gtt_alignment(dev,
-                                                  obj->base.size,
-                                                  obj->tiling_mode,
-                                                  false);
-               size = flags & PIN_MAPPABLE ? fence_size : obj->base.size;
+               size = max_t(u64, size, obj->base.size);
+               alignment = 4096;
        }
 
        start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
        end = vm->total;
        if (flags & PIN_MAPPABLE)
-               end = min_t(u64, end, ggtt->mappable_end);
+               end = min_t(u64, end, dev_priv->ggtt.mappable_end);
        if (flags & PIN_ZONE_4G)
                end = min_t(u64, end, (1ULL << 32) - PAGE_SIZE);
 
-       if (alignment == 0)
-               alignment = flags & PIN_MAPPABLE ? fence_alignment :
-                                               unfenced_alignment;
-       if (flags & PIN_MAPPABLE && alignment & (fence_alignment - 1)) {
-               DRM_DEBUG("Invalid object (view type=%u) alignment requested %llx\n",
-                         ggtt_view ? ggtt_view->type : 0,
-                         alignment);
-               return ERR_PTR(-EINVAL);
-       }
-
        /* If binding the object/GGTT view requires more space than the entire
         * aperture has, reject it early before evicting everything in a vain
         * attempt to find space.
         */
        if (size > end) {
-               DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%llu > %s aperture=%llu\n",
+               DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: request=%llu [object=%zd] > %s aperture=%llu\n",
                          ggtt_view ? ggtt_view->type : 0,
-                         size,
+                         size, obj->base.size,
                          flags & PIN_MAPPABLE ? "mappable" : "total",
                          end);
                return ERR_PTR(-E2BIG);
         * (e.g. libkms for the bootup splash), we have to ensure that we
         * always use map_and_fenceable for all scanout buffers.
         */
-       ret = i915_gem_object_ggtt_pin(obj, view, alignment,
+       ret = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
                                       view->type == I915_GGTT_VIEW_NORMAL ?
                                       PIN_MAPPABLE : 0);
        if (ret)
 }
 
 static bool
-i915_vma_misplaced(struct i915_vma *vma, u64 alignment, u64 flags)
+i915_vma_misplaced(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
 {
        struct drm_i915_gem_object *obj = vma->obj;
 
-       if (alignment &&
-           vma->node.start & (alignment - 1))
+       if (vma->node.size < size)
+               return true;
+
+       if (alignment && vma->node.start & (alignment - 1))
                return true;
 
        if (flags & PIN_MAPPABLE && !obj->map_and_fenceable)
 i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
                       struct i915_address_space *vm,
                       const struct i915_ggtt_view *ggtt_view,
+                      u64 size,
                       u64 alignment,
                       u64 flags)
 {
                if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
                        return -EBUSY;
 
-               if (i915_vma_misplaced(vma, alignment, flags)) {
+               if (i915_vma_misplaced(vma, size, alignment, flags)) {
                        WARN(vma->pin_count,
                             "bo is already pinned in %s with incorrect alignment:"
                             " offset=%08x %08x, req.alignment=%llx, req.map_and_fenceable=%d,"
 
        bound = vma ? vma->bound : 0;
        if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
-               vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view, alignment,
-                                                flags);
+               vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view,
+                                                size, alignment, flags);
                if (IS_ERR(vma))
                        return PTR_ERR(vma);
        } else {
 int
 i915_gem_object_pin(struct drm_i915_gem_object *obj,
                    struct i915_address_space *vm,
+                   u64 size,
                    u64 alignment,
                    u64 flags)
 {
        return i915_gem_object_do_pin(obj, vm,
                                      i915_is_ggtt(vm) ? &i915_ggtt_view_normal : NULL,
-                                     alignment, flags);
+                                     size, alignment, flags);
 }
 
 int
 i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
                         const struct i915_ggtt_view *view,
+                        u64 size,
                         u64 alignment,
                         u64 flags)
 {
        BUG_ON(!view);
 
        return i915_gem_object_do_pin(obj, &ggtt->base, view,
-                                     alignment, flags | PIN_GLOBAL);
+                                     size, alignment, flags | PIN_GLOBAL);
 }
 
 void