Commit 32160e6a authored by Zack Rusin's avatar Zack Rusin
Browse files

drm/vmwgfx: Implement MSI/MSI-X support for IRQs



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: default avatarZack Rusin <zackr@vmware.com>
Reviewed-by: default avatarMartin Krastev <krastevm@vmware.com>
Reviewed-by: default avatarMaaz Mombasawala <mombasawalam@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220307162412.1183049-1-zack@kde.org
parent 5405d25b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+8 −1
Original line number Diff line number Diff line
@@ -65,6 +65,11 @@
#define VMWGFX_PCI_ID_SVGA2              0x0405
#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.
 */
@@ -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);
+49 −6
Original line number Diff line number Diff line
@@ -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,
	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;
}