fpu.S 5.8 KB

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