aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2013-03-26 09:14:18 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-03-27 12:13:44 -0400
commit2db76d7c3c6db93058f983c8240f7c7c25e87ee6 (patch)
treea35f01706b353841b71645da050bc721c9f0467b
parent693db1842d864ca2771e881127cdb4d09979758b (diff)
lib/scatterlist: sg_page_iter: support sg lists w/o backing pages
The i915 driver uses sg lists for memory without backing 'struct page' pages, similarly to other IO memory regions, setting only the DMA address for these. It does this, so that it can program the HW MMU tables in a uniform way both for sg lists with and without backing pages. Without a valid page pointer we can't call nth_page to get the current page in __sg_page_iter_next, so add a helper that relevant users can call separately. Also add a helper to get the DMA address of the current page (idea from Daniel). Convert all places in i915, to use the new API. Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Damien Lespiau <damien.lespiau@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/drm_cache.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c8
-rw-r--r--drivers/gpu/drm/i915/i915_gem_dmabuf.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c6
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c4
-rw-r--r--include/linux/scatterlist.h28
-rw-r--r--lib/scatterlist.c4
8 files changed, 35 insertions, 21 deletions
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index bc8edbeca3fd..bb8f58012189 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -109,7 +109,7 @@ drm_clflush_sg(struct sg_table *st)
109 109
110 mb(); 110 mb();
111 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) 111 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
112 drm_clflush_page(sg_iter.page); 112 drm_clflush_page(sg_page_iter_page(&sg_iter));
113 mb(); 113 mb();
114 114
115 return; 115 return;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1d091ea12fad..f69538508d8c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1543,7 +1543,7 @@ static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *
1543 struct sg_page_iter sg_iter; 1543 struct sg_page_iter sg_iter;
1544 1544
1545 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n) 1545 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n)
1546 return sg_iter.page; 1546 return sg_page_iter_page(&sg_iter);
1547 1547
1548 return NULL; 1548 return NULL;
1549} 1549}
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index a1123a32dc27..911bd40ef513 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -442,7 +442,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
442 442
443 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 443 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
444 offset >> PAGE_SHIFT) { 444 offset >> PAGE_SHIFT) {
445 struct page *page = sg_iter.page; 445 struct page *page = sg_page_iter_page(&sg_iter);
446 446
447 if (remain <= 0) 447 if (remain <= 0)
448 break; 448 break;
@@ -765,7 +765,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
765 765
766 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 766 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
767 offset >> PAGE_SHIFT) { 767 offset >> PAGE_SHIFT) {
768 struct page *page = sg_iter.page; 768 struct page *page = sg_page_iter_page(&sg_iter);
769 int partial_cacheline_write; 769 int partial_cacheline_write;
770 770
771 if (remain <= 0) 771 if (remain <= 0)
@@ -1647,7 +1647,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
1647 obj->dirty = 0; 1647 obj->dirty = 0;
1648 1648
1649 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { 1649 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
1650 struct page *page = sg_iter.page; 1650 struct page *page = sg_page_iter_page(&sg_iter);
1651 1651
1652 if (obj->dirty) 1652 if (obj->dirty)
1653 set_page_dirty(page); 1653 set_page_dirty(page);
@@ -1827,7 +1827,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
1827err_pages: 1827err_pages:
1828 sg_mark_end(sg); 1828 sg_mark_end(sg);
1829 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) 1829 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
1830 page_cache_release(sg_iter.page); 1830 page_cache_release(sg_page_iter_page(&sg_iter));
1831 sg_free_table(st); 1831 sg_free_table(st);
1832 kfree(st); 1832 kfree(st);
1833 return PTR_ERR(page); 1833 return PTR_ERR(page);
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index 898615d2d5e2..c6dfc1466e3a 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -130,7 +130,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
130 130
131 i = 0; 131 i = 0;
132 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0); 132 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0);
133 pages[i++] = sg_iter.page; 133 pages[i++] = sg_page_iter_page(&sg_iter);
134 134
135 obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL); 135 obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL);
136 drm_free_large(pages); 136 drm_free_large(pages);
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 4cbae7bbb833..24a23b31b55f 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -123,8 +123,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
123 for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { 123 for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
124 dma_addr_t page_addr; 124 dma_addr_t page_addr;
125 125
126 page_addr = sg_dma_address(sg_iter.sg) + 126 page_addr = sg_page_iter_dma_address(&sg_iter);
127 (sg_iter.sg_pgoffset << PAGE_SHIFT);
128 pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, 127 pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr,
129 cache_level); 128 cache_level);
130 if (++act_pte == I915_PPGTT_PT_ENTRIES) { 129 if (++act_pte == I915_PPGTT_PT_ENTRIES) {
@@ -424,8 +423,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
424 dma_addr_t addr; 423 dma_addr_t addr;
425 424
426 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { 425 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
427 addr = sg_dma_address(sg_iter.sg) + 426 addr = sg_page_iter_dma_address(&sg_iter);
428 (sg_iter.sg_pgoffset << PAGE_SHIFT);
429 iowrite32(gen6_pte_encode(dev, addr, level), &gtt_entries[i]); 427 iowrite32(gen6_pte_encode(dev, addr, level), &gtt_entries[i]);
430 i++; 428 i++;
431 } 429 }
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index f799708bcb85..c807eb93755b 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -481,7 +481,7 @@ i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
481 481
482 i = 0; 482 i = 0;
483 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { 483 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
484 struct page *page = sg_iter.page; 484 struct page *page = sg_page_iter_page(&sg_iter);
485 char new_bit_17 = page_to_phys(page) >> 17; 485 char new_bit_17 = page_to_phys(page) >> 17;
486 if ((new_bit_17 & 0x1) != 486 if ((new_bit_17 & 0x1) !=
487 (test_bit(i, obj->bit_17) != 0)) { 487 (test_bit(i, obj->bit_17) != 0)) {
@@ -511,7 +511,7 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
511 511
512 i = 0; 512 i = 0;
513 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { 513 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
514 if (page_to_phys(sg_iter.page) & (1 << 17)) 514 if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17))
515 __set_bit(i, obj->bit_17); 515 __set_bit(i, obj->bit_17);
516 else 516 else
517 __clear_bit(i, obj->bit_17); 517 __clear_bit(i, obj->bit_17);
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 2d8bdaef9611..e96b9546c4c6 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -235,13 +235,13 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
235 * sg page iterator 235 * sg page iterator
236 * 236 *
237 * Iterates over sg entries page-by-page. On each successful iteration, 237 * Iterates over sg entries page-by-page. On each successful iteration,
238 * @piter->page points to the current page, @piter->sg to the sg holding this 238 * you can call sg_page_iter_page(@piter) and sg_page_iter_dma_address(@piter)
239 * page and @piter->sg_pgoffset to the page's page offset within the sg. The 239 * to get the current page and its dma address. @piter->sg will point to the
240 * iteration will stop either when a maximum number of sg entries was reached 240 * sg holding this page and @piter->sg_pgoffset to the page's page offset
241 * or a terminating sg (sg_last(sg) == true) was reached. 241 * within the sg. The iteration will stop either when a maximum number of sg
242 * entries was reached or a terminating sg (sg_last(sg) == true) was reached.
242 */ 243 */
243struct sg_page_iter { 244struct sg_page_iter {
244 struct page *page; /* current page */
245 struct scatterlist *sg; /* sg holding the page */ 245 struct scatterlist *sg; /* sg holding the page */
246 unsigned int sg_pgoffset; /* page offset within the sg */ 246 unsigned int sg_pgoffset; /* page offset within the sg */
247 247
@@ -255,6 +255,24 @@ bool __sg_page_iter_next(struct sg_page_iter *piter);
255void __sg_page_iter_start(struct sg_page_iter *piter, 255void __sg_page_iter_start(struct sg_page_iter *piter,
256 struct scatterlist *sglist, unsigned int nents, 256 struct scatterlist *sglist, unsigned int nents,
257 unsigned long pgoffset); 257 unsigned long pgoffset);
258/**
259 * sg_page_iter_page - get the current page held by the page iterator
260 * @piter: page iterator holding the page
261 */
262static inline struct page *sg_page_iter_page(struct sg_page_iter *piter)
263{
264 return nth_page(sg_page(piter->sg), piter->sg_pgoffset);
265}
266
267/**
268 * sg_page_iter_dma_address - get the dma address of the current page held by
269 * the page iterator.
270 * @piter: page iterator holding the page
271 */
272static inline dma_addr_t sg_page_iter_dma_address(struct sg_page_iter *piter)
273{
274 return sg_dma_address(piter->sg) + (piter->sg_pgoffset << PAGE_SHIFT);
275}
258 276
259/** 277/**
260 * for_each_sg_page - iterate over the pages of the given sg list 278 * for_each_sg_page - iterate over the pages of the given sg list
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index b83c144d731f..a1cf8cae60e7 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -401,7 +401,6 @@ void __sg_page_iter_start(struct sg_page_iter *piter,
401 piter->__pg_advance = 0; 401 piter->__pg_advance = 0;
402 piter->__nents = nents; 402 piter->__nents = nents;
403 403
404 piter->page = NULL;
405 piter->sg = sglist; 404 piter->sg = sglist;
406 piter->sg_pgoffset = pgoffset; 405 piter->sg_pgoffset = pgoffset;
407} 406}
@@ -426,7 +425,6 @@ bool __sg_page_iter_next(struct sg_page_iter *piter)
426 if (!--piter->__nents || !piter->sg) 425 if (!--piter->__nents || !piter->sg)
427 return false; 426 return false;
428 } 427 }
429 piter->page = nth_page(sg_page(piter->sg), piter->sg_pgoffset);
430 428
431 return true; 429 return true;
432} 430}
@@ -496,7 +494,7 @@ bool sg_miter_next(struct sg_mapping_iter *miter)
496 miter->__remaining = min_t(unsigned long, miter->__remaining, 494 miter->__remaining = min_t(unsigned long, miter->__remaining,
497 PAGE_SIZE - miter->__offset); 495 PAGE_SIZE - miter->__offset);
498 } 496 }
499 miter->page = miter->piter.page; 497 miter->page = sg_page_iter_page(&miter->piter);
500 miter->consumed = miter->length = miter->__remaining; 498 miter->consumed = miter->length = miter->__remaining;
501 499
502 if (miter->__flags & SG_MITER_ATOMIC) 500 if (miter->__flags & SG_MITER_ATOMIC)