Unverified Commit f0d3a3cf authored by Ilia Levi's avatar Ilia Levi Committed by Rodrigo Vivi
Browse files

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: default avatarIlia Levi <ilia.levi@intel.com>
Reviewed-by: default avatarPiotr Piórkowski <piotr.piorkowski@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241213072538.6823-4-ilia.levi@intel.com


Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 21d07f5f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;

+76 −20
Original line number Diff line number Diff line
@@ -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));
}
+5 −0
Original line number Diff line number Diff line
@@ -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