162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/lib/csumpartial.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1995-1998 Russell King 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/linkage.h> 862306a36Sopenharmony_ci#include <asm/assembler.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci .text 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * Function: __u32 csum_partial(const char *src, int len, __u32 sum) 1462306a36Sopenharmony_ci * Params : r0 = buffer, r1 = len, r2 = checksum 1562306a36Sopenharmony_ci * Returns : r0 = new checksum 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cibuf .req r0 1962306a36Sopenharmony_cilen .req r1 2062306a36Sopenharmony_cisum .req r2 2162306a36Sopenharmony_citd0 .req r3 2262306a36Sopenharmony_citd1 .req r4 @ save before use 2362306a36Sopenharmony_citd2 .req r5 @ save before use 2462306a36Sopenharmony_citd3 .req lr 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci.Lzero: mov r0, sum 2762306a36Sopenharmony_ci add sp, sp, #4 2862306a36Sopenharmony_ci ldr pc, [sp], #4 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* 3162306a36Sopenharmony_ci * Handle 0 to 7 bytes, with any alignment of source and 3262306a36Sopenharmony_ci * destination pointers. Note that when we get here, C = 0 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci.Lless8: teq len, #0 @ check for zero count 3562306a36Sopenharmony_ci beq .Lzero 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* we must have at least one byte. */ 3862306a36Sopenharmony_ci tst buf, #1 @ odd address? 3962306a36Sopenharmony_ci movne sum, sum, ror #8 4062306a36Sopenharmony_ci ldrbne td0, [buf], #1 4162306a36Sopenharmony_ci subne len, len, #1 4262306a36Sopenharmony_ci adcsne sum, sum, td0, put_byte_1 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci.Lless4: tst len, #6 4562306a36Sopenharmony_ci beq .Lless8_byte 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* we are now half-word aligned */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci.Lless8_wordlp: 5062306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 4 5162306a36Sopenharmony_ci ldrh td0, [buf], #2 5262306a36Sopenharmony_ci sub len, len, #2 5362306a36Sopenharmony_ci#else 5462306a36Sopenharmony_ci ldrb td0, [buf], #1 5562306a36Sopenharmony_ci ldrb td3, [buf], #1 5662306a36Sopenharmony_ci sub len, len, #2 5762306a36Sopenharmony_ci#ifndef __ARMEB__ 5862306a36Sopenharmony_ci orr td0, td0, td3, lsl #8 5962306a36Sopenharmony_ci#else 6062306a36Sopenharmony_ci orr td0, td3, td0, lsl #8 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci adcs sum, sum, td0 6462306a36Sopenharmony_ci tst len, #6 6562306a36Sopenharmony_ci bne .Lless8_wordlp 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci.Lless8_byte: tst len, #1 @ odd number of bytes 6862306a36Sopenharmony_ci ldrbne td0, [buf], #1 @ include last byte 6962306a36Sopenharmony_ci adcsne sum, sum, td0, put_byte_0 @ update checksum 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci.Ldone: adc r0, sum, #0 @ collect up the last carry 7262306a36Sopenharmony_ci ldr td0, [sp], #4 7362306a36Sopenharmony_ci tst td0, #1 @ check buffer alignment 7462306a36Sopenharmony_ci movne r0, r0, ror #8 @ rotate checksum by 8 bits 7562306a36Sopenharmony_ci ldr pc, [sp], #4 @ return 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci.Lnot_aligned: tst buf, #1 @ odd address 7862306a36Sopenharmony_ci ldrbne td0, [buf], #1 @ make even 7962306a36Sopenharmony_ci subne len, len, #1 8062306a36Sopenharmony_ci adcsne sum, sum, td0, put_byte_1 @ update checksum 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci tst buf, #2 @ 32-bit aligned? 8362306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 4 8462306a36Sopenharmony_ci ldrhne td0, [buf], #2 @ make 32-bit aligned 8562306a36Sopenharmony_ci subne len, len, #2 8662306a36Sopenharmony_ci#else 8762306a36Sopenharmony_ci ldrbne td0, [buf], #1 8862306a36Sopenharmony_ci ldrbne ip, [buf], #1 8962306a36Sopenharmony_ci subne len, len, #2 9062306a36Sopenharmony_ci#ifndef __ARMEB__ 9162306a36Sopenharmony_ci orrne td0, td0, ip, lsl #8 9262306a36Sopenharmony_ci#else 9362306a36Sopenharmony_ci orrne td0, ip, td0, lsl #8 9462306a36Sopenharmony_ci#endif 9562306a36Sopenharmony_ci#endif 9662306a36Sopenharmony_ci adcsne sum, sum, td0 @ update checksum 9762306a36Sopenharmony_ci ret lr 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciENTRY(csum_partial) 10062306a36Sopenharmony_ci stmfd sp!, {buf, lr} 10162306a36Sopenharmony_ci cmp len, #8 @ Ensure that we have at least 10262306a36Sopenharmony_ci blo .Lless8 @ 8 bytes to copy. 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci tst buf, #1 10562306a36Sopenharmony_ci movne sum, sum, ror #8 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci adds sum, sum, #0 @ C = 0 10862306a36Sopenharmony_ci tst buf, #3 @ Test destination alignment 10962306a36Sopenharmony_ci blne .Lnot_aligned @ align destination, return here 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci1: bics ip, len, #31 11262306a36Sopenharmony_ci beq 3f 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci stmfd sp!, {r4 - r5} 11562306a36Sopenharmony_ci2: ldmia buf!, {td0, td1, td2, td3} 11662306a36Sopenharmony_ci adcs sum, sum, td0 11762306a36Sopenharmony_ci adcs sum, sum, td1 11862306a36Sopenharmony_ci adcs sum, sum, td2 11962306a36Sopenharmony_ci adcs sum, sum, td3 12062306a36Sopenharmony_ci ldmia buf!, {td0, td1, td2, td3} 12162306a36Sopenharmony_ci adcs sum, sum, td0 12262306a36Sopenharmony_ci adcs sum, sum, td1 12362306a36Sopenharmony_ci adcs sum, sum, td2 12462306a36Sopenharmony_ci adcs sum, sum, td3 12562306a36Sopenharmony_ci sub ip, ip, #32 12662306a36Sopenharmony_ci teq ip, #0 12762306a36Sopenharmony_ci bne 2b 12862306a36Sopenharmony_ci ldmfd sp!, {r4 - r5} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci3: tst len, #0x1c @ should not change C 13162306a36Sopenharmony_ci beq .Lless4 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci4: ldr td0, [buf], #4 13462306a36Sopenharmony_ci sub len, len, #4 13562306a36Sopenharmony_ci adcs sum, sum, td0 13662306a36Sopenharmony_ci tst len, #0x1c 13762306a36Sopenharmony_ci bne 4b 13862306a36Sopenharmony_ci b .Lless4 13962306a36Sopenharmony_ciENDPROC(csum_partial) 140