vector.S 9.7 KB

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