18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file contains assembly-language implementations 48c2ecf20Sopenharmony_ci * of IP-style 1's complement checksum routines. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au). 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/sys.h> 128c2ecf20Sopenharmony_ci#include <asm/processor.h> 138c2ecf20Sopenharmony_ci#include <asm/cache.h> 148c2ecf20Sopenharmony_ci#include <asm/errno.h> 158c2ecf20Sopenharmony_ci#include <asm/ppc_asm.h> 168c2ecf20Sopenharmony_ci#include <asm/export.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci .text 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * computes the checksum of a memory block at buff, length len, 228c2ecf20Sopenharmony_ci * and adds in "sum" (32-bit) 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * __csum_partial(buff, len, sum) 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci_GLOBAL(__csum_partial) 278c2ecf20Sopenharmony_ci subi r3,r3,4 288c2ecf20Sopenharmony_ci srawi. r6,r4,2 /* Divide len by 4 and also clear carry */ 298c2ecf20Sopenharmony_ci beq 3f /* if we're doing < 4 bytes */ 308c2ecf20Sopenharmony_ci andi. r0,r3,2 /* Align buffer to longword boundary */ 318c2ecf20Sopenharmony_ci beq+ 1f 328c2ecf20Sopenharmony_ci lhz r0,4(r3) /* do 2 bytes to get aligned */ 338c2ecf20Sopenharmony_ci subi r4,r4,2 348c2ecf20Sopenharmony_ci addi r3,r3,2 358c2ecf20Sopenharmony_ci srwi. r6,r4,2 /* # words to do */ 368c2ecf20Sopenharmony_ci adde r5,r5,r0 378c2ecf20Sopenharmony_ci beq 3f 388c2ecf20Sopenharmony_ci1: andi. r6,r6,3 /* Prepare to handle words 4 by 4 */ 398c2ecf20Sopenharmony_ci beq 21f 408c2ecf20Sopenharmony_ci mtctr r6 418c2ecf20Sopenharmony_ci2: lwzu r0,4(r3) 428c2ecf20Sopenharmony_ci adde r5,r5,r0 438c2ecf20Sopenharmony_ci bdnz 2b 448c2ecf20Sopenharmony_ci21: srwi. r6,r4,4 /* # blocks of 4 words to do */ 458c2ecf20Sopenharmony_ci beq 3f 468c2ecf20Sopenharmony_ci lwz r0,4(r3) 478c2ecf20Sopenharmony_ci mtctr r6 488c2ecf20Sopenharmony_ci lwz r6,8(r3) 498c2ecf20Sopenharmony_ci adde r5,r5,r0 508c2ecf20Sopenharmony_ci lwz r7,12(r3) 518c2ecf20Sopenharmony_ci adde r5,r5,r6 528c2ecf20Sopenharmony_ci lwzu r8,16(r3) 538c2ecf20Sopenharmony_ci adde r5,r5,r7 548c2ecf20Sopenharmony_ci bdz 23f 558c2ecf20Sopenharmony_ci22: lwz r0,4(r3) 568c2ecf20Sopenharmony_ci adde r5,r5,r8 578c2ecf20Sopenharmony_ci lwz r6,8(r3) 588c2ecf20Sopenharmony_ci adde r5,r5,r0 598c2ecf20Sopenharmony_ci lwz r7,12(r3) 608c2ecf20Sopenharmony_ci adde r5,r5,r6 618c2ecf20Sopenharmony_ci lwzu r8,16(r3) 628c2ecf20Sopenharmony_ci adde r5,r5,r7 638c2ecf20Sopenharmony_ci bdnz 22b 648c2ecf20Sopenharmony_ci23: adde r5,r5,r8 658c2ecf20Sopenharmony_ci3: andi. r0,r4,2 668c2ecf20Sopenharmony_ci beq+ 4f 678c2ecf20Sopenharmony_ci lhz r0,4(r3) 688c2ecf20Sopenharmony_ci addi r3,r3,2 698c2ecf20Sopenharmony_ci adde r5,r5,r0 708c2ecf20Sopenharmony_ci4: andi. r0,r4,1 718c2ecf20Sopenharmony_ci beq+ 5f 728c2ecf20Sopenharmony_ci lbz r0,4(r3) 738c2ecf20Sopenharmony_ci slwi r0,r0,8 /* Upper byte of word */ 748c2ecf20Sopenharmony_ci adde r5,r5,r0 758c2ecf20Sopenharmony_ci5: addze r3,r5 /* add in final carry */ 768c2ecf20Sopenharmony_ci blr 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__csum_partial) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * Computes the checksum of a memory block at src, length len, 818c2ecf20Sopenharmony_ci * and adds in 0xffffffff, while copying the block to dst. 828c2ecf20Sopenharmony_ci * If an access exception occurs it returns zero. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * csum_partial_copy_generic(src, dst, len) 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define CSUM_COPY_16_BYTES_WITHEX(n) \ 878c2ecf20Sopenharmony_ci8 ## n ## 0: \ 888c2ecf20Sopenharmony_ci lwz r7,4(r4); \ 898c2ecf20Sopenharmony_ci8 ## n ## 1: \ 908c2ecf20Sopenharmony_ci lwz r8,8(r4); \ 918c2ecf20Sopenharmony_ci8 ## n ## 2: \ 928c2ecf20Sopenharmony_ci lwz r9,12(r4); \ 938c2ecf20Sopenharmony_ci8 ## n ## 3: \ 948c2ecf20Sopenharmony_ci lwzu r10,16(r4); \ 958c2ecf20Sopenharmony_ci8 ## n ## 4: \ 968c2ecf20Sopenharmony_ci stw r7,4(r6); \ 978c2ecf20Sopenharmony_ci adde r12,r12,r7; \ 988c2ecf20Sopenharmony_ci8 ## n ## 5: \ 998c2ecf20Sopenharmony_ci stw r8,8(r6); \ 1008c2ecf20Sopenharmony_ci adde r12,r12,r8; \ 1018c2ecf20Sopenharmony_ci8 ## n ## 6: \ 1028c2ecf20Sopenharmony_ci stw r9,12(r6); \ 1038c2ecf20Sopenharmony_ci adde r12,r12,r9; \ 1048c2ecf20Sopenharmony_ci8 ## n ## 7: \ 1058c2ecf20Sopenharmony_ci stwu r10,16(r6); \ 1068c2ecf20Sopenharmony_ci adde r12,r12,r10 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define CSUM_COPY_16_BYTES_EXCODE(n) \ 1098c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 0b, fault); \ 1108c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 1b, fault); \ 1118c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 2b, fault); \ 1128c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 3b, fault); \ 1138c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 4b, fault); \ 1148c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 5b, fault); \ 1158c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 6b, fault); \ 1168c2ecf20Sopenharmony_ci EX_TABLE(8 ## n ## 7b, fault); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci .text 1198c2ecf20Sopenharmony_ci .stabs "arch/powerpc/lib/",N_SO,0,0,0f 1208c2ecf20Sopenharmony_ci .stabs "checksum_32.S",N_SO,0,0,0f 1218c2ecf20Sopenharmony_ci0: 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciCACHELINE_BYTES = L1_CACHE_BYTES 1248c2ecf20Sopenharmony_ciLG_CACHELINE_BYTES = L1_CACHE_SHIFT 1258c2ecf20Sopenharmony_ciCACHELINE_MASK = (L1_CACHE_BYTES-1) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci_GLOBAL(csum_partial_copy_generic) 1288c2ecf20Sopenharmony_ci li r12,-1 1298c2ecf20Sopenharmony_ci addic r0,r0,0 /* clear carry */ 1308c2ecf20Sopenharmony_ci addi r6,r4,-4 1318c2ecf20Sopenharmony_ci neg r0,r4 1328c2ecf20Sopenharmony_ci addi r4,r3,-4 1338c2ecf20Sopenharmony_ci andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ 1348c2ecf20Sopenharmony_ci crset 4*cr7+eq 1358c2ecf20Sopenharmony_ci beq 58f 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci cmplw 0,r5,r0 /* is this more than total to do? */ 1388c2ecf20Sopenharmony_ci blt 63f /* if not much to do */ 1398c2ecf20Sopenharmony_ci rlwinm r7,r6,3,0x8 1408c2ecf20Sopenharmony_ci rlwnm r12,r12,r7,0,31 /* odd destination address: rotate one byte */ 1418c2ecf20Sopenharmony_ci cmplwi cr7,r7,0 /* is destination address even ? */ 1428c2ecf20Sopenharmony_ci andi. r8,r0,3 /* get it word-aligned first */ 1438c2ecf20Sopenharmony_ci mtctr r8 1448c2ecf20Sopenharmony_ci beq+ 61f 1458c2ecf20Sopenharmony_ci li r3,0 1468c2ecf20Sopenharmony_ci70: lbz r9,4(r4) /* do some bytes */ 1478c2ecf20Sopenharmony_ci addi r4,r4,1 1488c2ecf20Sopenharmony_ci slwi r3,r3,8 1498c2ecf20Sopenharmony_ci rlwimi r3,r9,0,24,31 1508c2ecf20Sopenharmony_ci71: stb r9,4(r6) 1518c2ecf20Sopenharmony_ci addi r6,r6,1 1528c2ecf20Sopenharmony_ci bdnz 70b 1538c2ecf20Sopenharmony_ci adde r12,r12,r3 1548c2ecf20Sopenharmony_ci61: subf r5,r0,r5 1558c2ecf20Sopenharmony_ci srwi. r0,r0,2 1568c2ecf20Sopenharmony_ci mtctr r0 1578c2ecf20Sopenharmony_ci beq 58f 1588c2ecf20Sopenharmony_ci72: lwzu r9,4(r4) /* do some words */ 1598c2ecf20Sopenharmony_ci adde r12,r12,r9 1608c2ecf20Sopenharmony_ci73: stwu r9,4(r6) 1618c2ecf20Sopenharmony_ci bdnz 72b 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ 1648c2ecf20Sopenharmony_ci clrlwi r5,r5,32-LG_CACHELINE_BYTES 1658c2ecf20Sopenharmony_ci li r11,4 1668c2ecf20Sopenharmony_ci beq 63f 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Here we decide how far ahead to prefetch the source */ 1698c2ecf20Sopenharmony_ci li r3,4 1708c2ecf20Sopenharmony_ci cmpwi r0,1 1718c2ecf20Sopenharmony_ci li r7,0 1728c2ecf20Sopenharmony_ci ble 114f 1738c2ecf20Sopenharmony_ci li r7,1 1748c2ecf20Sopenharmony_ci#if MAX_COPY_PREFETCH > 1 1758c2ecf20Sopenharmony_ci /* Heuristically, for large transfers we prefetch 1768c2ecf20Sopenharmony_ci MAX_COPY_PREFETCH cachelines ahead. For small transfers 1778c2ecf20Sopenharmony_ci we prefetch 1 cacheline ahead. */ 1788c2ecf20Sopenharmony_ci cmpwi r0,MAX_COPY_PREFETCH 1798c2ecf20Sopenharmony_ci ble 112f 1808c2ecf20Sopenharmony_ci li r7,MAX_COPY_PREFETCH 1818c2ecf20Sopenharmony_ci112: mtctr r7 1828c2ecf20Sopenharmony_ci111: dcbt r3,r4 1838c2ecf20Sopenharmony_ci addi r3,r3,CACHELINE_BYTES 1848c2ecf20Sopenharmony_ci bdnz 111b 1858c2ecf20Sopenharmony_ci#else 1868c2ecf20Sopenharmony_ci dcbt r3,r4 1878c2ecf20Sopenharmony_ci addi r3,r3,CACHELINE_BYTES 1888c2ecf20Sopenharmony_ci#endif /* MAX_COPY_PREFETCH > 1 */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci114: subf r8,r7,r0 1918c2ecf20Sopenharmony_ci mr r0,r7 1928c2ecf20Sopenharmony_ci mtctr r8 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci53: dcbt r3,r4 1958c2ecf20Sopenharmony_ci54: dcbz r11,r6 1968c2ecf20Sopenharmony_ci/* the main body of the cacheline loop */ 1978c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(0) 1988c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 32 1998c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(1) 2008c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 64 2018c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(2) 2028c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(3) 2038c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 128 2048c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(4) 2058c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(5) 2068c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(6) 2078c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_WITHEX(7) 2088c2ecf20Sopenharmony_ci#endif 2098c2ecf20Sopenharmony_ci#endif 2108c2ecf20Sopenharmony_ci#endif 2118c2ecf20Sopenharmony_ci bdnz 53b 2128c2ecf20Sopenharmony_ci cmpwi r0,0 2138c2ecf20Sopenharmony_ci li r3,4 2148c2ecf20Sopenharmony_ci li r7,0 2158c2ecf20Sopenharmony_ci bne 114b 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci63: srwi. r0,r5,2 2188c2ecf20Sopenharmony_ci mtctr r0 2198c2ecf20Sopenharmony_ci beq 64f 2208c2ecf20Sopenharmony_ci30: lwzu r0,4(r4) 2218c2ecf20Sopenharmony_ci adde r12,r12,r0 2228c2ecf20Sopenharmony_ci31: stwu r0,4(r6) 2238c2ecf20Sopenharmony_ci bdnz 30b 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci64: andi. r0,r5,2 2268c2ecf20Sopenharmony_ci beq+ 65f 2278c2ecf20Sopenharmony_ci40: lhz r0,4(r4) 2288c2ecf20Sopenharmony_ci addi r4,r4,2 2298c2ecf20Sopenharmony_ci41: sth r0,4(r6) 2308c2ecf20Sopenharmony_ci adde r12,r12,r0 2318c2ecf20Sopenharmony_ci addi r6,r6,2 2328c2ecf20Sopenharmony_ci65: andi. r0,r5,1 2338c2ecf20Sopenharmony_ci beq+ 66f 2348c2ecf20Sopenharmony_ci50: lbz r0,4(r4) 2358c2ecf20Sopenharmony_ci51: stb r0,4(r6) 2368c2ecf20Sopenharmony_ci slwi r0,r0,8 2378c2ecf20Sopenharmony_ci adde r12,r12,r0 2388c2ecf20Sopenharmony_ci66: addze r3,r12 2398c2ecf20Sopenharmony_ci beqlr+ cr7 2408c2ecf20Sopenharmony_ci rlwinm r3,r3,8,0,31 /* odd destination address: rotate one byte */ 2418c2ecf20Sopenharmony_ci blr 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cifault: 2448c2ecf20Sopenharmony_ci li r3,0 2458c2ecf20Sopenharmony_ci blr 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci EX_TABLE(70b, fault); 2488c2ecf20Sopenharmony_ci EX_TABLE(71b, fault); 2498c2ecf20Sopenharmony_ci EX_TABLE(72b, fault); 2508c2ecf20Sopenharmony_ci EX_TABLE(73b, fault); 2518c2ecf20Sopenharmony_ci EX_TABLE(54b, fault); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * this stuff handles faults in the cacheline loop and branches to either 2558c2ecf20Sopenharmony_ci * fault (if in read part) or fault (if in write part) 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(0) 2588c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 32 2598c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(1) 2608c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 64 2618c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(2) 2628c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(3) 2638c2ecf20Sopenharmony_ci#if L1_CACHE_BYTES >= 128 2648c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(4) 2658c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(5) 2668c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(6) 2678c2ecf20Sopenharmony_ci CSUM_COPY_16_BYTES_EXCODE(7) 2688c2ecf20Sopenharmony_ci#endif 2698c2ecf20Sopenharmony_ci#endif 2708c2ecf20Sopenharmony_ci#endif 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci EX_TABLE(30b, fault); 2738c2ecf20Sopenharmony_ci EX_TABLE(31b, fault); 2748c2ecf20Sopenharmony_ci EX_TABLE(40b, fault); 2758c2ecf20Sopenharmony_ci EX_TABLE(41b, fault); 2768c2ecf20Sopenharmony_ci EX_TABLE(50b, fault); 2778c2ecf20Sopenharmony_ci EX_TABLE(51b, fault); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_partial_copy_generic) 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/* 2828c2ecf20Sopenharmony_ci * __sum16 csum_ipv6_magic(const struct in6_addr *saddr, 2838c2ecf20Sopenharmony_ci * const struct in6_addr *daddr, 2848c2ecf20Sopenharmony_ci * __u32 len, __u8 proto, __wsum sum) 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci_GLOBAL(csum_ipv6_magic) 2888c2ecf20Sopenharmony_ci lwz r8, 0(r3) 2898c2ecf20Sopenharmony_ci lwz r9, 4(r3) 2908c2ecf20Sopenharmony_ci addc r0, r7, r8 2918c2ecf20Sopenharmony_ci lwz r10, 8(r3) 2928c2ecf20Sopenharmony_ci adde r0, r0, r9 2938c2ecf20Sopenharmony_ci lwz r11, 12(r3) 2948c2ecf20Sopenharmony_ci adde r0, r0, r10 2958c2ecf20Sopenharmony_ci lwz r8, 0(r4) 2968c2ecf20Sopenharmony_ci adde r0, r0, r11 2978c2ecf20Sopenharmony_ci lwz r9, 4(r4) 2988c2ecf20Sopenharmony_ci adde r0, r0, r8 2998c2ecf20Sopenharmony_ci lwz r10, 8(r4) 3008c2ecf20Sopenharmony_ci adde r0, r0, r9 3018c2ecf20Sopenharmony_ci lwz r11, 12(r4) 3028c2ecf20Sopenharmony_ci adde r0, r0, r10 3038c2ecf20Sopenharmony_ci add r5, r5, r6 /* assumption: len + proto doesn't carry */ 3048c2ecf20Sopenharmony_ci adde r0, r0, r11 3058c2ecf20Sopenharmony_ci adde r0, r0, r5 3068c2ecf20Sopenharmony_ci addze r0, r0 3078c2ecf20Sopenharmony_ci rotlwi r3, r0, 16 3088c2ecf20Sopenharmony_ci add r3, r0, r3 3098c2ecf20Sopenharmony_ci not r3, r3 3108c2ecf20Sopenharmony_ci rlwinm r3, r3, 16, 16, 31 3118c2ecf20Sopenharmony_ci blr 3128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_ipv6_magic) 313