[Intel-gfx] [RFC 2/7] drm/i915: Use i915_sg_create for userptr
Tvrtko Ursulin
tursulin at ursulin.net
Thu Oct 13 09:03:59 UTC 2016
From: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Now that we have a helper which builds the sg lists, use it
from the userptr code as well.
To do this we first export the API and add kerneldoc for it.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 33 +++++++++++++++++
drivers/gpu/drm/i915/i915_gem.c | 65 +++++++++++++++++++++++----------
drivers/gpu/drm/i915/i915_gem_userptr.c | 51 +++++---------------------
3 files changed, 87 insertions(+), 62 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index bf397b643cc0..e226794ffc1b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3999,4 +3999,37 @@ int remap_io_mapping(struct vm_area_struct *vma,
__T; \
})
+/**
+ * struct i915_sg_create_state - state object for the sg creation helpers
+ * @st: sg_table being created
+ * @sg: Current scatterlist entry iterated over
+ * @idx: Current page index iterated over
+ * @page_count: Number of pages requested for the sg table to hold at creation
+ * @max_segment: Maximum size in bytes of a single sg entry
+ * @last_pfn: Page frame number of the previously added page
+ */
+struct i915_sg_create_state {
+ struct sg_table *st;
+ struct scatterlist *sg;
+ unsigned int idx;
+ unsigned int page_count;
+ unsigned long max_segment;
+ unsigned long last_pfn;
+};
+
+struct i915_sg_create_state *i915_sg_create(unsigned int page_count);
+void i915_sg_add_page(struct i915_sg_create_state *state, struct page *page);
+struct sg_table *i915_sg_complete(struct i915_sg_create_state *state);
+void i915_sg_abort(struct i915_sg_create_state *state);
+
+/**
+ * i915_sg_for_each_page - sg creation iterator
+ * @state: state object created by i915_sg_create
+ *
+ * Iterates page_count times over the created state allowing the caller to
+ * call i915_sg_add_page for all the pages it wants to build the list from.
+ */
+#define i915_sg_for_each_page(state) \
+ for( ; (state)->idx < (state)->page_count; )
+
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 93b047735e6b..1c1aa3bbde8a 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2216,17 +2216,16 @@ static unsigned long swiotlb_max_size(void)
#endif
}
-struct i915_sg_create_state {
- struct sg_table *st;
- struct scatterlist *sg;
- unsigned int idx;
- unsigned int page_count;
- unsigned long max_segment;
- unsigned long last_pfn;
-};
-
-static struct i915_sg_create_state *
-i915_sg_create(unsigned int page_count)
+/**
+ * i915_sg_create - creates the state object for sg list building
+ * @page_count: number of pages the caller intends to add to the list
+ *
+ * This function creates a state object which is to be used with the
+ * accompanying family of functions used to build the scatter-gather list.
+ *
+ * Returns a pointer to the state structure or ERR_PTR otherwise.
+ */
+struct i915_sg_create_state *i915_sg_create(unsigned int page_count)
{
struct i915_sg_create_state *state;
struct sg_table *st;
@@ -2260,8 +2259,17 @@ i915_sg_create(unsigned int page_count)
return state;
}
-static void
-i915_sg_add_page(struct i915_sg_create_state *state, struct page *page)
+/**
+ * i915_sg_add_page - adds a page to the sg list being built
+ * @state: state created with i915_sg_create
+ * @page: struct page pointer of the page to add to the list
+ *
+ * Intended to be called under the i915_sg_for_each_page iterator once for each
+ * page which needs to be added to the sg list.
+ * Function manages the internal state which can be read (only!) by the caller
+ * where appropriate.
+ */
+void i915_sg_add_page(struct i915_sg_create_state *state, struct page *page)
{
unsigned long pfn = page_to_pfn(page);
struct scatterlist *sg = state->sg;
@@ -2282,8 +2290,17 @@ i915_sg_add_page(struct i915_sg_create_state *state, struct page *page)
state->idx++;
}
-static struct sg_table *
-i915_sg_complete(struct i915_sg_create_state *state)
+/**
+ * i915_sg_complete - completes the sg list building
+ * @state: state created with i915_sg_create
+ *
+ * When all the pages have been successsfuly added to the sg list, this function
+ * is called to retrieve the fully build sg_table pointer.
+ * State object is not valid after this is called.
+ *
+ * Returns the sg_table pointer ready to be used.
+ */
+struct sg_table *i915_sg_complete(struct i915_sg_create_state *state)
{
struct sg_table *st = state->st;
@@ -2295,17 +2312,25 @@ i915_sg_complete(struct i915_sg_create_state *state)
return st;
}
-static void
-i915_sg_abort(struct i915_sg_create_state *state)
+/**
+ * i915_sg_abort - aborts the sg list building
+ * @state: state previously created with i915_sg_create
+ *
+ * In cases when something goes wrong with the sg list building, callers need
+ * to call this function to cleanup the objects and state allocated by the
+ * i915_sg_create.
+ * State object must not be accessed after calling this.
+ * Callers are responsible to do the correct thing with regards to individual
+ * page freeing/releasing themselves, but this helper will free the sg table
+ * and scatter gather entries.
+ */
+void i915_sg_abort(struct i915_sg_create_state *state)
{
sg_free_table(state->st);
kfree(state->st);
kfree(state);
}
-#define i915_sg_for_each_page(state) \
- for( ; (state)->idx < (state)->page_count; )
-
static int
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
{
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index e537930c64b5..ced19610d911 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -397,54 +397,21 @@ struct get_pages_work {
struct task_struct *task;
};
-#if IS_ENABLED(CONFIG_SWIOTLB)
-#define swiotlb_active() swiotlb_nr_tbl()
-#else
-#define swiotlb_active() 0
-#endif
-
-static int
-st_set_pages(struct sg_table **st, struct page **pvec, int num_pages)
-{
- struct scatterlist *sg;
- int ret, n;
-
- *st = kmalloc(sizeof(**st), GFP_KERNEL);
- if (*st == NULL)
- return -ENOMEM;
-
- if (swiotlb_active()) {
- ret = sg_alloc_table(*st, num_pages, GFP_KERNEL);
- if (ret)
- goto err;
-
- for_each_sg((*st)->sgl, sg, num_pages, n)
- sg_set_page(sg, pvec[n], PAGE_SIZE, 0);
- } else {
- ret = sg_alloc_table_from_pages(*st, pvec, num_pages,
- 0, num_pages << PAGE_SHIFT,
- GFP_KERNEL);
- if (ret)
- goto err;
- }
-
- return 0;
-
-err:
- kfree(*st);
- *st = NULL;
- return ret;
-}
-
static int
__i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj,
struct page **pvec, int num_pages)
{
+ struct i915_sg_create_state *state;
int ret;
- ret = st_set_pages(&obj->pages, pvec, num_pages);
- if (ret)
- return ret;
+ state = i915_sg_create(num_pages);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ i915_sg_for_each_page(state)
+ i915_sg_add_page(state, pvec[state->idx]);
+
+ obj->pages = i915_sg_complete(state);
ret = i915_gem_gtt_prepare_object(obj);
if (ret) {
--
2.7.4
More information about the Intel-gfx
mailing list