1*d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 21da177e4SLinus Torvalds/* 31da177e4SLinus Torvalds * linux/arch/arm/lib/csumpartial.S 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1995-1998 Russell King 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds#include <linux/linkage.h> 81da177e4SLinus Torvalds#include <asm/assembler.h> 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds .text 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds/* 131da177e4SLinus Torvalds * Function: __u32 csum_partial(const char *src, int len, __u32 sum) 141da177e4SLinus Torvalds * Params : r0 = buffer, r1 = len, r2 = checksum 151da177e4SLinus Torvalds * Returns : r0 = new checksum 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 181da177e4SLinus Torvaldsbuf .req r0 191da177e4SLinus Torvaldslen .req r1 201da177e4SLinus Torvaldssum .req r2 211da177e4SLinus Torvaldstd0 .req r3 221da177e4SLinus Torvaldstd1 .req r4 @ save before use 231da177e4SLinus Torvaldstd2 .req r5 @ save before use 241da177e4SLinus Torvaldstd3 .req lr 251da177e4SLinus Torvalds 268adbb371SNicolas Pitre.Lzero: mov r0, sum 271da177e4SLinus Torvalds add sp, sp, #4 281da177e4SLinus Torvalds ldr pc, [sp], #4 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * Handle 0 to 7 bytes, with any alignment of source and 321da177e4SLinus Torvalds * destination pointers. Note that when we get here, C = 0 331da177e4SLinus Torvalds */ 348adbb371SNicolas Pitre.Lless8: teq len, #0 @ check for zero count 358adbb371SNicolas Pitre beq .Lzero 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds /* we must have at least one byte. */ 381da177e4SLinus Torvalds tst buf, #1 @ odd address? 39af36bef0SRussell King movne sum, sum, ror #8 40e44fc388SStefan Agner ldrbne td0, [buf], #1 411da177e4SLinus Torvalds subne len, len, #1 42e44fc388SStefan Agner adcsne sum, sum, td0, put_byte_1 431da177e4SLinus Torvalds 448adbb371SNicolas Pitre.Lless4: tst len, #6 458adbb371SNicolas Pitre beq .Lless8_byte 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* we are now half-word aligned */ 481da177e4SLinus Torvalds 498adbb371SNicolas Pitre.Lless8_wordlp: 501da177e4SLinus Torvalds#if __LINUX_ARM_ARCH__ >= 4 511da177e4SLinus Torvalds ldrh td0, [buf], #2 521da177e4SLinus Torvalds sub len, len, #2 531da177e4SLinus Torvalds#else 541da177e4SLinus Torvalds ldrb td0, [buf], #1 551da177e4SLinus Torvalds ldrb td3, [buf], #1 561da177e4SLinus Torvalds sub len, len, #2 571da177e4SLinus Torvalds#ifndef __ARMEB__ 581da177e4SLinus Torvalds orr td0, td0, td3, lsl #8 591da177e4SLinus Torvalds#else 601da177e4SLinus Torvalds orr td0, td3, td0, lsl #8 611da177e4SLinus Torvalds#endif 621da177e4SLinus Torvalds#endif 631da177e4SLinus Torvalds adcs sum, sum, td0 641da177e4SLinus Torvalds tst len, #6 658adbb371SNicolas Pitre bne .Lless8_wordlp 661da177e4SLinus Torvalds 678adbb371SNicolas Pitre.Lless8_byte: tst len, #1 @ odd number of bytes 68e44fc388SStefan Agner ldrbne td0, [buf], #1 @ include last byte 69e44fc388SStefan Agner adcsne sum, sum, td0, put_byte_0 @ update checksum 701da177e4SLinus Torvalds 718adbb371SNicolas Pitre.Ldone: adc r0, sum, #0 @ collect up the last carry 721da177e4SLinus Torvalds ldr td0, [sp], #4 731da177e4SLinus Torvalds tst td0, #1 @ check buffer alignment 741da177e4SLinus Torvalds movne r0, r0, ror #8 @ rotate checksum by 8 bits 751da177e4SLinus Torvalds ldr pc, [sp], #4 @ return 761da177e4SLinus Torvalds 778adbb371SNicolas Pitre.Lnot_aligned: tst buf, #1 @ odd address 78e44fc388SStefan Agner ldrbne td0, [buf], #1 @ make even 791da177e4SLinus Torvalds subne len, len, #1 80e44fc388SStefan Agner adcsne sum, sum, td0, put_byte_1 @ update checksum 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds tst buf, #2 @ 32-bit aligned? 831da177e4SLinus Torvalds#if __LINUX_ARM_ARCH__ >= 4 84e44fc388SStefan Agner ldrhne td0, [buf], #2 @ make 32-bit aligned 851da177e4SLinus Torvalds subne len, len, #2 861da177e4SLinus Torvalds#else 87e44fc388SStefan Agner ldrbne td0, [buf], #1 88e44fc388SStefan Agner ldrbne ip, [buf], #1 891da177e4SLinus Torvalds subne len, len, #2 901da177e4SLinus Torvalds#ifndef __ARMEB__ 911da177e4SLinus Torvalds orrne td0, td0, ip, lsl #8 921da177e4SLinus Torvalds#else 931da177e4SLinus Torvalds orrne td0, ip, td0, lsl #8 941da177e4SLinus Torvalds#endif 951da177e4SLinus Torvalds#endif 96e44fc388SStefan Agner adcsne sum, sum, td0 @ update checksum 976ebbf2ceSRussell King ret lr 981da177e4SLinus Torvalds 991da177e4SLinus TorvaldsENTRY(csum_partial) 1001da177e4SLinus Torvalds stmfd sp!, {buf, lr} 1011da177e4SLinus Torvalds cmp len, #8 @ Ensure that we have at least 1028adbb371SNicolas Pitre blo .Lless8 @ 8 bytes to copy. 1031da177e4SLinus Torvalds 104af36bef0SRussell King tst buf, #1 105af36bef0SRussell King movne sum, sum, ror #8 106af36bef0SRussell King 1071da177e4SLinus Torvalds adds sum, sum, #0 @ C = 0 1081da177e4SLinus Torvalds tst buf, #3 @ Test destination alignment 1098adbb371SNicolas Pitre blne .Lnot_aligned @ align destination, return here 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds1: bics ip, len, #31 1121da177e4SLinus Torvalds beq 3f 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds stmfd sp!, {r4 - r5} 1151da177e4SLinus Torvalds2: ldmia buf!, {td0, td1, td2, td3} 1161da177e4SLinus Torvalds adcs sum, sum, td0 1171da177e4SLinus Torvalds adcs sum, sum, td1 1181da177e4SLinus Torvalds adcs sum, sum, td2 1191da177e4SLinus Torvalds adcs sum, sum, td3 1201da177e4SLinus Torvalds ldmia buf!, {td0, td1, td2, td3} 1211da177e4SLinus Torvalds adcs sum, sum, td0 1221da177e4SLinus Torvalds adcs sum, sum, td1 1231da177e4SLinus Torvalds adcs sum, sum, td2 1241da177e4SLinus Torvalds adcs sum, sum, td3 1251da177e4SLinus Torvalds sub ip, ip, #32 1261da177e4SLinus Torvalds teq ip, #0 1271da177e4SLinus Torvalds bne 2b 1281da177e4SLinus Torvalds ldmfd sp!, {r4 - r5} 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds3: tst len, #0x1c @ should not change C 1318adbb371SNicolas Pitre beq .Lless4 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds4: ldr td0, [buf], #4 1341da177e4SLinus Torvalds sub len, len, #4 1351da177e4SLinus Torvalds adcs sum, sum, td0 1361da177e4SLinus Torvalds tst len, #0x1c 1371da177e4SLinus Torvalds bne 4b 1388adbb371SNicolas Pitre b .Lless4 13993ed3970SCatalin MarinasENDPROC(csum_partial) 140