OSDN Git Service

drm/vmwgfx: Implement MSI/MSI-X support for IRQs
authorZack Rusin <zackr@vmware.com>
Mon, 7 Mar 2022 16:24:12 +0000 (11:24 -0500)
committerZack Rusin <zackr@vmware.com>
Fri, 11 Mar 2022 18:29:37 +0000 (13:29 -0500)
SVGAv3 deprecates legacy interrupts and adds support for MSI/MSI-X. With
MSI the driver visible side remains largely unchanged but with MSI-X
each interrupt gets delivered on its own vector.

Add support for MSI/MSI-X while preserving the old functionality for
SVGAv2. Code between the SVGAv2 and SVGAv3 is exactly the same, only
the number of available vectors changes, in particular between legacy
and MSI-X interrupts.

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: Martin Krastev <krastevm@vmware.com>
Reviewed-by: Maaz Mombasawala <mombasawalam@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220307162412.1183049-1-zack@kde.org
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c

index f43afd5..791f9a5 100644 (file)
@@ -980,7 +980,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
        }
 
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
-               ret = vmw_irq_install(&dev_priv->drm, pdev->irq);
+               ret = vmw_irq_install(dev_priv);
                if (ret != 0) {
                        drm_err(&dev_priv->drm,
                                "Failed installing irq: %d\n", ret);
index 12eb4de..be19aa6 100644 (file)
 #define VMWGFX_PCI_ID_SVGA3              0x0406
 
 /*
+ * This has to match get_count_order(SVGA_IRQFLAG_MAX)
+ */
+#define VMWGFX_MAX_NUM_IRQS 6
+
+/*
  * Perhaps we should have sysfs entries for these.
  */
 #define VMWGFX_NUM_GB_CONTEXT 256
@@ -532,6 +537,8 @@ struct vmw_private {
        bool has_mob;
        spinlock_t hw_lock;
        bool assume_16bpp;
+       u32 irqs[VMWGFX_MAX_NUM_IRQS];
+       u32 num_irq_vectors;
 
        enum vmw_sm_type sm_type;
 
@@ -1158,7 +1165,7 @@ bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
  * IRQs and wating - vmwgfx_irq.c
  */
 
-extern int vmw_irq_install(struct drm_device *dev, int irq);
+extern int vmw_irq_install(struct vmw_private *dev_priv);
 extern void vmw_irq_uninstall(struct drm_device *dev);
 extern bool vmw_seqno_passed(struct vmw_private *dev_priv,
                                uint32_t seqno);
index fe4732b..086e69a 100644 (file)
@@ -300,6 +300,7 @@ void vmw_irq_uninstall(struct drm_device *dev)
        struct vmw_private *dev_priv = vmw_priv(dev);
        struct pci_dev *pdev = to_pci_dev(dev->dev);
        uint32_t status;
+       u32 i;
 
        if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
                return;
@@ -309,20 +310,62 @@ void vmw_irq_uninstall(struct drm_device *dev)
        status = vmw_irq_status_read(dev_priv);
        vmw_irq_status_write(dev_priv, status);
 
-       free_irq(pdev->irq, dev);
+       for (i = 0; i < dev_priv->num_irq_vectors; ++i)
+               free_irq(dev_priv->irqs[i], dev);
+
+       pci_free_irq_vectors(pdev);
+       dev_priv->num_irq_vectors = 0;
 }
 
 /**
  * vmw_irq_install - Install the irq handlers
  *
- * @dev:  Pointer to the drm device.
- * @irq:  The irq number.
+ * @dev_priv:  Pointer to the vmw_private device.
  * Return:  Zero if successful. Negative number otherwise.
  */
-int vmw_irq_install(struct drm_device *dev, int irq)
+int vmw_irq_install(struct vmw_private *dev_priv)
 {
+       struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+       struct drm_device *dev = &dev_priv->drm;
+       int ret;
+       int nvec;
+       int i = 0;
+
+       BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1);
+       BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX));
+
+       nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS,
+                                    PCI_IRQ_ALL_TYPES);
+
+       if (nvec <= 0) {
+               drm_err(&dev_priv->drm,
+                       "IRQ's are unavailable, nvec: %d\n", nvec);
+               ret = nvec;
+               goto done;
+       }
+
        vmw_irq_preinstall(dev);
 
-       return request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn,
-                                   IRQF_SHARED, VMWGFX_DRIVER_NAME, dev);
+       for (i = 0; i < nvec; ++i) {
+               ret = pci_irq_vector(pdev, i);
+               if (ret < 0) {
+                       drm_err(&dev_priv->drm,
+                               "failed getting irq vector: %d\n", ret);
+                       goto done;
+               }
+               dev_priv->irqs[i] = ret;
+
+               ret = request_threaded_irq(dev_priv->irqs[i], vmw_irq_handler, vmw_thread_fn,
+                                          IRQF_SHARED, VMWGFX_DRIVER_NAME, dev);
+               if (ret != 0) {
+                       drm_err(&dev_priv->drm,
+                               "Failed installing irq(%d): %d\n",
+                               dev_priv->irqs[i], ret);
+                       goto done;
+               }
+       }
+
+done:
+       dev_priv->num_irq_vectors = i;
+       return ret;
 }