1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Quick'n'dirty IP checksum ... 7 * 8 * Copyright (C) 1998, 1999 Ralf Baechle 9 * Copyright (C) 1999 Silicon Graphics, Inc. 10 */ 11#include <asm/asm.h> 12#include <asm/regdef.h> 13 14#ifdef CONFIG_64BIT 15/* 16 * As we are sharing code base with the mips32 tree (which use the o32 ABI 17 * register definitions). We need to redefine the register definitions from 18 * the n64 ABI register naming to the o32 ABI register naming. 19 */ 20#undef t0 21#undef t1 22#undef t2 23#undef t3 24#define t0 $8 25#define t1 $9 26#define t2 $10 27#define t3 $11 28#define t4 $12 29#define t5 $13 30#define t6 $14 31#define t7 $15 32 33#define USE_DOUBLE 34#endif 35 36#ifdef USE_DOUBLE 37 38#define LOAD ld 39#define ADD daddu 40#define NBYTES 8 41 42#else 43 44#define LOAD lw 45#define ADD addu 46#define NBYTES 4 47 48#endif /* USE_DOUBLE */ 49 50#define UNIT(unit) ((unit)*NBYTES) 51 52#define ADDC(sum,reg) \ 53 ADD sum, reg; \ 54 sltu v1, sum, reg; \ 55 ADD sum, v1 56 57#define CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3) \ 58 LOAD _t0, (offset + UNIT(0))(src); \ 59 LOAD _t1, (offset + UNIT(1))(src); \ 60 LOAD _t2, (offset + UNIT(2))(src); \ 61 LOAD _t3, (offset + UNIT(3))(src); \ 62 ADDC(sum, _t0); \ 63 ADDC(sum, _t1); \ 64 ADDC(sum, _t2); \ 65 ADDC(sum, _t3) 66 67#ifdef USE_DOUBLE 68#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3) \ 69 CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3) 70#else 71#define CSUM_BIGCHUNK(src, offset, sum, _t0, _t1, _t2, _t3) \ 72 CSUM_BIGCHUNK1(src, offset, sum, _t0, _t1, _t2, _t3); \ 73 CSUM_BIGCHUNK1(src, offset + 0x10, sum, _t0, _t1, _t2, _t3) 74#endif 75 76/* 77 * a0: source address 78 * a1: length of the area to checksum 79 * a2: partial checksum 80 */ 81 82#define src a0 83#define sum v0 84 85 .text 86 .set noreorder 87 .align 5 88LEAF(csum_partial) 89 move sum, zero 90 move t7, zero 91 92 sltiu t8, a1, 0x8 93 bnez t8, small_csumcpy /* < 8 bytes to copy */ 94 move t2, a1 95 96 andi t7, src, 0x1 /* odd buffer? */ 97 98hword_align: 99 beqz t7, word_align 100 andi t8, src, 0x2 101 102 lbu t0, (src) 103 LONG_SUBU a1, a1, 0x1 104#ifdef __MIPSEL__ 105 sll t0, t0, 8 106#endif 107 ADDC(sum, t0) 108 PTR_ADDU src, src, 0x1 109 andi t8, src, 0x2 110 111word_align: 112 beqz t8, dword_align 113 sltiu t8, a1, 56 114 115 lhu t0, (src) 116 LONG_SUBU a1, a1, 0x2 117 ADDC(sum, t0) 118 sltiu t8, a1, 56 119 PTR_ADDU src, src, 0x2 120 121dword_align: 122 bnez t8, do_end_words 123 move t8, a1 124 125 andi t8, src, 0x4 126 beqz t8, qword_align 127 andi t8, src, 0x8 128 129 lw t0, 0x00(src) 130 LONG_SUBU a1, a1, 0x4 131 ADDC(sum, t0) 132 PTR_ADDU src, src, 0x4 133 andi t8, src, 0x8 134 135qword_align: 136 beqz t8, oword_align 137 andi t8, src, 0x10 138 139#ifdef USE_DOUBLE 140 ld t0, 0x00(src) 141 LONG_SUBU a1, a1, 0x8 142 ADDC(sum, t0) 143#else 144 lw t0, 0x00(src) 145 lw t1, 0x04(src) 146 LONG_SUBU a1, a1, 0x8 147 ADDC(sum, t0) 148 ADDC(sum, t1) 149#endif 150 PTR_ADDU src, src, 0x8 151 andi t8, src, 0x10 152 153oword_align: 154 beqz t8, begin_movement 155 LONG_SRL t8, a1, 0x7 156 157#ifdef USE_DOUBLE 158 ld t0, 0x00(src) 159 ld t1, 0x08(src) 160 ADDC(sum, t0) 161 ADDC(sum, t1) 162#else 163 CSUM_BIGCHUNK1(src, 0x00, sum, t0, t1, t3, t4) 164#endif 165 LONG_SUBU a1, a1, 0x10 166 PTR_ADDU src, src, 0x10 167 LONG_SRL t8, a1, 0x7 168 169begin_movement: 170 beqz t8, 1f 171 andi t2, a1, 0x40 172 173move_128bytes: 174 CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4) 175 CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4) 176 CSUM_BIGCHUNK(src, 0x40, sum, t0, t1, t3, t4) 177 CSUM_BIGCHUNK(src, 0x60, sum, t0, t1, t3, t4) 178 LONG_SUBU t8, t8, 0x01 179 bnez t8, move_128bytes 180 PTR_ADDU src, src, 0x80 181 1821: 183 beqz t2, 1f 184 andi t2, a1, 0x20 185 186move_64bytes: 187 CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4) 188 CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4) 189 PTR_ADDU src, src, 0x40 190 1911: 192 beqz t2, do_end_words 193 andi t8, a1, 0x1c 194 195move_32bytes: 196 CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4) 197 andi t8, a1, 0x1c 198 PTR_ADDU src, src, 0x20 199 200do_end_words: 201 beqz t8, small_csumcpy 202 andi t2, a1, 0x3 203 LONG_SRL t8, t8, 0x2 204 205end_words: 206 lw t0, (src) 207 LONG_SUBU t8, t8, 0x1 208 ADDC(sum, t0) 209 bnez t8, end_words 210 PTR_ADDU src, src, 0x4 211 212/* unknown src alignment and < 8 bytes to go */ 213small_csumcpy: 214 move a1, t2 215 216 andi t0, a1, 4 217 beqz t0, 1f 218 andi t0, a1, 2 219 220 /* Still a full word to go */ 221 ulw t1, (src) 222 PTR_ADDIU src, 4 223 ADDC(sum, t1) 224 2251: move t1, zero 226 beqz t0, 1f 227 andi t0, a1, 1 228 229 /* Still a halfword to go */ 230 ulhu t1, (src) 231 PTR_ADDIU src, 2 232 2331: beqz t0, 1f 234 sll t1, t1, 16 235 236 lbu t2, (src) 237 nop 238 239#ifdef __MIPSEB__ 240 sll t2, t2, 8 241#endif 242 or t1, t2 243 2441: ADDC(sum, t1) 245 246 /* fold checksum */ 247#ifdef USE_DOUBLE 248 dsll32 v1, sum, 0 249 daddu sum, v1 250 sltu v1, sum, v1 251 dsra32 sum, sum, 0 252 addu sum, v1 253#endif 254 sll v1, sum, 16 255 addu sum, v1 256 sltu v1, sum, v1 257 srl sum, sum, 16 258 addu sum, v1 259 260 /* odd buffer alignment? */ 261 beqz t7, 1f 262 nop 263 sll v1, sum, 8 264 srl sum, sum, 8 265 or sum, v1 266 andi sum, 0xffff 2671: 268 .set reorder 269 /* Add the passed partial csum. */ 270 ADDC(sum, a2) 271 jr ra 272 .set noreorder 273 END(csum_partial) 274