Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Imre Deak and committed by
Daniel Vetter
2db76d7c 693db184

+35 -21
+1 -1
drivers/gpu/drm/drm_cache.c
··· 109 109 110 110 mb(); 111 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 113 mb(); 114 114 115 115 return;
+1 -1
drivers/gpu/drm/i915/i915_drv.h
··· 1543 1543 struct sg_page_iter sg_iter; 1544 1544 1545 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 1548 return NULL; 1549 1549 }
+4 -4
drivers/gpu/drm/i915/i915_gem.c
··· 442 442 443 443 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 444 444 offset >> PAGE_SHIFT) { 445 - struct page *page = sg_iter.page; 445 + struct page *page = sg_page_iter_page(&sg_iter); 446 446 447 447 if (remain <= 0) 448 448 break; ··· 765 765 766 766 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 767 767 offset >> PAGE_SHIFT) { 768 - struct page *page = sg_iter.page; 768 + struct page *page = sg_page_iter_page(&sg_iter); 769 769 int partial_cacheline_write; 770 770 771 771 if (remain <= 0) ··· 1647 1647 obj->dirty = 0; 1648 1648 1649 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 1652 if (obj->dirty) 1653 1653 set_page_dirty(page); ··· 1827 1827 err_pages: 1828 1828 sg_mark_end(sg); 1829 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 1831 sg_free_table(st); 1832 1832 kfree(st); 1833 1833 return PTR_ERR(page);
+1 -1
drivers/gpu/drm/i915/i915_gem_dmabuf.c
··· 130 130 131 131 i = 0; 132 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 135 obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL); 136 136 drm_free_large(pages);
+2 -4
drivers/gpu/drm/i915/i915_gem_gtt.c
··· 123 123 for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { 124 124 dma_addr_t page_addr; 125 125 126 - page_addr = sg_dma_address(sg_iter.sg) + 127 - (sg_iter.sg_pgoffset << PAGE_SHIFT); 126 + page_addr = sg_page_iter_dma_address(&sg_iter); 128 127 pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, 129 128 cache_level); 130 129 if (++act_pte == I915_PPGTT_PT_ENTRIES) { ··· 423 424 dma_addr_t addr; 424 425 425 426 for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { 426 - addr = sg_dma_address(sg_iter.sg) + 427 - (sg_iter.sg_pgoffset << PAGE_SHIFT); 427 + addr = sg_page_iter_dma_address(&sg_iter); 428 428 iowrite32(gen6_pte_encode(dev, addr, level), &gtt_entries[i]); 429 429 i++; 430 430 }
+2 -2
drivers/gpu/drm/i915/i915_gem_tiling.c
··· 481 481 482 482 i = 0; 483 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 485 char new_bit_17 = page_to_phys(page) >> 17; 486 486 if ((new_bit_17 & 0x1) != 487 487 (test_bit(i, obj->bit_17) != 0)) { ··· 511 511 512 512 i = 0; 513 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 515 __set_bit(i, obj->bit_17); 516 516 else 517 517 __clear_bit(i, obj->bit_17);
+23 -5
include/linux/scatterlist.h
··· 235 235 * sg page iterator 236 236 * 237 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 239 - * page and @piter->sg_pgoffset to the page's page offset within the sg. The 240 - * iteration will stop either when a maximum number of sg entries was reached 241 - * or a terminating sg (sg_last(sg) == true) was reached. 238 + * you can call sg_page_iter_page(@piter) and sg_page_iter_dma_address(@piter) 239 + * to get the current page and its dma address. @piter->sg will point to the 240 + * sg holding this page and @piter->sg_pgoffset to the page's page offset 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 */ 243 244 struct sg_page_iter { 244 - struct page *page; /* current page */ 245 245 struct scatterlist *sg; /* sg holding the page */ 246 246 unsigned int sg_pgoffset; /* page offset within the sg */ 247 247 ··· 255 255 void __sg_page_iter_start(struct sg_page_iter *piter, 256 256 struct scatterlist *sglist, unsigned int nents, 257 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 + */ 262 + static 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 + */ 272 + static 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 278 * for_each_sg_page - iterate over the pages of the given sg list
+1 -3
lib/scatterlist.c
··· 401 401 piter->__pg_advance = 0; 402 402 piter->__nents = nents; 403 403 404 - piter->page = NULL; 405 404 piter->sg = sglist; 406 405 piter->sg_pgoffset = pgoffset; 407 406 } ··· 425 426 if (!--piter->__nents || !piter->sg) 426 427 return false; 427 428 } 428 - piter->page = nth_page(sg_page(piter->sg), piter->sg_pgoffset); 429 429 430 430 return true; 431 431 } ··· 494 496 miter->__remaining = min_t(unsigned long, miter->__remaining, 495 497 PAGE_SIZE - miter->__offset); 496 498 } 497 - miter->page = miter->piter.page; 499 + miter->page = sg_page_iter_page(&miter->piter); 498 500 miter->consumed = miter->length = miter->__remaining; 499 501 500 502 if (miter->__flags & SG_MITER_ATOMIC)