mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
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: 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
This commit is contained in:
parent
5405d25b9e
commit
32160e6a98
3 changed files with 58 additions and 8 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue