All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anup Patel <apatel@ventanamicro.com>
To: Palmer Dabbelt <palmer@dabbelt.com>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Frank Rowand <frowand.list@gmail.com>,
	Conor Dooley <conor+dt@kernel.org>
Cc: "Marc Zyngier" <maz@kernel.org>, "Björn Töpel" <bjorn@kernel.org>,
	"Atish Patra" <atishp@atishpatra.org>,
	"Andrew Jones" <ajones@ventanamicro.com>,
	"Sunil V L" <sunilvl@ventanamicro.com>,
	"Saravana Kannan" <saravanak@google.com>,
	"Anup Patel" <anup@brainfault.org>,
	linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	"Anup Patel" <apatel@ventanamicro.com>
Subject: [PATCH v12 19/25] irqchip/riscv-imsic: Add device MSI domain support for platform devices
Date: Sat, 27 Jan 2024 21:47:47 +0530	[thread overview]
Message-ID: <20240127161753.114685-20-apatel@ventanamicro.com> (raw)
In-Reply-To: <20240127161753.114685-1-apatel@ventanamicro.com>

The Linux platform MSI support allows per-device MSI domains so let
us add a platform irqchip driver for RISC-V IMSIC which provides a
base IRQ domain with MSI parent support for platform device domains.

This driver assumes that the IMSIC state is already initialized by
the IMSIC early driver.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
 drivers/irqchip/Makefile                   |   2 +-
 drivers/irqchip/irq-riscv-imsic-platform.c | 371 +++++++++++++++++++++
 drivers/irqchip/irq-riscv-imsic-state.h    |   2 +-
 3 files changed, 373 insertions(+), 2 deletions(-)
 create mode 100644 drivers/irqchip/irq-riscv-imsic-platform.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d714724387ce..abca445a3229 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -95,7 +95,7 @@ obj-$(CONFIG_QCOM_MPM)			+= irq-qcom-mpm.o
 obj-$(CONFIG_CSKY_MPINTC)		+= irq-csky-mpintc.o
 obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
 obj-$(CONFIG_RISCV_INTC)		+= irq-riscv-intc.o
-obj-$(CONFIG_RISCV_IMSIC)		+= irq-riscv-imsic-state.o irq-riscv-imsic-early.o
+obj-$(CONFIG_RISCV_IMSIC)		+= irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o
 obj-$(CONFIG_SIFIVE_PLIC)		+= irq-sifive-plic.o
 obj-$(CONFIG_IMX_IRQSTEER)		+= irq-imx-irqsteer.o
 obj-$(CONFIG_IMX_INTMUX)		+= irq-imx-intmux.o
diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
new file mode 100644
index 000000000000..65791a6b0727
--- /dev/null
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.
+ * Copyright (C) 2022 Ventana Micro Systems Inc.
+ */
+
+#define pr_fmt(fmt) "riscv-imsic: " fmt
+#include <linux/bitmap.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+
+#include "irq-riscv-imsic-state.h"
+
+static int imsic_cpu_page_phys(unsigned int cpu,
+			       unsigned int guest_index,
+			       phys_addr_t *out_msi_pa)
+{
+	struct imsic_global_config *global;
+	struct imsic_local_config *local;
+
+	global = &imsic->global;
+	local = per_cpu_ptr(global->local, cpu);
+
+	if (BIT(global->guest_index_bits) <= guest_index)
+		return -EINVAL;
+
+	if (out_msi_pa)
+		*out_msi_pa = local->msi_pa +
+			      (guest_index * IMSIC_MMIO_PAGE_SZ);
+
+	return 0;
+}
+
+static void imsic_irq_mask(struct irq_data *d)
+{
+	imsic_vector_mask(irq_data_get_irq_chip_data(d));
+}
+
+static void imsic_irq_unmask(struct irq_data *d)
+{
+	imsic_vector_unmask(irq_data_get_irq_chip_data(d));
+}
+
+static int imsic_irq_retrigger(struct irq_data *d)
+{
+	struct imsic_vector *vec = irq_data_get_irq_chip_data(d);
+	struct imsic_local_config *local;
+
+	if (WARN_ON(vec == NULL))
+		return -ENOENT;
+
+	local = per_cpu_ptr(imsic->global.local, vec->cpu);
+	writel(vec->local_id, local->msi_va);
+	return 0;
+}
+
+static void imsic_irq_compose_vector_msg(struct imsic_vector *vec,
+					 struct msi_msg *msg)
+{
+	phys_addr_t msi_addr;
+	int err;
+
+	if (WARN_ON(vec == NULL))
+		return;
+
+	err = imsic_cpu_page_phys(vec->cpu, 0, &msi_addr);
+	if (WARN_ON(err))
+		return;
+
+	msg->address_hi = upper_32_bits(msi_addr);
+	msg->address_lo = lower_32_bits(msi_addr);
+	msg->data = vec->local_id;
+}
+
+static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	imsic_irq_compose_vector_msg(irq_data_get_irq_chip_data(d), msg);
+}
+
+#ifdef CONFIG_SMP
+static void imsic_msi_update_msg(struct irq_data *d, struct imsic_vector *vec)
+{
+	struct msi_msg msg[2] = { [1] = { }, };
+
+	imsic_irq_compose_vector_msg(vec, msg);
+	irq_data_get_irq_chip(d)->irq_write_msi_msg(d, msg);
+}
+
+static int imsic_irq_set_affinity(struct irq_data *d,
+				  const struct cpumask *mask_val,
+				  bool force)
+{
+	struct imsic_vector *old_vec, *new_vec;
+	struct irq_data *pd = d->parent_data;
+
+	old_vec = irq_data_get_irq_chip_data(pd);
+	if (WARN_ON(old_vec == NULL))
+		return -ENOENT;
+
+	/* Get a new vector on the desired set of CPUs */
+	new_vec = imsic_vector_alloc(old_vec->hwirq, mask_val);
+	if (!new_vec)
+		return -ENOSPC;
+
+	/* If old vector belongs to the desired CPU then do nothing */
+	if (old_vec->cpu == new_vec->cpu) {
+		imsic_vector_free(new_vec);
+		return IRQ_SET_MASK_OK_DONE;
+	}
+
+	/* Point device to the new vector */
+	imsic_msi_update_msg(d, new_vec);
+
+	/* Update irq descriptors with the new vector */
+	pd->chip_data = new_vec;
+
+	/* Update effective affinity of parent irq data */
+	irq_data_update_effective_affinity(pd, cpumask_of(new_vec->cpu));
+
+	/* Move state of the old vector to the new vector */
+	imsic_vector_move(old_vec, new_vec);
+
+	return IRQ_SET_MASK_OK_DONE;
+}
+#endif
+
+static struct irq_chip imsic_irq_base_chip = {
+	.name			= "IMSIC",
+	.irq_mask		= imsic_irq_mask,
+	.irq_unmask		= imsic_irq_unmask,
+	.irq_retrigger		= imsic_irq_retrigger,
+	.irq_compose_msi_msg	= imsic_irq_compose_msg,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_MASK_ON_SUSPEND,
+};
+
+static int imsic_irq_domain_alloc(struct irq_domain *domain,
+				  unsigned int virq, unsigned int nr_irqs,
+				  void *args)
+{
+	struct imsic_vector *vec;
+	int hwirq;
+
+	/* Legacy-MSI or multi-MSI not supported yet. */
+	if (nr_irqs > 1)
+		return -ENOTSUPP;
+
+	hwirq = imsic_hwirq_alloc();
+	if (hwirq < 0)
+		return hwirq;
+
+	vec = imsic_vector_alloc(hwirq, cpu_online_mask);
+	if (!vec) {
+		imsic_hwirq_free(hwirq);
+		return -ENOSPC;
+	}
+
+	irq_domain_set_info(domain, virq, hwirq,
+			    &imsic_irq_base_chip, vec,
+			    handle_simple_irq, NULL, NULL);
+	irq_set_noprobe(virq);
+	irq_set_affinity(virq, cpu_online_mask);
+
+	/*
+	 * IMSIC does not implement irq_disable() so Linux interrupt
+	 * subsystem will take a lazy approach for disabling an IMSIC
+	 * interrupt. This means IMSIC interrupts are left unmasked
+	 * upon system suspend and interrupts are not processed
+	 * immediately upon system wake up. To tackle this, we disable
+	 * the lazy approach for all IMSIC interrupts.
+	 */
+	irq_set_status_flags(virq, IRQ_DISABLE_UNLAZY);
+
+	return 0;
+}
+
+static void imsic_irq_domain_free(struct irq_domain *domain,
+				  unsigned int virq,
+				  unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+
+	imsic_vector_free(irq_data_get_irq_chip_data(d));
+	imsic_hwirq_free(d->hwirq);
+	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)
+{
+	if (!irqd) {
+		imsic_vector_debug_show_summary(m, ind);
+		return;
+	}
+
+	imsic_vector_debug_show(m, irq_data_get_irq_chip_data(irqd), ind);
+}
+#endif
+
+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,
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+	.debug_show	= imsic_irq_debug_show,
+#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 = imsic_irq_set_affinity;
+#endif
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return false;
+	}
+
+	/* Is the target supported? */
+	switch (info->bus_token) {
+	case DOMAIN_BUS_DEVICE_IMS:
+		/*
+		 * Per device IMS 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,
+	.required_flags		= MSI_FLAG_USE_DEF_DOM_OPS |
+				  MSI_FLAG_USE_DEF_CHIP_OPS,
+	.bus_select_token	= DOMAIN_BUS_NEXUS,
+	.bus_select_mask	= MATCH_PLATFORM_MSI,
+	.init_dev_msi_info	= imsic_init_dev_msi_info,
+};
+
+int imsic_irqdomain_init(void)
+{
+	struct imsic_global_config *global;
+
+	if (!imsic || !imsic->fwnode) {
+		pr_err("early driver not probed\n");
+		return -ENODEV;
+	}
+
+	if (imsic->base_domain) {
+		pr_err("%pfwP: irq domain already created\n", imsic->fwnode);
+		return -ENODEV;
+	}
+
+	global = &imsic->global;
+
+	/* Create Base IRQ domain */
+	imsic->base_domain = irq_domain_create_tree(imsic->fwnode,
+					&imsic_base_domain_ops, imsic);
+	if (!imsic->base_domain) {
+		pr_err("%pfwP: failed to create IMSIC base domain\n",
+			imsic->fwnode);
+		return -ENOMEM;
+	}
+	imsic->base_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+	imsic->base_domain->msi_parent_ops = &imsic_msi_parent_ops;
+
+	irq_domain_update_bus_token(imsic->base_domain, DOMAIN_BUS_NEXUS);
+
+	pr_info("%pfwP:  hart-index-bits: %d,  guest-index-bits: %d\n",
+		imsic->fwnode, global->hart_index_bits, global->guest_index_bits);
+	pr_info("%pfwP: group-index-bits: %d, group-index-shift: %d\n",
+		imsic->fwnode, global->group_index_bits, global->group_index_shift);
+	pr_info("%pfwP: per-CPU IDs %d at base PPN %pa\n",
+		imsic->fwnode, global->nr_ids, &global->base_addr);
+	pr_info("%pfwP: total %d interrupts available\n",
+		imsic->fwnode, imsic->nr_hwirqs);
+
+	return 0;
+}
+
+static int imsic_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	if (imsic && imsic->fwnode != dev->fwnode) {
+		dev_err(dev, "fwnode mismatch\n");
+		return -ENODEV;
+	}
+
+	return imsic_irqdomain_init();
+}
+
+static const struct of_device_id imsic_platform_match[] = {
+	{ .compatible = "riscv,imsics" },
+	{}
+};
+
+static struct platform_driver imsic_platform_driver = {
+	.driver = {
+		.name		= "riscv-imsic",
+		.of_match_table	= imsic_platform_match,
+	},
+	.probe = imsic_platform_probe,
+};
+builtin_platform_driver(imsic_platform_driver);
diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
index de83b649221c..c76cab08bf78 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -62,7 +62,6 @@ struct imsic_priv {
 
 	/* IRQ domains (created by platform driver) */
 	struct irq_domain *base_domain;
-	struct irq_domain *plat_domain;
 };
 
 extern struct imsic_priv *imsic;
@@ -101,5 +100,6 @@ void imsic_hwirq_free(unsigned int hwirq);
 void imsic_state_online(void);
 void imsic_state_offline(void);
 int imsic_setup_state(struct fwnode_handle *fwnode);
+int imsic_irqdomain_init(void);
 
 #endif
-- 
2.34.1


WARNING: multiple messages have this Message-ID (diff)
From: Anup Patel <apatel@ventanamicro.com>
To: Palmer Dabbelt <palmer@dabbelt.com>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Frank Rowand <frowand.list@gmail.com>,
	Conor Dooley <conor+dt@kernel.org>
