fpu.S 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * FPU helper code to use FPU operations from inside the kernel
  4. *
  5. * Copyright (C) 2010 Alexander Graf (agraf@suse.de)
  6. */
  7. #include <linux/pgtable.h>
  8. #include <asm/reg.h>
  9. #include <asm/page.h>
  10. #include <asm/mmu.h>
  11. #include <asm/cputable.h>
  12. #include <asm/cache.h>
  13. #include <asm/thread_info.h>
  14. #include <asm/ppc_asm.h>
  15. #include <asm/asm-offsets.h>
  16. /* Instructions operating on single parameters */
  17. /*
  18. * Single operation with one input operand
  19. *
  20. * R3 = (double*)&fpscr
  21. * R4 = (short*)&result
  22. * R5 = (short*)&param1
  23. */
  24. #define FPS_ONE_IN(name) \
  25. _GLOBAL(fps_ ## name); \
  26. lfd 0,0(r3); /* load up fpscr value */ \
  27. MTFSF_L(0); \
  28. lfs 0,0(r5); \
  29. \
  30. name 0,0; \
  31. \
  32. stfs 0,0(r4); \
  33. mffs 0; \
  34. stfd 0,0(r3); /* save new fpscr value */ \
  35. blr
  36. /*
  37. * Single operation with two input operands
  38. *
  39. * R3 = (double*)&fpscr
  40. * R4 = (short*)&result
  41. * R5 = (short*)&param1
  42. * R6 = (short*)&param2
  43. */
  44. #define FPS_TWO_IN(name) \
  45. _GLOBAL(fps_ ## name); \
  46. lfd 0,0(r3); /* load up fpscr value */ \
  47. MTFSF_L(0); \
  48. lfs 0,0(r5); \
  49. lfs 1,0(r6); \
  50. \
  51. name 0,0,1; \
  52. \
  53. stfs 0,0(r4); \
  54. mffs 0; \
  55. stfd 0,0(r3); /* save new fpscr value */ \
  56. blr
  57. /*
  58. * Single operation with three input operands
  59. *
  60. * R3 = (double*)&fpscr
  61. * R4 = (short*)&result
  62. * R5 = (short*)&param1
  63. * R6 = (short*)&param2
  64. * R7 = (short*)&param3
  65. */
  66. #define FPS_THREE_IN(name) \
  67. _GLOBAL(fps_ ## name); \
  68. lfd 0,0(r3); /* load up fpscr value */ \
  69. MTFSF_L(0); \
  70. lfs 0,0(r5); \
  71. lfs 1,0(r6); \
  72. lfs 2,0(r7); \
  73. \
  74. name 0,0,1,2; \
  75. \
  76. stfs 0,0(r4); \
  77. mffs 0; \
  78. stfd 0,0(r3); /* save new fpscr value */ \
  79. blr
  80. FPS_ONE_IN(fres)
  81. FPS_ONE_IN(frsqrte)
  82. FPS_ONE_IN(fsqrts)
  83. FPS_TWO_IN(fadds)
  84. FPS_TWO_IN(fdivs)
  85. FPS_TWO_IN(fmuls)
  86. FPS_TWO_IN(fsubs)
  87. FPS_THREE_IN(fmadds)
  88. FPS_THREE_IN(fmsubs)
  89. FPS_THREE_IN(fnmadds)
  90. FPS_THREE_IN(fnmsubs)
  91. FPS_THREE_IN(fsel)
  92. /* Instructions operating on double parameters */
  93. /*
  94. * Beginning of double instruction processing
  95. *
  96. * R3 = (double*)&fpscr
  97. * R4 = (u32*)&cr
  98. * R5 = (double*)&result
  99. * R6 = (double*)&param1
  100. * R7 = (double*)&param2 [load_two]
  101. * R8 = (double*)&param3 [load_three]
  102. * LR = instruction call function
  103. */
  104. fpd_load_three:
  105. lfd 2,0(r8) /* load param3 */
  106. fpd_load_two:
  107. lfd 1,0(r7) /* load param2 */
  108. fpd_load_one:
  109. lfd 0,0(r6) /* load param1 */
  110. fpd_load_none:
  111. lfd 3,0(r3) /* load up fpscr value */
  112. MTFSF_L(3)
  113. lwz r6, 0(r4) /* load cr */
  114. mtcr r6
  115. blr
  116. /*
  117. * End of double instruction processing
  118. *
  119. * R3 = (double*)&fpscr
  120. * R4 = (u32*)&cr
  121. * R5 = (double*)&result
  122. * LR = caller of instruction call function
  123. */
  124. fpd_return:
  125. mfcr r6
  126. stfd 0,0(r5) /* save result */
  127. mffs 0
  128. stfd 0,0(r3) /* save new fpscr value */
  129. stw r6,0(r4) /* save new cr value */
  130. blr
  131. /*
  132. * Double operation with no input operand
  133. *
  134. * R3 = (double*)&fpscr
  135. * R4 = (u32*)&cr
  136. * R5 = (double*)&result
  137. */
  138. #define FPD_NONE_IN(name) \
  139. _GLOBAL(fpd_ ## name); \
  140. mflr r12; \
  141. bl fpd_load_none; \
  142. mtlr r12; \
  143. \
  144. name. 0; /* call instruction */ \
  145. b fpd_return
  146. /*
  147. * Double operation with one input operand
  148. *
  149. * R3 = (double*)&fpscr
  150. * R4 = (u32*)&cr
  151. * R5 = (double*)&result
  152. * R6 = (double*)&param1
  153. */
  154. #define FPD_ONE_IN(name) \
  155. _GLOBAL(fpd_ ## name); \
  156. mflr r12; \
  157. bl fpd_load_one; \
  158. mtlr r12; \
  159. \
  160. name. 0,0; /* call instruction */ \
  161. b fpd_return
  162. /*
  163. * Double operation with two input operands
  164. *
  165. * R3 = (double*)&fpscr
  166. * R4 = (u32*)&cr
  167. * R5 = (double*)&result
  168. * R6 = (double*)&param1
  169. * R7 = (double*)&param2
  170. * R8 = (double*)&param3
  171. */
  172. #define FPD_TWO_IN(name) \
  173. _GLOBAL(fpd_ ## name); \
  174. mflr r12; \
  175. bl fpd_load_two; \
  176. mtlr r12; \
  177. \
  178. name. 0,0,1; /* call instruction */ \
  179. b fpd_return
  180. /*
  181. * CR Double operation with two input operands
  182. *
  183. * R3 = (double*)&fpscr
  184. * R4 = (u32*)&cr
  185. * R5 = (double*)&param1
  186. * R6 = (double*)&param2
  187. * R7 = (double*)&param3
  188. */
  189. #define FPD_TWO_IN_CR(name) \
  190. _GLOBAL(fpd_ ## name); \
  191. lfd 1,0(r6); /* load param2 */ \
  192. lfd 0,0(r5); /* load param1 */ \
  193. lfd 3,0(r3); /* load up fpscr value */ \
  194. MTFSF_L(3); \
  195. lwz r6, 0(r4); /* load cr */ \
  196. mtcr r6; \
  197. \
  198. name 0,0,1; /* call instruction */ \
  199. mfcr r6; \
  200. mffs 0; \
  201. stfd 0,0(r3); /* save new fpscr value */ \
  202. stw r6,0(r4); /* save new cr value */ \
  203. blr
  204. /*
  205. * Double operation with three input operands
  206. *
  207. * R3 = (double*)&fpscr
  208. * R4 = (u32*)&cr
  209. * R5 = (double*)&result
  210. * R6 = (double*)&param1
  211. * R7 = (double*)&param2
  212. * R8 = (double*)&param3
  213. */
  214. #define FPD_THREE_IN(name) \
  215. _GLOBAL(fpd_ ## name); \
  216. mflr r12; \
  217. bl fpd_load_three; \
  218. mtlr r12; \
  219. \
  220. name. 0,0,1,2; /* call instruction */ \
  221. b fpd_return
  222. FPD_ONE_IN(fsqrts)
  223. FPD_ONE_IN(frsqrtes)
  224. FPD_ONE_IN(fres)
  225. FPD_ONE_IN(frsp)
  226. FPD_ONE_IN(fctiw)
  227. FPD_ONE_IN(fctiwz)
  228. FPD_ONE_IN(fsqrt)
  229. FPD_ONE_IN(fre)
  230. FPD_ONE_IN(frsqrte)
  231. FPD_ONE_IN(fneg)
  232. FPD_ONE_IN(fabs)
  233. FPD_TWO_IN(fadds)
  234. FPD_TWO_IN(fsubs)
  235. FPD_TWO_IN(fdivs)
  236. FPD_TWO_IN(fmuls)
  237. FPD_TWO_IN_CR(fcmpu)
  238. FPD_TWO_IN(fcpsgn)
  239. FPD_TWO_IN(fdiv)
  240. FPD_TWO_IN(fadd)
  241. FPD_TWO_IN(fmul)
  242. FPD_TWO_IN_CR(fcmpo)
  243. FPD_TWO_IN(fsub)
  244. FPD_THREE_IN(fmsubs)
  245. FPD_THREE_IN(fmadds)
  246. FPD_THREE_IN(fnmsubs)
  247. FPD_THREE_IN(fnmadds)
  248. FPD_THREE_IN(fsel)
  249. FPD_THREE_IN(fmsub)
  250. FPD_THREE_IN(fmadd)
  251. FPD_THREE_IN(fnmsub)
  252. FPD_THREE_IN(fnmadd)
  253. _GLOBAL(kvm_cvt_fd)
  254. lfs 0,0(r3)
  255. stfd 0,0(r4)
  256. blr
  257. _GLOBAL(kvm_cvt_df)
  258. lfd 0,0(r3)
  259. stfs 0,0(r4)
  260. blr