aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/dw_mmc.c4
-rw-r--r--include/linux/scatterlist.h6
-rw-r--r--lib/scatterlist.c48
3 files changed, 28 insertions, 30 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 60063ccb4c4b..98342213ed21 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1453,7 +1453,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
1453 if (!sg_miter_next(sg_miter)) 1453 if (!sg_miter_next(sg_miter))
1454 goto done; 1454 goto done;
1455 1455
1456 host->sg = sg_miter->__sg; 1456 host->sg = sg_miter->piter.sg;
1457 buf = sg_miter->addr; 1457 buf = sg_miter->addr;
1458 remain = sg_miter->length; 1458 remain = sg_miter->length;
1459 offset = 0; 1459 offset = 0;
@@ -1508,7 +1508,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
1508 if (!sg_miter_next(sg_miter)) 1508 if (!sg_miter_next(sg_miter))
1509 goto done; 1509 goto done;
1510 1510
1511 host->sg = sg_miter->__sg; 1511 host->sg = sg_miter->piter.sg;
1512 buf = sg_miter->addr; 1512 buf = sg_miter->addr;
1513 remain = sg_miter->length; 1513 remain = sg_miter->length;
1514 offset = 0; 1514 offset = 0;
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 788a853aa7a7..2d8bdaef9611 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -293,11 +293,11 @@ struct sg_mapping_iter {
293 void *addr; /* pointer to the mapped area */ 293 void *addr; /* pointer to the mapped area */
294 size_t length; /* length of the mapped area */ 294 size_t length; /* length of the mapped area */
295 size_t consumed; /* number of consumed bytes */ 295 size_t consumed; /* number of consumed bytes */
296 struct sg_page_iter piter; /* page iterator */
296 297
297 /* these are internal states, keep away */ 298 /* these are internal states, keep away */
298 struct scatterlist *__sg; /* current entry */ 299 unsigned int __offset; /* offset within page */
299 unsigned int __nents; /* nr of remaining entries */ 300 unsigned int __remaining; /* remaining bytes on page */
300 unsigned int __offset; /* offset within sg */
301 unsigned int __flags; 301 unsigned int __flags;
302}; 302};
303 303
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index a1d15647d7db..b83c144d731f 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -449,9 +449,7 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
449{ 449{
450 memset(miter, 0, sizeof(struct sg_mapping_iter)); 450 memset(miter, 0, sizeof(struct sg_mapping_iter));
451 451
452 miter->__sg = sgl; 452 __sg_page_iter_start(&miter->piter, sgl, nents, 0);
453 miter->__nents = nents;
454 miter->__offset = 0;
455 WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG))); 453 WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG)));
456 miter->__flags = flags; 454 miter->__flags = flags;
457} 455}
@@ -476,36 +474,35 @@ EXPORT_SYMBOL(sg_miter_start);
476 */ 474 */
477bool sg_miter_next(struct sg_mapping_iter *miter) 475bool sg_miter_next(struct sg_mapping_iter *miter)
478{ 476{
479 unsigned int off, len;
480
481 /* check for end and drop resources from the last iteration */
482 if (!miter->__nents)
483 return false;
484
485 sg_miter_stop(miter); 477 sg_miter_stop(miter);
486 478
487 /* get to the next sg if necessary. __offset is adjusted by stop */ 479 /*
488 while (miter->__offset == miter->__sg->length) { 480 * Get to the next page if necessary.
489 if (--miter->__nents) { 481 * __remaining, __offset is adjusted by sg_miter_stop
490 miter->__sg = sg_next(miter->__sg); 482 */
491 miter->__offset = 0; 483 if (!miter->__remaining) {
492 } else 484 struct scatterlist *sg;
485 unsigned long pgoffset;
486
487 if (!__sg_page_iter_next(&miter->piter))
493 return false; 488 return false;
494 }
495 489
496 /* map the next page */ 490 sg = miter->piter.sg;
497 off = miter->__sg->offset + miter->__offset; 491 pgoffset = miter->piter.sg_pgoffset;
498 len = miter->__sg->length - miter->__offset;
499 492
500 miter->page = nth_page(sg_page(miter->__sg), off >> PAGE_SHIFT); 493 miter->__offset = pgoffset ? 0 : sg->offset;
501 off &= ~PAGE_MASK; 494 miter->__remaining = sg->offset + sg->length -
502 miter->length = min_t(unsigned int, len, PAGE_SIZE - off); 495 (pgoffset << PAGE_SHIFT) - miter->__offset;
503 miter->consumed = miter->length; 496 miter->__remaining = min_t(unsigned long, miter->__remaining,
497 PAGE_SIZE - miter->__offset);
498 }
499 miter->page = miter->piter.page;
500 miter->consumed = miter->length = miter->__remaining;
504 501
505 if (miter->__flags & SG_MITER_ATOMIC) 502 if (miter->__flags & SG_MITER_ATOMIC)
506 miter->addr = kmap_atomic(miter->page) + off; 503 miter->addr = kmap_atomic(miter->page) + miter->__offset;
507 else 504 else
508 miter->addr = kmap(miter->page) + off; 505 miter->addr = kmap(miter->page) + miter->__offset;
509 506
510 return true; 507 return true;
511} 508}
@@ -532,6 +529,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
532 /* drop resources from the last iteration */ 529 /* drop resources from the last iteration */
533 if (miter->addr) { 530 if (miter->addr) {
534 miter->__offset += miter->consumed; 531 miter->__offset += miter->consumed;
532 miter->__remaining -= miter->consumed;
535 533
536 if (miter->__flags & SG_MITER_TO_SG) 534 if (miter->__flags & SG_MITER_TO_SG)
537 flush_kernel_dcache_page(miter->page); 535 flush_kernel_dcache_page(miter->page);