[Intel-gfx] [PATCH] drm/i915: Use the existing pages when retrying to DMA map
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Mon Jan 9 12:23:37 UTC 2017
Hi,
On 20/12/2016 13:42, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
>
> Rather than freeing and re-allocating the pages when DMA mapping
> in large chunks fails, we can just rebuild the sg table with no
> coalescing.
>
> Also change back the page counter to unsigned int because that
> is what the sg API supports.
>
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> Only compile tested!
> ---
> drivers/gpu/drm/i915/i915_gem.c | 40 ++++++++++++++++++++++++++++++----------
> 1 file changed, 30 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 5275f6248ce3..e73f9f5a5d23 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2340,12 +2340,36 @@ static void i915_sg_trim(struct sg_table *orig_st)
> *orig_st = new_st;
> }
>
> +static void i915_sg_uncoalesce(struct sg_table *orig_st, unsigned long nents)
> +{
> + struct sg_table new_st;
> + struct scatterlist *new_sg;
> + struct sgt_iter sgt_iter;
> + struct page *page;
> +
> + if (sg_alloc_table(&new_st, nents, GFP_KERNEL))
> + return;
> +
> + new_sg = new_st.sgl;
> + for_each_sgt_page(page, sgt_iter, orig_st) {
> + sg_set_page(new_sg, page, PAGE_SIZE, 0);
> + /* called before being DMA mapped, no need to copy sg->dma_* */
> + new_sg = sg_next(new_sg);
> + }
> +
> + GEM_BUG_ON(new_sg); /* Should walk exactly nents and hit the end */
> +
> + sg_free_table(orig_st);
> +
> + *orig_st = new_st;
> +}
> +
> static struct sg_table *
> i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
> {
> struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
> - const unsigned long page_count = obj->base.size / PAGE_SIZE;
> - unsigned long i;
> + const unsigned int page_count = obj->base.size / PAGE_SIZE;
> + unsigned int i;
> struct address_space *mapping;
> struct sg_table *st;
> struct scatterlist *sg;
> @@ -2371,7 +2395,6 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
> if (st == NULL)
> return ERR_PTR(-ENOMEM);
>
> -rebuild_st:
> if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
> kfree(st);
> return ERR_PTR(-ENOMEM);
> @@ -2429,6 +2452,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
> /* Trim unused sg entries to avoid wasting memory. */
> i915_sg_trim(st);
>
> +prepare_gtt:
> ret = i915_gem_gtt_prepare_pages(obj, st);
> if (ret) {
> /* DMA remapping failed? One possible cause is that
> @@ -2436,16 +2460,12 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
> * for PAGE_SIZE chunks instead may be helpful.
> */
> if (max_segment > PAGE_SIZE) {
> - for_each_sgt_page(page, sgt_iter, st)
> - put_page(page);
> - sg_free_table(st);
> -
> + i915_sg_uncoalesce(st, page_count);
> max_segment = PAGE_SIZE;
> - goto rebuild_st;
> + goto prepare_gtt;
> } else {
> dev_warn(&dev_priv->drm.pdev->dev,
> - "Failed to DMA remap %lu pages\n",
> - page_count);
> + "Failed to DMA remap %u pages\n", page_count);
> goto err_pages;
> }
> }
>
Are you still against this? As a reminder it saves a put_page/allocate
page-from-shmemfs cycle on dma mapping failures.
Regards,
Tvrtko
More information about the Intel-gfx
mailing list