@@ -313,6 +313,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
{
int ret;
int total_page_count;
+ int base_page_count, scratch_page_count;
struct drm_i915_gem_object *obj;
struct drm_i915_gem_create *args = data;
@@ -340,7 +341,35 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
obj->gem_resize.stop = total_page_count;
obj->gem_resize.scratch_page = NULL;
- return 0;
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
+ base_page_count = args->base_size / PAGE_SIZE;
+ if (base_page_count > total_page_count) {
+ DRM_DEBUG_DRIVER("invalid object size, base_size(%d) > total_size(%d)\n",
+ base_page_count, total_page_count);
+ goto unlock;
+ }
+ obj->gem_resize.base_size = args->base_size;
+ scratch_page_count = total_page_count - base_page_count;
+ /* allocate backing store only for base size */
+ obj->gem_resize.stop = base_page_count;
+
+ obj->gem_resize.scratch_page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+ if (obj->gem_resize.scratch_page == NULL) {
+ DRM_DEBUG_DRIVER("No memory to allocate scratch page\n");
+ ret = -ENOMEM;
+ goto unlock;
+ }
+ DRM_DEBUG_DRIVER("scratch page created 0x%p, base(%d) + scratch(%d) = total(%d)\n",
+ obj->gem_resize.scratch_page, base_page_count,
+ scratch_page_count, total_page_count);
+
+unlock:
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
}
static inline int
@@ -1911,6 +1940,11 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
struct page *page;
unsigned long last_pfn = 0; /* suppress gcc warning */
gfp_t gfp;
+ int j;
+ bool allow_resize = false;
+ struct page *scratch_page = NULL;
+ int scratch_page_count = 0;
+ uint32_t stop;
/* Assert that the object is not currently in any GPU domain. As it
* wasn't in the GTT, there shouldn't be any way it could have been in
@@ -1929,6 +1963,15 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
return -ENOMEM;
}
+ stop = obj->gem_resize.stop;
+ if (stop && (stop < page_count) && obj->gem_resize.scratch_page) {
+ DRM_DEBUG_DRIVER("allow this object to resize later\n");
+ allow_resize = true;
+ scratch_page_count = page_count - obj->gem_resize.stop;
+ page_count = obj->gem_resize.stop;
+ scratch_page = obj->gem_resize.scratch_page;
+ }
+
/* Get the list of pages out of our struct file. They'll be pinned
* at this point until we release them.
*
@@ -1983,6 +2026,15 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
/* Check that the i965g/gm workaround works. */
WARN_ON((gfp & __GFP_DMA32) && (last_pfn >= 0x00100000UL));
}
+
+ if (allow_resize == true) {
+ for (j = 0; j < scratch_page_count; ++j) {
+ st->nents++;
+ sg = sg_next(sg);
+ sg_set_page(sg, scratch_page, PAGE_SIZE, 0);
+ }
+ }
+
#ifdef CONFIG_SWIOTLB
if (!swiotlb_nr_tbl())
#endif