vbox_irq.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-License-Identifier: MIT
  2. /*
  3. * Copyright (C) 2016-2017 Oracle Corporation
  4. * This file is based on qxl_irq.c
  5. * Copyright 2013 Red Hat Inc.
  6. * Authors: Dave Airlie
  7. * Alon Levy
  8. * Michael Thayer <michael.thayer@oracle.com,
  9. * Hans de Goede <hdegoede@redhat.com>
  10. */
  11. #include <linux/pci.h>
  12. #include <drm/drm_drv.h>
  13. #include <drm/drm_print.h>
  14. #include <drm/drm_probe_helper.h>
  15. #include "vbox_drv.h"
  16. #include "vboxvideo.h"
  17. static void vbox_clear_irq(void)
  18. {
  19. outl((u32)~0, VGA_PORT_HGSMI_HOST);
  20. }
  21. static u32 vbox_get_flags(struct vbox_private *vbox)
  22. {
  23. return readl(vbox->guest_heap + HOST_FLAGS_OFFSET);
  24. }
  25. void vbox_report_hotplug(struct vbox_private *vbox)
  26. {
  27. schedule_work(&vbox->hotplug_work);
  28. }
  29. static irqreturn_t vbox_irq_handler(int irq, void *arg)
  30. {
  31. struct drm_device *dev = (struct drm_device *)arg;
  32. struct vbox_private *vbox = to_vbox_dev(dev);
  33. u32 host_flags = vbox_get_flags(vbox);
  34. if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
  35. return IRQ_NONE;
  36. /*
  37. * Due to a bug in the initial host implementation of hot-plug irqs,
  38. * the hot-plug and cursor capability flags were never cleared.
  39. * Fortunately we can tell when they would have been set by checking
  40. * that the VSYNC flag is not set.
  41. */
  42. if (host_flags &
  43. (HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES) &&
  44. !(host_flags & HGSMIHOSTFLAGS_VSYNC))
  45. vbox_report_hotplug(vbox);
  46. vbox_clear_irq();
  47. return IRQ_HANDLED;
  48. }
  49. /*
  50. * Check that the position hints provided by the host are suitable for GNOME
  51. * shell (i.e. all screens disjoint and hints for all enabled screens) and if
  52. * not replace them with default ones. Providing valid hints improves the
  53. * chances that we will get a known screen layout for pointer mapping.
  54. */
  55. static void validate_or_set_position_hints(struct vbox_private *vbox)
  56. {
  57. struct vbva_modehint *hintsi, *hintsj;
  58. bool valid = true;
  59. u16 currentx = 0;
  60. int i, j;
  61. for (i = 0; i < vbox->num_crtcs; ++i) {
  62. for (j = 0; j < i; ++j) {
  63. hintsi = &vbox->last_mode_hints[i];
  64. hintsj = &vbox->last_mode_hints[j];
  65. if (hintsi->enabled && hintsj->enabled) {
  66. if (hintsi->dx >= 0xffff ||
  67. hintsi->dy >= 0xffff ||
  68. hintsj->dx >= 0xffff ||
  69. hintsj->dy >= 0xffff ||
  70. (hintsi->dx <
  71. hintsj->dx + (hintsj->cx & 0x8fff) &&
  72. hintsi->dx + (hintsi->cx & 0x8fff) >
  73. hintsj->dx) ||
  74. (hintsi->dy <
  75. hintsj->dy + (hintsj->cy & 0x8fff) &&
  76. hintsi->dy + (hintsi->cy & 0x8fff) >
  77. hintsj->dy))
  78. valid = false;
  79. }
  80. }
  81. }
  82. if (!valid)
  83. for (i = 0; i < vbox->num_crtcs; ++i) {
  84. if (vbox->last_mode_hints[i].enabled) {
  85. vbox->last_mode_hints[i].dx = currentx;
  86. vbox->last_mode_hints[i].dy = 0;
  87. currentx +=
  88. vbox->last_mode_hints[i].cx & 0x8fff;
  89. }
  90. }
  91. }
  92. /* Query the host for the most recent video mode hints. */
  93. static void vbox_update_mode_hints(struct vbox_private *vbox)
  94. {
  95. struct drm_connector_list_iter conn_iter;
  96. struct drm_device *dev = &vbox->ddev;
  97. struct drm_connector *connector;
  98. struct vbox_connector *vbox_conn;
  99. struct vbva_modehint *hints;
  100. u16 flags;
  101. bool disconnected;
  102. unsigned int crtc_id;
  103. int ret;
  104. ret = hgsmi_get_mode_hints(vbox->guest_pool, vbox->num_crtcs,
  105. vbox->last_mode_hints);
  106. if (ret) {
  107. DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret);
  108. return;
  109. }
  110. validate_or_set_position_hints(vbox);
  111. drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
  112. drm_connector_list_iter_begin(dev, &conn_iter);
  113. drm_for_each_connector_iter(connector, &conn_iter) {
  114. vbox_conn = to_vbox_connector(connector);
  115. hints = &vbox->last_mode_hints[vbox_conn->vbox_crtc->crtc_id];
  116. if (hints->magic != VBVAMODEHINT_MAGIC)
  117. continue;
  118. disconnected = !(hints->enabled);
  119. crtc_id = vbox_conn->vbox_crtc->crtc_id;
  120. vbox_conn->mode_hint.width = hints->cx;
  121. vbox_conn->mode_hint.height = hints->cy;
  122. vbox_conn->vbox_crtc->x_hint = hints->dx;
  123. vbox_conn->vbox_crtc->y_hint = hints->dy;
  124. vbox_conn->mode_hint.disconnected = disconnected;
  125. if (vbox_conn->vbox_crtc->disconnected == disconnected)
  126. continue;
  127. if (disconnected)
  128. flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED;
  129. else
  130. flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_BLANK;
  131. hgsmi_process_display_info(vbox->guest_pool, crtc_id, 0, 0, 0,
  132. hints->cx * 4, hints->cx,
  133. hints->cy, 0, flags);
  134. vbox_conn->vbox_crtc->disconnected = disconnected;
  135. }
  136. drm_connector_list_iter_end(&conn_iter);
  137. drm_modeset_unlock(&dev->mode_config.connection_mutex);
  138. }
  139. static void vbox_hotplug_worker(struct work_struct *work)
  140. {
  141. struct vbox_private *vbox = container_of(work, struct vbox_private,
  142. hotplug_work);
  143. vbox_update_mode_hints(vbox);
  144. drm_kms_helper_hotplug_event(&vbox->ddev);
  145. }
  146. int vbox_irq_init(struct vbox_private *vbox)
  147. {
  148. struct drm_device *dev = &vbox->ddev;
  149. struct pci_dev *pdev = to_pci_dev(dev->dev);
  150. INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
  151. vbox_update_mode_hints(vbox);
  152. /* PCI devices require shared interrupts. */
  153. return request_irq(pdev->irq, vbox_irq_handler, IRQF_SHARED, dev->driver->name, dev);
  154. }
  155. void vbox_irq_fini(struct vbox_private *vbox)
  156. {
  157. struct drm_device *dev = &vbox->ddev;
  158. struct pci_dev *pdev = to_pci_dev(dev->dev);
  159. free_irq(pdev->irq, dev);
  160. flush_work(&vbox->hotplug_work);
  161. }