summaryrefslogtreecommitdiffstats
path: root/arch/mips/lib/checksum.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-03-25 23:40:36 +0000
committer <ralf@linux-mips.org>1997-03-25 23:40:36 +0000
commit7206675c40394c78a90e74812bbdbf8cf3cca1be (patch)
tree251895cf5a0008e2b4ce438cb01ad4d55fb5b97b /arch/mips/lib/checksum.c
parentbeb116954b9b7f3bb56412b2494b562f02b864b1 (diff)
Import of Linux/MIPS 2.1.14.2
Diffstat (limited to 'arch/mips/lib/checksum.c')
-rw-r--r--arch/mips/lib/checksum.c180
1 files changed, 65 insertions, 115 deletions
diff --git a/arch/mips/lib/checksum.c b/arch/mips/lib/checksum.c
index 0e04ac5e8..dd1583892 100644
--- a/arch/mips/lib/checksum.c
+++ b/arch/mips/lib/checksum.c
@@ -17,124 +17,76 @@
#include <net/checksum.h>
#include <asm/string.h>
+static inline unsigned short from32to16(unsigned long x)
+{
+ /* 32 bits --> 16 bits + carry */
+ x = (x & 0xffff) + (x >> 16);
+ /* 16 bits + carry --> 16 bits including carry */
+ x = (x & 0xffff) + (x >> 16);
+ return x;
+}
+
+static inline unsigned long do_csum(const unsigned char * buff, int len)
+{
+ int odd, count;
+ unsigned long result = 0;
+
+ if (len <= 0)
+ goto out;
+ odd = 1 & (unsigned long) buff;
+ if (odd) {
+ result = *buff;
+ len--;
+ buff++;
+ }
+ count = len >> 1; /* nr of 16-bit words.. */
+ if (count) {
+ if (2 & (unsigned long) buff) {
+ result += *(unsigned short *) buff;
+ count--;
+ len -= 2;
+ buff += 2;
+ }
+ count >>= 1; /* nr of 32-bit words.. */
+ if (count) {
+ unsigned long carry = 0;
+ do {
+ unsigned long w = *(unsigned long *) buff;
+ count--;
+ buff += 4;
+ result += carry;
+ result += w;
+ carry = (w > result);
+ } while (count);
+ result += carry;
+ result = (result & 0xffff) + (result >> 16);
+ }
+ if (len & 2) {
+ result += *(unsigned short *) buff;
+ buff += 2;
+ }
+ }
+ if (len & 1)
+ result += (*buff << 8);
+ result = from32to16(result);
+ if (odd)
+ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+ return result;
+}
+
/*
* computes a partial checksum, e.g. for TCP/UDP fragments
*/
unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
{
- unsigned long scratch1;
- unsigned long scratch2;
-
- /*
- * This is for 32-bit MIPS processors.
- */
- __asm__("
- .set noreorder
- .set noat
- andi $1,%4,2 # Check alignment
- beqz $1,2f # Branch if ok
- nop # delay slot
- subu $1,%3,2 # Alignment uses up two bytes
- bgez $1,1f # Jump if we had at least two bytes
- move %3,$1 # delay slot
- j 4f
- addiu %3,2 # delay slot; len was < 2. Deal with it
-
-1: lhu %2,(%4)
- addiu %4,2
- addu %0,%2
- sltu $1,%0,%2
- addu %0,$1
-
-2: srl %1,%3,5
- beqz %1,2f
- sll %1,%1,5 # delay slot
-
- addu %1,%4
-1: lw %2,0(%4)
- addu %4,32
- addu %0,%2
- sltu $1,%0,%2
+ unsigned long result = do_csum(buff, len);
- lw %2,-28(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- lw %2,-24(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- lw %2,-20(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- lw %2,-16(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- lw %2,-12(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- lw %2,-8(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- lw %2,-4(%4)
- addu %0,$1
- addu %0,%2
- sltu $1,%0,%2
-
- bne %4,%1,1b
- addu %0,$1 # delay slot
-
-2: andi %1,%3,0x1c
- beqz %1,4f
- addu %1,%4 # delay slot
-3: lw %2,0(%4)
- addu %4,4
- addu %0,%2
- sltu $1,%0,%2
- bne %4,%1,3b
- addu %0,$1 # delay slot
-
-4: andi $1,%3,3
- beqz $1,7f
- andi $1,%3,2 # delay slot
- beqz $1,5f
- move %2,$0 # delay slot
- lhu %2,(%4)
- addiu %4,2 # delay slot
-
-5: andi $1,%3,1
- beqz $1,6f
- nop # delay slot
- lbu %1,(%4)
- sll %2,16\n\t"
-#ifdef __MIPSEB__
- "sll %1,8\n\t"
-#endif
- "or %2,%1
-6: addu %0,%2
- sltu $1,%0,%2
- addu %0,$1
-7: .set at
- .set reorder"
- : "=r"(sum),
- "=&r" (scratch1),
- "=&r" (scratch2),
- "=r" (len),
- "=r" (buff)
- : "0"(sum), "3"(len), "4"(buff)
- : "$1");
-
- return sum;
+ /* add in old sum, and carry.. */
+ result += sum;
+ if(sum > result)
+ result += 1;
+ return result;
}
/*
@@ -144,12 +96,10 @@ unsigned int csum_partial_copy(const char *src, char *dst,
int len, unsigned int sum)
{
/*
- * It's 2:30 am and I don't feel like doing it right ...
+ * It's 2:30 am and I don't feel like doing it real ...
* This is lots slower than the real thing (tm)
*
* XXX This may nuke the kernel for unaligned src addresses!!!
- * (Due to software address error fixing no longer true, but
- * seems to happen very rarely only anyway.)
*/
sum = csum_partial(src, len, sum);
memcpy(dst, src, len);