vector.S 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. #include <asm/processor.h>
  2. #include <asm/ppc_asm.h>
  3. #include <asm/reg.h>
  4. #include <asm/asm-offsets.h>
  5. #include <asm/cputable.h>
  6. #include <asm/thread_info.h>
  7. #include <asm/page.h>
  8. #include <asm/ptrace.h>
  9. /*
  10. * load_up_altivec(unused, unused, tsk)
  11. * Disable VMX for the task which had it previously,
  12. * and save its vector registers in its thread_struct.
  13. * Enables the VMX for use in the kernel on return.
  14. * On SMP we know the VMX is free, since we give it up every
  15. * switch (ie, no lazy save of the vector registers).
  16. */
  17. _GLOBAL(load_up_altivec)
  18. mfmsr r5 /* grab the current MSR */
  19. oris r5,r5,MSR_VEC@h
  20. MTMSRD(r5) /* enable use of AltiVec now */
  21. isync
  22. /*
  23. * For SMP, we don't do lazy VMX switching because it just gets too
  24. * horrendously complex, especially when a task switches from one CPU
  25. * to another. Instead we call giveup_altvec in switch_to.
  26. * VRSAVE isn't dealt with here, that is done in the normal context
  27. * switch code. Note that we could rely on vrsave value to eventually
  28. * avoid saving all of the VREGs here...
  29. */
  30. #ifndef CONFIG_SMP
  31. LOAD_REG_ADDRBASE(r3, last_task_used_altivec)
  32. toreal(r3)
  33. PPC_LL r4,ADDROFF(last_task_used_altivec)(r3)
  34. PPC_LCMPI 0,r4,0
  35. beq 1f
  36. /* Save VMX state to last_task_used_altivec's THREAD struct */
  37. toreal(r4)
  38. addi r4,r4,THREAD
  39. SAVE_32VRS(0,r5,r4)
  40. mfvscr vr0
  41. li r10,THREAD_VSCR
  42. stvx vr0,r10,r4
  43. /* Disable VMX for last_task_used_altivec */
  44. PPC_LL r5,PT_REGS(r4)
  45. toreal(r5)
  46. PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  47. lis r10,MSR_VEC@h
  48. andc r4,r4,r10
  49. PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  50. 1:
  51. #endif /* CONFIG_SMP */
  52. /* Hack: if we get an altivec unavailable trap with VRSAVE
  53. * set to all zeros, we assume this is a broken application
  54. * that fails to set it properly, and thus we switch it to
  55. * all 1's
  56. */
  57. mfspr r4,SPRN_VRSAVE
  58. cmpwi 0,r4,0
  59. bne+ 1f
  60. li r4,-1
  61. mtspr SPRN_VRSAVE,r4
  62. 1:
  63. /* enable use of VMX after return */
  64. #ifdef CONFIG_PPC32
  65. mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
  66. oris r9,r9,MSR_VEC@h
  67. #else
  68. ld r4,PACACURRENT(r13)
  69. addi r5,r4,THREAD /* Get THREAD */
  70. oris r12,r12,MSR_VEC@h
  71. std r12,_MSR(r1)
  72. #endif
  73. li r4,1
  74. li r10,THREAD_VSCR
  75. stw r4,THREAD_USED_VR(r5)
  76. lvx vr0,r10,r5
  77. mtvscr vr0
  78. REST_32VRS(0,r4,r5)
  79. #ifndef CONFIG_SMP
  80. /* Update last_task_used_altivec to 'current' */
  81. subi r4,r5,THREAD /* Back to 'current' */
  82. fromreal(r4)
  83. PPC_STL r4,ADDROFF(last_task_used_altivec)(r3)
  84. #endif /* CONFIG_SMP */
  85. /* restore registers and return */
  86. blr
  87. _GLOBAL(giveup_altivec_notask)
  88. mfmsr r3
  89. andis. r4,r3,MSR_VEC@h
  90. bnelr /* Already enabled? */
  91. oris r3,r3,MSR_VEC@h
  92. SYNC
  93. MTMSRD(r3) /* enable use of VMX now */
  94. isync
  95. blr
  96. /*
  97. * giveup_altivec(tsk)
  98. * Disable VMX for the task given as the argument,
  99. * and save the vector registers in its thread_struct.
  100. * Enables the VMX for use in the kernel on return.
  101. */
  102. _GLOBAL(giveup_altivec)
  103. mfmsr r5
  104. oris r5,r5,MSR_VEC@h
  105. SYNC
  106. MTMSRD(r5) /* enable use of VMX now */
  107. isync
  108. PPC_LCMPI 0,r3,0
  109. beqlr /* if no previous owner, done */
  110. addi r3,r3,THREAD /* want THREAD of task */
  111. PPC_LL r5,PT_REGS(r3)
  112. PPC_LCMPI 0,r5,0
  113. SAVE_32VRS(0,r4,r3)
  114. mfvscr vr0
  115. li r4,THREAD_VSCR
  116. stvx vr0,r4,r3
  117. beq 1f
  118. PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  119. #ifdef CONFIG_VSX
  120. BEGIN_FTR_SECTION
  121. lis r3,(MSR_VEC|MSR_VSX)@h
  122. FTR_SECTION_ELSE
  123. lis r3,MSR_VEC@h
  124. ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
  125. #else
  126. lis r3,MSR_VEC@h
  127. #endif
  128. andc r4,r4,r3 /* disable FP for previous task */
  129. PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  130. 1:
  131. #ifndef CONFIG_SMP
  132. li r5,0
  133. LOAD_REG_ADDRBASE(r4,last_task_used_altivec)
  134. PPC_STL r5,ADDROFF(last_task_used_altivec)(r4)
  135. #endif /* CONFIG_SMP */
  136. blr
  137. #ifdef CONFIG_VSX
  138. #ifdef CONFIG_PPC32
  139. #error This asm code isn't ready for 32-bit kernels
  140. #endif
  141. /*
  142. * load_up_vsx(unused, unused, tsk)
  143. * Disable VSX for the task which had it previously,
  144. * and save its vector registers in its thread_struct.
  145. * Reuse the fp and vsx saves, but first check to see if they have
  146. * been saved already.
  147. */
  148. _GLOBAL(load_up_vsx)
  149. /* Load FP and VSX registers if they haven't been done yet */
  150. andi. r5,r12,MSR_FP
  151. beql+ load_up_fpu /* skip if already loaded */
  152. andis. r5,r12,MSR_VEC@h
  153. beql+ load_up_altivec /* skip if already loaded */
  154. #ifndef CONFIG_SMP
  155. ld r3,last_task_used_vsx@got(r2)
  156. ld r4,0(r3)
  157. cmpdi 0,r4,0
  158. beq 1f
  159. /* Disable VSX for last_task_used_vsx */
  160. addi r4,r4,THREAD
  161. ld r5,PT_REGS(r4)
  162. ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  163. lis r6,MSR_VSX@h
  164. andc r6,r4,r6
  165. std r6,_MSR-STACK_FRAME_OVERHEAD(r5)
  166. 1:
  167. #endif /* CONFIG_SMP */
  168. ld r4,PACACURRENT(r13)
  169. addi r4,r4,THREAD /* Get THREAD */
  170. li r6,1
  171. stw r6,THREAD_USED_VSR(r4) /* ... also set thread used vsr */
  172. /* enable use of VSX after return */
  173. oris r12,r12,MSR_VSX@h
  174. std r12,_MSR(r1)
  175. #ifndef CONFIG_SMP
  176. /* Update last_task_used_vsx to 'current' */
  177. ld r4,PACACURRENT(r13)
  178. std r4,0(r3)
  179. #endif /* CONFIG_SMP */
  180. b fast_exception_return
  181. /*
  182. * __giveup_vsx(tsk)
  183. * Disable VSX for the task given as the argument.
  184. * Does NOT save vsx registers.
  185. * Enables the VSX for use in the kernel on return.
  186. */
  187. _GLOBAL(__giveup_vsx)
  188. mfmsr r5
  189. oris r5,r5,MSR_VSX@h
  190. mtmsrd r5 /* enable use of VSX now */
  191. isync
  192. cmpdi 0,r3,0
  193. beqlr- /* if no previous owner, done */
  194. addi r3,r3,THREAD /* want THREAD of task */
  195. ld r5,PT_REGS(r3)
  196. cmpdi 0,r5,0
  197. beq 1f
  198. ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  199. lis r3,MSR_VSX@h
  200. andc r4,r4,r3 /* disable VSX for previous task */
  201. std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
  202. 1:
  203. #ifndef CONFIG_SMP
  204. li r5,0
  205. ld r4,last_task_used_vsx@got(r2)
  206. std r5,0(r4)
  207. #endif /* CONFIG_SMP */
  208. blr
  209. #endif /* CONFIG_VSX */
  210. /*
  211. * The routines below are in assembler so we can closely control the
  212. * usage of floating-point registers. These routines must be called
  213. * with preempt disabled.
  214. */
  215. #ifdef CONFIG_PPC32
  216. .data
  217. fpzero:
  218. .long 0
  219. fpone:
  220. .long 0x3f800000 /* 1.0 in single-precision FP */
  221. fphalf:
  222. .long 0x3f000000 /* 0.5 in single-precision FP */
  223. #define LDCONST(fr, name) \
  224. lis r11,name@ha; \
  225. lfs fr,name@l(r11)
  226. #else
  227. .section ".toc","aw"
  228. fpzero:
  229. .tc FD_0_0[TC],0
  230. fpone:
  231. .tc FD_3ff00000_0[TC],0x3ff0000000000000 /* 1.0 */
  232. fphalf:
  233. .tc FD_3fe00000_0[TC],0x3fe0000000000000 /* 0.5 */
  234. #define LDCONST(fr, name) \
  235. lfd fr,name@toc(r2)
  236. #endif
  237. .text
  238. /*
  239. * Internal routine to enable floating point and set FPSCR to 0.
  240. * Don't call it from C; it doesn't use the normal calling convention.
  241. */
  242. fpenable:
  243. #ifdef CONFIG_PPC32
  244. stwu r1,-64(r1)
  245. #else
  246. stdu r1,-64(r1)
  247. #endif
  248. mfmsr r10
  249. ori r11,r10,MSR_FP
  250. mtmsr r11
  251. isync
  252. stfd fr0,24(r1)
  253. stfd fr1,16(r1)
  254. stfd fr31,8(r1)
  255. LDCONST(fr1, fpzero)
  256. mffs fr31
  257. MTFSF_L(fr1)
  258. blr
  259. fpdisable:
  260. mtlr r12
  261. MTFSF_L(fr31)
  262. lfd fr31,8(r1)
  263. lfd fr1,16(r1)
  264. lfd fr0,24(r1)
  265. mtmsr r10
  266. isync
  267. addi r1,r1,64
  268. blr
  269. /*
  270. * Vector add, floating point.
  271. */
  272. _GLOBAL(vaddfp)
  273. mflr r12
  274. bl fpenable
  275. li r0,4
  276. mtctr r0
  277. li r6,0
  278. 1: lfsx fr0,r4,r6
  279. lfsx fr1,r5,r6
  280. fadds fr0,fr0,fr1
  281. stfsx fr0,r3,r6
  282. addi r6,r6,4
  283. bdnz 1b
  284. b fpdisable
  285. /*
  286. * Vector subtract, floating point.
  287. */
  288. _GLOBAL(vsubfp)
  289. mflr r12
  290. bl fpenable
  291. li r0,4
  292. mtctr r0
  293. li r6,0
  294. 1: lfsx fr0,r4,r6
  295. lfsx fr1,r5,r6
  296. fsubs fr0,fr0,fr1
  297. stfsx fr0,r3,r6
  298. addi r6,r6,4
  299. bdnz 1b
  300. b fpdisable
  301. /*
  302. * Vector multiply and add, floating point.
  303. */
  304. _GLOBAL(vmaddfp)
  305. mflr r12
  306. bl fpenable
  307. stfd fr2,32(r1)
  308. li r0,4
  309. mtctr r0
  310. li r7,0
  311. 1: lfsx fr0,r4,r7
  312. lfsx fr1,r5,r7
  313. lfsx fr2,r6,r7
  314. fmadds fr0,fr0,fr2,fr1
  315. stfsx fr0,r3,r7
  316. addi r7,r7,4
  317. bdnz 1b
  318. lfd fr2,32(r1)
  319. b fpdisable
  320. /*
  321. * Vector negative multiply and subtract, floating point.
  322. */
  323. _GLOBAL(vnmsubfp)
  324. mflr r12
  325. bl fpenable
  326. stfd fr2,32(r1)
  327. li r0,4
  328. mtctr r0
  329. li r7,0
  330. 1: lfsx fr0,r4,r7
  331. lfsx fr1,r5,r7
  332. lfsx fr2,r6,r7
  333. fnmsubs fr0,fr0,fr2,fr1
  334. stfsx fr0,r3,r7
  335. addi r7,r7,4
  336. bdnz 1b
  337. lfd fr2,32(r1)
  338. b fpdisable
  339. /*
  340. * Vector reciprocal estimate. We just compute 1.0/x.
  341. * r3 -> destination, r4 -> source.
  342. */
  343. _GLOBAL(vrefp)
  344. mflr r12
  345. bl fpenable
  346. li r0,4
  347. LDCONST(fr1, fpone)
  348. mtctr r0
  349. li r6,0
  350. 1: lfsx fr0,r4,r6
  351. fdivs fr0,fr1,fr0
  352. stfsx fr0,r3,r6
  353. addi r6,r6,4
  354. bdnz 1b
  355. b fpdisable
  356. /*
  357. * Vector reciprocal square-root estimate, floating point.
  358. * We use the frsqrte instruction for the initial estimate followed
  359. * by 2 iterations of Newton-Raphson to get sufficient accuracy.
  360. * r3 -> destination, r4 -> source.
  361. */
  362. _GLOBAL(vrsqrtefp)
  363. mflr r12
  364. bl fpenable
  365. stfd fr2,32(r1)
  366. stfd fr3,40(r1)
  367. stfd fr4,48(r1)
  368. stfd fr5,56(r1)
  369. li r0,4
  370. LDCONST(fr4, fpone)
  371. LDCONST(fr5, fphalf)
  372. mtctr r0
  373. li r6,0
  374. 1: lfsx fr0,r4,r6
  375. frsqrte fr1,fr0 /* r = frsqrte(s) */
  376. fmuls fr3,fr1,fr0 /* r * s */
  377. fmuls fr2,fr1,fr5 /* r * 0.5 */
  378. fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */
  379. fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */
  380. fmuls fr3,fr1,fr0 /* r * s */
  381. fmuls fr2,fr1,fr5 /* r * 0.5 */
  382. fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */
  383. fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */
  384. stfsx fr1,r3,r6
  385. addi r6,r6,4
  386. bdnz 1b
  387. lfd fr5,56(r1)
  388. lfd fr4,48(r1)
  389. lfd fr3,40(r1)
  390. lfd fr2,32(r1)
  391. b fpdisable