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