summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/scatterlist.h2
-rw-r--r--lib/scatterlist.c16
2 files changed, 14 insertions, 4 deletions
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index e5996984ddd0..9aaf5bfdad1a 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -242,6 +242,8 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
*/
#define SG_MITER_ATOMIC (1 << 0) /* use kmap_atomic */
+#define SG_MITER_TO_SG (1 << 1) /* flush back to phys on unmap */
+#define SG_MITER_FROM_SG (1 << 2) /* nop */
struct sg_mapping_iter {
/* the following three fields can be accessed directly */
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index a295e404e908..0d475d8167bf 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -314,6 +314,7 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
miter->__sg = sgl;
miter->__nents = nents;
miter->__offset = 0;
+ WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG)));
miter->__flags = flags;
}
EXPORT_SYMBOL(sg_miter_start);
@@ -394,6 +395,9 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
if (miter->addr) {
miter->__offset += miter->consumed;
+ if (miter->__flags & SG_MITER_TO_SG)
+ flush_kernel_dcache_page(miter->page);
+
if (miter->__flags & SG_MITER_ATOMIC) {
WARN_ON(!irqs_disabled());
kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ);
@@ -426,8 +430,14 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
unsigned int offset = 0;
struct sg_mapping_iter miter;
unsigned long flags;
+ unsigned int sg_flags = SG_MITER_ATOMIC;
+
+ if (to_buffer)
+ sg_flags |= SG_MITER_FROM_SG;
+ else
+ sg_flags |= SG_MITER_TO_SG;
- sg_miter_start(&miter, sgl, nents, SG_MITER_ATOMIC);
+ sg_miter_start(&miter, sgl, nents, sg_flags);
local_irq_save(flags);
@@ -438,10 +448,8 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
if (to_buffer)
memcpy(buf + offset, miter.addr, len);
- else {
+ else
memcpy(miter.addr, buf + offset, len);
- flush_kernel_dcache_page(miter.page);
- }
offset += len;
}