Cc: "Anup Patel" <apatel@ventanamicro.com>,
	devicetree@vger.kernel.org,
	"Saravana Kannan" <saravanak@google.com>,
	"Marc Zyngier" <maz@kernel.org>,
	"Anup Patel" <anup@brainfault.org>,
	linux-kernel@vger.kernel.org, "Björn Töpel" <bjorn@kernel.org>,
	"Atish Patra" <atishp@atishpatra.org>,
	linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	"Andrew Jones" <ajones@ventanamicro.com>
Subject: [PATCH v12 19/25] irqchip/riscv-imsic: Add device MSI domain support for platform devices
Date: Sat, 27 Jan 2024 21:47:47 +0530	[thread overview]
Message-ID: <20240127161753.114685-20-apatel@ventanamicro.com> (raw)
In-Reply-To: <20240127161753.114685-1-apatel@ventanamicro.com>

The Linux platform MSI support allows per-device MSI domains so let
us add a platform irqchip driver for RISC-V IMSIC which provides a
base IRQ domain with MSI parent support for platform device domains.

This driver assumes that the IMSIC state is already initialized by
the IMSIC early driver.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
 drivers/irqchip/Makefile                   |   2 +-
 drivers/irqchip/irq-riscv-imsic-platform.c | 371 +++++++++++++++++++++
 drivers/irqchip/irq-riscv-imsic-state.h    |   2 +-
 3 files changed, 373 insertions(+), 2 deletions(-)
 create mode 100644 drivers/irqchip/irq-riscv-imsic-platform.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d714724387ce..abca445a3229 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -95,7 +95,7 @@ obj-$(CONFIG_QCOM_MPM)			+= irq-qcom-mpm.o
 obj-$(CONFIG_CSKY_MPINTC)		+= irq-csky-mpintc.o
 obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
 obj-$(CONFIG_RISCV_INTC)		+= irq-riscv-intc.o
-obj-$(CONFIG_RISCV_IMSIC)		+= irq-riscv-imsic-state.o irq-riscv-imsic-early.o
+obj-$(CONFIG_RISCV_IMSIC)		+= irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o
 obj-$(CONFIG_SIFIVE_PLIC)		+= irq-sifive-plic.o
 obj-$(CONFIG_IMX_IRQSTEER)		+= irq-imx-irqsteer.o
 obj-$(CONFIG_IMX_INTMUX)		+= irq-imx-intmux.o
diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
new file mode 100644
index 000000000000..65791a6b0727
--- /dev/null
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.
+ * Copyright (C) 2022 Ventana Micro Systems Inc.
+ */
+
+#define pr_fmt(fmt) "riscv-imsic: " fmt
+#include <linux/bitmap.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+
+#include "irq-riscv-imsic-state.h"
+
+static int imsic_cpu_page_phys(unsigned int cpu,
+			       unsigned int guest_index,
+			       phys_addr_t *out_msi_pa)
+{
+	struct imsic_global_config *global;
+	struct imsic_local_config *local;
+
+	global = &imsic->global;
+	local = per_cpu_ptr(global->local, cpu);
+
+	if (BIT(global->guest_index_bits) <= guest_index)
+		return -EINVAL;
+
+	if (out_msi_pa)
+		*out_msi_pa = local->msi_pa +
+			      (guest_index * IMSIC_MMIO_PAGE_SZ);
+
+	return 0;
+}
+
+static void imsic_irq_mask(struct irq_data *d)
+{
+	imsic_vector_mask(irq_data_get_irq_chip_data(d));
+}
+
+static void imsic_irq_unmask(struct irq_data *d)
+{
+	imsic_vector_unmask(irq_data_get_irq_chip_data(d));
+}
+
+static int imsic_irq_retrigger(struct irq_data *d)
+{
+	struct imsic_vector *vec = irq_data_get_irq_chip_data(d);
+	struct imsic_local_config *local;
+
+	if (WARN_ON(vec == NULL))
+		return -ENOENT;
+
+	local = per_cpu_ptr(imsic->global.local, vec->cpu);
+	writel(vec->local_id, local->msi_va);
+	return 0;
+}
+
+static void imsic_irq_compose_vector_msg(struct imsic_vector *vec,
+					 struct msi_msg *msg)
+{
+	phys_addr_t msi_addr;
+	int err;
+
+	if (WARN_ON(vec == NULL))
+		return;
+
+	err = imsic_cpu_page_phys(vec->cpu, 0, &msi_addr);
+	if (WARN_ON(err))
+		return;
+
+	msg->address_hi = upper_32_bits(msi_addr);
+	msg->address_lo = lower_32_bits(msi_addr);
+	msg->data = vec->local_id;
+}
+
+static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	imsic_irq_compose_vector_msg(irq_data_get_irq_chip_data(d), msg);
+}
+
+#ifdef CONFIG_SMP
+static void imsic_msi_update_msg(struct irq_data *d, struct imsic_vector *vec)
+{
+	struct msi_msg msg[2] = { [1] = { }, };
+
+	imsic_irq_compose_vector_msg(vec, msg);
+	irq_data_get_irq_chip(d)->irq_write_msi_msg(d, msg);
+}
+
+static int imsic_irq_set_affinity(struct irq_data *d,
+				  const struct cpumask *mask_val,
+				  bool force)
+{
+	struct imsic_vector *old_vec, *new_vec;
+	struct irq_data *pd = d->parent_data;
+
+	old_vec = irq_data_get_irq_chip_data(pd);
+	if (WARN_ON(old_vec == NULL))
+		return -ENOENT;
+
+	/* Get a new vector on the desired set of CPUs */
+	new_vec = imsic_vector_alloc(old_vec->hwirq, mask_val);
+	if (!new_vec)
+		return -ENOSPC;
+
+	/* If old vector belongs to the desired CPU then do nothing */
+	if (old_vec->cpu == new_vec->cpu) {
+		imsic_vector_free(new_vec);
+		return IRQ_SET_MASK_OK_DONE;
+	}
+
+	/* Point device to the new vector */
+	imsic_msi_update_msg(d, new_vec);
+
+	/* Update irq descriptors with the new vector */
+	pd->chip_data = new_vec;
+
+	/* Update effective affinity of parent irq data */
+	irq_data_update_effective_affinity(pd, cpumask_of(new_vec->cpu));
+
+	/* Move state of the old vector to the new vector */
+	imsic_vector_move(old_vec, new_vec);
+
+	return IRQ_SET_MASK_OK_DONE;
+}
+#endif
+
+static struct irq_chip imsic_irq_base_chip = {
+	.name			= "IMSIC",
+	.irq_mask		= imsic_irq_mask,
+	.irq_unmask		= imsic_irq_unmask,
+	.irq_retrigger		= imsic_irq_retrigger,
+	.irq_compose_msi_msg	= imsic_irq_compose_msg,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_MASK_ON_SUSPEND,
+};
+
+static int imsic_irq_domain_alloc(struct irq_domain *domain,
+				  unsigned int virq, unsigned int nr_irqs,
+				  void *args)
+{
+	struct imsic_vector *vec;
+	int hwirq;
+
+	/* Legacy-MSI or multi-MSI not supported yet. */
+	if (nr_irqs > 1)
+		return -ENOTSUPP;
+
+	hwirq = imsic_hwirq_alloc();
+	if (hwirq < 0)
+		return hwirq;
+
+	vec = imsic_vector_alloc(hwirq, cpu_online_mask);
+	if (!vec) {
+		imsic_hwirq_free(hwirq);
+		return -ENOSPC;
+	}
+
+	irq_domain_set_info(domain, virq, hwirq,
+			    &imsic_irq_base_chip, vec,
+			    handle_simple_irq, NULL, NULL);
+	irq_set_noprobe(virq);
+	irq_set_affinity(virq, cpu_online_mask);
+
+	/*
+	 * IMSIC does not implement irq_disable() so Linux interrupt
+	 * subsystem will take a lazy approach for disabling an IMSIC
+	 * interrupt. This means IMSIC interrupts are left unmasked
+	 * upon system suspend and interrupts are not processed
+	 * immediately upon system wake up. To tackle this, we disable
+	 * the lazy approach for all IMSIC interrupts.
+	 */
+	irq_set_status_flags(virq, IRQ_DISABLE_UNLAZY);
+
+	return 0;
+}
+
+static void imsic_irq_domain_free(struct irq_domain *domain,
+				  unsigned int virq,
+				  unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+
+	imsic_vector_free(irq_data_get_irq_chip_data(d));
+	imsic_hwirq_free(d->hwirq);
+	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)
+{
+	if (!irqd) {
+		imsic_vector_debug_show_summary(m, ind);
+		return;
+	}
+
+	imsic_vector_debug_show(m, irq_data_get_irq_chip_data(irqd), ind);
+}
+#endif
+
+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,
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+	.debug_show	= imsic_irq_debug_show,
+#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 = imsic_irq_set_affinity;
+#endif
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return false;
+	}
+
+	/* Is the target supported? */
+	switch (info->bus_token) {
+	case DOMAIN_BUS_DEVICE_IMS:
+		/*
+		 * Per device IMS 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,
+	.required_flags		= MSI_FLAG_USE_DEF_DOM_OPS |
+				  MSI_FLAG_USE_DEF_CHIP_OPS,
+	.bus_select_token	= DOMAIN_BUS_NEXUS,
+	.bus_select_mask	= MATCH_PLATFORM_MSI,
+	.init_dev_msi_info	= imsic_init_dev_msi_info,
+};
+
+int imsic_irqdomain_init(void)
+{
+	struct imsic_global_config *global;
+
+	if (!imsic || !imsic->fwnode) {
+		pr_err("early driver not probed\n");
+		return -ENODEV;
+	}
+
+	if (imsic->base_domain) {
+		pr_err("%pfwP: irq domain already created\n", imsic->fwnode);
+		return -ENODEV;
+	}
+
+	global = &imsic->global;
+
+	/* Create Base IRQ domain */
+	imsic->base_domain = irq_domain_create_tree(imsic->fwnode,
+					&imsic_base_domain_ops, imsic);
+	if (!imsic->base_domain) {
+		pr_err("%pfwP: failed to create IMSIC base domain\n",
+			imsic->fwnode);
+		return -ENOMEM;
+	}
+	imsic->base_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+	imsic->base_domain->msi_parent_ops = &imsic_msi_parent_ops;
+
+	irq_domain_update_bus_token(imsic->base_domain, DOMAIN_BUS_NEXUS);
+
+	pr_info("%pfwP:  hart-index-bits: %d,  guest-index-bits: %d\n",
+		imsic->fwnode, global->hart_index_bits, global->guest_index_bits);
+	pr_info("%pfwP: group-index-bits: %d, group-index-shift: %d\n",
+		imsic->fwnode, global->group_index_bits, global->group_index_shift);
+	pr_info("%pfwP: per-CPU IDs %d at base PPN %pa\n",
+		imsic->fwnode, global->nr_ids, &global->base_addr);
+	pr_info("%pfwP: total %d interrupts available\n",
+		imsic->fwnode, imsic->nr_hwirqs);
+
+	return 0;
+}
+
+static int imsic_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	if (imsic && imsic->fwnode != dev->fwnode) {
+		dev_err(dev, "fwnode mismatch\n");
+		return -ENODEV;
+	}
+
+	return imsic_irqdomain_init();
+}
+
+static const struct of_device_id imsic_platform_match[] = {
+	{ .compatible = "riscv,imsics" },
+	{}
+};
+
+static struct platform_driver imsic_platform_driver = {
+	.driver = {
+		.name		= "riscv-imsic",
+		.of_match_table	= imsic_platform_match,
+	},
+	.probe = imsic_platform_probe,
+};
+builtin_platform_driver(imsic_platform_driver);
diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
index de83b649221c..c76cab08bf78 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -62,7 +62,6 @@ struct imsic_priv {
 
 	/* IRQ domains (created by platform driver) */
 	struct irq_domain *base_domain;
-	struct irq_domain *plat_domain;
 };
 
 extern struct imsic_priv *imsic;
@@ -101,5 +100,6 @@ void imsic_hwirq_free(unsigned int hwirq);
 void imsic_state_online(void);
 void imsic_state_offline(void);
 int imsic_setup_state(struct fwnode_handle *fwnode);
+int imsic_irqdomain_init(void);
 
 #endif
-- 
2.34.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

WARNING: multiple messages have this Message-ID (diff)
From: Anup Patel <apatel@ventanamicro.com>
To: Palmer Dabbelt <palmer@dabbelt.com>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Frank Rowand <frowand.list@gmail.com>,
	Conor Dooley <conor+dt@kernel.org>
