diff options
author | Jason Gunthorpe <jgg@mellanox.com> | 2019-01-04 13:40:21 -0500 |
---|---|---|
committer | Jason Gunthorpe <jgg@mellanox.com> | 2019-02-11 17:02:33 -0500 |
commit | d901b2760dc6cd5fbbf2eac31d71d94baa6c4aef (patch) | |
tree | 6598a5b011cea1bcdf160c2be9fd4e677d387e2b | |
parent | f368ff188ae4b3ef6f740a15999ea0373261b619 (diff) |
lib/scatterlist: Provide a DMA page iterator
Commit 2db76d7c3c6d ("lib/scatterlist: sg_page_iter: support sg lists w/o
backing pages") introduced the sg_page_iter_dma_address() function without
providing a way to use it in the general case. If the sg_dma_len() is not
equal to the sg length callers cannot safely use the
for_each_sg_page/sg_page_iter_dma_address combination.
Resolve this API mistake by providing a DMA specific iterator,
for_each_sg_dma_page(), that uses the right length so
sg_page_iter_dma_address() works as expected with all sglists.
A new iterator type is introduced to provide compile-time safety against
wrongly mixing accessors and iterators.
Acked-by: Christoph Hellwig <hch@lst.de> (for scatterlist)
Acked-by: Thomas Hellstrom <thellstrom@vmware.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com> (ipu3-cio2)
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
-rw-r--r-- | .clang-format | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c | 8 | ||||
-rw-r--r-- | drivers/media/pci/intel/ipu3/ipu3-cio2.c | 4 | ||||
-rw-r--r-- | include/linux/scatterlist.h | 49 | ||||
-rw-r--r-- | lib/scatterlist.c | 26 |
5 files changed, 76 insertions, 12 deletions
diff --git a/.clang-format b/.clang-format index bc2ffb2a0b53..335ce29ab813 100644 --- a/.clang-format +++ b/.clang-format | |||
@@ -240,6 +240,7 @@ ForEachMacros: | |||
240 | - 'for_each_set_bit' | 240 | - 'for_each_set_bit' |
241 | - 'for_each_set_bit_from' | 241 | - 'for_each_set_bit_from' |
242 | - 'for_each_sg' | 242 | - 'for_each_sg' |
243 | - 'for_each_sg_dma_page' | ||
243 | - 'for_each_sg_page' | 244 | - 'for_each_sg_page' |
244 | - 'for_each_sibling_event' | 245 | - 'for_each_sibling_event' |
245 | - '__for_each_thread' | 246 | - '__for_each_thread' |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 31786b200afc..a3357ff7540d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c | |||
@@ -311,7 +311,13 @@ static dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter) | |||
311 | 311 | ||
312 | static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter) | 312 | static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter) |
313 | { | 313 | { |
314 | return sg_page_iter_dma_address(&viter->iter); | 314 | /* |
315 | * FIXME: This driver wrongly mixes DMA and CPU SG list iteration and | ||
316 | * needs revision. See | ||
317 | * https://lore.kernel.org/lkml/20190104223531.GA1705@ziepe.ca/ | ||
318 | */ | ||
319 | return sg_page_iter_dma_address( | ||
320 | container_of(&viter->iter, struct sg_dma_page_iter, base)); | ||
315 | } | 321 | } |
316 | 322 | ||
317 | 323 | ||
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index cdb79ae2d8dc..9fbfbda74171 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c | |||
@@ -846,7 +846,7 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb) | |||
846 | unsigned int pages = DIV_ROUND_UP(vb->planes[0].length, CIO2_PAGE_SIZE); | 846 | unsigned int pages = DIV_ROUND_UP(vb->planes[0].length, CIO2_PAGE_SIZE); |
847 | unsigned int lops = DIV_ROUND_UP(pages + 1, entries_per_page); | 847 | unsigned int lops = DIV_ROUND_UP(pages + 1, entries_per_page); |
848 | struct sg_table *sg; | 848 | struct sg_table *sg; |
849 | struct sg_page_iter sg_iter; | 849 | struct sg_dma_page_iter sg_iter; |
850 | int i, j; | 850 | int i, j; |
851 | 851 | ||
852 | if (lops <= 0 || lops > CIO2_MAX_LOPS) { | 852 | if (lops <= 0 || lops > CIO2_MAX_LOPS) { |
@@ -873,7 +873,7 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb) | |||
873 | b->offset = sg->sgl->offset; | 873 | b->offset = sg->sgl->offset; |
874 | 874 | ||
875 | i = j = 0; | 875 | i = j = 0; |
876 | for_each_sg_page(sg->sgl, &sg_iter, sg->nents, 0) { | 876 | for_each_sg_dma_page (sg->sgl, &sg_iter, sg->nents, 0) { |
877 | if (!pages--) | 877 | if (!pages--) |
878 | break; | 878 | break; |
879 | b->lop[i][j] = sg_page_iter_dma_address(&sg_iter) >> PAGE_SHIFT; | 879 | b->lop[i][j] = sg_page_iter_dma_address(&sg_iter) >> PAGE_SHIFT; |
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index b96f0d0b5b8f..b4be960c7e5d 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h | |||
@@ -339,12 +339,12 @@ int sg_alloc_table_chained(struct sg_table *table, int nents, | |||
339 | /* | 339 | /* |
340 | * sg page iterator | 340 | * sg page iterator |
341 | * | 341 | * |
342 | * Iterates over sg entries page-by-page. On each successful iteration, | 342 | * Iterates over sg entries page-by-page. On each successful iteration, you |
343 | * you can call sg_page_iter_page(@piter) and sg_page_iter_dma_address(@piter) | 343 | * can call sg_page_iter_page(@piter) to get the current page and its dma |
344 | * to get the current page and its dma address. @piter->sg will point to the | 344 | * address. @piter->sg will point to the sg holding this page and |
345 | * sg holding this page and @piter->sg_pgoffset to the page's page offset | 345 | * @piter->sg_pgoffset to the page's page offset within the sg. The iteration |
346 | * within the sg. The iteration will stop either when a maximum number of sg | 346 | * will stop either when a maximum number of sg entries was reached or a |
347 | * entries was reached or a terminating sg (sg_last(sg) == true) was reached. | 347 | * terminating sg (sg_last(sg) == true) was reached. |
348 | */ | 348 | */ |
349 | struct sg_page_iter { | 349 | struct sg_page_iter { |
350 | struct scatterlist *sg; /* sg holding the page */ | 350 | struct scatterlist *sg; /* sg holding the page */ |
@@ -356,7 +356,19 @@ struct sg_page_iter { | |||
356 | * next step */ | 356 | * next step */ |
357 | }; | 357 | }; |
358 | 358 | ||
359 | /* | ||
360 | * sg page iterator for DMA addresses | ||
361 | * | ||
362 | * This is the same as sg_page_iter however you can call | ||
363 | * sg_page_iter_dma_address(@dma_iter) to get the page's DMA | ||
364 | * address. sg_page_iter_page() cannot be called on this iterator. | ||
365 | */ | ||
366 | struct sg_dma_page_iter { | ||
367 | struct sg_page_iter base; | ||
368 | }; | ||
369 | |||
359 | bool __sg_page_iter_next(struct sg_page_iter *piter); | 370 | bool __sg_page_iter_next(struct sg_page_iter *piter); |
371 | bool __sg_page_iter_dma_next(struct sg_dma_page_iter *dma_iter); | ||
360 | void __sg_page_iter_start(struct sg_page_iter *piter, | 372 | void __sg_page_iter_start(struct sg_page_iter *piter, |
361 | struct scatterlist *sglist, unsigned int nents, | 373 | struct scatterlist *sglist, unsigned int nents, |
362 | unsigned long pgoffset); | 374 | unsigned long pgoffset); |
@@ -372,11 +384,13 @@ static inline struct page *sg_page_iter_page(struct sg_page_iter *piter) | |||
372 | /** | 384 | /** |
373 | * sg_page_iter_dma_address - get the dma address of the current page held by | 385 | * sg_page_iter_dma_address - get the dma address of the current page held by |
374 | * the page iterator. | 386 | * the page iterator. |
375 | * @piter: page iterator holding the page | 387 | * @dma_iter: page iterator holding the page |
376 | */ | 388 | */ |
377 | static inline dma_addr_t sg_page_iter_dma_address(struct sg_page_iter *piter) | 389 | static inline dma_addr_t |
390 | sg_page_iter_dma_address(struct sg_dma_page_iter *dma_iter) | ||
378 | { | 391 | { |
379 | return sg_dma_address(piter->sg) + (piter->sg_pgoffset << PAGE_SHIFT); | 392 | return sg_dma_address(dma_iter->base.sg) + |
393 | (dma_iter->base.sg_pgoffset << PAGE_SHIFT); | ||
380 | } | 394 | } |
381 | 395 | ||
382 | /** | 396 | /** |
@@ -385,11 +399,28 @@ static inline dma_addr_t sg_page_iter_dma_address(struct sg_page_iter *piter) | |||
385 | * @piter: page iterator to hold current page, sg, sg_pgoffset | 399 | * @piter: page iterator to hold current page, sg, sg_pgoffset |
386 | * @nents: maximum number of sg entries to iterate over | 400 | * @nents: maximum number of sg entries to iterate over |
387 | * @pgoffset: starting page offset | 401 | * @pgoffset: starting page offset |
402 | * | ||
403 | * Callers may use sg_page_iter_page() to get each page pointer. | ||
388 | */ | 404 | */ |
389 | #define for_each_sg_page(sglist, piter, nents, pgoffset) \ | 405 | #define for_each_sg_page(sglist, piter, nents, pgoffset) \ |
390 | for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \ | 406 | for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \ |
391 | __sg_page_iter_next(piter);) | 407 | __sg_page_iter_next(piter);) |
392 | 408 | ||
409 | /** | ||
410 | * for_each_sg_dma_page - iterate over the pages of the given sg list | ||
411 | * @sglist: sglist to iterate over | ||
412 | * @dma_iter: page iterator to hold current page | ||
413 | * @dma_nents: maximum number of sg entries to iterate over, this is the value | ||
414 | * returned from dma_map_sg | ||
415 | * @pgoffset: starting page offset | ||
416 | * | ||
417 | * Callers may use sg_page_iter_dma_address() to get each page's DMA address. | ||
418 | */ | ||
419 | #define for_each_sg_dma_page(sglist, dma_iter, dma_nents, pgoffset) \ | ||
420 | for (__sg_page_iter_start(&(dma_iter)->base, sglist, dma_nents, \ | ||
421 | pgoffset); \ | ||
422 | __sg_page_iter_dma_next(dma_iter);) | ||
423 | |||
393 | /* | 424 | /* |
394 | * Mapping sg iterator | 425 | * Mapping sg iterator |
395 | * | 426 | * |
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 9ba349e775ef..739dc9fe2c55 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
@@ -625,6 +625,32 @@ bool __sg_page_iter_next(struct sg_page_iter *piter) | |||
625 | } | 625 | } |
626 | EXPORT_SYMBOL(__sg_page_iter_next); | 626 | EXPORT_SYMBOL(__sg_page_iter_next); |
627 | 627 | ||
628 | static int sg_dma_page_count(struct scatterlist *sg) | ||
629 | { | ||
630 | return PAGE_ALIGN(sg->offset + sg_dma_len(sg)) >> PAGE_SHIFT; | ||
631 | } | ||
632 | |||
633 | bool __sg_page_iter_dma_next(struct sg_dma_page_iter *dma_iter) | ||
634 | { | ||
635 | struct sg_page_iter *piter = &dma_iter->base; | ||
636 | |||
637 | if (!piter->__nents || !piter->sg) | ||
638 | return false; | ||
639 | |||
640 | piter->sg_pgoffset += piter->__pg_advance; | ||
641 | piter->__pg_advance = 1; | ||
642 | |||
643 | while (piter->sg_pgoffset >= sg_dma_page_count(piter->sg)) { | ||
644 | piter->sg_pgoffset -= sg_dma_page_count(piter->sg); | ||
645 | piter->sg = sg_next(piter->sg); | ||
646 | if (!--piter->__nents || !piter->sg) | ||
647 | return false; | ||
648 | } | ||
649 | |||
650 | return true; | ||
651 | } | ||
652 | EXPORT_SYMBOL(__sg_page_iter_dma_next); | ||
653 | |||
628 | /** | 654 | /** |
629 | * sg_miter_start - start mapping iteration over a sg list | 655 | * sg_miter_start - start mapping iteration over a sg list |
630 | * @miter: sg mapping iter to be started | 656 | * @miter: sg mapping iter to be started |