Commit fe35ecee authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

irqchip/riscv-imsic: Move to common MSI library



Simplify the leaf MSI domain handling in the RISC-V IMSIC driver by
using msi_lib_init_dev_msi_info() and msi_lib_irq_domain_select()
provided by the common MSI library.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarAndrew Jones <ajones@ventanamicro.com>
Signed-off-by: default avatarAnup Patel <apatel@ventanamicro.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250217085657.789309-4-apatel@ventanamicro.com
parent 1c000dca
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -589,13 +589,7 @@ config RISCV_IMSIC
	select IRQ_DOMAIN_HIERARCHY
	select GENERIC_IRQ_MATRIX_ALLOCATOR
	select GENERIC_MSI_IRQ

config RISCV_IMSIC_PCI
	bool
	depends on RISCV_IMSIC
	depends on PCI
	depends on PCI_MSI
	default RISCV_IMSIC
	select IRQ_MSI_LIB

config SIFIVE_PLIC
	bool
+5 −109
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/spinlock.h>
#include <linux/smp.h>

#include "irq-msi-lib.h"
#include "irq-riscv-imsic-state.h"

static bool imsic_cpu_page_phys(unsigned int cpu, unsigned int guest_index,
@@ -174,22 +175,6 @@ static void imsic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
}

static int imsic_irq_domain_select(struct irq_domain *domain, struct irq_fwspec *fwspec,
				   enum irq_domain_bus_token bus_token)
{
	const struct msi_parent_ops *ops = domain->msi_parent_ops;
	u32 busmask = BIT(bus_token);

	if (fwspec->fwnode != domain->fwnode || fwspec->param_count != 0)
		return 0;

	/* Handle pure domain searches */
	if (bus_token == ops->bus_select_token)
		return 1;

	return !!(ops->bus_select_mask & busmask);
}

#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
static void imsic_irq_debug_show(struct seq_file *m, struct irq_domain *d,
				 struct irq_data *irqd, int ind)
@@ -206,110 +191,21 @@ static void imsic_irq_debug_show(struct seq_file *m, struct irq_domain *d,
static const struct irq_domain_ops imsic_base_domain_ops = {
	.alloc		= imsic_irq_domain_alloc,
	.free		= imsic_irq_domain_free,
	.select		= imsic_irq_domain_select,
	.select		= msi_lib_irq_domain_select,
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
	.debug_show	= imsic_irq_debug_show,
#endif
};

#ifdef CONFIG_RISCV_IMSIC_PCI

static void imsic_pci_mask_irq(struct irq_data *d)
{
	pci_msi_mask_irq(d);
	irq_chip_mask_parent(d);
}

static void imsic_pci_unmask_irq(struct irq_data *d)
{
	irq_chip_unmask_parent(d);
	pci_msi_unmask_irq(d);
}

#define MATCH_PCI_MSI		BIT(DOMAIN_BUS_PCI_MSI)

#else

#define MATCH_PCI_MSI		0

#endif

static bool imsic_init_dev_msi_info(struct device *dev,
				    struct irq_domain *domain,
				    struct irq_domain *real_parent,
				    struct msi_domain_info *info)
{
	const struct msi_parent_ops *pops = real_parent->msi_parent_ops;

	/* MSI parent domain specific settings */
	switch (real_parent->bus_token) {
	case DOMAIN_BUS_NEXUS:
		if (WARN_ON_ONCE(domain != real_parent))
			return false;
#ifdef CONFIG_SMP
		info->chip->irq_set_affinity = irq_chip_set_affinity_parent;
#endif
		break;
	default:
		WARN_ON_ONCE(1);
		return false;
	}

	/* Is the target supported? */
	switch (info->bus_token) {
#ifdef CONFIG_RISCV_IMSIC_PCI
	case DOMAIN_BUS_PCI_DEVICE_MSI:
	case DOMAIN_BUS_PCI_DEVICE_MSIX:
		info->chip->irq_mask = imsic_pci_mask_irq;
		info->chip->irq_unmask = imsic_pci_unmask_irq;
		break;
#endif
	case DOMAIN_BUS_DEVICE_MSI:
		/*
		 * Per-device MSI should never have any MSI feature bits
		 * set. It's sole purpose is to create a dumb interrupt
		 * chip which has a device specific irq_write_msi_msg()
		 * callback.
		 */
		if (WARN_ON_ONCE(info->flags))
			return false;

		/* Core managed MSI descriptors */
		info->flags |= MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS |
			       MSI_FLAG_FREE_MSI_DESCS;
		break;
	case DOMAIN_BUS_WIRED_TO_MSI:
		break;
	default:
		WARN_ON_ONCE(1);
		return false;
	}

	/* Use hierarchial chip operations re-trigger */
	info->chip->irq_retrigger = irq_chip_retrigger_hierarchy;

	/*
	 * Mask out the domain specific MSI feature flags which are not
	 * supported by the real parent.
	 */
	info->flags &= pops->supported_flags;

	/* Enforce the required flags */
	info->flags |= pops->required_flags;

	return true;
}

#define MATCH_PLATFORM_MSI		BIT(DOMAIN_BUS_PLATFORM_MSI)

static const struct msi_parent_ops imsic_msi_parent_ops = {
	.supported_flags	= MSI_GENERIC_FLAGS_MASK |
				  MSI_FLAG_PCI_MSIX,
	.required_flags		= MSI_FLAG_USE_DEF_DOM_OPS |
				  MSI_FLAG_USE_DEF_CHIP_OPS,
				  MSI_FLAG_USE_DEF_CHIP_OPS |
				  MSI_FLAG_PCI_MSI_MASK_PARENT,
	.bus_select_token	= DOMAIN_BUS_NEXUS,
	.bus_select_mask	= MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
	.init_dev_msi_info	= imsic_init_dev_msi_info,
	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
};

int imsic_irqdomain_init(void)