mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
drm/xe/irq: Manage MSI-X interrupts allocation
Expose functions to request and free MSI-X interrupts. The request has two flavors: - Static MSI-X allocation, for known MSI-X interrupts (e.g. GuC-to-host) - Dynamic MSI-X allocation, which uses the next available MSI-X interrupt Signed-off-by: Ilia Levi <ilia.levi@intel.com> Reviewed-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20241213072538.6823-4-ilia.levi@intel.com Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
@@ -353,6 +353,8 @@ struct xe_device {
|
||||
struct {
|
||||
/** @irq.msix.nvec: number of MSI-X interrupts */
|
||||
u16 nvec;
|
||||
/** @irq.msix.indexes: used to allocate MSI-X indexes */
|
||||
struct xarray indexes;
|
||||
} msix;
|
||||
} irq;
|
||||
|
||||
|
||||
@@ -830,6 +830,7 @@ static int xe_irq_msix_init(struct xe_device *xe)
|
||||
}
|
||||
|
||||
xe->irq.msix.nvec = nvec;
|
||||
xa_init_flags(&xe->irq.msix.indexes, XA_FLAGS_ALLOC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -879,8 +880,32 @@ static irqreturn_t xe_irq_msix_default_hwe_handler(int irq, void *arg)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler,
|
||||
const char *name, u16 msix)
|
||||
static int xe_irq_msix_alloc_vector(struct xe_device *xe, void *irq_buf,
|
||||
bool dynamic_msix, u16 *msix)
|
||||
{
|
||||
struct xa_limit limit;
|
||||
int ret;
|
||||
u32 id;
|
||||
|
||||
limit = (dynamic_msix) ? XA_LIMIT(NUM_OF_STATIC_MSIX, xe->irq.msix.nvec - 1) :
|
||||
XA_LIMIT(*msix, *msix);
|
||||
ret = xa_alloc(&xe->irq.msix.indexes, &id, irq_buf, limit, GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dynamic_msix)
|
||||
*msix = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xe_irq_msix_release_vector(struct xe_device *xe, u16 msix)
|
||||
{
|
||||
xa_erase(&xe->irq.msix.indexes, msix);
|
||||
}
|
||||
|
||||
static int xe_irq_msix_request_irq_internal(struct xe_device *xe, irq_handler_t handler,
|
||||
void *irq_buf, const char *name, u16 msix)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
|
||||
int ret, irq;
|
||||
@@ -889,17 +914,41 @@ static int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler,
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = request_irq(irq, handler, IRQF_SHARED, name, xe);
|
||||
ret = request_irq(irq, handler, IRQF_SHARED, name, irq_buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix)
|
||||
int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler, void *irq_buf,
|
||||
const char *name, bool dynamic_msix, u16 *msix)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xe_irq_msix_alloc_vector(xe, irq_buf, dynamic_msix, msix);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xe_irq_msix_request_irq_internal(xe, handler, irq_buf, name, *msix);
|
||||
if (ret) {
|
||||
drm_err(&xe->drm, "Failed to request IRQ for MSI-X %u\n", *msix);
|
||||
xe_irq_msix_release_vector(xe, *msix);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
|
||||
int irq;
|
||||
void *irq_buf;
|
||||
|
||||
irq_buf = xa_load(&xe->irq.msix.indexes, msix);
|
||||
if (!irq_buf)
|
||||
return;
|
||||
|
||||
irq = pci_irq_vector(pdev, msix);
|
||||
if (irq < 0) {
|
||||
@@ -907,24 +956,25 @@ static void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix)
|
||||
return;
|
||||
}
|
||||
|
||||
free_irq(irq, xe);
|
||||
free_irq(irq, irq_buf);
|
||||
xe_irq_msix_release_vector(xe, msix);
|
||||
}
|
||||
|
||||
static int xe_irq_msix_request_irqs(struct xe_device *xe)
|
||||
int xe_irq_msix_request_irqs(struct xe_device *xe)
|
||||
{
|
||||
int err;
|
||||
u16 msix;
|
||||
|
||||
err = xe_irq_msix_request_irq(xe, guc2host_irq_handler,
|
||||
DRIVER_NAME "-guc2host", GUC2HOST_MSIX);
|
||||
if (err) {
|
||||
drm_err(&xe->drm, "Failed to request MSI-X IRQ %d: %d\n", GUC2HOST_MSIX, err);
|
||||
msix = GUC2HOST_MSIX;
|
||||
err = xe_irq_msix_request_irq(xe, guc2host_irq_handler, xe,
|
||||
DRIVER_NAME "-guc2host", false, &msix);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = xe_irq_msix_request_irq(xe, xe_irq_msix_default_hwe_handler,
|
||||
DRIVER_NAME "-default-msix", DEFAULT_MSIX);
|
||||
msix = DEFAULT_MSIX;
|
||||
err = xe_irq_msix_request_irq(xe, xe_irq_msix_default_hwe_handler, xe,
|
||||
DRIVER_NAME "-default-msix", false, &msix);
|
||||
if (err) {
|
||||
drm_err(&xe->drm, "Failed to request MSI-X IRQ %d: %d\n", DEFAULT_MSIX, err);
|
||||
xe_irq_msix_free_irq(xe, GUC2HOST_MSIX);
|
||||
return err;
|
||||
}
|
||||
@@ -932,16 +982,22 @@ static int xe_irq_msix_request_irqs(struct xe_device *xe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xe_irq_msix_free(struct xe_device *xe)
|
||||
void xe_irq_msix_free(struct xe_device *xe)
|
||||
{
|
||||
xe_irq_msix_free_irq(xe, GUC2HOST_MSIX);
|
||||
xe_irq_msix_free_irq(xe, DEFAULT_MSIX);
|
||||
unsigned long msix;
|
||||
u32 *dummy;
|
||||
|
||||
xa_for_each(&xe->irq.msix.indexes, msix, dummy)
|
||||
xe_irq_msix_free_irq(xe, msix);
|
||||
xa_destroy(&xe->irq.msix.indexes);
|
||||
}
|
||||
|
||||
static void xe_irq_msix_synchronize_irq(struct xe_device *xe)
|
||||
void xe_irq_msix_synchronize_irq(struct xe_device *xe)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
|
||||
unsigned long msix;
|
||||
u32 *dummy;
|
||||
|
||||
synchronize_irq(pci_irq_vector(pdev, GUC2HOST_MSIX));
|
||||
synchronize_irq(pci_irq_vector(pdev, DEFAULT_MSIX));
|
||||
xa_for_each(&xe->irq.msix.indexes, msix, dummy)
|
||||
synchronize_irq(pci_irq_vector(pdev, msix));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef _XE_IRQ_H_
|
||||
#define _XE_IRQ_H_
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#define XE_IRQ_DEFAULT_MSIX 1
|
||||
|
||||
struct xe_device;
|
||||
@@ -17,5 +19,8 @@ int xe_irq_install(struct xe_device *xe);
|
||||
void xe_irq_suspend(struct xe_device *xe);
|
||||
void xe_irq_resume(struct xe_device *xe);
|
||||
void xe_irq_enable_hwe(struct xe_gt *gt);
|
||||
int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler, void *irq_buf,
|
||||
const char *name, bool dynamic_msix, u16 *msix);
|
||||
void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user