forked from Minki/linux
e9c4943a10
The generic csum_ipv6_magic() generates a pretty bad result 00000000 <csum_ipv6_magic>: (PPC32) 0: 81 23 00 00 lwz r9,0(r3) 4: 81 03 00 04 lwz r8,4(r3) 8: 7c e7 4a 14 add r7,r7,r9 c: 7d 29 38 10 subfc r9,r9,r7 10: 7d 4a 51 10 subfe r10,r10,r10 14: 7d 27 42 14 add r9,r7,r8 18: 7d 2a 48 50 subf r9,r10,r9 1c: 80 e3 00 08 lwz r7,8(r3) 20: 7d 08 48 10 subfc r8,r8,r9 24: 7d 4a 51 10 subfe r10,r10,r10 28: 7d 29 3a 14 add r9,r9,r7 2c: 81 03 00 0c lwz r8,12(r3) 30: 7d 2a 48 50 subf r9,r10,r9 34: 7c e7 48 10 subfc r7,r7,r9 38: 7d 4a 51 10 subfe r10,r10,r10 3c: 7d 29 42 14 add r9,r9,r8 40: 7d 2a 48 50 subf r9,r10,r9 44: 80 e4 00 00 lwz r7,0(r4) 48: 7d 08 48 10 subfc r8,r8,r9 4c: 7d 4a 51 10 subfe r10,r10,r10 50: 7d 29 3a 14 add r9,r9,r7 54: 7d 2a 48 50 subf r9,r10,r9 58: 81 04 00 04 lwz r8,4(r4) 5c: 7c e7 48 10 subfc r7,r7,r9 60: 7d 4a 51 10 subfe r10,r10,r10 64: 7d 29 42 14 add r9,r9,r8 68: 7d 2a 48 50 subf r9,r10,r9 6c: 80 e4 00 08 lwz r7,8(r4) 70: 7d 08 48 10 subfc r8,r8,r9 74: 7d 4a 51 10 subfe r10,r10,r10 78: 7d 29 3a 14 add r9,r9,r7 7c: 7d 2a 48 50 subf r9,r10,r9 80: 81 04 00 0c lwz r8,12(r4) 84: 7c e7 48 10 subfc r7,r7,r9 88: 7d 4a 51 10 subfe r10,r10,r10 8c: 7d 29 42 14 add r9,r9,r8 90: 7d 2a 48 50 subf r9,r10,r9 94: 7d 08 48 10 subfc r8,r8,r9 98: 7d 4a 51 10 subfe r10,r10,r10 9c: 7d 29 2a 14 add r9,r9,r5 a0: 7d 2a 48 50 subf r9,r10,r9 a4: 7c a5 48 10 subfc r5,r5,r9 a8: 7c 63 19 10 subfe r3,r3,r3 ac: 7d 29 32 14 add r9,r9,r6 b0: 7d 23 48 50 subf r9,r3,r9 b4: 7c c6 48 10 subfc r6,r6,r9 b8: 7c 63 19 10 subfe r3,r3,r3 bc: 7c 63 48 50 subf r3,r3,r9 c0: 54 6a 80 3e rotlwi r10,r3,16 c4: 7c 63 52 14 add r3,r3,r10 c8: 7c 63 18 f8 not r3,r3 cc: 54 63 84 3e rlwinm r3,r3,16,16,31 d0: 4e 80 00 20 blr 0000000000000000 <.csum_ipv6_magic>: (PPC64) 0: 81 23 00 00 lwz r9,0(r3) 4: 80 03 00 04 lwz r0,4(r3) 8: 81 63 00 08 lwz r11,8(r3) c: 7c e7 4a 14 add r7,r7,r9 10: 7f 89 38 40 cmplw cr7,r9,r7 14: 7d 47 02 14 add r10,r7,r0 18: 7d 30 10 26 mfocrf r9,1 1c: 55 29 f7 fe rlwinm r9,r9,30,31,31 20: 7d 4a 4a 14 add r10,r10,r9 24: 7f 80 50 40 cmplw cr7,r0,r10 28: 7d 2a 5a 14 add r9,r10,r11 2c: 80 03 00 0c lwz r0,12(r3) 30: 81 44 00 00 lwz r10,0(r4) 34: 7d 10 10 26 mfocrf r8,1 38: 55 08 f7 fe rlwinm r8,r8,30,31,31 3c: 7d 29 42 14 add r9,r9,r8 40: 81 04 00 04 lwz r8,4(r4) 44: 7f 8b 48 40 cmplw cr7,r11,r9 48: 7d 29 02 14 add r9,r9,r0 4c: 7d 70 10 26 mfocrf r11,1 50: 55 6b f7 fe rlwinm r11,r11,30,31,31 54: 7d 29 5a 14 add r9,r9,r11 58: 7f 80 48 40 cmplw cr7,r0,r9 5c: 7d 29 52 14 add r9,r9,r10 60: 7c 10 10 26 mfocrf r0,1 64: 54 00 f7 fe rlwinm r0,r0,30,31,31 68: 7d 69 02 14 add r11,r9,r0 6c: 7f 8a 58 40 cmplw cr7,r10,r11 70: 7c 0b 42 14 add r0,r11,r8 74: 81 44 00 08 lwz r10,8(r4) 78: 7c f0 10 26 mfocrf r7,1 7c: 54 e7 f7 fe rlwinm r7,r7,30,31,31 80: 7c 00 3a 14 add r0,r0,r7 84: 7f 88 00 40 cmplw cr7,r8,r0 88: 7d 20 52 14 add r9,r0,r10 8c: 80 04 00 0c lwz r0,12(r4) 90: 7d 70 10 26 mfocrf r11,1 94: 55 6b f7 fe rlwinm r11,r11,30,31,31 98: 7d 29 5a 14 add r9,r9,r11 9c: 7f 8a 48 40 cmplw cr7,r10,r9 a0: 7d 29 02 14 add r9,r9,r0 a4: 7d 70 10 26 mfocrf r11,1 a8: 55 6b f7 fe rlwinm r11,r11,30,31,31 ac: 7d 29 5a 14 add r9,r9,r11 b0: 7f 80 48 40 cmplw cr7,r0,r9 b4: 7d 29 2a 14 add r9,r9,r5 b8: 7c 10 10 26 mfocrf r0,1 bc: 54 00 f7 fe rlwinm r0,r0,30,31,31 c0: 7d 29 02 14 add r9,r9,r0 c4: 7f 85 48 40 cmplw cr7,r5,r9 c8: 7c 09 32 14 add r0,r9,r6 cc: 7d 50 10 26 mfocrf r10,1 d0: 55 4a f7 fe rlwinm r10,r10,30,31,31 d4: 7c 00 52 14 add r0,r0,r10 d8: 7f 80 30 40 cmplw cr7,r0,r6 dc: 7d 30 10 26 mfocrf r9,1 e0: 55 29 ef fe rlwinm r9,r9,29,31,31 e4: 7c 09 02 14 add r0,r9,r0 e8: 54 03 80 3e rotlwi r3,r0,16 ec: 7c 03 02 14 add r0,r3,r0 f0: 7c 03 00 f8 not r3,r0 f4: 78 63 84 22 rldicl r3,r3,48,48 f8: 4e 80 00 20 blr This patch implements it in assembly for both PPC32 and PPC64 Link: https://github.com/linuxppc/linux/issues/9 Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Reviewed-by: Segher Boessenkool <segher@kernel.crashing.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
338 lines
7.0 KiB
ArmAsm
338 lines
7.0 KiB
ArmAsm
/*
|
|
* This file contains assembly-language implementations
|
|
* of IP-style 1's complement checksum routines.
|
|
*
|
|
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
* Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
|
|
*/
|
|
|
|
#include <linux/sys.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/errno.h>
|
|
#include <asm/ppc_asm.h>
|
|
#include <asm/export.h>
|
|
|
|
.text
|
|
|
|
/*
|
|
* computes the checksum of a memory block at buff, length len,
|
|
* and adds in "sum" (32-bit)
|
|
*
|
|
* __csum_partial(buff, len, sum)
|
|
*/
|
|
_GLOBAL(__csum_partial)
|
|
subi r3,r3,4
|
|
srawi. r6,r4,2 /* Divide len by 4 and also clear carry */
|
|
beq 3f /* if we're doing < 4 bytes */
|
|
andi. r0,r3,2 /* Align buffer to longword boundary */
|
|
beq+ 1f
|
|
lhz r0,4(r3) /* do 2 bytes to get aligned */
|
|
subi r4,r4,2
|
|
addi r3,r3,2
|
|
srwi. r6,r4,2 /* # words to do */
|
|
adde r5,r5,r0
|
|
beq 3f
|
|
1: andi. r6,r6,3 /* Prepare to handle words 4 by 4 */
|
|
beq 21f
|
|
mtctr r6
|
|
2: lwzu r0,4(r3)
|
|
adde r5,r5,r0
|
|
bdnz 2b
|
|
21: srwi. r6,r4,4 /* # blocks of 4 words to do */
|
|
beq 3f
|
|
lwz r0,4(r3)
|
|
mtctr r6
|
|
lwz r6,8(r3)
|
|
adde r5,r5,r0
|
|
lwz r7,12(r3)
|
|
adde r5,r5,r6
|
|
lwzu r8,16(r3)
|
|
adde r5,r5,r7
|
|
bdz 23f
|
|
22: lwz r0,4(r3)
|
|
adde r5,r5,r8
|
|
lwz r6,8(r3)
|
|
adde r5,r5,r0
|
|
lwz r7,12(r3)
|
|
adde r5,r5,r6
|
|
lwzu r8,16(r3)
|
|
adde r5,r5,r7
|
|
bdnz 22b
|
|
23: adde r5,r5,r8
|
|
3: andi. r0,r4,2
|
|
beq+ 4f
|
|
lhz r0,4(r3)
|
|
addi r3,r3,2
|
|
adde r5,r5,r0
|
|
4: andi. r0,r4,1
|
|
beq+ 5f
|
|
lbz r0,4(r3)
|
|
slwi r0,r0,8 /* Upper byte of word */
|
|
adde r5,r5,r0
|
|
5: addze r3,r5 /* add in final carry */
|
|
blr
|
|
EXPORT_SYMBOL(__csum_partial)
|
|
|
|
/*
|
|
* Computes the checksum of a memory block at src, length len,
|
|
* and adds in "sum" (32-bit), while copying the block to dst.
|
|
* If an access exception occurs on src or dst, it stores -EFAULT
|
|
* to *src_err or *dst_err respectively, and (for an error on
|
|
* src) zeroes the rest of dst.
|
|
*
|
|
* csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
|
|
*/
|
|
#define CSUM_COPY_16_BYTES_WITHEX(n) \
|
|
8 ## n ## 0: \
|
|
lwz r7,4(r4); \
|
|
8 ## n ## 1: \
|
|
lwz r8,8(r4); \
|
|
8 ## n ## 2: \
|
|
lwz r9,12(r4); \
|
|
8 ## n ## 3: \
|
|
lwzu r10,16(r4); \
|
|
8 ## n ## 4: \
|
|
stw r7,4(r6); \
|
|
adde r12,r12,r7; \
|
|
8 ## n ## 5: \
|
|
stw r8,8(r6); \
|
|
adde r12,r12,r8; \
|
|
8 ## n ## 6: \
|
|
stw r9,12(r6); \
|
|
adde r12,r12,r9; \
|
|
8 ## n ## 7: \
|
|
stwu r10,16(r6); \
|
|
adde r12,r12,r10
|
|
|
|
#define CSUM_COPY_16_BYTES_EXCODE(n) \
|
|
EX_TABLE(8 ## n ## 0b, src_error); \
|
|
EX_TABLE(8 ## n ## 1b, src_error); \
|
|
EX_TABLE(8 ## n ## 2b, src_error); \
|
|
EX_TABLE(8 ## n ## 3b, src_error); \
|
|
EX_TABLE(8 ## n ## 4b, dst_error); \
|
|
EX_TABLE(8 ## n ## 5b, dst_error); \
|
|
EX_TABLE(8 ## n ## 6b, dst_error); \
|
|
EX_TABLE(8 ## n ## 7b, dst_error);
|
|
|
|
.text
|
|
.stabs "arch/powerpc/lib/",N_SO,0,0,0f
|
|
.stabs "checksum_32.S",N_SO,0,0,0f
|
|
0:
|
|
|
|
CACHELINE_BYTES = L1_CACHE_BYTES
|
|
LG_CACHELINE_BYTES = L1_CACHE_SHIFT
|
|
CACHELINE_MASK = (L1_CACHE_BYTES-1)
|
|
|
|
_GLOBAL(csum_partial_copy_generic)
|
|
stwu r1,-16(r1)
|
|
stw r7,12(r1)
|
|
stw r8,8(r1)
|
|
|
|
addic r12,r6,0
|
|
addi r6,r4,-4
|
|
neg r0,r4
|
|
addi r4,r3,-4
|
|
andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */
|
|
crset 4*cr7+eq
|
|
beq 58f
|
|
|
|
cmplw 0,r5,r0 /* is this more than total to do? */
|
|
blt 63f /* if not much to do */
|
|
rlwinm r7,r6,3,0x8
|
|
rlwnm r12,r12,r7,0,31 /* odd destination address: rotate one byte */
|
|
cmplwi cr7,r7,0 /* is destination address even ? */
|
|
andi. r8,r0,3 /* get it word-aligned first */
|
|
mtctr r8
|
|
beq+ 61f
|
|
li r3,0
|
|
70: lbz r9,4(r4) /* do some bytes */
|
|
addi r4,r4,1
|
|
slwi r3,r3,8
|
|
rlwimi r3,r9,0,24,31
|
|
71: stb r9,4(r6)
|
|
addi r6,r6,1
|
|
bdnz 70b
|
|
adde r12,r12,r3
|
|
61: subf r5,r0,r5
|
|
srwi. r0,r0,2
|
|
mtctr r0
|
|
beq 58f
|
|
72: lwzu r9,4(r4) /* do some words */
|
|
adde r12,r12,r9
|
|
73: stwu r9,4(r6)
|
|
bdnz 72b
|
|
|
|
58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
|
|
clrlwi r5,r5,32-LG_CACHELINE_BYTES
|
|
li r11,4
|
|
beq 63f
|
|
|
|
/* Here we decide how far ahead to prefetch the source */
|
|
li r3,4
|
|
cmpwi r0,1
|
|
li r7,0
|
|
ble 114f
|
|
li r7,1
|
|
#if MAX_COPY_PREFETCH > 1
|
|
/* Heuristically, for large transfers we prefetch
|
|
MAX_COPY_PREFETCH cachelines ahead. For small transfers
|
|
we prefetch 1 cacheline ahead. */
|
|
cmpwi r0,MAX_COPY_PREFETCH
|
|
ble 112f
|
|
li r7,MAX_COPY_PREFETCH
|
|
112: mtctr r7
|
|
111: dcbt r3,r4
|
|
addi r3,r3,CACHELINE_BYTES
|
|
bdnz 111b
|
|
#else
|
|
dcbt r3,r4
|
|
addi r3,r3,CACHELINE_BYTES
|
|
#endif /* MAX_COPY_PREFETCH > 1 */
|
|
|
|
114: subf r8,r7,r0
|
|
mr r0,r7
|
|
mtctr r8
|
|
|
|
53: dcbt r3,r4
|
|
54: dcbz r11,r6
|
|
/* the main body of the cacheline loop */
|
|
CSUM_COPY_16_BYTES_WITHEX(0)
|
|
#if L1_CACHE_BYTES >= 32
|
|
CSUM_COPY_16_BYTES_WITHEX(1)
|
|
#if L1_CACHE_BYTES >= 64
|
|
CSUM_COPY_16_BYTES_WITHEX(2)
|
|
CSUM_COPY_16_BYTES_WITHEX(3)
|
|
#if L1_CACHE_BYTES >= 128
|
|
CSUM_COPY_16_BYTES_WITHEX(4)
|
|
CSUM_COPY_16_BYTES_WITHEX(5)
|
|
CSUM_COPY_16_BYTES_WITHEX(6)
|
|
CSUM_COPY_16_BYTES_WITHEX(7)
|
|
#endif
|
|
#endif
|
|
#endif
|
|
bdnz 53b
|
|
cmpwi r0,0
|
|
li r3,4
|
|
li r7,0
|
|
bne 114b
|
|
|
|
63: srwi. r0,r5,2
|
|
mtctr r0
|
|
beq 64f
|
|
30: lwzu r0,4(r4)
|
|
adde r12,r12,r0
|
|
31: stwu r0,4(r6)
|
|
bdnz 30b
|
|
|
|
64: andi. r0,r5,2
|
|
beq+ 65f
|
|
40: lhz r0,4(r4)
|
|
addi r4,r4,2
|
|
41: sth r0,4(r6)
|
|
adde r12,r12,r0
|
|
addi r6,r6,2
|
|
65: andi. r0,r5,1
|
|
beq+ 66f
|
|
50: lbz r0,4(r4)
|
|
51: stb r0,4(r6)
|
|
slwi r0,r0,8
|
|
adde r12,r12,r0
|
|
66: addze r3,r12
|
|
addi r1,r1,16
|
|
beqlr+ cr7
|
|
rlwinm r3,r3,8,0,31 /* odd destination address: rotate one byte */
|
|
blr
|
|
|
|
/* read fault */
|
|
src_error:
|
|
lwz r7,12(r1)
|
|
addi r1,r1,16
|
|
cmpwi cr0,r7,0
|
|
beqlr
|
|
li r0,-EFAULT
|
|
stw r0,0(r7)
|
|
blr
|
|
/* write fault */
|
|
dst_error:
|
|
lwz r8,8(r1)
|
|
addi r1,r1,16
|
|
cmpwi cr0,r8,0
|
|
beqlr
|
|
li r0,-EFAULT
|
|
stw r0,0(r8)
|
|
blr
|
|
|
|
EX_TABLE(70b, src_error);
|
|
EX_TABLE(71b, dst_error);
|
|
EX_TABLE(72b, src_error);
|
|
EX_TABLE(73b, dst_error);
|
|
EX_TABLE(54b, dst_error);
|
|
|
|
/*
|
|
* this stuff handles faults in the cacheline loop and branches to either
|
|
* src_error (if in read part) or dst_error (if in write part)
|
|
*/
|
|
CSUM_COPY_16_BYTES_EXCODE(0)
|
|
#if L1_CACHE_BYTES >= 32
|
|
CSUM_COPY_16_BYTES_EXCODE(1)
|
|
#if L1_CACHE_BYTES >= 64
|
|
CSUM_COPY_16_BYTES_EXCODE(2)
|
|
CSUM_COPY_16_BYTES_EXCODE(3)
|
|
#if L1_CACHE_BYTES >= 128
|
|
CSUM_COPY_16_BYTES_EXCODE(4)
|
|
CSUM_COPY_16_BYTES_EXCODE(5)
|
|
CSUM_COPY_16_BYTES_EXCODE(6)
|
|
CSUM_COPY_16_BYTES_EXCODE(7)
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
EX_TABLE(30b, src_error);
|
|
EX_TABLE(31b, dst_error);
|
|
EX_TABLE(40b, src_error);
|
|
EX_TABLE(41b, dst_error);
|
|
EX_TABLE(50b, src_error);
|
|
EX_TABLE(51b, dst_error);
|
|
|
|
EXPORT_SYMBOL(csum_partial_copy_generic)
|
|
|
|
/*
|
|
* __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
|
|
* const struct in6_addr *daddr,
|
|
* __u32 len, __u8 proto, __wsum sum)
|
|
*/
|
|
|
|
_GLOBAL(csum_ipv6_magic)
|
|
lwz r8, 0(r3)
|
|
lwz r9, 4(r3)
|
|
addc r0, r7, r8
|
|
lwz r10, 8(r3)
|
|
adde r0, r0, r9
|
|
lwz r11, 12(r3)
|
|
adde r0, r0, r10
|
|
lwz r8, 0(r4)
|
|
adde r0, r0, r11
|
|
lwz r9, 4(r4)
|
|
adde r0, r0, r8
|
|
lwz r10, 8(r4)
|
|
adde r0, r0, r9
|
|
lwz r11, 12(r4)
|
|
adde r0, r0, r10
|
|
add r5, r5, r6 /* assumption: len + proto doesn't carry */
|
|
adde r0, r0, r11
|
|
adde r0, r0, r5
|
|
addze r0, r0
|
|
rotlwi r3, r0, 16
|
|
add r3, r0, r3
|
|
not r3, r3
|
|
rlwinm r3, r3, 16, 16, 31
|
|
blr
|
|
EXPORT_SYMBOL(csum_ipv6_magic)
|