Cc: "Marc Zyngier" <maz@kernel.org>, "Björn Töpel" <bjorn@kernel.org>,
	"Atish Patra" <atishp@atishpatra.org>,
	"Andrew Jones" <ajones@ventanamicro.com>,
	"Sunil V L" <sunilvl@ventanamicro.com>,
	"Saravana Kannan" <saravanak@google.com>,
	"Anup Patel" <anup@brainfault.org>,
	linux-riscv@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	"Anup Patel" <apatel@ventanamicro.com>
Subject: [PATCH v12 19/25] irqchip/riscv-imsic: Add device MSI domain support for platform devices
Date: Sat, 27 Jan 2024 21:47:47 +0530	[thread overview]
Message-ID: <20240127161753.114685-20-apatel@ventanamicro.com> (raw)
In-Reply-To: <20240127161753.114685-1-apatel@ventanamicro.com>

The Linux platform MSI support allows per-device MSI domains so let
us add a platform irqchip driver for RISC-V IMSIC which provides a
base IRQ domain with MSI parent support for platform device domains.

This driver assumes that the IMSIC state is already initialized by
the IMSIC early driver.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
 drivers/irqchip/Makefile                   |   2 +-
 drivers/irqchip/irq-riscv-imsic-platform.c | 371 +++++++++++++++++++++
 drivers/irqchip/irq-riscv-imsic-state.h    |   2 +-
 3 files changed, 373 insertions(+), 2 deletions(-)
 create mode 100644 drivers/irqchip/irq-riscv-imsic-platform.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d714724387ce..abca445a3229 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -95,7 +95,7 @@ obj-$(CONFIG_QCOM_MPM)			+= irq-qcom-mpm.o
 obj-$(CONFIG_CSKY_MPINTC)		+= irq-csky-mpintc.o
 obj-$(CONFIG_CSKY_APB_INTC)		+= irq-csky-apb-intc.o
 obj-$(CONFIG_RISCV_INTC)		+= irq-riscv-intc.o
-obj-$(CONFIG_RISCV_IMSIC)		+= irq-riscv-imsic-state.o irq-riscv-imsic-early.o
+obj-$(CONFIG_RISCV_IMSIC)		+= irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o
 obj-$(CONFIG_SIFIVE_PLIC)		+= irq-sifive-plic.o
 obj-$(CONFIG_IMX_IRQSTEER)		+= irq-imx-irqsteer.o
 obj-$(CONFIG_IMX_INTMUX)		+= irq-imx-intmux.o
diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
new file mode 100644
index 000000000000..65791a6b0727
--- /dev/null
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.
+ * Copyright (C) 2022 Ventana Micro Systems Inc.
+ */
+
+#define pr_fmt(fmt) "riscv-imsic: " fmt
+#include <linux/bitmap.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+
+#include "irq-riscv-imsic-state.h"
+
+static int imsic_cpu_page_phys(unsigned int cpu,
+			       unsigned int guest_index,
+			       phys_addr_t *out_msi_pa)
+{
+	struct imsic_global_config *global;
+	struct imsic_local_config *local;
+
+	global = &imsic->global;
+	local = per_cpu_ptr(global->local, cpu);
+
+	if (BIT(global->guest_index_bits) <= guest_index)
+		return -EINVAL;
+
+	if (out_msi_pa)
+		*out_msi_pa = local->msi_pa +
+			      (guest_index * IMSIC_MMIO_PAGE_SZ);
+
+	return 0;
+}
+
+static void imsic_irq_mask(struct irq_data *d)
+{
+	imsic_vector_mask(irq_data_get_irq_chip_data(d));
+}
+
+static void imsic_irq_unmask(struct irq_data *d)
+{
+	imsic_vector_unmask(irq_data_get_irq_chip_data(d));
+}
+
+static int imsic_irq_retrigger(struct irq_data *d)
+{
+	struct imsic_vector *vec = irq_data_get_irq_chip_data(d);
+	struct imsic_local_config *local;
+
+	if (WARN_ON(vec == NULL))
+		return -ENOENT;
+
+	local = per_cpu_ptr(imsic->global.local, vec->cpu);
+	writel(vec->local_id, local->msi_va);
+	return 0;
+}
+
+static void imsic_irq_compose_vector_msg(struct imsic_vector *vec,
+					 struct msi_msg *msg)
+{
+	phys_addr_t msi_addr;
+	int err;
+
+	if (WARN_ON(vec == NULL))
+		return;
+
+	err = imsic_cpu_page_phys(vec->cpu, 0, &msi_addr);
+	if (WARN_ON(err))
+		return;
+
+	msg->address_hi = upper_32_bits(msi_addr);
+	msg->address_lo = lower_32_bits(msi_addr);
+	msg->data = vec->local_id;
+}
+
+static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	imsic_irq_compose_vector_msg(irq_data_get_irq_chip_data(d), msg);
+}
+
+#ifdef CONFIG_SMP
+static void imsic_msi_update_msg(struct irq_data *d, struct imsic_vector *vec)
+{
+	struct msi_msg msg[2] = { [1] = { }, };
+
+	imsic_irq_compose_vector_msg(vec, msg);
+	irq_data_get_irq_chip(d)->irq_write_msi_msg(d, msg);
+}
+
+static int imsic_irq_set_affinity(struct irq_data *d,
+				  const struct cpumask *mask_val,
+				  bool force)
+{
+	struct imsic_vector *old_vec, *new_vec;
+	struct irq_data *pd = d->parent_data;
+
+	old_vec = irq_data_get_irq_chip_data(pd);
+	if (WARN_ON(old_vec == NULL))
+		return -ENOENT;
+
+	/* Get a new vector on the desired set of CPUs */
+	new_vec = imsic_vector_alloc(old_vec->hwirq, mask_val);
+	if (!new_vec)
+		return -ENOSPC;
+
+	/* If old vector belongs to the desired CPU then do nothing */
+	if (old_vec->cpu == new_vec->cpu) {
+		imsic_vector_free(new_vec);
+		return IRQ_SET_MASK_OK_DONE;
+	}
+
+	/* Point device to the new vector */
+	imsic_msi_update_msg(d, new_vec);
+
+	/* Update irq descriptors with the new vector */
+	pd->chip_data = new_vec;
+
+	/* Update effective affinity of parent irq data */
+	irq_data_update_effective_affinity(pd, cpumask_of(new_vec->cpu));
+
+	/* Move state of the old vector to the new vector */
+	imsic_vector_move(old_vec, new_vec);
+
+	return IRQ_SET_MASK_OK_DONE;
+}
+#endif
+
+static struct irq_chip imsic_irq_base_chip = {
+	.name			= "IMSIC",
+	.irq_mask		= imsic_irq_mask,
+	.irq_unmask		= imsic_irq_unmask,
+	.irq_retrigger		= imsic_irq_retrigger,
+	.irq_compose_msi_msg	= imsic_irq_compose_msg,
+	.flags			= IRQCHIP_SKIP_SET_WAKE |
+				  IRQCHIP_MASK_ON_SUSPEND,
+};
+
+static int imsic_irq_domain_alloc(struct irq_domain *domain,
+				  unsigned int virq, unsigned int nr_irqs,
+				  void *args)
+{
+	struct imsic_vector *vec;
+	int hwirq;
+
+	/* Legacy-MSI or multi-MSI not supported yet. */
+	if (nr_irqs > 1)
+		return -ENOTSUPP;
+
+	hwirq = imsic_hwirq_alloc();
+	if (hwirq < 0)
+		return hwirq;
+
+	vec = imsic_vector_alloc(hwirq, cpu_online_mask);
+	if (!vec) {
+		imsic_hwirq_free(hwirq);
+		return -ENOSPC;
+	}
+
+	irq_domain_set_info(domain, virq, hwirq,
+			    &imsic_irq_base_chip, vec,
+			    handle_simple_irq, NULL, NULL);
+	irq_set_noprobe(virq);
+	irq_set_affinity(virq, cpu_online_mask);
+
+	/*
+	 * IMSIC does not implement irq_disable() so Linux interrupt
+	 * subsystem will take a lazy approach for disabling an IMSIC
+	 * interrupt. This means IMSIC interrupts are left unmasked
+	 * upon system suspend and interrupts are not processed
+	 * immediately upon system wake up. To tackle this, we disable
+	 * the lazy approach for all IMSIC interrupts.
+	 */
+	irq_set_status_flags(virq, IRQ_DISABLE_UNLAZY);
+
+	return 0;
+}
+
+static void imsic_irq_domain_free(struct irq_domain *domain,
+				  unsigned int virq,
+				  unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+
+	imsic_vector_free(irq_data_get_irq_chip_data(d));
+	imsic_hwirq_free(d->hwirq);
+	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)
+{
+	if (!irqd) {
+		imsic_vector_debug_show_summary(m, ind);
+		return;
+	}
+
+	imsic_vector_debug_show(m, irq_data_get_irq_chip_data(irqd), ind);
+}
+#endif
+
+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,
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+	.debug_show	= imsic_irq_debug_show,
+#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 = imsic_irq_set_affinity;
+#endif
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return false;
+	}
+
+	/* Is the target supported? */
+	switch (info->bus_token) {
+	case DOMAIN_BUS_DEVICE_IMS:
+		/*
+		 * Per device IMS 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,
+	.required_flags		= MSI_FLAG_USE_DEF_DOM_OPS |
+				  MSI_FLAG_USE_DEF_CHIP_OPS,
+	.bus_select_token	= DOMAIN_BUS_NEXUS,
+	.bus_select_mask	= MATCH_PLATFORM_MSI,
+	.init_dev_msi_info	= imsic_init_dev_msi_info,
+};
+
+int imsic_irqdomain_init(void)
+{
+	struct imsic_global_config *global;
+
+	if (!imsic || !imsic->fwnode) {
+		pr_err("early driver not probed\n");
+		return -ENODEV;
+	}
+
+	if (imsic->base_domain) {
+		pr_err("%pfwP: irq domain already created\n", imsic->fwnode);
+		return -ENODEV;
+	}
+
+	global = &imsic->global;
+
+	/* Create Base IRQ domain */
+	imsic->base_domain = irq_domain_create_tree(imsic->fwnode,
+					&imsic_base_domain_ops, imsic);
+	if (!imsic->base_domain) {
+		pr_err("%pfwP: failed to create IMSIC base domain\n",
+			imsic->fwnode);
+		return -ENOMEM;
+	}
+	imsic->base_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+	imsic->base_domain->msi_parent_ops = &imsic_msi_parent_ops;
+
+	irq_domain_update_bus_token(imsic->base_domain, DOMAIN_BUS_NEXUS);
+
+	pr_info("%pfwP:  hart-index-bits: %d,  guest-index-bits: %d\n",
+		imsic->fwnode, global->hart_index_bits, global->guest_index_bits);
+	pr_info("%pfwP: group-index-bits: %d, group-index-shift: %d\n",
+		imsic->fwnode, global->group_index_bits, global->group_index_shift);
+	pr_info("%pfwP: per-CPU IDs %d at base PPN %pa\n",
+		imsic->fwnode, global->nr_ids, &global->base_addr);
+	pr_info("%pfwP: total %d interrupts available\n",
+		imsic->fwnode, imsic->nr_hwirqs);
+
+	return 0;
+}
+
+static int imsic_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	if (imsic && imsic->fwnode != dev->fwnode) {
+		dev_err(dev, "fwnode mismatch\n");
+		return -ENODEV;
+	}
+
+	return imsic_irqdomain_init();
+}
+
+static const struct of_device_id imsic_platform_match[] = {
+	{ .compatible = "riscv,imsics" },
+	{}
+};
+
+static struct platform_driver imsic_platform_driver = {
+	.driver = {
+		.name		= "riscv-imsic",
+		.of_match_table	= imsic_platform_match,
+	},
+	.probe = imsic_platform_probe,
+};
+builtin_platform_driver(imsic_platform_driver);
diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
index de83b649221c..c76cab08bf78 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -62,7 +62,6 @@ struct imsic_priv {
 
 	/* IRQ domains (created by platform driver) */
 	struct irq_domain *base_domain;
-	struct irq_domain *plat_domain;
 };
 
 extern struct imsic_priv *imsic;
@@ -101,5 +100,6 @@ void imsic_hwirq_free(unsigned int hwirq);
 void imsic_state_online(void);
 void imsic_state_offline(void);
 int imsic_setup_state(struct fwnode_handle *fwnode);
+int imsic_irqdomain_init(void);
 
 #endif
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2024-01-27 16:20 UTC|newest]

