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 u8 *buf; 31 int i; 32 33 if (WARN((vgpu_opregion(vgpu)->va), 34 "vgpu%d: opregion has been initialized already.\n", 35 vgpu->id)) 36 return -EINVAL; 37 38 vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL | 39 __GFP_ZERO, 40 get_order(INTEL_GVT_OPREGION_SIZE)); 41 42 if (!vgpu_opregion(vgpu)->va) 43 return -ENOMEM; 44 45 memcpy(vgpu_opregion(vgpu)->va, vgpu->gvt->opregion.opregion_va, 46 INTEL_GVT_OPREGION_SIZE); 47 48 for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) 49 vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i; 50 51 /* for unknown reason, the value in LID field is incorrect 52 * which block the windows guest, so workaround it by force 53 * setting it to "OPEN" 54 */ 55 buf = (u8 *)vgpu_opregion(vgpu)->va; 56 buf[INTEL_GVT_OPREGION_CLID] = 0x3; 57 58 return 0; 59 } 60 61 static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map) 62 { 63 u64 mfn; 64 int i, ret; 65 66 for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) { 67 mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu)->va 68 + i * PAGE_SIZE); 69 if (mfn == INTEL_GVT_INVALID_ADDR) { 70 gvt_err("fail to get MFN from VA\n"); 71 return -EINVAL; 72 } 73 ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, 74 vgpu_opregion(vgpu)->gfn[i], 75 mfn, 1, map); 76 if (ret) { 77 gvt_err("fail to map GFN to MFN, errno: %d\n", ret); 78 return ret; 79 } 80 } 81 return 0; 82 } 83 84 /** 85 * intel_vgpu_clean_opregion - clean the stuff used to emulate opregion 86 * @vgpu: a vGPU 87 * 88 */ 89 void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu) 90 { 91 gvt_dbg_core("vgpu%d: clean vgpu opregion\n", vgpu->id); 92 93 if (!vgpu_opregion(vgpu)->va) 94 return; 95 96 if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) { 97 map_vgpu_opregion(vgpu, false); 98 free_pages((unsigned long)vgpu_opregion(vgpu)->va, 99 get_order(INTEL_GVT_OPREGION_SIZE)); 100 101 vgpu_opregion(vgpu)->va = NULL; 102 } 103 } 104 105 /** 106 * intel_vgpu_init_opregion - initialize the stuff used to emulate opregion 107 * @vgpu: a vGPU 108 * @gpa: guest physical address of opregion 109 * 110 * Returns: 111 * Zero on success, negative error code if failed. 112 */ 113 int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa) 114 { 115 int ret; 116 117 gvt_dbg_core("vgpu%d: init vgpu opregion\n", vgpu->id); 118 119 if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) { 120 gvt_dbg_core("emulate opregion from kernel\n"); 121 122 ret = init_vgpu_opregion(vgpu, gpa); 123 if (ret) 124 return ret; 125 126 ret = map_vgpu_opregion(vgpu, true); 127 if (ret) 128 return ret; 129 } 130 131 return 0; 132 } 133 134 /** 135 * intel_gvt_clean_opregion - clean host opergion related stuffs 136 * @gvt: a GVT device 137 * 138 */ 139 void intel_gvt_clean_opregion(struct intel_gvt *gvt) 140 { 141 memunmap(gvt->opregion.opregion_va); 142 gvt->opregion.opregion_va = NULL; 143 } 144 145 /** 146 * intel_gvt_init_opregion - initialize host opergion related stuffs 147 * @gvt: a GVT device 148 * 149 * Returns: 150 * Zero on success, negative error code if failed. 151 */ 152 int intel_gvt_init_opregion(struct intel_gvt *gvt) 153 { 154 gvt_dbg_core("init host opregion\n"); 155 156 pci_read_config_dword(gvt->dev_priv->drm.pdev, INTEL_GVT_PCI_OPREGION, 157 &gvt->opregion.opregion_pa); 158 159 gvt->opregion.opregion_va = memremap(gvt->opregion.opregion_pa, 160 INTEL_GVT_OPREGION_SIZE, MEMREMAP_WB); 161 if (!gvt->opregion.opregion_va) { 162 gvt_err("fail to map host opregion\n"); 163 return -EFAULT; 164 } 165 return 0; 166 } 167 168 #define GVT_OPREGION_FUNC(scic) \ 169 ({ \ 170 u32 __ret; \ 171 __ret = (scic & OPREGION_SCIC_FUNC_MASK) >> \ 172 OPREGION_SCIC_FUNC_SHIFT; \ 173 __ret; \ 174 }) 175 176 #define GVT_OPREGION_SUBFUNC(scic) \ 177 ({ \ 178 u32 __ret; \ 179 __ret = (scic & OPREGION_SCIC_SUBFUNC_MASK) >> \ 180 OPREGION_SCIC_SUBFUNC_SHIFT; \ 181 __ret; \ 182 }) 183 184 static const char *opregion_func_name(u32 func) 185 { 186 const char *name = NULL; 187 188 switch (func) { 189 case 0 ... 3: 190 case 5: 191 case 7 ... 15: 192 name = "Reserved"; 193 break; 194 195 case 4: 196 name = "Get BIOS Data"; 197 break; 198 199 case 6: 200 name = "System BIOS Callbacks"; 201 break; 202 203 default: 204 name = "Unknown"; 205 break; 206 } 207 return name; 208 } 209 210 static const char *opregion_subfunc_name(u32 subfunc) 211 { 212 const char *name = NULL; 213 214 switch (subfunc) { 215 case 0: 216 name = "Supported Calls"; 217 break; 218 219 case 1: 220 name = "Requested Callbacks"; 221 break; 222 223 case 2 ... 3: 224 case 8 ... 9: 225 name = "Reserved"; 226 break; 227 228 case 5: 229 name = "Boot Display"; 230 break; 231 232 case 6: 233 name = "TV-Standard/Video-Connector"; 234 break; 235 236 case 7: 237 name = "Internal Graphics"; 238 break; 239 240 case 10: 241 name = "Spread Spectrum Clocks"; 242 break; 243 244 case 11: 245 name = "Get AKSV"; 246 break; 247 248 default: 249 name = "Unknown"; 250 break; 251 } 252 return name; 253 }; 254 255 static bool querying_capabilities(u32 scic) 256 { 257 u32 func, subfunc; 258 259 func = GVT_OPREGION_FUNC(scic); 260 subfunc = GVT_OPREGION_SUBFUNC(scic); 261 262 if ((func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSDATA && 263 subfunc == INTEL_GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS) 264 || (func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSDATA && 265 subfunc == INTEL_GVT_OPREGION_SCIC_SF_REQEUSTEDCALLBACKS) 266 || (func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSCALLBACKS && 267 subfunc == INTEL_GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS)) { 268 return true; 269 } 270 return false; 271 } 272 273 /** 274 * intel_vgpu_emulate_opregion_request - emulating OpRegion request 275 * @vgpu: a vGPU 276 * @swsci: SWSCI request 277 * 278 * Returns: 279 * Zero on success, negative error code if failed 280 */ 281 int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci) 282 { 283 u32 *scic, *parm; 284 u32 func, subfunc; 285 286 scic = vgpu_opregion(vgpu)->va + INTEL_GVT_OPREGION_SCIC; 287 parm = vgpu_opregion(vgpu)->va + INTEL_GVT_OPREGION_PARM; 288 289 if (!(swsci & SWSCI_SCI_SELECT)) { 290 gvt_err("vgpu%d: requesting SMI service\n", vgpu->id); 291 return 0; 292 } 293 /* ignore non 0->1 trasitions */ 294 if ((vgpu_cfg_space(vgpu)[INTEL_GVT_PCI_SWSCI] 295 & SWSCI_SCI_TRIGGER) || 296 !(swsci & SWSCI_SCI_TRIGGER)) { 297 return 0; 298 } 299 300 func = GVT_OPREGION_FUNC(*scic); 301 subfunc = GVT_OPREGION_SUBFUNC(*scic); 302 if (!querying_capabilities(*scic)) { 303 gvt_err("vgpu%d: requesting runtime service: func \"%s\"," 304 " subfunc \"%s\"\n", 305 vgpu->id, 306 opregion_func_name(func), 307 opregion_subfunc_name(subfunc)); 308 /* 309 * emulate exit status of function call, '0' means 310 * "failure, generic, unsupported or unknown cause" 311 */ 312 *scic &= ~OPREGION_SCIC_EXIT_MASK; 313 return 0; 314 } 315 316 *scic = 0; 317 *parm = 0; 318 return 0; 319 } 320