checksum_32.S 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. * This file contains assembly-language implementations
  3. * of IP-style 1's complement checksum routines.
  4. *
  5. * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version
  10. * 2 of the License, or (at your option) any later version.
  11. *
  12. * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
  13. */
  14. #include <linux/sys.h>
  15. #include <asm/processor.h>
  16. #include <asm/cache.h>
  17. #include <asm/errno.h>
  18. #include <asm/ppc_asm.h>
  19. #include <asm/export.h>
  20. .text
  21. /*
  22. * computes the checksum of a memory block at buff, length len,
  23. * and adds in "sum" (32-bit)
  24. *
  25. * __csum_partial(buff, len, sum)
  26. */
  27. _GLOBAL(__csum_partial)
  28. subi r3,r3,4
  29. srawi. r6,r4,2 /* Divide len by 4 and also clear carry */
  30. beq 3f /* if we're doing < 4 bytes */
  31. andi. r0,r3,2 /* Align buffer to longword boundary */
  32. beq+ 1f
  33. lhz r0,4(r3) /* do 2 bytes to get aligned */
  34. subi r4,r4,2
  35. addi r3,r3,2
  36. srwi. r6,r4,2 /* # words to do */
  37. adde r5,r5,r0
  38. beq 3f
  39. 1: andi. r6,r6,3 /* Prepare to handle words 4 by 4 */
  40. beq 21f
  41. mtctr r6
  42. 2: lwzu r0,4(r3)
  43. adde r5,r5,r0
  44. bdnz 2b
  45. 21: srwi. r6,r4,4 /* # blocks of 4 words to do */
  46. beq 3f
  47. lwz r0,4(r3)
  48. mtctr r6
  49. lwz r6,8(r3)
  50. adde r5,r5,r0
  51. lwz r7,12(r3)
  52. adde r5,r5,r6
  53. lwzu r8,16(r3)
  54. adde r5,r5,r7
  55. bdz 23f
  56. 22: lwz r0,4(r3)
  57. adde r5,r5,r8
  58. lwz r6,8(r3)
  59. adde r5,r5,r0
  60. lwz r7,12(r3)
  61. adde r5,r5,r6
  62. lwzu r8,16(r3)
  63. adde r5,r5,r7
  64. bdnz 22b
  65. 23: adde r5,r5,r8
  66. 3: andi. r0,r4,2
  67. beq+ 4f
  68. lhz r0,4(r3)
  69. addi r3,r3,2
  70. adde r5,r5,r0
  71. 4: andi. r0,r4,1
  72. beq+ 5f
  73. lbz r0,4(r3)
  74. slwi r0,r0,8 /* Upper byte of word */
  75. adde r5,r5,r0
  76. 5: addze r3,r5 /* add in final carry */
  77. blr
  78. EXPORT_SYMBOL(__csum_partial)
  79. /*
  80. * Computes the checksum of a memory block at src, length len,
  81. * and adds in "sum" (32-bit), while copying the block to dst.
  82. * If an access exception occurs on src or dst, it stores -EFAULT
  83. * to *src_err or *dst_err respectively, and (for an error on
  84. * src) zeroes the rest of dst.
  85. *
  86. * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
  87. */
  88. #define CSUM_COPY_16_BYTES_WITHEX(n) \
  89. 8 ## n ## 0: \
  90. lwz r7,4(r4); \
  91. 8 ## n ## 1: \
  92. lwz r8,8(r4); \
  93. 8 ## n ## 2: \
  94. lwz r9,12(r4); \
  95. 8 ## n ## 3: \
  96. lwzu r10,16(r4); \
  97. 8 ## n ## 4: \
  98. stw r7,4(r6); \
  99. adde r12,r12,r7; \
  100. 8 ## n ## 5: \
  101. stw r8,8(r6); \
  102. adde r12,r12,r8; \
  103. 8 ## n ## 6: \
  104. stw r9,12(r6); \
  105. adde r12,r12,r9; \
  106. 8 ## n ## 7: \
  107. stwu r10,16(r6); \
  108. adde r12,r12,r10
  109. #define CSUM_COPY_16_BYTES_EXCODE(n) \
  110. EX_TABLE(8 ## n ## 0b, src_error); \
  111. EX_TABLE(8 ## n ## 1b, src_error); \
  112. EX_TABLE(8 ## n ## 2b, src_error); \
  113. EX_TABLE(8 ## n ## 3b, src_error); \
  114. EX_TABLE(8 ## n ## 4b, dst_error); \
  115. EX_TABLE(8 ## n ## 5b, dst_error); \
  116. EX_TABLE(8 ## n ## 6b, dst_error); \
  117. EX_TABLE(8 ## n ## 7b, dst_error);
  118. .text
  119. .stabs "arch/powerpc/lib/",N_SO,0,0,0f
  120. .stabs "checksum_32.S",N_SO,0,0,0f
  121. 0:
  122. CACHELINE_BYTES = L1_CACHE_BYTES
  123. LG_CACHELINE_BYTES = L1_CACHE_SHIFT
  124. CACHELINE_MASK = (L1_CACHE_BYTES-1)
  125. _GLOBAL(csum_partial_copy_generic)
  126. stwu r1,-16(r1)
  127. stw r7,12(r1)
  128. stw r8,8(r1)
  129. addic r12,r6,0
  130. addi r6,r4,-4
  131. neg r0,r4
  132. addi r4,r3,-4
  133. andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */
  134. crset 4*cr7+eq
  135. beq 58f
  136. cmplw 0,r5,r0 /* is this more than total to do? */
  137. blt 63f /* if not much to do */
  138. rlwinm r7,r6,3,0x8
  139. rlwnm r12,r12,r7,0,31 /* odd destination address: rotate one byte */
  140. cmplwi cr7,r7,0 /* is destination address even ? */
  141. andi. r8,r0,3 /* get it word-aligned first */
  142. mtctr r8
  143. beq+ 61f
  144. li r3,0
  145. 70: lbz r9,4(r4) /* do some bytes */
  146. addi r4,r4,1
  147. slwi r3,r3,8
  148. rlwimi r3,r9,0,24,31
  149. 71: stb r9,4(r6)
  150. addi r6,r6,1
  151. bdnz 70b
  152. adde r12,r12,r3
  153. 61: subf r5,r0,r5
  154. srwi. r0,r0,2
  155. mtctr r0
  156. beq 58f
  157. 72: lwzu r9,4(r4) /* do some words */
  158. adde r12,r12,r9
  159. 73: stwu r9,4(r6)
  160. bdnz 72b
  161. 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
  162. clrlwi r5,r5,32-LG_CACHELINE_BYTES
  163. li r11,4
  164. beq 63f
  165. /* Here we decide how far ahead to prefetch the source */
  166. li r3,4
  167. cmpwi r0,1
  168. li r7,0
  169. ble 114f
  170. li r7,1
  171. #if MAX_COPY_PREFETCH > 1
  172. /* Heuristically, for large transfers we prefetch
  173. MAX_COPY_PREFETCH cachelines ahead. For small transfers
  174. we prefetch 1 cacheline ahead. */
  175. cmpwi r0,MAX_COPY_PREFETCH
  176. ble 112f
  177. li r7,MAX_COPY_PREFETCH
  178. 112: mtctr r7
  179. 111: dcbt r3,r4
  180. addi r3,r3,CACHELINE_BYTES
  181. bdnz 111b
  182. #else
  183. dcbt r3,r4
  184. addi r3,r3,CACHELINE_BYTES
  185. #endif /* MAX_COPY_PREFETCH > 1 */
  186. 114: subf r8,r7,r0
  187. mr r0,r7
  188. mtctr r8
  189. 53: dcbt r3,r4
  190. 54: dcbz r11,r6
  191. /* the main body of the cacheline loop */
  192. CSUM_COPY_16_BYTES_WITHEX(0)
  193. #if L1_CACHE_BYTES >= 32
  194. CSUM_COPY_16_BYTES_WITHEX(1)
  195. #if L1_CACHE_BYTES >= 64
  196. CSUM_COPY_16_BYTES_WITHEX(2)
  197. CSUM_COPY_16_BYTES_WITHEX(3)
  198. #if L1_CACHE_BYTES >= 128
  199. CSUM_COPY_16_BYTES_WITHEX(4)
  200. CSUM_COPY_16_BYTES_WITHEX(5)
  201. CSUM_COPY_16_BYTES_WITHEX(6)
  202. CSUM_COPY_16_BYTES_WITHEX(7)
  203. #endif
  204. #endif
  205. #endif
  206. bdnz 53b
  207. cmpwi r0,0
  208. li r3,4
  209. li r7,0
  210. bne 114b
  211. 63: srwi. r0,r5,2
  212. mtctr r0
  213. beq 64f
  214. 30: lwzu r0,4(r4)
  215. adde r12,r12,r0
  216. 31: stwu r0,4(r6)
  217. bdnz 30b
  218. 64: andi. r0,r5,2
  219. beq+ 65f
  220. 40: lhz r0,4(r4)
  221. addi r4,r4,2
  222. 41: sth r0,4(r6)
  223. adde r12,r12,r0
  224. addi r6,r6,2
  225. 65: andi. r0,r5,1
  226. beq+ 66f
  227. 50: lbz r0,4(r4)
  228. 51: stb r0,4(r6)
  229. slwi r0,r0,8
  230. adde r12,r12,r0
  231. 66: addze r3,r12
  232. addi r1,r1,16
  233. beqlr+ cr7
  234. rlwinm r3,r3,8,0,31 /* odd destination address: rotate one byte */
  235. blr
  236. /* read fault */
  237. src_error:
  238. lwz r7,12(r1)
  239. addi r1,r1,16
  240. cmpwi cr0,r7,0
  241. beqlr
  242. li r0,-EFAULT
  243. stw r0,0(r7)
  244. blr
  245. /* write fault */
  246. dst_error:
  247. lwz r8,8(r1)
  248. addi r1,r1,16
  249. cmpwi cr0,r8,0
  250. beqlr
  251. li r0,-EFAULT
  252. stw r0,0(r8)
  253. blr
  254. EX_TABLE(70b, src_error);
  255. EX_TABLE(71b, dst_error);
  256. EX_TABLE(72b, src_error);
  257. EX_TABLE(73b, dst_error);
  258. EX_TABLE(54b, dst_error);
  259. /*
  260. * this stuff handles faults in the cacheline loop and branches to either
  261. * src_error (if in read part) or dst_error (if in write part)
  262. */
  263. CSUM_COPY_16_BYTES_EXCODE(0)
  264. #if L1_CACHE_BYTES >= 32
  265. CSUM_COPY_16_BYTES_EXCODE(1)
  266. #if L1_CACHE_BYTES >= 64
  267. CSUM_COPY_16_BYTES_EXCODE(2)
  268. CSUM_COPY_16_BYTES_EXCODE(3)
  269. #if L1_CACHE_BYTES >= 128
  270. CSUM_COPY_16_BYTES_EXCODE(4)
  271. CSUM_COPY_16_BYTES_EXCODE(5)
  272. CSUM_COPY_16_BYTES_EXCODE(6)
  273. CSUM_COPY_16_BYTES_EXCODE(7)
  274. #endif
  275. #endif
  276. #endif
  277. EX_TABLE(30b, src_error);
  278. EX_TABLE(31b, dst_error);
  279. EX_TABLE(40b, src_error);
  280. EX_TABLE(41b, dst_error);
  281. EX_TABLE(50b, src_error);
  282. EX_TABLE(51b, dst_error);
  283. EXPORT_SYMBOL(csum_partial_copy_generic)
  284. /*
  285. * __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  286. * const struct in6_addr *daddr,
  287. * __u32 len, __u8 proto, __wsum sum)
  288. */
  289. _GLOBAL(csum_ipv6_magic)
  290. lwz r8, 0(r3)
  291. lwz r9, 4(r3)
  292. addc r0, r7, r8
  293. lwz r10, 8(r3)
  294. adde r0, r0, r9
  295. lwz r11, 12(r3)
  296. adde r0, r0, r10
  297. lwz r8, 0(r4)
  298. adde r0, r0, r11
  299. lwz r9, 4(r4)
  300. adde r0, r0, r8
  301. lwz r10, 8(r4)
  302. adde r0, r0, r9
  303. lwz r11, 12(r4)
  304. adde r0, r0, r10
  305. add r5, r5, r6 /* assumption: len + proto doesn't carry */
  306. adde r0, r0, r11
  307. adde r0, r0, r5
  308. addze r0, r0
  309. rotlwi r3, r0, 16
  310. add r3, r0, r3
  311. not r3, r3
  312. rlwinm r3, r3, 16, 16, 31
  313. blr
  314. EXPORT_SYMBOL(csum_ipv6_magic)