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 |
