root/arch/xtensa/lib/checksum.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0-or-later */
   2 /*
   3  * INET         An implementation of the TCP/IP protocol suite for the LINUX
   4  *              operating system.  INET is implemented using the  BSD Socket
   5  *              interface as the means of communication with the user level.
   6  *
   7  *              IP/TCP/UDP checksumming routines
   8  *
   9  * Xtensa version:  Copyright (C) 2001 Tensilica, Inc. by Kevin Chea
  10  *                  Optimized by Joe Taylor
  11  */
  12 
  13 #include <linux/errno.h>
  14 #include <linux/linkage.h>
  15 #include <asm/asmmacro.h>
  16 #include <asm/core.h>
  17 
  18 /*
  19  * computes a partial checksum, e.g. for TCP/UDP fragments
  20  */
  21 
  22 /*
  23  * unsigned int csum_partial(const unsigned char *buf, int len,
  24  *                           unsigned int sum);
  25  *    a2 = buf
  26  *    a3 = len
  27  *    a4 = sum
  28  *
  29  * This function assumes 2- or 4-byte alignment.  Other alignments will fail!
  30  */
  31 
  32 /* ONES_ADD converts twos-complement math to ones-complement. */
  33 #define ONES_ADD(sum, val)        \
  34         add     sum, sum, val   ; \
  35         bgeu    sum, val, 99f   ; \
  36         addi    sum, sum, 1     ; \
  37 99:                             ;
  38 
  39 .text
  40 ENTRY(csum_partial)
  41 
  42         /*
  43          * Experiments with Ethernet and SLIP connections show that buf
  44          * is aligned on either a 2-byte or 4-byte boundary.
  45          */
  46         abi_entry_default
  47         extui   a5, a2, 0, 2
  48         bnez    a5, 8f          /* branch if 2-byte aligned */
  49         /* Fall-through on common case, 4-byte alignment */
  50 1:
  51         srli    a5, a3, 5       /* 32-byte chunks */
  52 #if XCHAL_HAVE_LOOPS
  53         loopgtz a5, 2f
  54 #else
  55         beqz    a5, 2f
  56         slli    a5, a5, 5
  57         add     a5, a5, a2      /* a5 = end of last 32-byte chunk */
  58 .Loop1:
  59 #endif
  60         l32i    a6, a2, 0
  61         l32i    a7, a2, 4
  62         ONES_ADD(a4, a6)
  63         ONES_ADD(a4, a7)
  64         l32i    a6, a2, 8
  65         l32i    a7, a2, 12
  66         ONES_ADD(a4, a6)
  67         ONES_ADD(a4, a7)
  68         l32i    a6, a2, 16
  69         l32i    a7, a2, 20
  70         ONES_ADD(a4, a6)
  71         ONES_ADD(a4, a7)
  72         l32i    a6, a2, 24
  73         l32i    a7, a2, 28
  74         ONES_ADD(a4, a6)
  75         ONES_ADD(a4, a7)
  76         addi    a2, a2, 4*8
  77 #if !XCHAL_HAVE_LOOPS
  78         blt     a2, a5, .Loop1
  79 #endif
  80 2:
  81         extui   a5, a3, 2, 3    /* remaining 4-byte chunks */
  82 #if XCHAL_HAVE_LOOPS
  83         loopgtz a5, 3f
  84 #else
  85         beqz    a5, 3f
  86         slli    a5, a5, 2
  87         add     a5, a5, a2      /* a5 = end of last 4-byte chunk */
  88 .Loop2:
  89 #endif
  90         l32i    a6, a2, 0
  91         ONES_ADD(a4, a6)
  92         addi    a2, a2, 4
  93 #if !XCHAL_HAVE_LOOPS
  94         blt     a2, a5, .Loop2
  95 #endif
  96 3:
  97         _bbci.l a3, 1, 5f       /* remaining 2-byte chunk */
  98         l16ui   a6, a2, 0
  99         ONES_ADD(a4, a6)
 100         addi    a2, a2, 2
 101 5:
 102         _bbci.l a3, 0, 7f       /* remaining 1-byte chunk */
 103 6:      l8ui    a6, a2, 0
 104 #ifdef __XTENSA_EB__
 105         slli    a6, a6, 8       /* load byte into bits 8..15 */
 106 #endif
 107         ONES_ADD(a4, a6)
 108 7:
 109         mov     a2, a4
 110         abi_ret_default
 111 
 112         /* uncommon case, buf is 2-byte aligned */
 113 8:
 114         beqz    a3, 7b          /* branch if len == 0 */
 115         beqi    a3, 1, 6b       /* branch if len == 1 */
 116 
 117         extui   a5, a2, 0, 1
 118         bnez    a5, 8f          /* branch if 1-byte aligned */
 119 
 120         l16ui   a6, a2, 0       /* common case, len >= 2 */
 121         ONES_ADD(a4, a6)
 122         addi    a2, a2, 2       /* adjust buf */
 123         addi    a3, a3, -2      /* adjust len */
 124         j       1b              /* now buf is 4-byte aligned */
 125 
 126         /* case: odd-byte aligned, len > 1
 127          * This case is dog slow, so don't give us an odd address.
 128          * (I don't think this ever happens, but just in case.)
 129          */
 130 8:
 131         srli    a5, a3, 2       /* 4-byte chunks */
 132 #if XCHAL_HAVE_LOOPS
 133         loopgtz a5, 2f
 134 #else
 135         beqz    a5, 2f
 136         slli    a5, a5, 2
 137         add     a5, a5, a2      /* a5 = end of last 4-byte chunk */
 138 .Loop3:
 139 #endif
 140         l8ui    a6, a2, 0       /* bits 24..31 */
 141         l16ui   a7, a2, 1       /* bits  8..23 */
 142         l8ui    a8, a2, 3       /* bits  0.. 8 */
 143 #ifdef  __XTENSA_EB__
 144         slli    a6, a6, 24
 145 #else
 146         slli    a8, a8, 24
 147 #endif
 148         slli    a7, a7, 8
 149         or      a7, a7, a6
 150         or      a7, a7, a8
 151         ONES_ADD(a4, a7)
 152         addi    a2, a2, 4
 153 #if !XCHAL_HAVE_LOOPS
 154         blt     a2, a5, .Loop3
 155 #endif
 156 2:
 157         _bbci.l a3, 1, 3f       /* remaining 2-byte chunk, still odd addr */
 158         l8ui    a6, a2, 0
 159         l8ui    a7, a2, 1
 160 #ifdef  __XTENSA_EB__
 161         slli    a6, a6, 8
 162 #else
 163         slli    a7, a7, 8
 164 #endif
 165         or      a7, a7, a6
 166         ONES_ADD(a4, a7)
 167         addi    a2, a2, 2
 168 3:
 169         j       5b              /* branch to handle the remaining byte */
 170 
 171 ENDPROC(csum_partial)
 172 
 173 /*
 174  * Copy from ds while checksumming, otherwise like csum_partial
 175  */
 176 
 177 /*
 178 unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
 179                                         int sum, int *src_err_ptr, int *dst_err_ptr)
 180         a2  = src
 181         a3  = dst
 182         a4  = len
 183         a5  = sum
 184         a6  = src_err_ptr
 185         a7  = dst_err_ptr
 186         a8  = temp
 187         a9  = temp
 188         a10 = temp
 189         a11 = original len for exception handling
 190         a12 = original dst for exception handling
 191 
 192     This function is optimized for 4-byte aligned addresses.  Other
 193     alignments work, but not nearly as efficiently.
 194  */
 195 
 196 ENTRY(csum_partial_copy_generic)
 197 
 198         abi_entry_default
 199         mov     a12, a3
 200         mov     a11, a4
 201         or      a10, a2, a3
 202 
 203         /* We optimize the following alignment tests for the 4-byte
 204         aligned case.  Two bbsi.l instructions might seem more optimal
 205         (commented out below).  However, both labels 5: and 3: are out
 206         of the imm8 range, so the assembler relaxes them into
 207         equivalent bbci.l, j combinations, which is actually
 208         slower. */
 209 
 210         extui   a9, a10, 0, 2
 211         beqz    a9, 1f          /* branch if both are 4-byte aligned */
 212         bbsi.l  a10, 0, 5f      /* branch if one address is odd */
 213         j       3f              /* one address is 2-byte aligned */
 214 
 215 /*      _bbsi.l a10, 0, 5f */   /* branch if odd address */
 216 /*      _bbsi.l a10, 1, 3f */   /* branch if 2-byte-aligned address */
 217 
 218 1:
 219         /* src and dst are both 4-byte aligned */
 220         srli    a10, a4, 5      /* 32-byte chunks */
 221 #if XCHAL_HAVE_LOOPS
 222         loopgtz a10, 2f
 223 #else
 224         beqz    a10, 2f
 225         slli    a10, a10, 5
 226         add     a10, a10, a2    /* a10 = end of last 32-byte src chunk */
 227 .Loop5:
 228 #endif
 229 EX(10f) l32i    a9, a2, 0
 230 EX(10f) l32i    a8, a2, 4
 231 EX(11f) s32i    a9, a3, 0
 232 EX(11f) s32i    a8, a3, 4
 233         ONES_ADD(a5, a9)
 234         ONES_ADD(a5, a8)
 235 EX(10f) l32i    a9, a2, 8
 236 EX(10f) l32i    a8, a2, 12
 237 EX(11f) s32i    a9, a3, 8
 238 EX(11f) s32i    a8, a3, 12
 239         ONES_ADD(a5, a9)
 240         ONES_ADD(a5, a8)
 241 EX(10f) l32i    a9, a2, 16
 242 EX(10f) l32i    a8, a2, 20
 243 EX(11f) s32i    a9, a3, 16
 244 EX(11f) s32i    a8, a3, 20
 245         ONES_ADD(a5, a9)
 246         ONES_ADD(a5, a8)
 247 EX(10f) l32i    a9, a2, 24
 248 EX(10f) l32i    a8, a2, 28
 249 EX(11f) s32i    a9, a3, 24
 250 EX(11f) s32i    a8, a3, 28
 251         ONES_ADD(a5, a9)
 252         ONES_ADD(a5, a8)
 253         addi    a2, a2, 32
 254         addi    a3, a3, 32
 255 #if !XCHAL_HAVE_LOOPS
 256         blt     a2, a10, .Loop5
 257 #endif
 258 2:
 259         extui   a10, a4, 2, 3   /* remaining 4-byte chunks */
 260         extui   a4, a4, 0, 2    /* reset len for general-case, 2-byte chunks */
 261 #if XCHAL_HAVE_LOOPS
 262         loopgtz a10, 3f
 263 #else
 264         beqz    a10, 3f
 265         slli    a10, a10, 2
 266         add     a10, a10, a2    /* a10 = end of last 4-byte src chunk */
 267 .Loop6:
 268 #endif
 269 EX(10f) l32i    a9, a2, 0
 270 EX(11f) s32i    a9, a3, 0
 271         ONES_ADD(a5, a9)
 272         addi    a2, a2, 4
 273         addi    a3, a3, 4
 274 #if !XCHAL_HAVE_LOOPS
 275         blt     a2, a10, .Loop6
 276 #endif
 277 3:
 278         /*
 279         Control comes to here in two cases: (1) It may fall through
 280         to here from the 4-byte alignment case to process, at most,
 281         one 2-byte chunk.  (2) It branches to here from above if
 282         either src or dst is 2-byte aligned, and we process all bytes
 283         here, except for perhaps a trailing odd byte.  It's
 284         inefficient, so align your addresses to 4-byte boundaries.
 285 
 286         a2 = src
 287         a3 = dst
 288         a4 = len
 289         a5 = sum
 290         */
 291         srli    a10, a4, 1      /* 2-byte chunks */
 292 #if XCHAL_HAVE_LOOPS
 293         loopgtz a10, 4f
 294 #else
 295         beqz    a10, 4f
 296         slli    a10, a10, 1
 297         add     a10, a10, a2    /* a10 = end of last 2-byte src chunk */
 298 .Loop7:
 299 #endif
 300 EX(10f) l16ui   a9, a2, 0
 301 EX(11f) s16i    a9, a3, 0
 302         ONES_ADD(a5, a9)
 303         addi    a2, a2, 2
 304         addi    a3, a3, 2
 305 #if !XCHAL_HAVE_LOOPS
 306         blt     a2, a10, .Loop7
 307 #endif
 308 4:
 309         /* This section processes a possible trailing odd byte. */
 310         _bbci.l a4, 0, 8f       /* 1-byte chunk */
 311 EX(10f) l8ui    a9, a2, 0
 312 EX(11f) s8i     a9, a3, 0
 313 #ifdef __XTENSA_EB__
 314         slli    a9, a9, 8       /* shift byte to bits 8..15 */
 315 #endif
 316         ONES_ADD(a5, a9)
 317 8:
 318         mov     a2, a5
 319         abi_ret_default
 320 
 321 5:
 322         /* Control branch to here when either src or dst is odd.  We
 323         process all bytes using 8-bit accesses.  Grossly inefficient,
 324         so don't feed us an odd address. */
 325 
 326         srli    a10, a4, 1      /* handle in pairs for 16-bit csum */
 327 #if XCHAL_HAVE_LOOPS
 328         loopgtz a10, 6f
 329 #else
 330         beqz    a10, 6f
 331         slli    a10, a10, 1
 332         add     a10, a10, a2    /* a10 = end of last odd-aligned, 2-byte src chunk */
 333 .Loop8:
 334 #endif
 335 EX(10f) l8ui    a9, a2, 0
 336 EX(10f) l8ui    a8, a2, 1
 337 EX(11f) s8i     a9, a3, 0
 338 EX(11f) s8i     a8, a3, 1
 339 #ifdef __XTENSA_EB__
 340         slli    a9, a9, 8       /* combine into a single 16-bit value */
 341 #else                           /* for checksum computation */
 342         slli    a8, a8, 8
 343 #endif
 344         or      a9, a9, a8
 345         ONES_ADD(a5, a9)
 346         addi    a2, a2, 2
 347         addi    a3, a3, 2
 348 #if !XCHAL_HAVE_LOOPS
 349         blt     a2, a10, .Loop8
 350 #endif
 351 6:
 352         j       4b              /* process the possible trailing odd byte */
 353 
 354 ENDPROC(csum_partial_copy_generic)
 355 
 356 
 357 # Exception handler:
 358 .section .fixup, "ax"
 359 /*
 360         a6  = src_err_ptr
 361         a7  = dst_err_ptr
 362         a11 = original len for exception handling
 363         a12 = original dst for exception handling
 364 */
 365 
 366 10:
 367         _movi   a2, -EFAULT
 368         s32i    a2, a6, 0       /* src_err_ptr */
 369 
 370         # clear the complete destination - computing the rest
 371         # is too much work
 372         movi    a2, 0
 373 #if XCHAL_HAVE_LOOPS
 374         loopgtz a11, 2f
 375 #else
 376         beqz    a11, 2f
 377         add     a11, a11, a12   /* a11 = ending address */
 378 .Leloop:
 379 #endif
 380         s8i     a2, a12, 0
 381         addi    a12, a12, 1
 382 #if !XCHAL_HAVE_LOOPS
 383         blt     a12, a11, .Leloop
 384 #endif
 385 2:
 386         abi_ret_default
 387 
 388 11:
 389         movi    a2, -EFAULT
 390         s32i    a2, a7, 0       /* dst_err_ptr */
 391         movi    a2, 0
 392         abi_ret_default
 393 
 394 .previous

/* [<][>][^][v][top][bottom][index][help] */