struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data);
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_ggtt_view view = i915_ggtt_view_normal;
        pgoff_t page_offset;
        unsigned long pfn;
        int ret = 0;
                goto unlock;
        }
 
-       /* Now bind it into the GTT if needed */
-       ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_MAPPABLE);
+       /* Use a partial view if the object is bigger than the aperture. */
+       if (obj->base.size >= dev_priv->gtt.mappable_end) {
+               static const unsigned int chunk_size = 256; // 1 MiB
+               memset(&view, 0, sizeof(view));
+               view.type = I915_GGTT_VIEW_PARTIAL;
+               view.params.partial.offset = rounddown(page_offset, chunk_size);
+               view.params.partial.size =
+                       min_t(unsigned int,
+                             chunk_size,
+                             (vma->vm_end - vma->vm_start)/PAGE_SIZE -
+                             view.params.partial.offset);
+       }
+
+       /* Now pin it into the GTT if needed */
+       ret = i915_gem_object_ggtt_pin(obj, &view, 0, PIN_MAPPABLE);
        if (ret)
                goto unlock;
 
                goto unpin;
 
        /* Finally, remap it using the new GTT offset */
-       pfn = dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj);
+       pfn = dev_priv->gtt.mappable_base +
+               i915_gem_obj_ggtt_offset_view(obj, &view);
        pfn >>= PAGE_SHIFT;
 
-       if (!obj->fault_mappable) {
-               unsigned long size = min_t(unsigned long,
-                                          vma->vm_end - vma->vm_start,
-                                          obj->base.size);
-               int i;
+       if (unlikely(view.type == I915_GGTT_VIEW_PARTIAL)) {
+               /* Overriding existing pages in partial view does not cause
+                * us any trouble as TLBs are still valid because the fault
+                * is due to userspace losing part of the mapping or never
+                * having accessed it before (at this partials' range).
+                */
+               unsigned long base = vma->vm_start +
+                                    (view.params.partial.offset << PAGE_SHIFT);
+               unsigned int i;
 
-               for (i = 0; i < size >> PAGE_SHIFT; i++) {
-                       ret = vm_insert_pfn(vma,
-                                           (unsigned long)vma->vm_start + i * PAGE_SIZE,
-                                           pfn + i);
+               for (i = 0; i < view.params.partial.size; i++) {
+                       ret = vm_insert_pfn(vma, base + i * PAGE_SIZE, pfn + i);
                        if (ret)
                                break;
                }
 
                obj->fault_mappable = true;
-       } else
-               ret = vm_insert_pfn(vma,
-                                   (unsigned long)vmf->virtual_address,
-                                   pfn + page_offset);
+       } else {
+               if (!obj->fault_mappable) {
+                       unsigned long size = min_t(unsigned long,
+                                                  vma->vm_end - vma->vm_start,
+                                                  obj->base.size);
+                       int i;
+
+                       for (i = 0; i < size >> PAGE_SHIFT; i++) {
+                               ret = vm_insert_pfn(vma,
+                                                   (unsigned long)vma->vm_start + i * PAGE_SIZE,
+                                                   pfn + i);
+                               if (ret)
+                                       break;
+                       }
+
+                       obj->fault_mappable = true;
+               } else
+                       ret = vm_insert_pfn(vma,
+                                           (unsigned long)vmf->virtual_address,
+                                           pfn + page_offset);
+       }
 unpin:
-       i915_gem_object_ggtt_unpin(obj);
+       i915_gem_object_ggtt_unpin_view(obj, &view);
 unlock:
        mutex_unlock(&dev->struct_mutex);
 out:
                goto unlock;
        }
 
-       if (obj->base.size > dev_priv->gtt.mappable_end) {
-               ret = -E2BIG;
-               goto out;
-       }
-
        if (obj->madv != I915_MADV_WILLNEED) {
                DRM_DEBUG("Attempting to mmap a purgeable buffer\n");
                ret = -EFAULT;