opregion.c 7.3 KB

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