1 /* 2 * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24 #include <linux/acpi.h> 25 #include "i915_drv.h" 26 #include "gvt.h" 27 28 static int init_vgpu_opregion(struct intel_vgpu *vgpu, u32 gpa) 29 { 30 void __iomem *host_va = vgpu->gvt->opregion.opregion_va; 31 u8 *buf; 32 int i; 33 34 if (WARN((vgpu_opregion(vgpu)->va), 35 "vgpu%d: opregion has been initialized already.\n", 36 vgpu->id)) 37 return -EINVAL; 38 39 vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_ATOMIC | 40 GFP_DMA32 | __GFP_ZERO, 41 INTEL_GVT_OPREGION_PORDER); 42 43 if (!vgpu_opregion(vgpu)->va) 44 return -ENOMEM; 45 46 memcpy_fromio(vgpu_opregion(vgpu)->va, host_va, 47 INTEL_GVT_OPREGION_SIZE); 48 49 for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) 50 vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i; 51 52 /* for unknown reason, the value in LID field is incorrect 53 * which block the windows guest, so workaround it by force 54 * setting it to "OPEN" 55 */ 56 buf = (u8 *)vgpu_opregion(vgpu)->va; 57 buf[INTEL_GVT_OPREGION_CLID] = 0x3; 58 59 return 0; 60 } 61 62 static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map) 63 { 64 u64 mfn; 65 int i, ret; 66 67 for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) { 68 mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu) 69 + i * PAGE_SIZE); 70 if (mfn == INTEL_GVT_INVALID_ADDR) { 71 gvt_err("fail to get MFN from VA\n"); 72 return -EINVAL; 73 } 74 ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, 75 vgpu_opregion(vgpu)->gfn[i], 76 mfn, 1, map, GVT_MAP_OPREGION); 77 if (ret) { 78 gvt_err("fail to map GFN to MFN, errno: %d\n", ret); 79 return ret; 80 } 81 } 82 return 0; 83 } 84 85 /** 86 * intel_vgpu_clean_opregion - clean the stuff used to emulate opregion 87 * @vgpu: a vGPU 88 * 89 */ 90 void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu) 91 { 92 int i; 93 94 gvt_dbg_core("vgpu%d: clean vgpu opregion\n", vgpu->id); 95 96 if (!vgpu_opregion(vgpu)->va) 97 return; 98 99 if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_KVM) { 100 vunmap(vgpu_opregion(vgpu)->va); 101 for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) { 102 if (vgpu_opregion(vgpu)->pages[i]) { 103 put_page(vgpu_opregion(vgpu)->pages[i]); 104 vgpu_opregion(vgpu)->pages[i] = NULL; 105 } 106 } 107 } else { 108 map_vgpu_opregion(vgpu, false); 109 free_pages((unsigned long)vgpu_opregion(vgpu)->va, 110 INTEL_GVT_OPREGION_PORDER); 111 } 112 113 vgpu_opregion(vgpu)->va = NULL; 114 } 115 116 /** 117 * intel_vgpu_init_opregion - initialize the stuff used to emulate opregion 118 * @vgpu: a vGPU 119 * @gpa: guest physical address of opregion 120 * 121 * Returns: 122 * Zero on success, negative error code if failed. 123 */ 124 int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa) 125 { 126 int ret; 127 128 gvt_dbg_core("vgpu%d: init vgpu opregion\n", vgpu->id); 129 130 if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) { 131 gvt_dbg_core("emulate opregion from kernel\n"); 132 133 ret = init_vgpu_opregion(vgpu, gpa); 134 if (ret) 135 return ret; 136 137 ret = map_vgpu_opregion(vgpu, true); 138 if (ret) 139 return ret; 140 } else { 141 gvt_dbg_core("emulate opregion from userspace\n"); 142 143 /* 144 * If opregion pages are not allocated from host kenrel, 145 * most of the params are meaningless 146 */ 147 ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, 148 0, /* not used */ 149 0, /* not used */ 150 2, /* not used */ 151 1, 152 GVT_MAP_OPREGION); 153 if (ret) 154 return ret; 155 } 156 return 0; 157 } 158 159 /** 160 * intel_gvt_clean_opregion - clean host opergion related stuffs 161 * @gvt: a GVT device 162 * 163 */ 164 void intel_gvt_clean_opregion(struct intel_gvt *gvt) 165 { 166 iounmap(gvt->opregion.opregion_va); 167 gvt->opregion.opregion_va = NULL; 168 } 169 170 /** 171 * intel_gvt_init_opregion - initialize host opergion related stuffs 172 * @gvt: a GVT device 173 * 174 * Returns: 175 * Zero on success, negative error code if failed. 176 */ 177 int intel_gvt_init_opregion(struct intel_gvt *gvt) 178 { 179 gvt_dbg_core("init host opregion\n"); 180 181 pci_read_config_dword(gvt->dev_priv->drm.pdev, INTEL_GVT_PCI_OPREGION, 182 &gvt->opregion.opregion_pa); 183 184 gvt->opregion.opregion_va = acpi_os_ioremap(gvt->opregion.opregion_pa, 185 INTEL_GVT_OPREGION_SIZE); 186 if (!gvt->opregion.opregion_va) { 187 gvt_err("fail to map host opregion\n"); 188 return -EFAULT; 189 } 190 return 0; 191 } 192 193 #define GVT_OPREGION_FUNC(scic) \ 194 ({ \ 195 u32 __ret; \ 196 __ret = (scic & OPREGION_SCIC_FUNC_MASK) >> \ 197 OPREGION_SCIC_FUNC_SHIFT; \ 198 __ret; \ 199 }) 200 201 #define GVT_OPREGION_SUBFUNC(scic) \ 202 ({ \ 203 u32 __ret; \ 204 __ret = (scic & OPREGION_SCIC_SUBFUNC_MASK) >> \ 205 OPREGION_SCIC_SUBFUNC_SHIFT; \ 206 __ret; \ 207 }) 208 209 static const char *opregion_func_name(u32 func) 210 { 211 const char *name = NULL; 212 213 switch (func) { 214 case 0 ... 3: 215 case 5: 216 case 7 ... 15: 217 name = "Reserved"; 218 break; 219 220 case 4: 221 name = "Get BIOS Data"; 222 break; 223 224 case 6: 225 name = "System BIOS Callbacks"; 226 break; 227 228 default: 229 name = "Unknown"; 230 break; 231 } 232 return name; 233 } 234 235 static const char *opregion_subfunc_name(u32 subfunc) 236 { 237 const char *name = NULL; 238 239 switch (subfunc) { 240 case 0: 241 name = "Supported Calls"; 242 break; 243 244 case 1: 245 name = "Requested Callbacks"; 246 break; 247 248 case 2 ... 3: 249 case 8 ... 9: 250 name = "Reserved"; 251 break; 252 253 case 5: 254 name = "Boot Display"; 255 break; 256 257 case 6: 258 name = "TV-Standard/Video-Connector"; 259 break; 260 261 case 7: 262 name = "Internal Graphics"; 263 break; 264 265 case 10: 266 name = "Spread Spectrum Clocks"; 267 break; 268 269 case 11: 270 name = "Get AKSV"; 271 break; 272 273 default: 274 name = "Unknown"; 275 break; 276 } 277 return name; 278 }; 279 280 static bool querying_capabilities(u32 scic) 281 { 282 u32 func, subfunc; 283 284 func = GVT_OPREGION_FUNC(scic); 285 subfunc = GVT_OPREGION_SUBFUNC(scic); 286 287 if ((func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSDATA && 288 subfunc == INTEL_GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS) 289 || (func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSDATA && 290 subfunc == INTEL_GVT_OPREGION_SCIC_SF_REQEUSTEDCALLBACKS) 291 || (func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSCALLBACKS && 292 subfunc == INTEL_GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS)) { 293 return true; 294 } 295 return false; 296 } 297 298 /** 299 * intel_vgpu_emulate_opregion_request - emulating OpRegion request 300 * @vgpu: a vGPU 301 * @swsci: SWSCI request 302 * 303 * Returns: 304 * Zero on success, negative error code if failed 305 */ 306 int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci) 307 { 308 u32 *scic, *parm; 309 u32 func, subfunc; 310 311 scic = vgpu_opregion(vgpu)->va + INTEL_GVT_OPREGION_SCIC; 312 parm = vgpu_opregion(vgpu)->va + INTEL_GVT_OPREGION_PARM; 313 314 if (!(swsci & SWSCI_SCI_SELECT)) { 315 gvt_err("vgpu%d: requesting SMI service\n", vgpu->id); 316 return 0; 317 } 318 /* ignore non 0->1 trasitions */ 319 if ((vgpu_cfg_space(vgpu)[INTEL_GVT_PCI_SWSCI] 320 & SWSCI_SCI_TRIGGER) || 321 !(swsci & SWSCI_SCI_TRIGGER)) { 322 return 0; 323 } 324 325 func = GVT_OPREGION_FUNC(*scic); 326 subfunc = GVT_OPREGION_SUBFUNC(*scic); 327 if (!querying_capabilities(*scic)) { 328 gvt_err("vgpu%d: requesting runtime service: func \"%s\"," 329 " subfunc \"%s\"\n", 330 vgpu->id, 331 opregion_func_name(func), 332 opregion_subfunc_name(subfunc)); 333 /* 334 * emulate exit status of function call, '0' means 335 * "failure, generic, unsupported or unknown cause" 336 */ 337 *scic &= ~OPREGION_SCIC_EXIT_MASK; 338 return 0; 339 } 340 341 *scic = 0; 342 *parm = 0; 343 return 0; 344 } 345