aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2010-08-02 16:11:36 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-09-02 00:07:30 -0400
commit8c77391475bc3284a380fc46aaf0bcf26bde3ae6 (patch)
tree0948ebdf02ce03948faf8dc41af8414f84652239 /arch
parentfdd374b62ca4df144c0138359dcffa83df7a0ea8 (diff)
powerpc: Add 64bit csum_and_copy_to_user
This adds the equivalent of csum_and_copy_from_user for the receive side so we can copy and checksum in one pass. It is modelled on the generic checksum routine. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/checksum.h3
-rw-r--r--arch/powerpc/lib/checksum_wrappers_64.c37
2 files changed, 40 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/checksum.h b/arch/powerpc/include/asm/checksum.h
index 9ea58c0e7cfb..ce0c28495f9a 100644
--- a/arch/powerpc/include/asm/checksum.h
+++ b/arch/powerpc/include/asm/checksum.h
@@ -57,6 +57,9 @@ extern __wsum csum_partial_copy_generic(const void *src, void *dst,
57#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER 57#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
58extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, 58extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
59 int len, __wsum sum, int *err_ptr); 59 int len, __wsum sum, int *err_ptr);
60#define HAVE_CSUM_COPY_USER
61extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
62 int len, __wsum sum, int *err_ptr);
60#else 63#else
61/* 64/*
62 * the same as csum_partial, but copies from src to dst while it 65 * the same as csum_partial, but copies from src to dst while it
diff --git a/arch/powerpc/lib/checksum_wrappers_64.c b/arch/powerpc/lib/checksum_wrappers_64.c
index 614cff1a8e0e..769b817fbb32 100644
--- a/arch/powerpc/lib/checksum_wrappers_64.c
+++ b/arch/powerpc/lib/checksum_wrappers_64.c
@@ -63,3 +63,40 @@ out:
63 return (__force __wsum)csum; 63 return (__force __wsum)csum;
64} 64}
65EXPORT_SYMBOL(csum_and_copy_from_user); 65EXPORT_SYMBOL(csum_and_copy_from_user);
66
67__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
68 __wsum sum, int *err_ptr)
69{
70 unsigned int csum;
71
72 might_sleep();
73
74 *err_ptr = 0;
75
76 if (!len) {
77 csum = 0;
78 goto out;
79 }
80
81 if (unlikely((len < 0) || !access_ok(VERIFY_WRITE, dst, len))) {
82 *err_ptr = -EFAULT;
83 csum = -1; /* invalid checksum */
84 goto out;
85 }
86
87 csum = csum_partial_copy_generic(src, (void __force *)dst,
88 len, sum, NULL, err_ptr);
89
90 if (unlikely(*err_ptr)) {
91 csum = csum_partial(src, len, sum);
92
93 if (copy_to_user(dst, src, len)) {
94 *err_ptr = -EFAULT;
95 csum = -1; /* invalid checksum */
96 }
97 }
98
99out:
100 return (__force __wsum)csum;
101}
102EXPORT_SYMBOL(csum_and_copy_to_user);