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 /include/linux | |
| 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>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/scatterlist.h | 49 |
1 files changed, 40 insertions, 9 deletions
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 | * |