Thread overview: 277+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-27 16:17 [PATCH v12 00/25] Linux RISC-V AIA Support Anup Patel
2024-01-27 16:17 ` Anup Patel
2024-01-27 16:17 ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 01/25] irqchip/gic-v3: Make gic_irq_domain_select() robust for zero parameter count Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 11:47   ` Marc Zyngier
2024-02-15 11:47     ` Marc Zyngier
2024-02-15 11:47     ` Marc Zyngier
2024-02-15 19:57   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 02/25] genirq/irqdomain: Remove the param count restriction from select() Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:57   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-02-19 15:50     ` Biju Das
2024-02-19 15:56   ` Marc Zyngier
2024-02-19 16:39     ` Biju Das
2024-02-19 17:39       ` Biju Das
2024-02-20  8:50     ` Thomas Gleixner
2024-02-20 16:33       ` [tip: irq/msi] irqchip/imx-intmux: Handle pure domain searches correctly tip-bot2 for Thomas Gleixner
2024-02-22 13:01   ` [PATCH v12 02/25] genirq/irqdomain: Remove the param count restriction from select() Aishwarya TCV
2024-02-22 13:01     ` Aishwarya TCV
2024-02-22 13:01     ` Aishwarya TCV
2024-02-22 16:28     ` Marc Zyngier
2024-02-22 16:28       ` Marc Zyngier
2024-02-22 16:28       ` Marc Zyngier
2024-02-22 22:59       ` Aishwarya TCV
2024-02-22 22:59         ` Aishwarya TCV
2024-02-22 22:59         ` Aishwarya TCV
     [not found]   ` <CGME20240223102258eucas1p119f38e40f769c883c0a502e9e26be888@eucas1p1.samsung.com>
