From: Rui Miguel Silva Date: Wed, 24 Jun 2015 22:20:27 +0000 (+0100) Subject: greybus: kernel_ver: add sg copy operations for kernel < 3.11 X-Git-Tag: v4.9-rc1~119^2~378^2~21^2~1445 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=8a01b408a6b071862efadf905bad60d10612e78a;p=karo-tx-linux.git greybus: kernel_ver: add sg copy operations for kernel < 3.11 For older kernel, < 3.11, no copy to/from buffer with skip support was defined. This could break builds for this versions of kernel. Add them here. Signed-off-by: Rui Miguel Silva Tested-by: Mark Greer Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/greybus/kernel_ver.h b/drivers/staging/greybus/kernel_ver.h index f95f302b2b2d..4fb949ba9b51 100644 --- a/drivers/staging/greybus/kernel_ver.h +++ b/drivers/staging/greybus/kernel_ver.h @@ -135,4 +135,104 @@ static inline void sysfs_remove_groups(struct kobject *kobj, #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) #define MMC_POWER_UNDEFINED_SUPPORTED #endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) +#include +static inline bool sg_miter_get_next_page(struct sg_mapping_iter *miter) +{ + if (!miter->__remaining) { + struct scatterlist *sg; + unsigned long pgoffset; + + if (!__sg_page_iter_next(&miter->piter)) + return false; + + sg = miter->piter.sg; + pgoffset = miter->piter.sg_pgoffset; + + 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); + } + + return true; +} + +static inline bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) +{ + sg_miter_stop(miter); + + while (offset) { + off_t consumed; + + if (!sg_miter_get_next_page(miter)) + return false; + + consumed = min_t(off_t, offset, miter->__remaining); + miter->__offset += consumed; + miter->__remaining -= consumed; + offset -= consumed; + } + + return true; +} + +static inline size_t _sg_copy_buffer(struct scatterlist *sgl, + unsigned int nents, void *buf, + size_t buflen, off_t skip, + bool to_buffer) +{ + 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_flags); + + if (!sg_miter_skip(&miter, skip)) + return false; + + local_irq_save(flags); + + while (sg_miter_next(&miter) && offset < buflen) { + unsigned int len; + + len = min(miter.length, buflen - offset); + + if (to_buffer) + memcpy(buf + offset, miter.addr, len); + else + memcpy(miter.addr, buf + offset, len); + + offset += len; + } + + sg_miter_stop(&miter); + + local_irq_restore(flags); + return offset; +} + +static inline size_t sg_pcopy_to_buffer(struct scatterlist *sgl, + unsigned int nents, void *buf, + size_t buflen, off_t skip) +{ + return _sg_copy_buffer(sgl, nents, buf, buflen, skip, true); +} + +static inline size_t sg_pcopy_from_buffer(struct scatterlist *sgl, + unsigned int nents, void *buf, + size_t buflen, off_t skip) +{ + return _sg_copy_buffer(sgl, nents, buf, buflen, skip, false); +} +#endif + #endif /* __GREYBUS_KERNEL_VER_H */