From: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> 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@xxxxxxxxx> --- 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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx