[Intel-gfx] [PATCH] drm/i915: Use the existing pages when retrying to DMA map
Chris Wilson
chris at chris-wilson.co.uk
Mon Jan 9 12:28:39 UTC 2017
On Mon, Jan 09, 2017 at 12:23:37PM +0000, Tvrtko Ursulin wrote:
>
> 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.
I still regard it as incomplete. Why bother saving that trip and not the
actual page allocation itself.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
More information about the Intel-gfx
mailing list