[PATCH 2/4] Introduce & use new SG page range iterator
Dave Gordon
david.s.gordon at intel.com
Thu May 12 17:36:12 UTC 2016
The existing for_each_sg_page() iterator is somewhat inconvenient; in
particular, the 'nents' parameters is not expressed in any useful way,
and so there is no way to get a precise (maximum) number of iterations
(and therefore pages) without knowing that the SGL has been constructed
in a specific way.
So here we introduce for_each_sgt_range() which accepts a count of the
maximum number of iterations to be performed rather than the number of
SG entries to be processed. This fits the usage required when processing
only a subrange of the pages, or to avoid any risk of overflow when
filling a bounded array with per-page data.
Several uses of for_each_sg_page() are then converted to the new macro.
Signed-off-by: Dave Gordon <david.s.gordon at intel.com>
Cc: Imre Deak <imre.deak at intel.com>
Cc: linux-kernel at vger.kernel.org
---
drivers/gpu/drm/i915/i915_cmd_parser.c | 8 ++++----
drivers/gpu/drm/i915/i915_gem.c | 9 +++------
drivers/gpu/drm/i915/i915_gem_gtt.c | 14 ++++++--------
include/linux/scatterlist.h | 12 ++++++++++++
lib/scatterlist.c | 26 ++++++++++++++++++++++++++
5 files changed, 51 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index d97f28b..f09feec 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -946,11 +946,11 @@ static u32 *vmap_batch(struct drm_i915_gem_object *obj,
}
i = 0;
- for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, first_page) {
+ for_each_sgt_page_range(&sg_iter, obj->pages, first_page, npages)
pages[i++] = sg_page_iter_page(&sg_iter);
- if (i == npages)
- break;
- }
+
+ if (WARN_ON(i != npages))
+ goto finish;
addr = vmap(pages, i, 0, PAGE_KERNEL);
if (addr == NULL) {
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 8881cb4..87dcc84 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -611,8 +611,7 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
offset = args->offset;
- for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
- offset >> PAGE_SHIFT) {
+ for_each_sgt_page_range(&sg_iter, obj->pages, offset >> PAGE_SHIFT, ~0u) {
struct page *page = sg_page_iter_page(&sg_iter);
if (remain <= 0)
@@ -935,8 +934,7 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
offset = args->offset;
obj->dirty = 1;
- for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
- offset >> PAGE_SHIFT) {
+ for_each_sgt_page_range(&sg_iter, obj->pages, offset >> PAGE_SHIFT, ~0u) {
struct page *page = sg_page_iter_page(&sg_iter);
int partial_cacheline_write;
@@ -2420,8 +2418,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
int n;
n = 0;
- for_each_sg_page(obj->pages->sgl, &sg_iter,
- obj->pages->nents, 0)
+ for_each_sgt_page_range(&sg_iter, obj->pages, 0, ~0u)
pages[n++] = sg_page_iter_page(&sg_iter);
obj->mapping = vmap(pages, n, 0, PAGE_KERNEL);
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index c50716c..3aa4d23 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -3388,6 +3388,7 @@ struct i915_vma *
intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
struct drm_i915_gem_object *obj)
{
+ const size_t n_pages = obj->base.size / PAGE_SIZE;
unsigned int size_pages = rot_info->plane[0].width * rot_info->plane[0].height;
unsigned int size_pages_uv;
struct sg_page_iter sg_iter;
@@ -3399,7 +3400,7 @@ struct i915_vma *
int ret = -ENOMEM;
/* Allocate a temporary list of source pages for random access. */
- page_addr_list = drm_malloc_gfp(obj->base.size / PAGE_SIZE,
+ page_addr_list = drm_malloc_gfp(n_pages,
sizeof(dma_addr_t),
GFP_TEMPORARY);
if (!page_addr_list)
@@ -3422,11 +3423,10 @@ struct i915_vma *
/* Populate source page list from the object. */
i = 0;
- for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
- page_addr_list[i] = sg_page_iter_dma_address(&sg_iter);
- i++;
- }
+ for_each_sgt_page_range(&sg_iter, obj->pages, 0, n_pages)
+ page_addr_list[i++] = sg_page_iter_dma_address(&sg_iter);
+ WARN_ON(i != n_pages);
st->nents = 0;
sg = st->sgl;
@@ -3492,9 +3492,7 @@ struct i915_vma *
sg = st->sgl;
st->nents = 0;
- for_each_sg_page(obj->pages->sgl, &obj_sg_iter, obj->pages->nents,
- view->params.partial.offset)
- {
+ for_each_sgt_page_range(&obj_sg_iter, obj->pages, view->params.partial.offset, ~0u) {
if (st->nents >= view->params.partial.size)
break;
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index df43b93..00eac15 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -305,6 +305,7 @@ struct sg_page_iter {
* next step */
};
+bool __sgt_page_iter_next(struct sg_page_iter *piter);
bool __sg_page_iter_next(struct sg_page_iter *piter);
void __sg_page_iter_start(struct sg_page_iter *piter,
struct scatterlist *sglist, unsigned int nents,
@@ -339,6 +340,17 @@ static inline dma_addr_t sg_page_iter_dma_address(struct sg_page_iter *piter)
for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \
__sg_page_iter_next(piter);)
+/**
+ * for_each_sgt_page_range - iterate over some pages of the given sg_table
+ * @piter: page iterator to hold current page, sg, sg_pgoffset
+ * @sgt: sg_table to iterate over
+ * @first: starting page offset
+ * @max: maxiumum number of pages to iterate over
+ */
+#define for_each_sgt_page_range(piter, sgt, first, max) \
+ for (__sg_page_iter_start((piter), (sgt)->sgl, (max), (first)); \
+ __sgt_page_iter_next(piter);)
+
/*
* New optimised iterator :)
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 004fc70..ceeea63 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -469,6 +469,32 @@ bool __sg_page_iter_next(struct sg_page_iter *piter)
}
EXPORT_SYMBOL(__sg_page_iter_next);
+/*
+ * Note: we use the same iterator structure as __sg_page_iter_next()
+ * above, but interpret the 'nents' member differently. Here it is
+ * an upper bound on the number of iterations to be performed, not
+ * the number of internal list elements to be traversed.
+ */
+bool __sgt_page_iter_next(struct sg_page_iter *piter)
+{
+ if (!piter->__nents || !piter->sg)
+ return false;
+
+ piter->sg_pgoffset += piter->__pg_advance;
+ piter->__pg_advance = 1;
+
+ while (piter->sg_pgoffset >= sg_page_count(piter->sg)) {
+ piter->sg_pgoffset -= sg_page_count(piter->sg);
+ piter->sg = sg_next(piter->sg);
+ if (!piter->sg)
+ return false;
+ }
+
+ --piter->__nents;
+ return true;
+}
+EXPORT_SYMBOL(__sgt_page_iter_next);
+
/**
* sg_miter_start - start mapping iteration over a sg list
* @miter: sg mapping iter to be started
--
1.9.1
More information about the Intel-gfx-trybot
mailing list