fpu.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * In-kernel vector facility support functions
  4. *
  5. * Copyright IBM Corp. 2015
  6. * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/cpu.h>
  10. #include <linux/sched.h>
  11. #include <asm/fpu.h>
  12. void __kernel_fpu_begin(struct kernel_fpu *state, int flags)
  13. {
  14. __vector128 *vxrs = state->vxrs;
  15. int mask;
  16. /*
  17. * Limit the save to the FPU/vector registers already
  18. * in use by the previous context.
  19. */
  20. flags &= state->hdr.mask;
  21. if (flags & KERNEL_FPC)
  22. fpu_stfpc(&state->hdr.fpc);
  23. if (!cpu_has_vx()) {
  24. if (flags & KERNEL_VXR_LOW)
  25. save_fp_regs_vx(vxrs);
  26. return;
  27. }
  28. mask = flags & KERNEL_VXR;
  29. if (mask == KERNEL_VXR) {
  30. vxrs += fpu_vstm(0, 15, vxrs);
  31. vxrs += fpu_vstm(16, 31, vxrs);
  32. return;
  33. }
  34. if (mask == KERNEL_VXR_MID) {
  35. vxrs += fpu_vstm(8, 23, vxrs);
  36. return;
  37. }
  38. mask = flags & KERNEL_VXR_LOW;
  39. if (mask) {
  40. if (mask == KERNEL_VXR_LOW)
  41. vxrs += fpu_vstm(0, 15, vxrs);
  42. else if (mask == KERNEL_VXR_V0V7)
  43. vxrs += fpu_vstm(0, 7, vxrs);
  44. else
  45. vxrs += fpu_vstm(8, 15, vxrs);
  46. }
  47. mask = flags & KERNEL_VXR_HIGH;
  48. if (mask) {
  49. if (mask == KERNEL_VXR_HIGH)
  50. vxrs += fpu_vstm(16, 31, vxrs);
  51. else if (mask == KERNEL_VXR_V16V23)
  52. vxrs += fpu_vstm(16, 23, vxrs);
  53. else
  54. vxrs += fpu_vstm(24, 31, vxrs);
  55. }
  56. }
  57. EXPORT_SYMBOL(__kernel_fpu_begin);
  58. void __kernel_fpu_end(struct kernel_fpu *state, int flags)
  59. {
  60. __vector128 *vxrs = state->vxrs;
  61. int mask;
  62. /*
  63. * Limit the restore to the FPU/vector registers of the
  64. * previous context that have been overwritten by the
  65. * current context.
  66. */
  67. flags &= state->hdr.mask;
  68. if (flags & KERNEL_FPC)
  69. fpu_lfpc(&state->hdr.fpc);
  70. if (!cpu_has_vx()) {
  71. if (flags & KERNEL_VXR_LOW)
  72. load_fp_regs_vx(vxrs);
  73. return;
  74. }
  75. mask = flags & KERNEL_VXR;
  76. if (mask == KERNEL_VXR) {
  77. vxrs += fpu_vlm(0, 15, vxrs);
  78. vxrs += fpu_vlm(16, 31, vxrs);
  79. return;
  80. }
  81. if (mask == KERNEL_VXR_MID) {
  82. vxrs += fpu_vlm(8, 23, vxrs);
  83. return;
  84. }
  85. mask = flags & KERNEL_VXR_LOW;
  86. if (mask) {
  87. if (mask == KERNEL_VXR_LOW)
  88. vxrs += fpu_vlm(0, 15, vxrs);
  89. else if (mask == KERNEL_VXR_V0V7)
  90. vxrs += fpu_vlm(0, 7, vxrs);
  91. else
  92. vxrs += fpu_vlm(8, 15, vxrs);
  93. }
  94. mask = flags & KERNEL_VXR_HIGH;
  95. if (mask) {
  96. if (mask == KERNEL_VXR_HIGH)
  97. vxrs += fpu_vlm(16, 31, vxrs);
  98. else if (mask == KERNEL_VXR_V16V23)
  99. vxrs += fpu_vlm(16, 23, vxrs);
  100. else
  101. vxrs += fpu_vlm(24, 31, vxrs);
  102. }
  103. }
  104. EXPORT_SYMBOL(__kernel_fpu_end);
  105. void load_fpu_state(struct fpu *state, int flags)
  106. {
  107. __vector128 *vxrs = &state->vxrs[0];
  108. int mask;
  109. if (flags & KERNEL_FPC)
  110. fpu_lfpc_safe(&state->fpc);
  111. if (!cpu_has_vx()) {
  112. if (flags & KERNEL_VXR_V0V7)
  113. load_fp_regs_vx(state->vxrs);
  114. return;
  115. }
  116. mask = flags & KERNEL_VXR;
  117. if (mask == KERNEL_VXR) {
  118. fpu_vlm(0, 15, &vxrs[0]);
  119. fpu_vlm(16, 31, &vxrs[16]);
  120. return;
  121. }
  122. if (mask == KERNEL_VXR_MID) {
  123. fpu_vlm(8, 23, &vxrs[8]);
  124. return;
  125. }
  126. mask = flags & KERNEL_VXR_LOW;
  127. if (mask) {
  128. if (mask == KERNEL_VXR_LOW)
  129. fpu_vlm(0, 15, &vxrs[0]);
  130. else if (mask == KERNEL_VXR_V0V7)
  131. fpu_vlm(0, 7, &vxrs[0]);
  132. else
  133. fpu_vlm(8, 15, &vxrs[8]);
  134. }
  135. mask = flags & KERNEL_VXR_HIGH;
  136. if (mask) {
  137. if (mask == KERNEL_VXR_HIGH)
  138. fpu_vlm(16, 31, &vxrs[16]);
  139. else if (mask == KERNEL_VXR_V16V23)
  140. fpu_vlm(16, 23, &vxrs[16]);
  141. else
  142. fpu_vlm(24, 31, &vxrs[24]);
  143. }
  144. }
  145. void save_fpu_state(struct fpu *state, int flags)
  146. {
  147. __vector128 *vxrs = &state->vxrs[0];
  148. int mask;
  149. if (flags & KERNEL_FPC)
  150. fpu_stfpc(&state->fpc);
  151. if (!cpu_has_vx()) {
  152. if (flags & KERNEL_VXR_LOW)
  153. save_fp_regs_vx(state->vxrs);
  154. return;
  155. }
  156. mask = flags & KERNEL_VXR;
  157. if (mask == KERNEL_VXR) {
  158. fpu_vstm(0, 15, &vxrs[0]);
  159. fpu_vstm(16, 31, &vxrs[16]);
  160. return;
  161. }
  162. if (mask == KERNEL_VXR_MID) {
  163. fpu_vstm(8, 23, &vxrs[8]);
  164. return;
  165. }
  166. mask = flags & KERNEL_VXR_LOW;
  167. if (mask) {
  168. if (mask == KERNEL_VXR_LOW)
  169. fpu_vstm(0, 15, &vxrs[0]);
  170. else if (mask == KERNEL_VXR_V0V7)
  171. fpu_vstm(0, 7, &vxrs[0]);
  172. else
  173. fpu_vstm(8, 15, &vxrs[8]);
  174. }
  175. mask = flags & KERNEL_VXR_HIGH;
  176. if (mask) {
  177. if (mask == KERNEL_VXR_HIGH)
  178. fpu_vstm(16, 31, &vxrs[16]);
  179. else if (mask == KERNEL_VXR_V16V23)
  180. fpu_vstm(16, 23, &vxrs[16]);
  181. else
  182. fpu_vstm(24, 31, &vxrs[24]);
  183. }
  184. }
  185. EXPORT_SYMBOL(save_fpu_state);