Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+58 -8
+1 -1
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
··· 980 980 } 981 981 982 982 if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { 983 - ret = vmw_irq_install(&dev_priv->drm, pdev->irq); 983 + ret = vmw_irq_install(dev_priv); 984 984 if (ret != 0) { 985 985 drm_err(&dev_priv->drm, 986 986 "Failed installing irq: %d\n", ret);
+8 -1
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 66 66 #define VMWGFX_PCI_ID_SVGA3 0x0406 67 67 68 68 /* 69 + * This has to match get_count_order(SVGA_IRQFLAG_MAX) 70 + */ 71 + #define VMWGFX_MAX_NUM_IRQS 6 72 + 73 + /* 69 74 * Perhaps we should have sysfs entries for these. 70 75 */ 71 76 #define VMWGFX_NUM_GB_CONTEXT 256 ··· 537 532 bool has_mob; 538 533 spinlock_t hw_lock; 539 534 bool assume_16bpp; 535 + u32 irqs[VMWGFX_MAX_NUM_IRQS]; 536 + u32 num_irq_vectors; 540 537 541 538 enum vmw_sm_type sm_type; 542 539 ··· 1165 1158 * IRQs and wating - vmwgfx_irq.c 1166 1159 */ 1167 1160 1168 - extern int vmw_irq_install(struct drm_device *dev, int irq); 1161 + extern int vmw_irq_install(struct vmw_private *dev_priv); 1169 1162 extern void vmw_irq_uninstall(struct drm_device *dev); 1170 1163 extern bool vmw_seqno_passed(struct vmw_private *dev_priv, 1171 1164 uint32_t seqno);
+49 -6
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
··· 300 300 struct vmw_private *dev_priv = vmw_priv(dev); 301 301 struct pci_dev *pdev = to_pci_dev(dev->dev); 302 302 uint32_t status; 303 + u32 i; 303 304 304 305 if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 305 306 return; ··· 310 309 status = vmw_irq_status_read(dev_priv); 311 310 vmw_irq_status_write(dev_priv, status); 312 311 313 - free_irq(pdev->irq, dev); 312 + for (i = 0; i < dev_priv->num_irq_vectors; ++i) 313 + free_irq(dev_priv->irqs[i], dev); 314 + 315 + pci_free_irq_vectors(pdev); 316 + dev_priv->num_irq_vectors = 0; 314 317 } 315 318 316 319 /** 317 320 * vmw_irq_install - Install the irq handlers 318 321 * 319 - * @dev: Pointer to the drm device. 320 - * @irq: The irq number. 322 + * @dev_priv: Pointer to the vmw_private device. 321 323 * Return: Zero if successful. Negative number otherwise. 322 324 */ 323 - int vmw_irq_install(struct drm_device *dev, int irq) 325 + int vmw_irq_install(struct vmw_private *dev_priv) 324 326 { 327 + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 328 + struct drm_device *dev = &dev_priv->drm; 329 + int ret; 330 + int nvec; 331 + int i = 0; 332 + 333 + BUILD_BUG_ON((SVGA_IRQFLAG_MAX >> VMWGFX_MAX_NUM_IRQS) != 1); 334 + BUG_ON(VMWGFX_MAX_NUM_IRQS != get_count_order(SVGA_IRQFLAG_MAX)); 335 + 336 + nvec = pci_alloc_irq_vectors(pdev, 1, VMWGFX_MAX_NUM_IRQS, 337 + PCI_IRQ_ALL_TYPES); 338 + 339 + if (nvec <= 0) { 340 + drm_err(&dev_priv->drm, 341 + "IRQ's are unavailable, nvec: %d\n", nvec); 342 + ret = nvec; 343 + goto done; 344 + } 345 + 325 346 vmw_irq_preinstall(dev); 326 347 327 - return request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn, 328 - IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); 348 + for (i = 0; i < nvec; ++i) { 349 + ret = pci_irq_vector(pdev, i); 350 + if (ret < 0) { 351 + drm_err(&dev_priv->drm, 352 + "failed getting irq vector: %d\n", ret); 353 + goto done; 354 + } 355 + dev_priv->irqs[i] = ret; 356 + 357 + ret = request_threaded_irq(dev_priv->irqs[i], vmw_irq_handler, vmw_thread_fn, 358 + IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); 359 + if (ret != 0) { 360 + drm_err(&dev_priv->drm, 361 + "Failed installing irq(%d): %d\n", 362 + dev_priv->irqs[i], ret); 363 + goto done; 364 + } 365 + } 366 + 367 + done: 368 + dev_priv->num_irq_vectors = i; 369 + return ret; 329 370 }