hyperv_drm_drv.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2021 Microsoft
  4. */
  5. #include <linux/aperture.h>
  6. #include <linux/efi.h>
  7. #include <linux/hyperv.h>
  8. #include <linux/module.h>
  9. #include <linux/pci.h>
  10. #include <drm/clients/drm_client_setup.h>
  11. #include <drm/drm_atomic_helper.h>
  12. #include <drm/drm_drv.h>
  13. #include <drm/drm_fbdev_shmem.h>
  14. #include <drm/drm_gem_shmem_helper.h>
  15. #include <drm/drm_print.h>
  16. #include <drm/drm_simple_kms_helper.h>
  17. #include "hyperv_drm.h"
  18. #define DRIVER_NAME "hyperv_drm"
  19. #define DRIVER_DESC "DRM driver for Hyper-V synthetic video device"
  20. #define DRIVER_MAJOR 1
  21. #define DRIVER_MINOR 0
  22. DEFINE_DRM_GEM_FOPS(hv_fops);
  23. static struct drm_driver hyperv_driver = {
  24. .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
  25. .name = DRIVER_NAME,
  26. .desc = DRIVER_DESC,
  27. .major = DRIVER_MAJOR,
  28. .minor = DRIVER_MINOR,
  29. .fops = &hv_fops,
  30. DRM_GEM_SHMEM_DRIVER_OPS,
  31. DRM_FBDEV_SHMEM_DRIVER_OPS,
  32. };
  33. static int hyperv_pci_probe(struct pci_dev *pdev,
  34. const struct pci_device_id *ent)
  35. {
  36. return 0;
  37. }
  38. static void hyperv_pci_remove(struct pci_dev *pdev)
  39. {
  40. }
  41. static const struct pci_device_id hyperv_pci_tbl[] = {
  42. {
  43. .vendor = PCI_VENDOR_ID_MICROSOFT,
  44. .device = PCI_DEVICE_ID_HYPERV_VIDEO,
  45. },
  46. { /* end of list */ }
  47. };
  48. /*
  49. * PCI stub to support gen1 VM.
  50. */
  51. static struct pci_driver hyperv_pci_driver = {
  52. .name = KBUILD_MODNAME,
  53. .id_table = hyperv_pci_tbl,
  54. .probe = hyperv_pci_probe,
  55. .remove = hyperv_pci_remove,
  56. };
  57. static int hyperv_setup_vram(struct hyperv_drm_device *hv,
  58. struct hv_device *hdev)
  59. {
  60. struct drm_device *dev = &hv->dev;
  61. int ret;
  62. hv->fb_size = (unsigned long)hv->mmio_megabytes * 1024 * 1024;
  63. ret = vmbus_allocate_mmio(&hv->mem, hdev, 0, -1, hv->fb_size, 0x100000,
  64. true);
  65. if (ret) {
  66. drm_err(dev, "Failed to allocate mmio\n");
  67. return -ENOMEM;
  68. }
  69. /*
  70. * Map the VRAM cacheable for performance. This is also required for VM
  71. * connect to display properly for ARM64 Linux VM, as the host also maps
  72. * the VRAM cacheable.
  73. */
  74. hv->vram = ioremap_cache(hv->mem->start, hv->fb_size);
  75. if (!hv->vram) {
  76. drm_err(dev, "Failed to map vram\n");
  77. ret = -ENOMEM;
  78. goto error;
  79. }
  80. hv->fb_base = hv->mem->start;
  81. return 0;
  82. error:
  83. vmbus_free_mmio(hv->mem->start, hv->fb_size);
  84. return ret;
  85. }
  86. static int hyperv_vmbus_probe(struct hv_device *hdev,
  87. const struct hv_vmbus_device_id *dev_id)
  88. {
  89. struct hyperv_drm_device *hv;
  90. struct drm_device *dev;
  91. int ret;
  92. hv = devm_drm_dev_alloc(&hdev->device, &hyperv_driver,
  93. struct hyperv_drm_device, dev);
  94. if (IS_ERR(hv))
  95. return PTR_ERR(hv);
  96. dev = &hv->dev;
  97. init_completion(&hv->wait);
  98. hv_set_drvdata(hdev, hv);
  99. hv->hdev = hdev;
  100. ret = hyperv_connect_vsp(hdev);
  101. if (ret) {
  102. drm_err(dev, "Failed to connect to vmbus.\n");
  103. goto err_hv_set_drv_data;
  104. }
  105. aperture_remove_all_conflicting_devices(hyperv_driver.name);
  106. ret = hyperv_setup_vram(hv, hdev);
  107. if (ret)
  108. goto err_vmbus_close;
  109. /*
  110. * Should be done only once during init and resume. Failing to update
  111. * vram location is not fatal. Device will update dirty area till
  112. * preferred resolution only.
  113. */
  114. ret = hyperv_update_vram_location(hdev, hv->fb_base);
  115. if (ret)
  116. drm_warn(dev, "Failed to update vram location.\n");
  117. ret = hyperv_mode_config_init(hv);
  118. if (ret)
  119. goto err_free_mmio;
  120. ret = drm_dev_register(dev, 0);
  121. if (ret) {
  122. drm_err(dev, "Failed to register drm driver.\n");
  123. goto err_free_mmio;
  124. }
  125. drm_client_setup(dev, NULL);
  126. return 0;
  127. err_free_mmio:
  128. iounmap(hv->vram);
  129. vmbus_free_mmio(hv->mem->start, hv->fb_size);
  130. err_vmbus_close:
  131. vmbus_close(hdev->channel);
  132. err_hv_set_drv_data:
  133. hv_set_drvdata(hdev, NULL);
  134. return ret;
  135. }
  136. static void hyperv_vmbus_remove(struct hv_device *hdev)
  137. {
  138. struct drm_device *dev = hv_get_drvdata(hdev);
  139. struct hyperv_drm_device *hv = to_hv(dev);
  140. drm_dev_unplug(dev);
  141. drm_atomic_helper_shutdown(dev);
  142. vmbus_close(hdev->channel);
  143. hv_set_drvdata(hdev, NULL);
  144. iounmap(hv->vram);
  145. vmbus_free_mmio(hv->mem->start, hv->fb_size);
  146. }
  147. static void hyperv_vmbus_shutdown(struct hv_device *hdev)
  148. {
  149. drm_atomic_helper_shutdown(hv_get_drvdata(hdev));
  150. }
  151. static int hyperv_vmbus_suspend(struct hv_device *hdev)
  152. {
  153. struct drm_device *dev = hv_get_drvdata(hdev);
  154. int ret;
  155. ret = drm_mode_config_helper_suspend(dev);
  156. if (ret)
  157. return ret;
  158. vmbus_close(hdev->channel);
  159. return 0;
  160. }
  161. static int hyperv_vmbus_resume(struct hv_device *hdev)
  162. {
  163. struct drm_device *dev = hv_get_drvdata(hdev);
  164. struct hyperv_drm_device *hv = to_hv(dev);
  165. int ret;
  166. ret = hyperv_connect_vsp(hdev);
  167. if (ret)
  168. return ret;
  169. ret = hyperv_update_vram_location(hdev, hv->fb_base);
  170. if (ret)
  171. return ret;
  172. return drm_mode_config_helper_resume(dev);
  173. }
  174. static const struct hv_vmbus_device_id hyperv_vmbus_tbl[] = {
  175. /* Synthetic Video Device GUID */
  176. {HV_SYNTHVID_GUID},
  177. {}
  178. };
  179. static struct hv_driver hyperv_hv_driver = {
  180. .name = KBUILD_MODNAME,
  181. .id_table = hyperv_vmbus_tbl,
  182. .probe = hyperv_vmbus_probe,
  183. .remove = hyperv_vmbus_remove,
  184. .shutdown = hyperv_vmbus_shutdown,
  185. .suspend = hyperv_vmbus_suspend,
  186. .resume = hyperv_vmbus_resume,
  187. .driver = {
  188. .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  189. },
  190. };
  191. static int __init hyperv_init(void)
  192. {
  193. int ret;
  194. if (drm_firmware_drivers_only())
  195. return -ENODEV;
  196. ret = pci_register_driver(&hyperv_pci_driver);
  197. if (ret != 0)
  198. return ret;
  199. return vmbus_driver_register(&hyperv_hv_driver);
  200. }
  201. static void __exit hyperv_exit(void)
  202. {
  203. vmbus_driver_unregister(&hyperv_hv_driver);
  204. pci_unregister_driver(&hyperv_pci_driver);
  205. }
  206. module_init(hyperv_init);
  207. module_exit(hyperv_exit);
  208. MODULE_DEVICE_TABLE(pci, hyperv_pci_tbl);
  209. MODULE_DEVICE_TABLE(vmbus, hyperv_vmbus_tbl);
  210. MODULE_LICENSE("GPL");
  211. MODULE_AUTHOR("Deepak Rawat <drawat.floss@gmail.com>");
  212. MODULE_DESCRIPTION("DRM driver for Hyper-V synthetic video device");