mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-12 05:24:12 +08:00
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 commit5584f1b1d7
("drm/i915: fix i915 running as dom0 under Xen") increased the max_order. Fixes:920cf41949
("drm/i915: Introduce an internal allocator for disposable private objects") Fixes:5584f1b1d7
("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: <drm-intel-fixes@lists.freedesktop.org> # v4.10-rc1+
This commit is contained in:
parent
3aac4acb89
commit
bb96dcf583
@ -48,24 +48,12 @@ static struct sg_table *
|
||||
i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||
unsigned int npages = obj->base.size / PAGE_SIZE;
|
||||
struct sg_table *st;
|
||||
struct scatterlist *sg;
|
||||
unsigned int npages;
|
||||
int max_order;
|
||||
gfp_t gfp;
|
||||
|
||||
st = kmalloc(sizeof(*st), GFP_KERNEL);
|
||||
if (!st)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (sg_alloc_table(st, npages, GFP_KERNEL)) {
|
||||
kfree(st);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sg = st->sgl;
|
||||
st->nents = 0;
|
||||
|
||||
max_order = MAX_ORDER;
|
||||
#ifdef CONFIG_SWIOTLB
|
||||
if (swiotlb_nr_tbl()) {
|
||||
@ -87,6 +75,20 @@ i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
|
||||
gfp |= __GFP_DMA32;
|
||||
}
|
||||
|
||||
create_st:
|
||||
st = kmalloc(sizeof(*st), GFP_KERNEL);
|
||||
if (!st)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
npages = obj->base.size / PAGE_SIZE;
|
||||
if (sg_alloc_table(st, npages, GFP_KERNEL)) {
|
||||
kfree(st);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sg = st->sgl;
|
||||
st->nents = 0;
|
||||
|
||||
do {
|
||||
int order = min(fls(npages) - 1, max_order);
|
||||
struct page *page;
|
||||
@ -114,8 +116,15 @@ i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
|
||||
sg = __sg_next(sg);
|
||||
} while (1);
|
||||
|
||||
if (i915_gem_gtt_prepare_pages(obj, st))
|
||||
if (i915_gem_gtt_prepare_pages(obj, st)) {
|
||||
/* Failed to dma-map try again with single page sg segments */
|
||||
if (get_order(st->sgl->length)) {
|
||||
internal_free_pages(st);
|
||||
max_order = 0;
|
||||
goto create_st;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Mark the pages as dontneed whilst they are still pinned. As soon
|
||||
* as they are unpinned they are allowed to be reaped by the shrinker,
|
||||
|
Loading…
Reference in New Issue
Block a user