@@ -62,16 +62,10 @@ static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk,
if (walk->offset >= walk->sg->offset + walk->sg->length)
scatterwalk_start(walk, sg_next(walk->sg));
return min(nbytes, scatterwalk_pagelen(walk));
}
-static inline void scatterwalk_advance(struct scatter_walk *walk,
- unsigned int nbytes)
-{
- walk->offset += nbytes;
-}
-
static inline struct page *scatterwalk_page(struct scatter_walk *walk)
{
return sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
}
@@ -84,10 +78,28 @@ static inline void *scatterwalk_map(struct scatter_walk *walk)
{
return kmap_local_page(scatterwalk_page(walk)) +
offset_in_page(walk->offset);
}
+/**
+ * scatterwalk_next() - Get the next data buffer in a scatterlist walk
+ * @walk: the scatter_walk
+ * @total: the total number of bytes remaining, > 0
+ * @nbytes_ret: (out) the next number of bytes available, <= @total
+ *
+ * Return: A virtual address for the next segment of data from the scatterlist.
+ * The caller must call scatterwalk_done_src() or scatterwalk_done_dst()
+ * when it is done using this virtual address.
+ */
+static inline void *scatterwalk_next(struct scatter_walk *walk,
+ unsigned int total,
+ unsigned int *nbytes_ret)
+{
+ *nbytes_ret = scatterwalk_clamp(walk, total);
+ return scatterwalk_map(walk);
+}
+
static inline void scatterwalk_pagedone(struct scatter_walk *walk, int out,
unsigned int more)
{
if (out) {
struct page *page;
@@ -106,10 +118,50 @@ static inline void scatterwalk_done(struct scatter_walk *walk, int out,
if (!more || walk->offset >= walk->sg->offset + walk->sg->length ||
!(walk->offset & (PAGE_SIZE - 1)))
scatterwalk_pagedone(walk, out, more);
}
+static inline void scatterwalk_advance(struct scatter_walk *walk,
+ unsigned int nbytes)
+{
+ walk->offset += nbytes;
+}
+
+/**
+ * scatterwalk_done_src() - Finish one step of a walk of source scatterlist
+ * @walk: the scatter_walk
+ * @vaddr: the address returned by scatterwalk_next()
+ * @nbytes: the number of bytes processed this step, less than or equal to the
+ * number of bytes that scatterwalk_next() returned.
+ *
+ * Use this if the @vaddr was not written to, i.e. it is source data.
+ */
+static inline void scatterwalk_done_src(struct scatter_walk *walk,
+ const void *vaddr, unsigned int nbytes)
+{
+ scatterwalk_unmap((void *)vaddr);
+ scatterwalk_advance(walk, nbytes);
+}
+
+/**
+ * scatterwalk_done_dst() - Finish one step of a walk of destination scatterlist
+ * @walk: the scatter_walk
+ * @vaddr: the address returned by scatterwalk_next()
+ * @nbytes: the number of bytes processed this step, less than or equal to the
+ * number of bytes that scatterwalk_next() returned.
+ *
+ * Use this if the @vaddr may have been written to, i.e. it is destination data.
+ */
+static inline void scatterwalk_done_dst(struct scatter_walk *walk,
+ void *vaddr, unsigned int nbytes)
+{
+ scatterwalk_unmap(vaddr);
+ if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE)
+ flush_dcache_page(scatterwalk_page(walk));
+ scatterwalk_advance(walk, nbytes);
+}
+
void scatterwalk_skip(struct scatter_walk *walk, unsigned int nbytes);
void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
size_t nbytes, int out);