diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2017-02-02 08:27:21 -0500 |
---|---|---|
committer | Jani Nikula <jani.nikula@intel.com> | 2017-02-16 04:59:09 -0500 |
commit | 2d2cfc12b1270c8451edc7d2dd5f79097b3a17d8 (patch) | |
tree | 3a60359c14723dfd5999b86038bb1ce3af6c9fe4 | |
parent | 33b7bfdf918af4dc6585afe6d21f5e6b7613de1b (diff) |
drm/i915: Recreate internal objects with single page segments if dmar fails
If we fail to dma-map the object, the most common cause is lack of space
inside the SW-IOTLB due to fragmentation. If we recreate the_sg_table
using segments of PAGE_SIZE (and single page allocations), we may succeed
in remapping the scatterlist.
First became a significant problem for the mock selftests after commit
5584f1b1d73e ("drm/i915: fix i915 running as dom0 under Xen") increased
the max_order.
Fixes: 920cf4194954 ("drm/i915: Introduce an internal allocator for disposable private objects")
Fixes: 5584f1b1d73e ("drm/i915: fix i915 running as dom0 under Xen")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202132721.12711-1-chris@chris-wilson.co.uk
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: <stable@vger.kernel.org> # v4.10
(cherry picked from commit bb96dcf5830e5d81a1da2e2a14e6c0f7dfc64348)
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_internal.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_internal.c b/drivers/gpu/drm/i915/i915_gem_internal.c index 17ce53d0d092..628699a91106 100644 --- a/drivers/gpu/drm/i915/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/i915_gem_internal.c | |||
@@ -46,24 +46,12 @@ static struct sg_table * | |||
46 | i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) | 46 | i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) |
47 | { | 47 | { |
48 | struct drm_i915_private *i915 = to_i915(obj->base.dev); | 48 | struct drm_i915_private *i915 = to_i915(obj->base.dev); |
49 | unsigned int npages = obj->base.size / PAGE_SIZE; | ||
50 | struct sg_table *st; | 49 | struct sg_table *st; |
51 | struct scatterlist *sg; | 50 | struct scatterlist *sg; |
51 | unsigned int npages; | ||
52 | int max_order; | 52 | int max_order; |
53 | gfp_t gfp; | 53 | gfp_t gfp; |
54 | 54 | ||
55 | st = kmalloc(sizeof(*st), GFP_KERNEL); | ||
56 | if (!st) | ||
57 | return ERR_PTR(-ENOMEM); | ||
58 | |||
59 | if (sg_alloc_table(st, npages, GFP_KERNEL)) { | ||
60 | kfree(st); | ||
61 | return ERR_PTR(-ENOMEM); | ||
62 | } | ||
63 | |||
64 | sg = st->sgl; | ||
65 | st->nents = 0; | ||
66 | |||
67 | max_order = MAX_ORDER; | 55 | max_order = MAX_ORDER; |
68 | #ifdef CONFIG_SWIOTLB | 56 | #ifdef CONFIG_SWIOTLB |
69 | if (swiotlb_nr_tbl()) /* minimum max swiotlb size is IO_TLB_SEGSIZE */ | 57 | if (swiotlb_nr_tbl()) /* minimum max swiotlb size is IO_TLB_SEGSIZE */ |
@@ -77,6 +65,20 @@ i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) | |||
77 | gfp |= __GFP_DMA32; | 65 | gfp |= __GFP_DMA32; |
78 | } | 66 | } |
79 | 67 | ||
68 | create_st: | ||
69 | st = kmalloc(sizeof(*st), GFP_KERNEL); | ||
70 | if (!st) | ||
71 | return ERR_PTR(-ENOMEM); | ||
72 | |||
73 | npages = obj->base.size / PAGE_SIZE; | ||
74 | if (sg_alloc_table(st, npages, GFP_KERNEL)) { | ||
75 | kfree(st); | ||
76 | return ERR_PTR(-ENOMEM); | ||
77 | } | ||
78 | |||
79 | sg = st->sgl; | ||
80 | st->nents = 0; | ||
81 | |||
80 | do { | 82 | do { |
81 | int order = min(fls(npages) - 1, max_order); | 83 | int order = min(fls(npages) - 1, max_order); |
82 | struct page *page; | 84 | struct page *page; |
@@ -104,8 +106,15 @@ i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) | |||
104 | sg = __sg_next(sg); | 106 | sg = __sg_next(sg); |
105 | } while (1); | 107 | } while (1); |
106 | 108 | ||
107 | if (i915_gem_gtt_prepare_pages(obj, st)) | 109 | if (i915_gem_gtt_prepare_pages(obj, st)) { |
110 | /* Failed to dma-map try again with single page sg segments */ | ||
111 | if (get_order(st->sgl->length)) { | ||
112 | internal_free_pages(st); | ||
113 | max_order = 0; | ||
114 | goto create_st; | ||
115 | } | ||
108 | goto err; | 116 | goto err; |
117 | } | ||
109 | 118 | ||
110 | /* Mark the pages as dontneed whilst they are still pinned. As soon | 119 | /* Mark the pages as dontneed whilst they are still pinned. As soon |
111 | * as they are unpinned they are allowed to be reaped by the shrinker, | 120 | * as they are unpinned they are allowed to be reaped by the shrinker, |