Merge to kernel-2.6.20-1.2949.fc6.vs2.2.0.1
[linux-2.6.git] / arch / parisc / lib / checksum.c
index abd29ac..462696d 100644 (file)
 #include <asm/string.h>
 #include <asm/uaccess.h>
 
+#define addc(_t,_r)                     \
+       __asm__ __volatile__ (          \
+"       add             %0, %1, %0\n"   \
+"       addc            %0, %%r0, %0\n" \
+       : "=r"(_t)                      \
+       : "r"(_r), "0"(_t));
+
 static inline unsigned short from32to16(unsigned int x)
 {
        /* 32 bits --> 16 bits + carry */
@@ -56,16 +63,25 @@ static inline unsigned int do_csum(const unsigned char * buff, int len)
                }
                count >>= 1;            /* nr of 32-bit words.. */
                if (count) {
-                       unsigned int carry = 0;
-                       do {
+                       while (count >= 4) {
+                               unsigned int r1, r2, r3, r4;
+                               r1 = *(unsigned int *)(buff + 0);
+                               r2 = *(unsigned int *)(buff + 4);
+                               r3 = *(unsigned int *)(buff + 8);
+                               r4 = *(unsigned int *)(buff + 12);
+                               addc(result, r1);
+                               addc(result, r2);
+                               addc(result, r3);
+                               addc(result, r4);
+                               count -= 4;
+                               buff += 16;
+                       }
+                       while (count) {
                                unsigned int w = *(unsigned int *) buff;
                                count--;
                                buff += 4;
-                               result += carry;
-                               result += w;
-                               carry = (w > result);
-                       } while (count);
-                       result += carry;
+                               addc(result, w);
+                       }
                        result = (result & 0xffff) + (result >> 16);
                }
                if (len & 2) {
@@ -77,7 +93,7 @@ static inline unsigned int do_csum(const unsigned char * buff, int len)
                result += le16_to_cpu(*buff);
        result = from32to16(result);
        if (odd)
-               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+               result = swab16(result);
 out:
        return result;
 }
@@ -85,15 +101,14 @@ out:
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
  */
-unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
+/*
+ * why bother folding?
+ */
+__wsum csum_partial(const void *buff, int len, __wsum sum)
 {
        unsigned int result = do_csum(buff, len);
-
-       /* add in old sum, and carry.. */
-       result += sum;
-       if(sum > result)
-               result += 1;
-       return result;
+       addc(result, sum);
+       return (__force __wsum)from32to16(result);
 }
 
 EXPORT_SYMBOL(csum_partial);
@@ -101,8 +116,8 @@ EXPORT_SYMBOL(csum_partial);
 /*
  * copy while checksumming, otherwise like csum_partial
  */
-unsigned int csum_partial_copy_nocheck(const char *src, char *dst, 
-                                      int len, unsigned int sum)
+__wsum csum_partial_copy_nocheck(const void *src, void *dst,
+                                      int len, __wsum sum)
 {
        /*
         * It's 2:30 am and I don't feel like doing it real ...
@@ -119,9 +134,9 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck);
  * Copy from userspace and compute checksum.  If we catch an exception
  * then zero the rest of the buffer.
  */
-unsigned int csum_partial_copy_from_user (const char *src, char *dst,
-                                          int len, unsigned int sum,
-                                          int *err_ptr)
+__wsum csum_partial_copy_from_user(const void __user *src,
+                                       void *dst, int len,
+                                       __wsum sum, int *err_ptr)
 {
        int missing;