2024-02-23 10:22     ` Marek Szyprowski
2024-02-23 10:22       ` Marek Szyprowski
2024-02-23 10:22       ` Marek Szyprowski
2024-02-23 10:45       ` Biju Das
2024-02-23 10:45         ` Biju Das
2024-02-23 10:45         ` Biju Das
2024-02-23 10:56         ` Marek Szyprowski
2024-02-23 10:56           ` Marek Szyprowski
2024-02-23 10:56           ` Marek Szyprowski
2024-02-23 11:01           ` Biju Das
2024-02-23 11:01             ` Biju Das
2024-02-23 11:01             ` Biju Das
2024-01-27 16:17 ` [PATCH v12 03/25] genirq/msi: Extend msi_parent_ops Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:57   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 04/25] genirq/irqdomain: Add DOMAIN_BUS_DEVICE_IMS Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 11:54   ` Marc Zyngier
2024-02-15 11:54     ` Marc Zyngier
2024-02-15 11:54     ` Marc Zyngier
2024-02-15 15:01     ` Thomas Gleixner
2024-02-15 15:01       ` Thomas Gleixner
2024-02-15 15:01       ` Thomas Gleixner
2024-02-15 19:57   ` [tip: irq/msi] genirq/irqdomain: Add DOMAIN_BUS_DEVICE_MSI tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 05/25] platform-msi: Prepare for real per device domains Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:57   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 06/25] irqchip: Convert all platform MSI users to the new API Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:57   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 07/25] genirq/msi: Provide optional translation op Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:57   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 08/25] genirq/msi: Split msi_domain_alloc_irq_at() Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:56   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 09/25] genirq/msi: Provide DOMAIN_BUS_WIRED_TO_MSI Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:56   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 10/25] genirq/msi: Optionally use dev->fwnode for device domain Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:56   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 11/25] genirq/msi: Provide allocation/free functions for "wired" MSI interrupts Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:56   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 12/25] genirq/irqdomain: Reroute device MSI create_mapping Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:56   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 13/25] genirq/msi: Provide MSI_FLAG_PARENT_PM_DEV Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-15 19:56   ` [tip: irq/msi] " tip-bot2 for Thomas Gleixner
2024-01-27 16:17 ` [PATCH v12 14/25] irqchip/sifive-plic: Convert PLIC driver into a platform driver Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-16 15:33   ` Thomas Gleixner
2024-02-16 15:33     ` Thomas Gleixner
2024-02-16 15:33     ` Thomas Gleixner
2024-02-16 17:11     ` Anup Patel
2024-02-16 17:11       ` Anup Patel
2024-02-16 17:11       ` Anup Patel
2024-02-16 20:22       ` Thomas Gleixner
2024-02-16 20:22         ` Thomas Gleixner
2024-02-16 20:22         ` Thomas Gleixner
2024-02-17  5:42         ` Anup Patel
2024-02-17  5:42           ` Anup Patel
2024-02-17  5:42           ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 15/25] irqchip/riscv-intc: Add support for RISC-V AIA Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 16/25] dt-bindings: interrupt-controller: Add RISC-V incoming MSI controller Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 17/25] genirq/matrix: Dynamic bitmap allocation Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 18/25] irqchip: Add RISC-V incoming MSI controller early driver Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-07  9:43   ` Björn Töpel
2024-02-07  9:43     ` Björn Töpel
2024-02-07  9:43     ` Björn Töpel
2024-02-16 18:40   ` Thomas Gleixner
2024-02-16 18:40     ` Thomas Gleixner
2024-02-16 18:40     ` Thomas Gleixner
2024-02-18 13:16     ` Anup Patel
2024-02-18 13:16       ` Anup Patel
2024-02-18 13:16       ` Anup Patel
2024-01-27 16:17 ` Anup Patel [this message]
2024-01-27 16:17   ` [PATCH v12 19/25] irqchip/riscv-imsic: Add device MSI domain support for platform devices Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-06 15:36   ` Björn Töpel
2024-02-06 15:36     ` Björn Töpel
2024-02-06 15:36     ` Björn Töpel
2024-02-16 20:12   ` Thomas Gleixner
2024-02-16 20:12     ` Thomas Gleixner
2024-02-16 20:12     ` Thomas Gleixner
2024-02-19  4:10     ` Anup Patel
2024-02-19  4:10       ` Anup Patel
2024-02-19  4:10       ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 20/25] irqchip/riscv-imsic: Add device MSI domain support for PCI devices Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-16 20:14   ` Thomas Gleixner
2024-02-16 20:14     ` Thomas Gleixner
2024-02-16 20:14     ` Thomas Gleixner
2024-02-19  4:41     ` Anup Patel
2024-02-19  4:41       ` Anup Patel
2024-02-19  4:41       ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 21/25] dt-bindings: interrupt-controller: Add RISC-V advanced PLIC Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 22/25] irqchip: Add RISC-V advanced PLIC driver for direct-mode Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-01  6:39   ` Andy Chiu
2024-02-01  6:39     ` Andy Chiu
2024-02-01  6:39     ` Andy Chiu
2024-02-19 10:28     ` Anup Patel
2024-02-19 10:28       ` Anup Patel
2024-02-19 10:28       ` Anup Patel
2024-02-02  9:29   ` Clément Léger
2024-02-02  9:29     ` Clément Léger
2024-02-02  9:29     ` Clément Léger
2024-02-02 10:30     ` Anup Patel
2024-02-02 10:30       ` Anup Patel
2024-02-02 10:30       ` Anup Patel
2024-02-02 10:33       ` Clément Léger
2024-02-02 10:33         ` Clément Léger
2024-02-02 10:33         ` Clément Léger
2024-02-16 20:50   ` Thomas Gleixner
2024-02-16 20:50     ` Thomas Gleixner
2024-02-16 20:50     ` Thomas Gleixner
2024-02-19  9:35     ` Anup Patel
2024-02-19  9:35       ` Anup Patel
2024-02-19  9:35       ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 23/25] irqchip/riscv-aplic: Add support for MSI-mode Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-02-16 21:04   ` Thomas Gleixner
2024-02-16 21:04     ` Thomas Gleixner
2024-02-16 21:04     ` Thomas Gleixner
2024-02-19  9:45     ` Anup Patel
2024-02-19  9:45       ` Anup Patel
2024-02-19  9:45       ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 24/25] RISC-V: Select APLIC and IMSIC drivers Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17 ` [PATCH v12 25/25] MAINTAINERS: Add entry for RISC-V AIA drivers Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:17   ` Anup Patel
2024-01-27 16:20 ` [PATCH v12 00/25] Linux RISC-V AIA Support Anup Patel
2024-01-27 16:20   ` Anup Patel
2024-01-27 16:20   ` Anup Patel
2024-02-14 19:54   ` Thomas Gleixner
2024-02-14 19:54     ` Thomas Gleixner
2024-02-14 19:54     ` Thomas Gleixner
2024-02-15  5:48     ` Anup Patel
2024-02-15  5:48       ` Anup Patel
2024-02-15  5:48       ` Anup Patel
2024-02-15 19:59       ` Thomas Gleixner
2024-02-15 19:59         ` Thomas Gleixner
2024-02-15 19:59         ` Thomas Gleixner
2024-02-16 21:05         ` Thomas Gleixner
2024-02-16 21:05           ` Thomas Gleixner
2024-02-16 21:05           ` Thomas Gleixner
2024-02-20  6:12           ` Anup Patel
2024-02-20  6:12             ` Anup Patel
2024-02-20  6:12             ` Anup Patel
2024-02-15 11:57     ` Marc Zyngier
2024-02-15 11:57       ` Marc Zyngier
2024-02-15 11:57       ` Marc Zyngier
2024-01-30  7:16 ` Björn Töpel
2024-01-30  7:16   ` Björn Töpel
2024-01-30  7:16   ` Björn Töpel
2024-01-30  7:52   ` Björn Töpel
2024-01-30  7:52     ` Björn Töpel
2024-01-30  7:52     ` Björn Töpel
2024-01-30 10:02     ` Anup Patel
2024-01-30 10:02       ` Anup Patel
2024-01-30 10:02       ` Anup Patel
2024-01-30 11:05       ` Björn Töpel
2024-01-30 11:05         ` Björn Töpel
2024-01-30 11:05         ` Björn Töpel
2024-01-30 10:23     ` Anup Patel
2024-01-30 10:23       ` Anup Patel
2024-01-30 10:23       ` Anup Patel
2024-01-30 11:46       ` Björn Töpel
2024-01-30 11:46         ` Björn Töpel
2024-01-30 11:46         ` Björn Töpel
2024-01-30 14:48         ` Björn Töpel
2024-01-30 14:48           ` Björn Töpel
2024-01-30 14:48           ` Björn Töpel
2024-01-30 15:19           ` Anup Patel
2024-01-30 15:19             ` Anup Patel
2024-01-30 15:19             ` Anup Patel
2024-01-30 15:48           ` Anup Patel
2024-01-30 15:48             ` Anup Patel
2024-01-30 15:48             ` Anup Patel
2024-01-30 17:49             ` Björn Töpel
2024-01-30 17:49               ` Björn Töpel
2024-01-30 17:49               ` Björn Töpel
2024-02-01 15:07               ` Anup Patel
2024-02-01 15:07                 ` Anup Patel
2024-02-01 15:07                 ` Anup Patel
2024-02-01 18:45                 ` Björn Töpel
2024-02-01 18:45                   ` Björn Töpel
2024-02-01 18:45                   ` Björn Töpel
2024-02-06 15:39 ` Björn Töpel
2024-02-06 15:39   ` Björn Töpel
2024-02-06 15:39   ` Björn Töpel
2024-02-06 17:39   ` Anup Patel
2024-02-06 17:39     ` Anup Patel
2024-02-06 17:39     ` Anup Patel
2024-02-07  7:27     ` Björn Töpel
2024-02-07  7:27       ` Björn Töpel
2024-02-07  7:27       ` Björn Töpel
2024-02-07  9:18       ` Anup Patel
2024-02-07  9:18         ` Anup Patel
2024-02-07  9:18         ` Anup Patel
2024-02-07  9:37         ` Björn Töpel
2024-02-07  9:37           ` Björn Töpel
2024-02-07  9:37           ` Björn Töpel
2024-02-07 12:55           ` Björn Töpel
2024-02-07 12:55             ` Björn Töpel
2024-02-07 12:55             ` Björn Töpel
2024-02-07 13:08             ` Anup Patel
2024-02-07 13:08               ` Anup Patel
2024-02-07 13:08               ` Anup Patel
2024-02-07 13:10             ` Anup Patel
2024-02-07 13:10               ` Anup Patel
2024-02-07 13:10               ` Anup Patel
2024-02-08 10:10 ` Andrea Parri
2024-02-08 10:10   ` Andrea Parri
2024-02-08 10:10   ` Andrea Parri
2024-02-16 11:33   ` Anup Patel
2024-02-16 11:33     ` Anup Patel
2024-02-16 11:33     ` Anup Patel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240127161753.114685-20-apatel@ventanamicro.com \
    --to=apatel@ventanamicro.com \
    --cc=ajones@ventanamicro.com \
    --cc=anup@brainfault.org \
    --cc=atishp@atishpatra.org \
    --cc=bjorn@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=maz@kernel.org \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=robh+dt@kernel.org \
    --cc=saravanak@google.com \
    --cc=sunilvl@ventanamicro.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.