vserver 1.9.5.x5
[linux-2.6.git] / arch / parisc / lib / checksum.c
index abd29ac..9866c93 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;
 }
@@ -88,12 +104,8 @@ out:
 unsigned int csum_partial(const unsigned char *buff, int len, unsigned int 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 from32to16(result);
 }
 
 EXPORT_SYMBOL(csum_partial);
@@ -101,7 +113,7 @@ EXPORT_SYMBOL(csum_partial);
 /*
  * copy while checksumming, otherwise like csum_partial
  */
-unsigned int csum_partial_copy_nocheck(const char *src, char *dst, 
+unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst,
                                       int len, unsigned int sum)
 {
        /*
@@ -119,7 +131,7 @@ 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,
+unsigned int csum_partial_copy_from_user (const unsigned char *src, unsigned char *dst,
                                           int len, unsigned int sum,
                                           int *err_ptr)
 {