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 | /* |
29 | * Note: Only for GVT-g virtual VBT generation, other usage must |
30 | * not do like this. |
31 | */ |
32 | #define _INTEL_BIOS_PRIVATE |
33 | #include "display/intel_vbt_defs.h" |
34 | |
35 | #define OPREGION_SIGNATURE "IntelGraphicsMem" |
36 | #define MBOX_VBT (1<<3) |
37 | |
38 | /* device handle */ |
39 | #define DEVICE_TYPE_CRT 0x01 |
40 | #define DEVICE_TYPE_EFP1 0x04 |
41 | #define DEVICE_TYPE_EFP2 0x40 |
42 | #define DEVICE_TYPE_EFP3 0x20 |
43 | #define DEVICE_TYPE_EFP4 0x10 |
44 | |
45 | struct { |
46 | u8 [16]; |
47 | u32 ; |
48 | u32 ; |
49 | u8 [32]; |
50 | u8 [16]; |
51 | u8 [16]; |
52 | u32 ; |
53 | u32 ; |
54 | u32 ; |
55 | u8 [32]; |
56 | u8 [124]; |
57 | } __packed; |
58 | |
59 | struct { |
60 | u8 ; |
61 | u16 ; /* data size */ |
62 | } __packed; |
63 | |
64 | /* For supporting windows guest with opregion, here hardcode the emulated |
65 | * bdb header version as '186', and the corresponding child_device_config |
66 | * length should be '33' but not '38'. |
67 | */ |
68 | struct efp_child_device_config { |
69 | u16 handle; |
70 | u16 device_type; |
71 | u16 device_class; |
72 | u8 i2c_speed; |
73 | u8 dp_onboard_redriver; /* 158 */ |
74 | u8 dp_ondock_redriver; /* 158 */ |
75 | u8 hdmi_level_shifter_value:4; /* 169 */ |
76 | u8 hdmi_max_data_rate:4; /* 204 */ |
77 | u16 dtd_buf_ptr; /* 161 */ |
78 | u8 edidless_efp:1; /* 161 */ |
79 | u8 compression_enable:1; /* 198 */ |
80 | u8 compression_method:1; /* 198 */ |
81 | u8 ganged_edp:1; /* 202 */ |
82 | u8 skip0:4; |
83 | u8 compression_structure_index:4; /* 198 */ |
84 | u8 skip1:4; |
85 | u8 slave_port; /* 202 */ |
86 | u8 skip2; |
87 | u8 dvo_port; |
88 | u8 i2c_pin; /* for add-in card */ |
89 | u8 slave_addr; /* for add-in card */ |
90 | u8 ddc_pin; |
91 | u16 edid_ptr; |
92 | u8 dvo_config; |
93 | u8 efp_docked_port:1; /* 158 */ |
94 | u8 lane_reversal:1; /* 184 */ |
95 | u8 onboard_lspcon:1; /* 192 */ |
96 | u8 iboost_enable:1; /* 196 */ |
97 | u8 hpd_invert:1; /* BXT 196 */ |
98 | u8 slip3:3; |
99 | u8 hdmi_compat:1; |
100 | u8 dp_compat:1; |
101 | u8 tmds_compat:1; |
102 | u8 skip4:5; |
103 | u8 aux_channel; |
104 | u8 dongle_detect; |
105 | u8 pipe_cap:2; |
106 | u8 sdvo_stall:1; /* 158 */ |
107 | u8 hpd_status:2; |
108 | u8 integrated_encoder:1; |
109 | u8 skip5:2; |
110 | u8 dvo_wiring; |
111 | u8 mipi_bridge_type; /* 171 */ |
112 | u16 device_class_ext; |
113 | u8 dvo_function; |
114 | } __packed; |
115 | |
116 | struct vbt { |
117 | /* header->bdb_offset point to bdb_header offset */ |
118 | struct vbt_header ; |
119 | struct bdb_header ; |
120 | |
121 | struct bdb_data_header ; |
122 | struct bdb_general_features general_features; |
123 | |
124 | struct bdb_data_header ; |
125 | struct bdb_general_definitions general_definitions; |
126 | |
127 | struct efp_child_device_config child0; |
128 | struct efp_child_device_config child1; |
129 | struct efp_child_device_config child2; |
130 | struct efp_child_device_config child3; |
131 | |
132 | struct bdb_data_header ; |
133 | struct bdb_driver_features driver_features; |
134 | }; |
135 | |
136 | static void virt_vbt_generation(struct vbt *v) |
137 | { |
138 | int num_child; |
139 | |
140 | memset(v, 0, sizeof(struct vbt)); |
141 | |
142 | v->header.signature[0] = '$'; |
143 | v->header.signature[1] = 'V'; |
144 | v->header.signature[2] = 'B'; |
145 | v->header.signature[3] = 'T'; |
146 | |
147 | /* there's features depending on version! */ |
148 | v->header.version = 155; |
149 | v->header.header_size = sizeof(v->header); |
150 | v->header.vbt_size = sizeof(struct vbt); |
151 | v->header.bdb_offset = offsetof(struct vbt, bdb_header); |
152 | |
153 | strcpy(p: &v->bdb_header.signature[0], q: "BIOS_DATA_BLOCK" ); |
154 | v->bdb_header.version = 186; /* child_dev_size = 33 */ |
155 | v->bdb_header.header_size = sizeof(v->bdb_header); |
156 | |
157 | v->bdb_header.bdb_size = sizeof(struct vbt) - sizeof(struct vbt_header); |
158 | |
159 | /* general features */ |
160 | v->general_features_header.id = BDB_GENERAL_FEATURES; |
161 | v->general_features_header.size = sizeof(struct bdb_general_features); |
162 | v->general_features.int_crt_support = 0; |
163 | v->general_features.int_tv_support = 0; |
164 | |
165 | /* child device */ |
166 | num_child = 4; /* each port has one child */ |
167 | v->general_definitions.child_dev_size = |
168 | sizeof(struct efp_child_device_config); |
169 | v->general_definitions_header.id = BDB_GENERAL_DEFINITIONS; |
170 | /* size will include child devices */ |
171 | v->general_definitions_header.size = |
172 | sizeof(struct bdb_general_definitions) + |
173 | num_child * v->general_definitions.child_dev_size; |
174 | |
175 | /* portA */ |
176 | v->child0.handle = DEVICE_TYPE_EFP1; |
177 | v->child0.device_type = DEVICE_TYPE_DP; |
178 | v->child0.dvo_port = DVO_PORT_DPA; |
179 | v->child0.aux_channel = DP_AUX_A; |
180 | v->child0.dp_compat = true; |
181 | v->child0.integrated_encoder = true; |
182 | |
183 | /* portB */ |
184 | v->child1.handle = DEVICE_TYPE_EFP2; |
185 | v->child1.device_type = DEVICE_TYPE_DP; |
186 | v->child1.dvo_port = DVO_PORT_DPB; |
187 | v->child1.aux_channel = DP_AUX_B; |
188 | v->child1.dp_compat = true; |
189 | v->child1.integrated_encoder = true; |
190 | |
191 | /* portC */ |
192 | v->child2.handle = DEVICE_TYPE_EFP3; |
193 | v->child2.device_type = DEVICE_TYPE_DP; |
194 | v->child2.dvo_port = DVO_PORT_DPC; |
195 | v->child2.aux_channel = DP_AUX_C; |
196 | v->child2.dp_compat = true; |
197 | v->child2.integrated_encoder = true; |
198 | |
199 | /* portD */ |
200 | v->child3.handle = DEVICE_TYPE_EFP4; |
201 | v->child3.device_type = DEVICE_TYPE_DP; |
202 | v->child3.dvo_port = DVO_PORT_DPD; |
203 | v->child3.aux_channel = DP_AUX_D; |
204 | v->child3.dp_compat = true; |
205 | v->child3.integrated_encoder = true; |
206 | |
207 | /* driver features */ |
208 | v->driver_features_header.id = BDB_DRIVER_FEATURES; |
209 | v->driver_features_header.size = sizeof(struct bdb_driver_features); |
210 | v->driver_features.lvds_config = BDB_DRIVER_FEATURE_NO_LVDS; |
211 | } |
212 | |
213 | /** |
214 | * intel_vgpu_init_opregion - initialize the stuff used to emulate opregion |
215 | * @vgpu: a vGPU |
216 | * |
217 | * Returns: |
218 | * Zero on success, negative error code if failed. |
219 | */ |
220 | int intel_vgpu_init_opregion(struct intel_vgpu *vgpu) |
221 | { |
222 | u8 *buf; |
223 | struct opregion_header *; |
224 | struct vbt v; |
225 | const char opregion_signature[16] = OPREGION_SIGNATURE; |
226 | |
227 | gvt_dbg_core("init vgpu%d opregion\n" , vgpu->id); |
228 | vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL | |
229 | __GFP_ZERO, |
230 | order: get_order(INTEL_GVT_OPREGION_SIZE)); |
231 | if (!vgpu_opregion(vgpu)->va) { |
232 | gvt_err("fail to get memory for vgpu virt opregion\n" ); |
233 | return -ENOMEM; |
234 | } |
235 | |
236 | /* emulated opregion with VBT mailbox only */ |
237 | buf = (u8 *)vgpu_opregion(vgpu)->va; |
238 | header = (struct opregion_header *)buf; |
239 | memcpy(header->signature, opregion_signature, |
240 | sizeof(opregion_signature)); |
241 | header->size = 0x8; |
242 | header->opregion_ver = 0x02000000; |
243 | header->mboxes = MBOX_VBT; |
244 | |
245 | /* for unknown reason, the value in LID field is incorrect |
246 | * which block the windows guest, so workaround it by force |
247 | * setting it to "OPEN" |
248 | */ |
249 | buf[INTEL_GVT_OPREGION_CLID] = 0x3; |
250 | |
251 | /* emulated vbt from virt vbt generation */ |
252 | virt_vbt_generation(v: &v); |
253 | memcpy(buf + INTEL_GVT_OPREGION_VBT_OFFSET, &v, sizeof(struct vbt)); |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | /** |
259 | * intel_vgpu_opregion_base_write_handler - Opregion base register write handler |
260 | * |
261 | * @vgpu: a vGPU |
262 | * @gpa: guest physical address of opregion |
263 | * |
264 | * Returns: |
265 | * Zero on success, negative error code if failed. |
266 | */ |
267 | int intel_vgpu_opregion_base_write_handler(struct intel_vgpu *vgpu, u32 gpa) |
268 | { |
269 | |
270 | int i; |
271 | |
272 | gvt_dbg_core("emulate opregion from kernel\n" ); |
273 | |
274 | for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) |
275 | vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i; |
276 | return 0; |
277 | } |
278 | |
279 | /** |
280 | * intel_vgpu_clean_opregion - clean the stuff used to emulate opregion |
281 | * @vgpu: a vGPU |
282 | * |
283 | */ |
284 | void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu) |
285 | { |
286 | gvt_dbg_core("vgpu%d: clean vgpu opregion\n" , vgpu->id); |
287 | |
288 | if (!vgpu_opregion(vgpu)->va) |
289 | return; |
290 | |
291 | /* Guest opregion is released by VFIO */ |
292 | free_pages(addr: (unsigned long)vgpu_opregion(vgpu)->va, |
293 | order: get_order(INTEL_GVT_OPREGION_SIZE)); |
294 | |
295 | vgpu_opregion(vgpu)->va = NULL; |
296 | |
297 | } |
298 | |
299 | |
300 | #define GVT_OPREGION_FUNC(scic) \ |
301 | ({ \ |
302 | u32 __ret; \ |
303 | __ret = (scic & OPREGION_SCIC_FUNC_MASK) >> \ |
304 | OPREGION_SCIC_FUNC_SHIFT; \ |
305 | __ret; \ |
306 | }) |
307 | |
308 | #define GVT_OPREGION_SUBFUNC(scic) \ |
309 | ({ \ |
310 | u32 __ret; \ |
311 | __ret = (scic & OPREGION_SCIC_SUBFUNC_MASK) >> \ |
312 | OPREGION_SCIC_SUBFUNC_SHIFT; \ |
313 | __ret; \ |
314 | }) |
315 | |
316 | static const char *opregion_func_name(u32 func) |
317 | { |
318 | const char *name = NULL; |
319 | |
320 | switch (func) { |
321 | case 0 ... 3: |
322 | case 5: |
323 | case 7 ... 15: |
324 | name = "Reserved" ; |
325 | break; |
326 | |
327 | case 4: |
328 | name = "Get BIOS Data" ; |
329 | break; |
330 | |
331 | case 6: |
332 | name = "System BIOS Callbacks" ; |
333 | break; |
334 | |
335 | default: |
336 | name = "Unknown" ; |
337 | break; |
338 | } |
339 | return name; |
340 | } |
341 | |
342 | static const char *opregion_subfunc_name(u32 subfunc) |
343 | { |
344 | const char *name = NULL; |
345 | |
346 | switch (subfunc) { |
347 | case 0: |
348 | name = "Supported Calls" ; |
349 | break; |
350 | |
351 | case 1: |
352 | name = "Requested Callbacks" ; |
353 | break; |
354 | |
355 | case 2 ... 3: |
356 | case 8 ... 9: |
357 | name = "Reserved" ; |
358 | break; |
359 | |
360 | case 5: |
361 | name = "Boot Display" ; |
362 | break; |
363 | |
364 | case 6: |
365 | name = "TV-Standard/Video-Connector" ; |
366 | break; |
367 | |
368 | case 7: |
369 | name = "Internal Graphics" ; |
370 | break; |
371 | |
372 | case 10: |
373 | name = "Spread Spectrum Clocks" ; |
374 | break; |
375 | |
376 | case 11: |
377 | name = "Get AKSV" ; |
378 | break; |
379 | |
380 | default: |
381 | name = "Unknown" ; |
382 | break; |
383 | } |
384 | return name; |
385 | }; |
386 | |
387 | static bool querying_capabilities(u32 scic) |
388 | { |
389 | u32 func, subfunc; |
390 | |
391 | func = GVT_OPREGION_FUNC(scic); |
392 | subfunc = GVT_OPREGION_SUBFUNC(scic); |
393 | |
394 | if ((func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSDATA && |
395 | subfunc == INTEL_GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS) |
396 | || (func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSDATA && |
397 | subfunc == INTEL_GVT_OPREGION_SCIC_SF_REQEUSTEDCALLBACKS) |
398 | || (func == INTEL_GVT_OPREGION_SCIC_F_GETBIOSCALLBACKS && |
399 | subfunc == INTEL_GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS)) { |
400 | return true; |
401 | } |
402 | return false; |
403 | } |
404 | |
405 | /** |
406 | * intel_vgpu_emulate_opregion_request - emulating OpRegion request |
407 | * @vgpu: a vGPU |
408 | * @swsci: SWSCI request |
409 | * |
410 | * Returns: |
411 | * Zero on success, negative error code if failed |
412 | */ |
413 | int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci) |
414 | { |
415 | u32 scic, parm; |
416 | u32 func, subfunc; |
417 | u64 scic_pa = 0, parm_pa = 0; |
418 | int ret; |
419 | |
420 | scic_pa = (vgpu_opregion(vgpu)->gfn[0] << PAGE_SHIFT) + |
421 | INTEL_GVT_OPREGION_SCIC; |
422 | parm_pa = (vgpu_opregion(vgpu)->gfn[0] << PAGE_SHIFT) + |
423 | INTEL_GVT_OPREGION_PARM; |
424 | ret = intel_gvt_read_gpa(vgpu, gpa: scic_pa, buf: &scic, len: sizeof(scic)); |
425 | if (ret) { |
426 | gvt_vgpu_err("guest opregion read error %d, gpa 0x%llx, len %lu\n" , |
427 | ret, scic_pa, sizeof(scic)); |
428 | return ret; |
429 | } |
430 | |
431 | ret = intel_gvt_read_gpa(vgpu, gpa: parm_pa, buf: &parm, len: sizeof(parm)); |
432 | if (ret) { |
433 | gvt_vgpu_err("guest opregion read error %d, gpa 0x%llx, len %lu\n" , |
434 | ret, scic_pa, sizeof(scic)); |
435 | return ret; |
436 | } |
437 | |
438 | if (!(swsci & SWSCI_SCI_SELECT)) { |
439 | gvt_vgpu_err("requesting SMI service\n" ); |
440 | return 0; |
441 | } |
442 | /* ignore non 0->1 trasitions */ |
443 | if ((vgpu_cfg_space(vgpu)[INTEL_GVT_PCI_SWSCI] |
444 | & SWSCI_SCI_TRIGGER) || |
445 | !(swsci & SWSCI_SCI_TRIGGER)) { |
446 | return 0; |
447 | } |
448 | |
449 | func = GVT_OPREGION_FUNC(scic); |
450 | subfunc = GVT_OPREGION_SUBFUNC(scic); |
451 | if (!querying_capabilities(scic)) { |
452 | gvt_vgpu_err("requesting runtime service: func \"%s\"," |
453 | " subfunc \"%s\"\n" , |
454 | opregion_func_name(func), |
455 | opregion_subfunc_name(subfunc)); |
456 | /* |
457 | * emulate exit status of function call, '0' means |
458 | * "failure, generic, unsupported or unknown cause" |
459 | */ |
460 | scic &= ~OPREGION_SCIC_EXIT_MASK; |
461 | goto out; |
462 | } |
463 | |
464 | scic = 0; |
465 | parm = 0; |
466 | |
467 | out: |
468 | ret = intel_gvt_write_gpa(vgpu, gpa: scic_pa, buf: &scic, len: sizeof(scic)); |
469 | if (ret) { |
470 | gvt_vgpu_err("guest opregion write error %d, gpa 0x%llx, len %lu\n" , |
471 | ret, scic_pa, sizeof(scic)); |
472 | return ret; |
473 | } |
474 | |
475 | ret = intel_gvt_write_gpa(vgpu, gpa: parm_pa, buf: &parm, len: sizeof(parm)); |
476 | if (ret) { |
477 | gvt_vgpu_err("guest opregion write error %d, gpa 0x%llx, len %lu\n" , |
478 | ret, scic_pa, sizeof(scic)); |
479 | return ret; |
480 | } |
481 | |
482 | return 0; |
483 | } |
484 | |