; ; linux/arch/c6x/lib/csum_64plus.s ; ; Port on Texas Instruments TMS320C6x architecture ; ; Copyright (C) 2006, 2009, 2010, 2011 Texas Instruments Incorporated ; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License version 2 as ; published by the Free Software Foundation. ; #include <linux/linkage.h> ; ;unsigned int csum_partial_copy(const char *src, char * dst, ; int len, int sum) ; ; A4: src ; B4: dst ; A6: len ; B6: sum ; return csum in A4 ; .text ENTRY(csum_partial_copy) MVC .S2 ILC,B30 MV .D1X B6,A31 ; given csum ZERO .D1 A9 ; csum (a side) || ZERO .D2 B9 ; csum (b side) || SHRU .S2X A6,2,B5 ; len / 4 ;; Check alignment and size AND .S1 3,A4,A1 || AND .S2 3,B4,B0 OR .L2X B0,A1,B0 ; non aligned condition || MVC .S2 B5,ILC || MVK .D2 1,B2 || MV .D1X B5,A1 ; words condition [!A1] B .S1 L8 [B0] BNOP .S1 L6,5 SPLOOP 1 ;; Main loop for aligned words LDW .D1T1 *A4++,A7 NOP 4 MV .S2X A7,B7 || EXTU .S1 A7,0,16,A16 STW .D2T2 B7,*B4++ || MPYU .M2 B7,B2,B8 || ADD .L1 A16,A9,A9 NOP SPKERNEL 8,0 || ADD .L2 B8,B9,B9 ZERO .D1 A1 || ADD .L1X A9,B9,A9 ; add csum from a and b sides L6: [!A1] BNOP .S1 L8,5 ;; Main loop for non-aligned words SPLOOP 2 || MVK .L1 1,A2 LDNW .D1T1 *A4++,A7 NOP 3 NOP MV .S2X A7,B7 || EXTU .S1 A7,0,16,A16 || MPYU .M1 A7,A2,A8 ADD .L1 A16,A9,A9 SPKERNEL 6,0 || STNW .D2T2 B7,*B4++ || ADD .L1 A8,A9,A9 L8: AND .S2X 2,A6,B5 CMPGT .L2 B5,0,B0 [!B0] BNOP .S1 L82,4 ;; Manage half-word ZERO .L1 A7 || ZERO .D1 A8 #ifdef CONFIG_CPU_BIG_ENDIAN LDBU .D1T1 *A4++,A7 LDBU .D1T1 *A4++,A8 NOP 3 SHL .S1 A7,8,A0 ADD .S1 A8,A9,A9 STB .D2T1 A7,*B4++ || ADD .S1 A0,A9,A9 STB .D2T1 A8,*B4++ #else LDBU .D1T1 *A4++,A7 LDBU .D1T1 *A4++,A8 NOP 3 ADD .S1 A7,A9,A9 SHL .S1 A8,8,A0 STB .D2T1 A7,*B4++ || ADD .S1 A0,A9,A9 STB .D2T1 A8,*B4++ #endif ;; Manage eventually the last byte L82: AND .S2X 1,A6,B0 [!B0] BNOP .S1 L9,5 || ZERO .L1 A7 L83: LDBU .D1T1 *A4++,A7 NOP 4 MV .L2X A7,B7 #ifdef CONFIG_CPU_BIG_ENDIAN STB .D2T2 B7,*B4++ || SHL .S1 A7,8,A7 ADD .S1 A7,A9,A9 #else STB .D2T2 B7,*B4++ || ADD .S1 A7,A9,A9 #endif ;; Fold the csum L9: SHRU .S2X A9,16,B0 [!B0] BNOP .S1 L10,5 L91: SHRU .S2X A9,16,B4 || EXTU .S1 A9,16,16,A3 ADD .D1X A3,B4,A9 SHRU .S1 A9,16,A0 [A0] BNOP .S1 L91,5 L10: ADD .D1 A31,A9,A9 MV .D1 A9,A4 BNOP .S2 B3,4 MVC .S2 B30,ILC ENDPROC(csum_partial_copy) ; ;unsigned short ;ip_fast_csum(unsigned char *iph, unsigned int ihl) ;{ ; unsigned int checksum = 0; ; unsigned short *tosum = (unsigned short *) iph; ; int len; ; ; len = ihl*4; ; ; if (len <= 0) ; return 0; ; ; while(len) { ; len -= 2; ; checksum += *tosum++; ; } ; if (len & 1) ; checksum += *(unsigned char*) tosum; ; ; while(checksum >> 16) ; checksum = (checksum & 0xffff) + (checksum >> 16); ; ; return ~checksum; ;} ; ; A4: iph ; B4: ihl ; return checksum in A4 ; .text ENTRY(ip_fast_csum) ZERO .D1 A5 || MVC .S2 ILC,B30 SHL .S2 B4,2,B0 CMPGT .L2 B0,0,B1 [!B1] BNOP .S1 L15,4 [!B1] ZERO .D1 A3 [!B0] B .S1 L12 SHRU .S2 B0,1,B0 MVC .S2 B0,ILC NOP 3 SPLOOP 1 LDHU .D1T1 *A4++,A3 NOP 3 NOP SPKERNEL 5,0 || ADD .L1 A3,A5,A5 L12: SHRU .S1 A5,16,A0 [!A0] BNOP .S1 L14,5 L13: SHRU .S2X A5,16,B4 EXTU .S1 A5,16,16,A3 ADD .D1X A3,B4,A5 SHRU .S1 A5,16,A0 [A0] BNOP .S1 L13,5 L14: NOT .D1 A5,A3 EXTU .S1 A3,16,16,A3 L15: BNOP .S2 B3,3 MVC .S2 B30,ILC MV .D1 A3,A4 ENDPROC(ip_fast_csum) ; ;unsigned short ;do_csum(unsigned char *buff, unsigned int len) ;{ ; int odd, count; ; unsigned int result = 0; ; ; if (len <= 0) ; goto out; ; odd = 1 & (unsigned long) buff; ; if (odd) { ;#ifdef __LITTLE_ENDIAN ; result += (*buff << 8); ;#else ; result = *buff; ;#endif ; len--; ; buff++; ; } ; count = len >> 1; /* nr of 16-bit words.. */ ; if (count) { ; if (2 & (unsigned long) buff) { ; result += *(unsigned short *) buff; ; count--; ; len -= 2; ; buff += 2; ; } ; count >>= 1; /* nr of 32-bit words.. */ ; if (count) { ; unsigned int carry = 0; ; do { ; unsigned int w = *(unsigned int *) buff; ; count--; ; buff += 4; ; result += carry; ; result += w; ; carry = (w > result); ; } while (count); ; result += carry; ; result = (result & 0xffff) + (result >> 16); ; } ; if (len & 2) { ; result += *(unsigned short *) buff; ; buff += 2; ; } ; } ; if (len & 1) ;#ifdef __LITTLE_ENDIAN ; result += *buff; ;#else ; result += (*buff << 8); ;#endif ; result = (result & 0xffff) + (result >> 16); ; /* add up carry.. */ ; result = (result & 0xffff) + (result >> 16); ; if (odd) ; result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); ;out: ; return result; ;} ; ; A4: buff ; B4: len ; return checksum in A4 ; ENTRY(do_csum) CMPGT .L2 B4,0,B0 [!B0] BNOP .S1 L26,3 EXTU .S1 A4,31,31,A0 MV .L1 A0,A3 || MV .S1X B3,A5 || MV .L2 B4,B3 || ZERO .D1 A1 #ifdef CONFIG_CPU_BIG_ENDIAN [A0] SUB .L2 B3,1,B3 || [A0] LDBU .D1T1 *A4++,A1 #else [!A0] BNOP .S1 L21,5 || [A0] LDBU .D1T1 *A4++,A0 SUB .L2 B3,1,B3 || SHL .S1 A0,8,A1 L21: #endif SHR .S2 B3,1,B0 [!B0] BNOP .S1 L24,3 MVK .L1 2,A0 AND .L1 A4,A0,A0 [!A0] BNOP .S1 L22,5 || [A0] LDHU .D1T1 *A4++,A0 SUB .L2 B0,1,B0 || SUB .S2 B3,2,B3 || ADD .L1 A0,A1,A1 L22: SHR .S2 B0,1,B0 || ZERO .L1 A0 [!B0] BNOP .S1 L23,5 || [B0] MVC .S2 B0,ILC SPLOOP 3 SPMASK L1 || MV .L1 A1,A2 || LDW .D1T1 *A4++,A1 NOP 4 ADD .L1 A0,A1,A0 ADD .L1 A2,A0,A2 SPKERNEL 1,2 || CMPGTU .L1 A1,A2,A0 ADD .L1 A0,A2,A6 EXTU .S1 A6,16,16,A7 SHRU .S2X A6,16,B0 NOP 1 ADD .L1X A7,B0,A1 L23: MVK .L2 2,B0 AND .L2 B3,B0,B0 [B0] LDHU .D1T1 *A4++,A0 NOP 4 [B0] ADD .L1 A0,A1,A1 L24: EXTU .S2 B3,31,31,B0 #ifdef CONFIG_CPU_BIG_ENDIAN [!B0] BNOP .S1 L25,4 || [B0] LDBU .D1T1 *A4,A0 SHL .S1 A0,8,A0 ADD .L1 A0,A1,A1 L25: #else [B0] LDBU .D1T1 *A4,A0 NOP 4 [B0] ADD .L1 A0,A1,A1 #endif EXTU .S1 A1,16,16,A0 SHRU .S2X A1,16,B0 NOP 1 ADD .L1X A0,B0,A0 SHRU .S1 A0,16,A1 ADD .L1 A0,A1,A0 EXTU .S1 A0,16,16,A1 EXTU .S1 A1,16,24,A2 EXTU .S1 A1,24,16,A0 || MV .L2X A3,B0 [B0] OR .L1 A0,A2,A1 L26: NOP 1 BNOP .S2X A5,4 MV .L1 A1,A4 ENDPROC(do_csum) ;__wsum csum_partial(const void *buff, int len, __wsum wsum) ;{ ; unsigned int sum = (__force unsigned int)wsum; ; unsigned int result = do_csum(buff, len); ; ; /* add in old sum, and carry.. */ ; result += sum; ; if (sum > result) ; result += 1; ; return (__force __wsum)result; ;} ; ENTRY(csum_partial) MV .L1X B3,A9 || CALLP .S2 do_csum,B3 || MV .S1 A6,A8 BNOP .S2X A9,2 ADD .L1 A8,A4,A1 CMPGTU .L1 A8,A1,A0 ADD .L1 A1,A0,A4 ENDPROC(csum_partial) ;unsigned short ;ip_compute_csum(unsigned char *buff, unsigned int len) ; ; A4: buff ; B4: len ; return checksum in A4 ENTRY(ip_compute_csum) MV .L1X B3,A9 || CALLP .S2 do_csum,B3 BNOP .S2X A9,3 NOT .S1 A4,A4 CLR .S1 A4,16,31,A4 ENDPROC(ip_compute_csum)