1/* 2 * linux/arch/arm/lib/csumpartial.S 3 * 4 * Copyright (C) 1995-1998 Russell King 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10#include <linux/linkage.h> 11#include <asm/assembler.h> 12 13 .text 14 15/* 16 * Function: __u32 csum_partial(const char *src, int len, __u32 sum) 17 * Params : r0 = buffer, r1 = len, r2 = checksum 18 * Returns : r0 = new checksum 19 */ 20 21buf .req r0 22len .req r1 23sum .req r2 24td0 .req r3 25td1 .req r4 @ save before use 26td2 .req r5 @ save before use 27td3 .req lr 28 29.zero: mov r0, sum 30 add sp, sp, #4 31 ldr pc, [sp], #4 32 33 /* 34 * Handle 0 to 7 bytes, with any alignment of source and 35 * destination pointers. Note that when we get here, C = 0 36 */ 37.less8: teq len, #0 @ check for zero count 38 beq .zero 39 40 /* we must have at least one byte. */ 41 tst buf, #1 @ odd address? 42 ldrneb td0, [buf], #1 43 subne len, len, #1 44 adcnes sum, sum, td0, put_byte_1 45 46.less4: tst len, #6 47 beq .less8_byte 48 49 /* we are now half-word aligned */ 50 51.less8_wordlp: 52#if __LINUX_ARM_ARCH__ >= 4 53 ldrh td0, [buf], #2 54 sub len, len, #2 55#else 56 ldrb td0, [buf], #1 57 ldrb td3, [buf], #1 58 sub len, len, #2 59#ifndef __ARMEB__ 60 orr td0, td0, td3, lsl #8 61#else 62 orr td0, td3, td0, lsl #8 63#endif 64#endif 65 adcs sum, sum, td0 66 tst len, #6 67 bne .less8_wordlp 68 69.less8_byte: tst len, #1 @ odd number of bytes 70 ldrneb td0, [buf], #1 @ include last byte 71 adcnes sum, sum, td0, put_byte_0 @ update checksum 72 73.done: adc r0, sum, #0 @ collect up the last carry 74 ldr td0, [sp], #4 75 tst td0, #1 @ check buffer alignment 76 movne r0, r0, ror #8 @ rotate checksum by 8 bits 77 ldr pc, [sp], #4 @ return 78 79.not_aligned: tst buf, #1 @ odd address 80 ldrneb td0, [buf], #1 @ make even 81 subne len, len, #1 82 adcnes sum, sum, td0, put_byte_1 @ update checksum 83 84 tst buf, #2 @ 32-bit aligned? 85#if __LINUX_ARM_ARCH__ >= 4 86 ldrneh td0, [buf], #2 @ make 32-bit aligned 87 subne len, len, #2 88#else 89 ldrneb td0, [buf], #1 90 ldrneb ip, [buf], #1 91 subne len, len, #2 92#ifndef __ARMEB__ 93 orrne td0, td0, ip, lsl #8 94#else 95 orrne td0, ip, td0, lsl #8 96#endif 97#endif 98 adcnes sum, sum, td0 @ update checksum 99 mov pc, lr 100 101ENTRY(csum_partial) 102 stmfd sp!, {buf, lr} 103 cmp len, #8 @ Ensure that we have at least 104 blo .less8 @ 8 bytes to copy. 105 106 adds sum, sum, #0 @ C = 0 107 tst buf, #3 @ Test destination alignment 108 blne .not_aligned @ aligh destination, return here 109 1101: bics ip, len, #31 111 beq 3f 112 113 stmfd sp!, {r4 - r5} 1142: ldmia buf!, {td0, td1, td2, td3} 115 adcs sum, sum, td0 116 adcs sum, sum, td1 117 adcs sum, sum, td2 118 adcs sum, sum, td3 119 ldmia buf!, {td0, td1, td2, td3} 120 adcs sum, sum, td0 121 adcs sum, sum, td1 122 adcs sum, sum, td2 123 adcs sum, sum, td3 124 sub ip, ip, #32 125 teq ip, #0 126 bne 2b 127 ldmfd sp!, {r4 - r5} 128 1293: tst len, #0x1c @ should not change C 130 beq .less4 131 1324: ldr td0, [buf], #4 133 sub len, len, #4 134 adcs sum, sum, td0 135 tst len, #0x1c 136 bne 4b 137 b .less4 138