Skip to content

Commit d901b27

Browse files
committed
lib/scatterlist: Provide a DMA page iterator
Commit 2db76d7 ("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>
1 parent f368ff1 commit d901b27

File tree

5 files changed

+76
-12
lines changed

5 files changed

+76
-12
lines changed

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ ForEachMacros:
240240
- 'for_each_set_bit'
241241
- 'for_each_set_bit_from'
242242
- 'for_each_sg'
243+
- 'for_each_sg_dma_page'
243244
- 'for_each_sg_page'
244245
- 'for_each_sibling_event'
245246
- '__for_each_thread'

drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,13 @@ static dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter)
311311

312312
static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter)
313313
{
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));
315321
}
316322

317323

drivers/media/pci/intel/ipu3/ipu3-cio2.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb)
846846
unsigned int pages = DIV_ROUND_UP(vb->planes[0].length, CIO2_PAGE_SIZE);
847847
unsigned int lops = DIV_ROUND_UP(pages + 1, entries_per_page);
848848
struct sg_table *sg;
849-
struct sg_page_iter sg_iter;
849+
struct sg_dma_page_iter sg_iter;
850850
int i, j;
851851

852852
if (lops <= 0 || lops > CIO2_MAX_LOPS) {
@@ -873,7 +873,7 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb)
873873
b->offset = sg->sgl->offset;
874874

875875
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) {
877877
if (!pages--)
878878
break;
879879
b->lop[i][j] = sg_page_iter_dma_address(&sg_iter) >> PAGE_SHIFT;

include/linux/scatterlist.h

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -339,12 +339,12 @@ int sg_alloc_table_chained(struct sg_table *table, int nents,
339339
/*
340340
* sg page iterator
341341
*
342-
* Iterates over sg entries page-by-page. On each successful iteration,
343-
* you can call sg_page_iter_page(@piter) and sg_page_iter_dma_address(@piter)
344-
* to get the current page and its dma address. @piter->sg will point to the
345-
* sg holding this page and @piter->sg_pgoffset to the page's page offset
346-
* within the sg. The iteration will stop either when a maximum number of sg
347-
* entries was reached or a terminating sg (sg_last(sg) == true) was reached.
342+
* Iterates over sg entries page-by-page. On each successful iteration, you
343+
* can call sg_page_iter_page(@piter) to get the current page and its dma
344+
* address. @piter->sg will point to the sg holding this page and
345+
* @piter->sg_pgoffset to the page's page offset within the sg. The iteration
346+
* will stop either when a maximum number of sg entries was reached or a
347+
* terminating sg (sg_last(sg) == true) was reached.
348348
*/
349349
struct sg_page_iter {
350350
struct scatterlist *sg; /* sg holding the page */
@@ -356,7 +356,19 @@ struct sg_page_iter {
356356
* next step */
357357
};
358358

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+
359370
bool __sg_page_iter_next(struct sg_page_iter *piter);
371+
bool __sg_page_iter_dma_next(struct sg_dma_page_iter *dma_iter);
360372
void __sg_page_iter_start(struct sg_page_iter *piter,
361373
struct scatterlist *sglist, unsigned int nents,
362374
unsigned long pgoffset);
@@ -372,11 +384,13 @@ static inline struct page *sg_page_iter_page(struct sg_page_iter *piter)
372384
/**
373385
* sg_page_iter_dma_address - get the dma address of the current page held by
374386
* the page iterator.
375-
* @piter: page iterator holding the page
387+
* @dma_iter: page iterator holding the page
376388
*/
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)
378391
{
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);
380394
}
381395

382396
/**
@@ -385,11 +399,28 @@ static inline dma_addr_t sg_page_iter_dma_address(struct sg_page_iter *piter)
385399
* @piter: page iterator to hold current page, sg, sg_pgoffset
386400
* @nents: maximum number of sg entries to iterate over
387401
* @pgoffset: starting page offset
402+
*
403+
* Callers may use sg_page_iter_page() to get each page pointer.
388404
*/
389405
#define for_each_sg_page(sglist, piter, nents, pgoffset) \
390406
for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \
391407
__sg_page_iter_next(piter);)
392408

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+
393424
/*
394425
* Mapping sg iterator
395426
*

lib/scatterlist.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,32 @@ bool __sg_page_iter_next(struct sg_page_iter *piter)
625625
}
626626
EXPORT_SYMBOL(__sg_page_iter_next);
627627

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+
628654
/**
629655
* sg_miter_start - start mapping iteration over a sg list
630656
* @miter: sg mapping iter to be started

0 commit comments

Comments
 (0)