diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3b6eb651d88a..c6f80bc3b7bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -2342,7 +2342,8 @@ static struct sg_table * | |||
| 2342 | i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | 2342 | i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) |
| 2343 | { | 2343 | { |
| 2344 | struct drm_i915_private *dev_priv = to_i915(obj->base.dev); | 2344 | struct drm_i915_private *dev_priv = to_i915(obj->base.dev); |
| 2345 | int page_count, i; | 2345 | const unsigned long page_count = obj->base.size / PAGE_SIZE; |
| 2346 | unsigned long i; | ||
| 2346 | struct address_space *mapping; | 2347 | struct address_space *mapping; |
| 2347 | struct sg_table *st; | 2348 | struct sg_table *st; |
| 2348 | struct scatterlist *sg; | 2349 | struct scatterlist *sg; |
| @@ -2368,7 +2369,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | |||
| 2368 | if (st == NULL) | 2369 | if (st == NULL) |
| 2369 | return ERR_PTR(-ENOMEM); | 2370 | return ERR_PTR(-ENOMEM); |
| 2370 | 2371 | ||
| 2371 | page_count = obj->base.size / PAGE_SIZE; | 2372 | rebuild_st: |
| 2372 | if (sg_alloc_table(st, page_count, GFP_KERNEL)) { | 2373 | if (sg_alloc_table(st, page_count, GFP_KERNEL)) { |
| 2373 | kfree(st); | 2374 | kfree(st); |
| 2374 | return ERR_PTR(-ENOMEM); | 2375 | return ERR_PTR(-ENOMEM); |
| @@ -2427,8 +2428,25 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | |||
| 2427 | i915_sg_trim(st); | 2428 | i915_sg_trim(st); |
| 2428 | 2429 | ||
| 2429 | ret = i915_gem_gtt_prepare_pages(obj, st); | 2430 | ret = i915_gem_gtt_prepare_pages(obj, st); |
| 2430 | if (ret) | 2431 | if (ret) { |
| 2431 | goto err_pages; | 2432 | /* DMA remapping failed? One possible cause is that |
| 2433 | * it could not reserve enough large entries, asking | ||
| 2434 | * for PAGE_SIZE chunks instead may be helpful. | ||
| 2435 | */ | ||
| 2436 | if (max_segment > PAGE_SIZE) { | ||
| 2437 | for_each_sgt_page(page, sgt_iter, st) | ||
| 2438 | put_page(page); | ||
| 2439 | sg_free_table(st); | ||
| 2440 | |||
| 2441 | max_segment = PAGE_SIZE; | ||
| 2442 | goto rebuild_st; | ||
| 2443 | } else { | ||
| 2444 | dev_warn(&dev_priv->drm.pdev->dev, | ||
| 2445 | "Failed to DMA remap %lu pages\n", | ||
| 2446 | page_count); | ||
| 2447 | goto err_pages; | ||
| 2448 | } | ||
| 2449 | } | ||
| 2432 | 2450 | ||
| 2433 | if (i915_gem_object_needs_bit17_swizzle(obj)) | 2451 | if (i915_gem_object_needs_bit17_swizzle(obj)) |
| 2434 | i915_gem_object_do_bit_17_swizzle(obj, st); | 2452 | i915_gem_object_do_bit_17_swizzle(obj, st); |
