vector.S 10.0 KB

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