lib/scatterlist: use page iterator in the mapping iterator
authorImre Deak <imre.deak@intel.com>
Thu, 28 Feb 2013 01:02:57 +0000 (17:02 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Feb 2013 03:10:10 +0000 (19:10 -0800)
For better code reuse use the newly added page iterator to iterate
through the pages.  The offset, length within the page is still
calculated by the mapping iterator as well as the actual mapping.  Idea
from Tejun Heo.

Signed-off-by: Imre Deak <imre.deak@intel.com>
Cc: Maxim Levitsky <maximlevitsky@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/mmc/host/dw_mmc.c
include/linux/scatterlist.h
lib/scatterlist.c

index 60063cc..9834221 100644 (file)
@@ -1453,7 +1453,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
                if (!sg_miter_next(sg_miter))
                        goto done;
 
-               host->sg = sg_miter->__sg;
+               host->sg = sg_miter->piter.sg;
                buf = sg_miter->addr;
                remain = sg_miter->length;
                offset = 0;
@@ -1508,7 +1508,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
                if (!sg_miter_next(sg_miter))
                        goto done;
 
-               host->sg = sg_miter->__sg;
+               host->sg = sg_miter->piter.sg;
                buf = sg_miter->addr;
                remain = sg_miter->length;
                offset = 0;
index 788a853..2d8bdae 100644 (file)
@@ -293,11 +293,11 @@ struct sg_mapping_iter {
        void                    *addr;          /* pointer to the mapped area */
        size_t                  length;         /* length of the mapped area */
        size_t                  consumed;       /* number of consumed bytes */
+       struct sg_page_iter     piter;          /* page iterator */
 
        /* these are internal states, keep away */
-       struct scatterlist      *__sg;          /* current entry */
-       unsigned int            __nents;        /* nr of remaining entries */
-       unsigned int            __offset;       /* offset within sg */
+       unsigned int            __offset;       /* offset within page */
+       unsigned int            __remaining;    /* remaining bytes on page */
        unsigned int            __flags;
 };
 
index a1d1564..b83c144 100644 (file)
@@ -449,9 +449,7 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
 {
        memset(miter, 0, sizeof(struct sg_mapping_iter));
 
-       miter->__sg = sgl;
-       miter->__nents = nents;
-       miter->__offset = 0;
+       __sg_page_iter_start(&miter->piter, sgl, nents, 0);
        WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG)));
        miter->__flags = flags;
 }
@@ -476,36 +474,35 @@ EXPORT_SYMBOL(sg_miter_start);
  */
 bool sg_miter_next(struct sg_mapping_iter *miter)
 {
-       unsigned int off, len;
-
-       /* check for end and drop resources from the last iteration */
-       if (!miter->__nents)
-               return false;
-
        sg_miter_stop(miter);
 
-       /* get to the next sg if necessary.  __offset is adjusted by stop */
-       while (miter->__offset == miter->__sg->length) {
-               if (--miter->__nents) {
-                       miter->__sg = sg_next(miter->__sg);
-                       miter->__offset = 0;
-               } else
+       /*
+        * Get to the next page if necessary.
+        * __remaining, __offset is adjusted by sg_miter_stop
+        */
+       if (!miter->__remaining) {
+               struct scatterlist *sg;
+               unsigned long pgoffset;
+
+               if (!__sg_page_iter_next(&miter->piter))
                        return false;
-       }
 
-       /* map the next page */
-       off = miter->__sg->offset + miter->__offset;
-       len = miter->__sg->length - miter->__offset;
+               sg = miter->piter.sg;
+               pgoffset = miter->piter.sg_pgoffset;
 
-       miter->page = nth_page(sg_page(miter->__sg), off >> PAGE_SHIFT);
-       off &= ~PAGE_MASK;
-       miter->length = min_t(unsigned int, len, PAGE_SIZE - off);
-       miter->consumed = miter->length;
+               miter->__offset = pgoffset ? 0 : sg->offset;
+               miter->__remaining = sg->offset + sg->length -
+                               (pgoffset << PAGE_SHIFT) - miter->__offset;
+               miter->__remaining = min_t(unsigned long, miter->__remaining,
+                                          PAGE_SIZE - miter->__offset);
+       }
+       miter->page = miter->piter.page;
+       miter->consumed = miter->length = miter->__remaining;
 
        if (miter->__flags & SG_MITER_ATOMIC)
-               miter->addr = kmap_atomic(miter->page) + off;
+               miter->addr = kmap_atomic(miter->page) + miter->__offset;
        else
-               miter->addr = kmap(miter->page) + off;
+               miter->addr = kmap(miter->page) + miter->__offset;
 
        return true;
 }
@@ -532,6 +529,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
        /* drop resources from the last iteration */
        if (miter->addr) {
                miter->__offset += miter->consumed;
+               miter->__remaining -= miter->consumed;
 
                if (miter->__flags & SG_MITER_TO_SG)
                        flush_kernel_dcache_page(miter->page);