do_csum.S
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *
  3.  * Optmized version of the standard do_csum() function
  4.  *
  5.  * Return: a 64bit quantity containing the 16bit Internet checksum
  6.  *
  7.  * Inputs:
  8.  * in0: address of buffer to checksum (char *)
  9.  * in1: length of the buffer (int)
  10.  *
  11.  * Copyright (C) 1999, 2001 Hewlett-Packard Co
  12.  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  13.  *
  14.  * 01/04/18 Jun Nakajima <jun.nakajima@intel.com>
  15.  * Clean up and optimize and the software pipeline, loading two
  16.  * back-to-back 8-byte words per loop. Clean up the initialization
  17.  * for the loop. Support the cases where load latency = 1 or 2.
  18.  * Set CONFIG_IA64_LOAD_LATENCY to 1 or 2 (default).
  19.  */
  20. #include <asm/asmmacro.h>
  21. //
  22. // Theory of operations:
  23. // The goal is to go as quickly as possible to the point where
  24. // we can checksum 16 bytes/loop. Before reaching that point we must
  25. // take care of incorrect alignment of first byte.
  26. //
  27. // The code hereafter also takes care of the "tail" part of the buffer
  28. // before entering the core loop, if any. The checksum is a sum so it
  29. // allows us to commute operations. So we do the "head" and "tail"
  30. // first to finish at full speed in the body. Once we get the head and
  31. // tail values, we feed them into the pipeline, very handy initialization.
  32. //
  33. // Of course we deal with the special case where the whole buffer fits
  34. // into one 8 byte word. In this case we have only one entry in the pipeline.
  35. //
  36. // We use a (LOAD_LATENCY+2)-stage pipeline in the loop to account for
  37. // possible load latency and also to accomodate for head and tail.
  38. //
  39. // The end of the function deals with folding the checksum from 64bits
  40. // down to 16bits taking care of the carry.
  41. //
  42. // This version avoids synchronization in the core loop by also using a
  43. // pipeline for the accumulation of the checksum in resultx[] (x=1,2).
  44. //
  45. //  wordx[] (x=1,2)
  46. // |---|
  47. //      |   | 0 : new value loaded in pipeline
  48. // |---|
  49. //      |   | - : in transit data
  50. // |---|
  51. //      |   | LOAD_LATENCY : current value to add to checksum
  52. // |---|
  53. //      |   | LOAD_LATENCY+1 : previous value added to checksum
  54. //      |---| (previous iteration)
  55. //
  56. // resultx[] (x=1,2)
  57. // |---|
  58. //      |   | 0 : initial value
  59. // |---|
  60. //      |   | LOAD_LATENCY-1 : new checksum
  61. // |---|
  62. //      |   | LOAD_LATENCY : previous value of checksum
  63. // |---|
  64. //      |   | LOAD_LATENCY+1 : final checksum when out of the loop
  65. //      |---|
  66. //
  67. //
  68. // See RFC1071 "Computing the Internet Checksum" for various techniques for
  69. // calculating the Internet checksum.
  70. //
  71. // NOT YET DONE:
  72. // - use the lfetch instruction to augment the chances of the data being in
  73. //   the cache when we need it.
  74. // - Maybe another algorithm which would take care of the folding at the
  75. //   end in a different manner
  76. // - Work with people more knowledgeable than me on the network stack
  77. //   to figure out if we could not split the function depending on the
  78. //   type of packet or alignment we get. Like the ip_fast_csum() routine
  79. //   where we know we have at least 20bytes worth of data to checksum.
  80. // - Do a better job of handling small packets.
  81. #define saved_pfs r11
  82. #define hmask r16
  83. #define tmask r17
  84. #define first1 r18
  85. #define firstval r19
  86. #define firstoff r20
  87. #define last r21
  88. #define lastval r22
  89. #define lastoff r23
  90. #define saved_lc r24
  91. #define saved_pr r25
  92. #define tmp1 r26
  93. #define tmp2 r27
  94. #define tmp3 r28
  95. #define carry1 r29
  96. #define carry2 r30
  97. #define first2 r31
  98. #define buf in0
  99. #define len in1
  100. #ifndef CONFIG_IA64_LOAD_LATENCY
  101. #define CONFIG_IA64_LOAD_LATENCY 2
  102. #endif
  103. #define LOAD_LATENCY 2 // XXX fix me
  104. #if (LOAD_LATENCY != 1) && (LOAD_LATENCY != 2)
  105. # error "Only 1 or 2 is supported/tested for LOAD_LATENCY."
  106. #endif
  107. #define PIPE_DEPTH (LOAD_LATENCY+2)
  108. #define ELD p[LOAD_LATENCY] // end of load
  109. #define ELD_1 p[LOAD_LATENCY+1] // and next stage
  110. // unsigned long do_csum(unsigned char *buf,long len)
  111. GLOBAL_ENTRY(do_csum)
  112. .prologue
  113. .save ar.pfs, saved_pfs
  114. alloc saved_pfs=ar.pfs,2,16,1,16
  115. .rotr word1[4], word2[4],result1[4],result2[4]
  116. .rotp p[PIPE_DEPTH]
  117. mov ret0=r0 // in case we have zero length
  118. cmp.lt p0,p6=r0,len // check for zero length or negative (32bit len)
  119. ;; // avoid WAW on CFM
  120. mov tmp3=0x7 // a temporary mask/value
  121. add tmp1=buf,len // last byte's address
  122. (p6) br.ret.spnt.many rp // return if true (hope we can avoid that)
  123. and firstoff=7,buf // how many bytes off for first1 element
  124. tbit.nz p15,p0=buf,0 // is buf an odd address ?
  125. mov hmask=-1 // intialize head mask
  126. ;;
  127. andcm first1=buf,tmp3 // 8byte aligned down address of first1 element
  128. mov tmask=-1 // initialize tail mask
  129. adds tmp2=-1,tmp1 // last-1
  130. ;;
  131. and lastoff=7,tmp1 // how many bytes off for last element
  132. andcm last=tmp2,tmp3 // address of word containing last byte
  133. .save pr, saved_pr
  134. mov saved_pr=pr // preserve predicates (rotation)
  135. ;;
  136. sub tmp3=last,first1 // tmp3=distance from first1 to last
  137. cmp.eq p8,p9=last,first1 // everything fits in one word ?
  138. sub tmp1=8,lastoff // complement to lastoff
  139. ld8 firstval=[first1],8 // load,ahead of time, "first1" word
  140. shl tmp2=firstoff,3 // number of bits
  141. ;;
  142. and tmp1=7, tmp1 // make sure that if tmp1==8 -> tmp1=0
  143. (p9) ld8 lastval=[last] // load,ahead of time, "last" word, if needed
  144. (p9) adds tmp3=-8,tmp3 // effectively loaded
  145. ;;
  146. (p8) mov lastval=r0 // we don't need lastval if first1==last
  147. shl tmp1=tmp1,3 // number of bits
  148. shl hmask=hmask,tmp2 // build head mask, mask off [0,first1off[
  149. ;;
  150. shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff]
  151. .save ar.lc, saved_lc
  152. mov saved_lc=ar.lc // save lc
  153. ;;
  154. .body
  155. #define count tmp3
  156. (p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only
  157. (p9) and word2[0]=lastval,tmask // mask last it as appropriate
  158. shr.u count=count,3 // we do 8 bytes per loop (count)
  159. ;;
  160. // If count is odd, finish this 8-byte word so that we can
  161. // load two back-to-back 8-byte words per loop thereafter.
  162. tbit.nz p10,p11=count,0 // if (count is odd)
  163. and word1[0]=firstval,hmask // and mask it as appropriate
  164. ;;
  165. (p8) mov result1[0]=word1[0]
  166. (p9) add result1[0]=word1[0],word2[0]
  167. ;;
  168. cmp.ltu p6,p0=result1[0],word1[0] // check the carry
  169. ;;
  170. (p6) adds result1[0]=1,result1[0]
  171. (p8) br.cond.dptk .do_csum_exit // if (within an 8-byte word)
  172. ;;
  173. (p11) br.cond.dptk .do_csum16 // if (count is even)
  174. ;;
  175. // Here count is odd.
  176. ld8 word1[1]=[first1],8 // load an 8-byte word
  177. cmp.eq p9,p10=1,count // if (count == 1)
  178. adds count=-1,count // loaded an 8-byte word
  179. ;;
  180. add result1[0]=result1[0],word1[1]
  181. ;;
  182. cmp.ltu p6,p0=result1[0],word1[1]
  183. ;;
  184. (p6) adds result1[0]=1,result1[0]
  185. ;;
  186. (p9) br.cond.sptk .do_csum_exit // if (count == 1) exit
  187. // Fall through to caluculate the checksum, feeding result1[0] as
  188. // the initial value in result1[0].
  189. ;;
  190. //
  191. // Calculate the checksum loading two 8-byte words per loop.
  192. //
  193. .do_csum16:
  194. mov saved_lc=ar.lc
  195. shr.u count=count,1 // we do 16 bytes per loop
  196. ;;
  197. cmp.eq p9,p10=r0,count // if (count == 0)
  198. brp.loop.imp 1f,2f
  199. ;;
  200. adds count=-1,count
  201. mov ar.ec=PIPE_DEPTH
  202. ;;
  203. mov ar.lc=count // set lc
  204. ;;
  205. // result1[0] must be initialized in advance.
  206. mov result2[0]=r0
  207. ;;
  208. mov pr.rot=1<<16
  209. ;;
  210. mov carry1=r0
  211. mov carry2=r0
  212. ;;
  213. add first2=8,first1
  214. ;;
  215. (p9) br.cond.sptk .do_csum_exit
  216. ;;
  217. nop.m 0
  218. nop.i 0
  219. ;;
  220. .align 32
  221. 1:
  222. (ELD_1) cmp.ltu p31,p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1]
  223. (p32) adds carry1=1,carry1
  224. (ELD_1) cmp.ltu p47,p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1]
  225. (p48) adds carry2=1,carry2
  226. (ELD) add result1[LOAD_LATENCY-1]=result1[LOAD_LATENCY],word1[LOAD_LATENCY]
  227. (ELD) add result2[LOAD_LATENCY-1]=result2[LOAD_LATENCY],word2[LOAD_LATENCY]
  228. 2:
  229. (p16) ld8 word1[0]=[first1],16
  230. (p16) ld8 word2[0]=[first2],16
  231. br.ctop.sptk 1b
  232. ;;
  233. // Since len is a 32-bit value, carry cannot be larger than
  234. // a 64-bit value.
  235. (p32) adds carry1=1,carry1 // since we miss the last one
  236. (p48) adds carry2=1,carry2
  237. ;;
  238. add result1[LOAD_LATENCY+1]=result1[LOAD_LATENCY+1],carry1
  239. add result2[LOAD_LATENCY+1]=result2[LOAD_LATENCY+1],carry2
  240. ;;
  241. cmp.ltu p6,p0=result1[LOAD_LATENCY+1],carry1
  242. cmp.ltu p7,p0=result2[LOAD_LATENCY+1],carry2
  243. ;;
  244. (p6) adds result1[LOAD_LATENCY+1]=1,result1[LOAD_LATENCY+1]
  245. (p7) adds result2[LOAD_LATENCY+1]=1,result2[LOAD_LATENCY+1]
  246. ;;
  247. add result1[0]=result1[LOAD_LATENCY+1],result2[LOAD_LATENCY+1]
  248. ;;
  249. cmp.ltu p6,p0=result1[0],result2[LOAD_LATENCY+1]
  250. ;;
  251. (p6) adds result1[0]=1,result1[0]
  252. ;;
  253. .do_csum_exit:
  254. movl tmp3=0xffffffff
  255. ;;
  256. // XXX Fixme
  257. //
  258. // now fold 64 into 16 bits taking care of carry
  259. // that's not very good because it has lots of sequentiality
  260. //
  261. and tmp1=result1[0],tmp3
  262. shr.u tmp2=result1[0],32
  263. ;;
  264. add result1[0]=tmp1,tmp2
  265. shr.u tmp3=tmp3,16
  266. ;;
  267. and tmp1=result1[0],tmp3
  268. shr.u tmp2=result1[0],16
  269. ;;
  270. add result1[0]=tmp1,tmp2
  271. ;;
  272. and tmp1=result1[0],tmp3
  273. shr.u tmp2=result1[0],16
  274. ;;
  275. add result1[0]=tmp1,tmp2
  276. ;;
  277. and tmp1=result1[0],tmp3
  278. shr.u tmp2=result1[0],16
  279. ;;
  280. add ret0=tmp1,tmp2
  281. mov pr=saved_pr,0xffffffffffff0000
  282. ;;
  283. // if buf was odd then swap bytes
  284. mov ar.pfs=saved_pfs // restore ar.ec
  285. (p15) mux1 ret0=ret0,@rev // reverse word
  286. ;;
  287. mov ar.lc=saved_lc
  288. (p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes
  289. br.ret.sptk.many rp
  290. // I (Jun Nakajima) wrote an equivalent code (see below), but it was
  291. // not much better than the original. So keep the original there so that
  292. // someone else can challenge.
  293. //
  294. // shr.u word1[0]=result1[0],32
  295. // zxt4 result1[0]=result1[0]
  296. // ;;
  297. // add result1[0]=result1[0],word1[0]
  298. // ;;
  299. // zxt2 result2[0]=result1[0]
  300. // extr.u word1[0]=result1[0],16,16
  301. // shr.u carry1=result1[0],32
  302. // ;;
  303. // add result2[0]=result2[0],word1[0]
  304. // ;;
  305. // add result2[0]=result2[0],carry1
  306. // ;;
  307. // extr.u ret0=result2[0],16,16
  308. // ;;
  309. // add ret0=ret0,result2[0]
  310. // ;;
  311. // zxt2 ret0=ret0
  312. // mov ar.pfs=saved_pfs  // restore ar.ec
  313. // mov pr=saved_pr,0xffffffffffff0000
  314. // ;;
  315. // // if buf was odd then swap bytes
  316. // mov ar.lc=saved_lc
  317. //(p15) mux1 ret0=ret0,@rev // reverse word
  318. // ;;
  319. //(p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes
  320. // br.ret.sptk.many rp
  321. END(do_csum)