Skip to contentSkip to conversation

armada-370-xp irqchip updates round 5

PATCH New Marek Behún 1 participant 13 messages Aug 7, 2024

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover armada-370-xp irqchip updates round 5

Hi Thomas, Andrew, Ilpo et al.,

This is v2 of the last round of updates for armada-370-xp irqchip before I send the one patch adding support for SoC Error interrupts.

I have addressed the issues pointed out by Thomas in v1, which you can see at
https://patchwork.kernel.org/project/linux-arm-kernel/list/?series=871321

This series can be applied on tip/irq/core.

Marek

Marek Behún (12):
irqchip/armada-370-xp: Drop IPI_DOORBELL_START and rename
IPI_DOORBELL_END
irqchip/armada-370-xp: Drop msi_doorbell_end() irqchip/armada-370-xp: Add the __init attribute to mpic_msi_init() irqchip/armada-370-xp: Put __init attribute after return type in

    mpic_ipi_init()

irqchip/armada-370-xp: Put static variables into driver private
structure
irqchip/armada-370-xp: Put MSI doorbell limits into the mpic structure irqchip/armada-370-xp: Pass around the driver private structure irqchip/armada-370-xp: Dynamically allocate the driver private
structure
irqchip/armada-370-xp: Correct reenabling last per-CPU interrupt irqchip/armada-370-xp: Iterate only valid bits of the per-CPU
interrupt cause register
irqchip/armada-370-xp: Allow mapping only per-CPU interrupts irqchip/armada-370-xp: Use the mpic_is_ipi_available() helper in one
more case

 drivers/irqchip/irq-armada-370-xp.c | 407 ++++++++++++++++------------
 1 file changed, 229 insertions(+), 178 deletions(-)
Signature · 1 line
2.44.2
#1 lore raw

PATCH v2 1/12 irqchip/armada-370-xp: Drop IPI_DOORBELL_START and rename IPI_DOORBELL_END

Drop IPI_DOORBELL_START since it is not used and rename IPI_DOORBELL_END to IPI_DOORBELL_NR.

---
 drivers/irqchip/irq-armada-370-xp.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +6 -7
index b11612acec78..9a431d04ed19 100644
@@ -136,8 +136,7 @@
 #define MPIC_MAX_PER_CPU_IRQS			28
 
 /* IPI and MSI interrupt definitions for IPI platforms */
-#define IPI_DOORBELL_START			0
-#define IPI_DOORBELL_END			8
+#define IPI_DOORBELL_NR				8
 #define IPI_DOORBELL_MASK			GENMASK(7, 0)
 #define PCI_MSI_DOORBELL_START			16
 #define PCI_MSI_DOORBELL_NR			16
@@ -452,7 +451,7 @@ static const struct irq_domain_ops mpic_ipi_domain_ops = {
 
 static void mpic_ipi_resume(void)
 {
-	for (irq_hw_number_t i = 0; i < IPI_DOORBELL_END; i++) {
+	for (irq_hw_number_t i = 0; i < IPI_DOORBELL_NR; i++) {
 		unsigned int virq = irq_find_mapping(mpic_ipi_domain, i);
 		struct irq_data *d;
 
@@ -468,17 +467,17 @@ static __init int mpic_ipi_init(struct device_node *node)
 {
 	int base_ipi;
 
-	mpic_ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), IPI_DOORBELL_END,
+	mpic_ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), IPI_DOORBELL_NR,
 						   &mpic_ipi_domain_ops, NULL);
 	if (WARN_ON(!mpic_ipi_domain))
 		return -ENOMEM;
 
 	irq_domain_update_bus_token(mpic_ipi_domain, DOMAIN_BUS_IPI);
-	base_ipi = irq_domain_alloc_irqs(mpic_ipi_domain, IPI_DOORBELL_END, NUMA_NO_NODE, NULL);
+	base_ipi = irq_domain_alloc_irqs(mpic_ipi_domain, IPI_DOORBELL_NR, NUMA_NO_NODE, NULL);
 	if (WARN_ON(!base_ipi))
 		return -ENOMEM;
 
-	set_smp_ipi_range(base_ipi, IPI_DOORBELL_END);
+	set_smp_ipi_range(base_ipi, IPI_DOORBELL_NR);
 
 	return 0;
 }
@@ -627,7 +626,7 @@ static void mpic_handle_ipi_irq(void)
 	cause = readl_relaxed(per_cpu_int_base + MPIC_IN_DRBEL_CAUSE);
 	cause &= IPI_DOORBELL_MASK;
 
-	for_each_set_bit(i, &cause, IPI_DOORBELL_END)
+	for_each_set_bit(i, &cause, IPI_DOORBELL_NR)
 		generic_handle_domain_irq(mpic_ipi_domain, i);
 }
 #else
Signature · 1 line
2.44.2
#2 lore raw

PATCH v2 2/12 irqchip/armada-370-xp: Drop msi_doorbell_end()

In reply to Marek Behún

Drop the msi_doorbell_end() function and related constants, it is not used anymore.

---
 drivers/irqchip/irq-armada-370-xp.c | 7 -------
 1 file changed, 7 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +0 -7
index 9a431d04ed19..fcfc5f86fbff 100644
@@ -140,13 +140,11 @@
 #define IPI_DOORBELL_MASK			GENMASK(7, 0)
 #define PCI_MSI_DOORBELL_START			16
 #define PCI_MSI_DOORBELL_NR			16
-#define PCI_MSI_DOORBELL_END			32
 #define PCI_MSI_DOORBELL_MASK			GENMASK(31, 16)
 
 /* MSI interrupt definitions for non-IPI platforms */
 #define PCI_MSI_FULL_DOORBELL_START		0
 #define PCI_MSI_FULL_DOORBELL_NR		32
-#define PCI_MSI_FULL_DOORBELL_END		32
 #define PCI_MSI_FULL_DOORBELL_MASK		GENMASK(31, 0)
 #define PCI_MSI_FULL_DOORBELL_SRC0_MASK		GENMASK(15, 0)
 #define PCI_MSI_FULL_DOORBELL_SRC1_MASK		GENMASK(31, 16)
@@ -190,11 +188,6 @@ static inline unsigned int msi_doorbell_size(void)
 	return mpic_is_ipi_available() ? PCI_MSI_DOORBELL_NR : PCI_MSI_FULL_DOORBELL_NR;
 }
 
-static inline unsigned int msi_doorbell_end(void)
-{
-	return mpic_is_ipi_available() ? PCI_MSI_DOORBELL_END : PCI_MSI_FULL_DOORBELL_END;
-}
-
 static inline bool mpic_is_percpu_irq(irq_hw_number_t hwirq)
 {
 	return hwirq <= MPIC_MAX_PER_CPU_IRQS;
Signature · 1 line
2.44.2
#3 lore raw

PATCH v2 3/12 irqchip/armada-370-xp: Add the __init attribute to mpic_msi_init()

In reply to Marek Behún

Add the __init attribute to the mpic_msi_init() function. It is only called from the device initializer, and so can be dropped after boot is complete.

---
 drivers/irqchip/irq-armada-370-xp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +1 -1
index fcfc5f86fbff..f5a693745785 100644
@@ -314,7 +314,7 @@ static void mpic_msi_reenable_percpu(void)
 	writel(1, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
 }
 
-static int mpic_msi_init(struct device_node *node, phys_addr_t main_int_phys_base)
+static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_phys_base)
 {
 	msi_doorbell_addr = main_int_phys_base + MPIC_SW_TRIG_INT;
 
Signature · 1 line
2.44.2
#4 lore raw

PATCH v2 4/12 irqchip/armada-370-xp: Put __init attribute after return type in mpic_ipi_init()

In reply to Marek Behún

For consistency with the rest of the driver, put the __init attribute after the return type of the mpic_ipi_init() function.

---
 drivers/irqchip/irq-armada-370-xp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +1 -1
index f5a693745785..07004ecec165 100644
@@ -456,7 +456,7 @@ static void mpic_ipi_resume(void)
 	}
 }
 
-static __init int mpic_ipi_init(struct device_node *node)
+static int __init mpic_ipi_init(struct device_node *node)
 {
 	int base_ipi;
 
Signature · 1 line
2.44.2
#5 lore raw

PATCH v2 5/12 irqchip/armada-370-xp: Put static variables into driver private structure

In reply to Marek Behún

In preparation for converting the driver to modern style put all the interrupt controller private static variables into driver private structure.

Access to these variables changes as:
main_int_base mpic->base
per_cpu_int_base mpic->per_cpu
mpic_domain mpic->domain
parent_irq mpic->parent_irq
...

---
 drivers/irqchip/irq-armada-370-xp.c | 223 +++++++++++++++-------------
 1 file changed, 122 insertions(+), 101 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +122 -101
index 07004ecec165..00f38428d2ba 100644
@@ -66,11 +66,11 @@
  *
  * The "global interrupt mask/unmask" is modified using the
  * MPIC_INT_SET_ENABLE and MPIC_INT_CLEAR_ENABLE
- * registers, which are relative to "main_int_base".
+ * registers, which are relative to "mpic->base".
  *
  * The "per-CPU mask/unmask" is modified using the MPIC_INT_SET_MASK
  * and MPIC_INT_CLEAR_MASK registers, which are relative to
- * "per_cpu_int_base". This base address points to a special address,
+ * "mpic->per_cpu". This base address points to a special address,
  * which automatically accesses the registers of the current CPU.
  *
  * The per-CPU mask/unmask can also be adjusted using the global
@@ -112,7 +112,7 @@
  *    at the per-CPU level.
  */
 
-/* Registers relative to main_int_base */
+/* Registers relative to mpic->base */
 #define MPIC_INT_CONTROL			0x00
 #define MPIC_INT_CONTROL_NUMINT_MASK		GENMASK(12, 2)
 #define MPIC_SW_TRIG_INT			0x04
@@ -122,7 +122,7 @@
 #define MPIC_INT_SOURCE_CPU_MASK		GENMASK(3, 0)
 #define MPIC_INT_IRQ_FIQ_MASK(cpuid)		((BIT(0) | BIT(8)) << (cpuid))
 
-/* Registers relative to per_cpu_int_base */
+/* Registers relative to mpic->per_cpu */
 #define MPIC_IN_DRBEL_CAUSE			0x08
 #define MPIC_IN_DRBEL_MASK			0x0c
 #define MPIC_PPI_CAUSE				0x10
@@ -149,18 +149,40 @@
 #define PCI_MSI_FULL_DOORBELL_SRC0_MASK		GENMASK(15, 0)
 #define PCI_MSI_FULL_DOORBELL_SRC1_MASK		GENMASK(31, 16)
 
-static void __iomem *per_cpu_int_base;
-static void __iomem *main_int_base;
-static struct irq_domain *mpic_domain;
-static u32 doorbell_mask_reg;
-static int parent_irq;
+/**
+ * struct mpic - MPIC private data structure
+ * @base:		MPIC registers base address
+ * @per_cpu:		per-CPU registers base address
+ * @parent_irq:		parent IRQ if MPIC is not top-level interrupt controller
+ * @domain:		MPIC main interrupt domain
+ * @ipi_domain:		IPI domain
+ * @msi_domain:		MSI domain
+ * @msi_inner_domain:	MSI inner domain
+ * @msi_used:		bitmap of used MSI numbers
+ * @msi_lock:		mutex serializing access to @msi_used
+ * @msi_doorbell_addr:	physical address of MSI doorbell register
+ * @doorbell_mask:	doorbell mask of MSIs and IPIs, stored on suspend, restored on resume
+ */
+struct mpic {
+	void __iomem *base;
+	void __iomem *per_cpu;
+	int parent_irq;
+	struct irq_domain *domain;
+#ifdef CONFIG_SMP
+	struct irq_domain *ipi_domain;
+#endif
 #ifdef CONFIG_PCI_MSI
-static struct irq_domain *mpic_msi_domain;
-static struct irq_domain *mpic_msi_inner_domain;
-static DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR);
-static DEFINE_MUTEX(msi_used_lock);
-static phys_addr_t msi_doorbell_addr;
+	struct irq_domain *msi_domain;
+	struct irq_domain *msi_inner_domain;
+	DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR);
+	struct mutex msi_lock;
+	phys_addr_t msi_doorbell_addr;
 #endif
+	u32 doorbell_mask;
+};
+
+static struct mpic mpic_data;
+static struct mpic * const mpic = &mpic_data;
 
 static inline bool mpic_is_ipi_available(void)
 {
@@ -170,7 +192,7 @@ static inline bool mpic_is_ipi_available(void)
 	 * interrupt controller (e.g. GIC) that takes care of inter-processor
 	 * interrupts.
 	 */
-	return parent_irq <= 0;
+	return mpic->parent_irq <= 0;
 }
 
 static inline u32 msi_doorbell_mask(void)
@@ -203,9 +225,9 @@ static void mpic_irq_mask(struct irq_data *d)
 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
 	if (!mpic_is_percpu_irq(hwirq))
-		writel(hwirq, main_int_base + MPIC_INT_CLEAR_ENABLE);
+		writel(hwirq, mpic->base + MPIC_INT_CLEAR_ENABLE);
 	else
-		writel(hwirq, per_cpu_int_base + MPIC_INT_SET_MASK);
+		writel(hwirq, mpic->per_cpu + MPIC_INT_SET_MASK);
 }
 
 static void mpic_irq_unmask(struct irq_data *d)
@@ -213,9 +235,9 @@ static void mpic_irq_unmask(struct irq_data *d)
 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
 	if (!mpic_is_percpu_irq(hwirq))
-		writel(hwirq, main_int_base + MPIC_INT_SET_ENABLE);
+		writel(hwirq, mpic->base + MPIC_INT_SET_ENABLE);
 	else
-		writel(hwirq, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+		writel(hwirq, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -236,8 +258,8 @@ static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
 {
 	unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
 
-	msg->address_lo = lower_32_bits(msi_doorbell_addr);
-	msg->address_hi = upper_32_bits(msi_doorbell_addr);
+	msg->address_lo = lower_32_bits(mpic->msi_doorbell_addr);
+	msg->address_hi = upper_32_bits(mpic->msi_doorbell_addr);
 	msg->data = BIT(cpu + 8) | (d->hwirq + msi_doorbell_start());
 }
 
@@ -269,10 +291,10 @@ static int mpic_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned
 {
 	int hwirq;
 
-	mutex_lock(&msi_used_lock);
-	hwirq = bitmap_find_free_region(msi_used, msi_doorbell_size(),
+	mutex_lock(&mpic->msi_lock);
+	hwirq = bitmap_find_free_region(mpic->msi_used, msi_doorbell_size(),
 					order_base_2(nr_irqs));
-	mutex_unlock(&msi_used_lock);
+	mutex_unlock(&mpic->msi_lock);
 
 	if (hwirq < 0)
 		return -ENOSPC;
@@ -291,9 +313,9 @@ static void mpic_msi_free(struct irq_domain *domain, unsigned int virq, unsigned
 {
 	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 
-	mutex_lock(&msi_used_lock);
-	bitmap_release_region(msi_used, d->hwirq, order_base_2(nr_irqs));
-	mutex_unlock(&msi_used_lock);
+	mutex_lock(&mpic->msi_lock);
+	bitmap_release_region(mpic->msi_used, d->hwirq, order_base_2(nr_irqs));
+	mutex_unlock(&mpic->msi_lock);
 }
 
 static const struct irq_domain_ops mpic_msi_domain_ops = {
@@ -306,27 +328,29 @@ static void mpic_msi_reenable_percpu(void)
 	u32 reg;
 
 	/* Enable MSI doorbell mask and combined cpu local interrupt */
-	reg = readl(per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 	reg |= msi_doorbell_mask();
-	writel(reg, per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
 	/* Unmask local doorbell interrupt */
-	writel(1, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+	writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 }
 
 static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_phys_base)
 {
-	msi_doorbell_addr = main_int_phys_base + MPIC_SW_TRIG_INT;
+	mpic->msi_doorbell_addr = main_int_phys_base + MPIC_SW_TRIG_INT;
+
+	mutex_init(&mpic->msi_lock);
 
-	mpic_msi_inner_domain = irq_domain_add_linear(NULL, msi_doorbell_size(),
-						      &mpic_msi_domain_ops, NULL);
-	if (!mpic_msi_inner_domain)
+	mpic->msi_inner_domain = irq_domain_add_linear(NULL, msi_doorbell_size(),
+						       &mpic_msi_domain_ops, NULL);
+	if (!mpic->msi_inner_domain)
 		return -ENOMEM;
 
-	mpic_msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), &mpic_msi_domain_info,
-						    mpic_msi_inner_domain);
-	if (!mpic_msi_domain) {
-		irq_domain_remove(mpic_msi_inner_domain);
+	mpic->msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node), &mpic_msi_domain_info,
+						     mpic->msi_inner_domain);
+	if (!mpic->msi_domain) {
+		irq_domain_remove(mpic->msi_inner_domain);
 		return -ENOMEM;
 	}
 
@@ -334,7 +358,7 @@ static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_p
 
 	/* Unmask low 16 MSI irqs on non-IPI platforms */
 	if (!mpic_is_ipi_available())
-		writel(0, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+		writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 
 	return 0;
 }
@@ -362,29 +386,26 @@ static void mpic_perf_init(void)
 	cpuid = cpu_logical_map(smp_processor_id());
 
 	/* Enable Performance Counter Overflow interrupts */
-	writel(MPIC_INT_CAUSE_PERF(cpuid),
-	       per_cpu_int_base + MPIC_INT_FABRIC_MASK);
+	writel(MPIC_INT_CAUSE_PERF(cpuid), mpic->per_cpu + MPIC_INT_FABRIC_MASK);
 }
 
 #ifdef CONFIG_SMP
-static struct irq_domain *mpic_ipi_domain;
-
 static void mpic_ipi_mask(struct irq_data *d)
 {
 	u32 reg;
 
-	reg = readl(per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 	reg &= ~BIT(d->hwirq);
-	writel(reg, per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 }
 
 static void mpic_ipi_unmask(struct irq_data *d)
 {
 	u32 reg;
 
-	reg = readl(per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 	reg |= BIT(d->hwirq);
-	writel(reg, per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 }
 
 static void mpic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
@@ -403,12 +424,12 @@ static void mpic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 	dsb();
 
 	/* submit softirq */
-	writel((map << 8) | d->hwirq, main_int_base + MPIC_SW_TRIG_INT);
+	writel((map << 8) | d->hwirq, mpic->base + MPIC_SW_TRIG_INT);
 }
 
 static void mpic_ipi_ack(struct irq_data *d)
 {
-	writel(~BIT(d->hwirq), per_cpu_int_base + MPIC_IN_DRBEL_CAUSE);
+	writel(~BIT(d->hwirq), mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 }
 
 static struct irq_chip mpic_ipi_irqchip = {
@@ -445,13 +466,13 @@ static const struct irq_domain_ops mpic_ipi_domain_ops = {
 static void mpic_ipi_resume(void)
 {
 	for (irq_hw_number_t i = 0; i < IPI_DOORBELL_NR; i++) {
-		unsigned int virq = irq_find_mapping(mpic_ipi_domain, i);
+		unsigned int virq = irq_find_mapping(mpic->ipi_domain, i);
 		struct irq_data *d;
 
 		if (!virq || !irq_percpu_is_enabled(virq))
 			continue;
 
-		d = irq_domain_get_irq_data(mpic_ipi_domain, virq);
+		d = irq_domain_get_irq_data(mpic->ipi_domain, virq);
 		mpic_ipi_unmask(d);
 	}
 }
@@ -460,13 +481,13 @@ static int __init mpic_ipi_init(struct device_node *node)
 {
 	int base_ipi;
 
-	mpic_ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), IPI_DOORBELL_NR,
-						   &mpic_ipi_domain_ops, NULL);
-	if (WARN_ON(!mpic_ipi_domain))
+	mpic->ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), IPI_DOORBELL_NR,
+						    &mpic_ipi_domain_ops, NULL);
+	if (WARN_ON(!mpic->ipi_domain))
 		return -ENOMEM;
 
-	irq_domain_update_bus_token(mpic_ipi_domain, DOMAIN_BUS_IPI);
-	base_ipi = irq_domain_alloc_irqs(mpic_ipi_domain, IPI_DOORBELL_NR, NUMA_NO_NODE, NULL);
+	irq_domain_update_bus_token(mpic->ipi_domain, DOMAIN_BUS_IPI);
+	base_ipi = irq_domain_alloc_irqs(mpic->ipi_domain, IPI_DOORBELL_NR, NUMA_NO_NODE, NULL);
 	if (WARN_ON(!base_ipi))
 		return -ENOMEM;
 
@@ -483,7 +504,7 @@ static int mpic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 	/* Select a single core from the affinity mask which is online */
 	cpu = cpumask_any_and(mask_val, cpu_online_mask);
 
-	atomic_io_modify(main_int_base + MPIC_INT_SOURCE_CTL(hwirq),
+	atomic_io_modify(mpic->base + MPIC_INT_SOURCE_CTL(hwirq),
 			 MPIC_INT_SOURCE_CPU_MASK, BIT(cpu_logical_map(cpu)));
 
 	irq_data_update_effective_affinity(d, cpumask_of(cpu));
@@ -493,27 +514,27 @@ static int mpic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 
 static void mpic_smp_cpu_init(void)
 {
-	for (irq_hw_number_t i = 0; i < mpic_domain->hwirq_max; i++)
-		writel(i, per_cpu_int_base + MPIC_INT_SET_MASK);
+	for (irq_hw_number_t i = 0; i < mpic->domain->hwirq_max; i++)
+		writel(i, mpic->per_cpu + MPIC_INT_SET_MASK);
 
 	if (!mpic_is_ipi_available())
 		return;
 
 	/* Disable all IPIs */
-	writel(0, per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	writel(0, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
 	/* Clear pending IPIs */
-	writel(0, per_cpu_int_base + MPIC_IN_DRBEL_CAUSE);
+	writel(0, mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 
 	/* Unmask IPI interrupt */
-	writel(0, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+	writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 }
 
 static void mpic_reenable_percpu(void)
 {
 	/* Re-enable per-CPU interrupts that were enabled before suspend */
 	for (irq_hw_number_t i = 0; i < MPIC_MAX_PER_CPU_IRQS; i++) {
-		unsigned int virq = irq_linear_revmap(mpic_domain, i);
+		unsigned int virq = irq_linear_revmap(mpic->domain, i);
 		struct irq_data *d;
 
 		if (!virq || !irq_percpu_is_enabled(virq))
@@ -542,7 +563,7 @@ static int mpic_cascaded_starting_cpu(unsigned int cpu)
 {
 	mpic_perf_init();
 	mpic_reenable_percpu();
-	enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
+	enable_percpu_irq(mpic->parent_irq, IRQ_TYPE_NONE);
 
 	return 0;
 }
@@ -571,9 +592,9 @@ static int mpic_irq_map(struct irq_domain *h, unsigned int virq,
 
 	mpic_irq_mask(irq_get_irq_data(virq));
 	if (!mpic_is_percpu_irq(hwirq))
-		writel(hwirq, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+		writel(hwirq, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 	else
-		writel(hwirq, main_int_base + MPIC_INT_SET_ENABLE);
+		writel(hwirq, mpic->base + MPIC_INT_SET_ENABLE);
 	irq_set_status_flags(virq, IRQ_LEVEL);
 
 	if (mpic_is_percpu_irq(hwirq)) {
@@ -598,12 +619,12 @@ static void mpic_handle_msi_irq(void)
 	unsigned long cause;
 	unsigned int i;
 
-	cause = readl_relaxed(per_cpu_int_base + MPIC_IN_DRBEL_CAUSE);
+	cause = readl_relaxed(mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 	cause &= msi_doorbell_mask();
-	writel(~cause, per_cpu_int_base + MPIC_IN_DRBEL_CAUSE);
+	writel(~cause, mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 
 	for_each_set_bit(i, &cause, BITS_PER_LONG)
-		generic_handle_domain_irq(mpic_msi_inner_domain,
+		generic_handle_domain_irq(mpic->msi_inner_domain,
 					  i - msi_doorbell_start());
 }
 #else
@@ -616,11 +637,11 @@ static void mpic_handle_ipi_irq(void)
 	unsigned long cause;
 	irq_hw_number_t i;
 
-	cause = readl_relaxed(per_cpu_int_base + MPIC_IN_DRBEL_CAUSE);
+	cause = readl_relaxed(mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 	cause &= IPI_DOORBELL_MASK;
 
 	for_each_set_bit(i, &cause, IPI_DOORBELL_NR)
-		generic_handle_domain_irq(mpic_ipi_domain, i);
+		generic_handle_domain_irq(mpic->ipi_domain, i);
 }
 #else
 static inline void mpic_handle_ipi_irq(void) {}
@@ -635,11 +656,11 @@ static void mpic_handle_cascade_irq(struct irq_desc *desc)
 
 	chained_irq_enter(chip, desc);
 
-	cause = readl_relaxed(per_cpu_int_base + MPIC_PPI_CAUSE);
+	cause = readl_relaxed(mpic->per_cpu + MPIC_PPI_CAUSE);
 	cpuid = cpu_logical_map(smp_processor_id());
 
 	for_each_set_bit(i, &cause, BITS_PER_LONG) {
-		irqsrc = readl_relaxed(main_int_base + MPIC_INT_SOURCE_CTL(i));
+		irqsrc = readl_relaxed(mpic->base + MPIC_INT_SOURCE_CTL(i));
 
 		/* Check if the interrupt is not masked on current CPU.
 		 * Test IRQ (0-1) and FIQ (8-9) mask bits.
@@ -652,7 +673,7 @@ static void mpic_handle_cascade_irq(struct irq_desc *desc)
 			continue;
 		}
 
-		generic_handle_domain_irq(mpic_domain, i);
+		generic_handle_domain_irq(mpic->domain, i);
 	}
 
 	chained_irq_exit(chip, desc);
@@ -664,14 +685,14 @@ static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs)
 	u32 irqstat;
 
 	do {
-		irqstat = readl_relaxed(per_cpu_int_base + MPIC_CPU_INTACK);
+		irqstat = readl_relaxed(mpic->per_cpu + MPIC_CPU_INTACK);
 		i = FIELD_GET(MPIC_CPU_INTACK_IID_MASK, irqstat);
 
 		if (i > 1022)
 			break;
 
 		if (i > 1)
-			generic_handle_domain_irq(mpic_domain, i);
+			generic_handle_domain_irq(mpic->domain, i);
 
 		/* MSI handling */
 		if (i == 1)
@@ -685,7 +706,7 @@ static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs)
 
 static int mpic_suspend(void)
 {
-	doorbell_mask_reg = readl(per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	mpic->doorbell_mask = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
 	return 0;
 }
@@ -695,8 +716,8 @@ static void mpic_resume(void)
 	bool src0, src1;
 
 	/* Re-enable interrupts */
-	for (irq_hw_number_t i = 0; i < mpic_domain->hwirq_max; i++) {
-		unsigned int virq = irq_linear_revmap(mpic_domain, i);
+	for (irq_hw_number_t i = 0; i < mpic->domain->hwirq_max; i++) {
+		unsigned int virq = irq_linear_revmap(mpic->domain, i);
 		struct irq_data *d;
 
 		if (!virq)
@@ -706,12 +727,12 @@ static void mpic_resume(void)
 
 		if (!mpic_is_percpu_irq(i)) {
 			/* Non per-CPU interrupts */
-			writel(i, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+			writel(i, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 			if (!irqd_irq_disabled(d))
 				mpic_irq_unmask(d);
 		} else {
 			/* Per-CPU interrupts */
-			writel(i, main_int_base + MPIC_INT_SET_ENABLE);
+			writel(i, mpic->base + MPIC_INT_SET_ENABLE);
 
 			/*
 			 * Re-enable on the current CPU, mpic_reenable_percpu()
@@ -723,20 +744,20 @@ static void mpic_resume(void)
 	}
 
 	/* Reconfigure doorbells for IPIs and MSIs */
-	writel(doorbell_mask_reg, per_cpu_int_base + MPIC_IN_DRBEL_MASK);
+	writel(mpic->doorbell_mask, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
 	if (mpic_is_ipi_available()) {
-		src0 = doorbell_mask_reg & IPI_DOORBELL_MASK;
-		src1 = doorbell_mask_reg & PCI_MSI_DOORBELL_MASK;
+		src0 = mpic->doorbell_mask & IPI_DOORBELL_MASK;
+		src1 = mpic->doorbell_mask & PCI_MSI_DOORBELL_MASK;
 	} else {
-		src0 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC0_MASK;
-		src1 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC1_MASK;
+		src0 = mpic->doorbell_mask & PCI_MSI_FULL_DOORBELL_SRC0_MASK;
+		src1 = mpic->doorbell_mask & PCI_MSI_FULL_DOORBELL_SRC1_MASK;
 	}
 
 	if (src0)
-		writel(0, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+		writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 	if (src1)
-		writel(1, per_cpu_int_base + MPIC_INT_CLEAR_MASK);
+		writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 
 	if (mpic_is_ipi_available())
 		mpic_ipi_resume();
@@ -784,32 +805,32 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 	unsigned int nr_irqs;
 	int err;
 
-	err = mpic_map_region(node, 0, &main_int_base, &phys_base);
+	err = mpic_map_region(node, 0, &mpic->base, &phys_base);
 	if (err)
 		return err;
 
-	err = mpic_map_region(node, 1, &per_cpu_int_base, NULL);
+	err = mpic_map_region(node, 1, &mpic->per_cpu, NULL);
 	if (err)
 		return err;
 
-	nr_irqs = FIELD_GET(MPIC_INT_CONTROL_NUMINT_MASK, readl(main_int_base + MPIC_INT_CONTROL));
+	nr_irqs = FIELD_GET(MPIC_INT_CONTROL_NUMINT_MASK, readl(mpic->base + MPIC_INT_CONTROL));
 
 	for (irq_hw_number_t i = 0; i < nr_irqs; i++)
-		writel(i, main_int_base + MPIC_INT_CLEAR_ENABLE);
+		writel(i, mpic->base + MPIC_INT_CLEAR_ENABLE);
 
-	mpic_domain = irq_domain_add_linear(node, nr_irqs, &mpic_irq_ops, NULL);
-	if (!mpic_domain) {
+	mpic->domain = irq_domain_add_linear(node, nr_irqs, &mpic_irq_ops, NULL);
+	if (!mpic->domain) {
 		pr_err("%pOF: Unable to add IRQ domain\n", node);
 		return -ENOMEM;
 	}
 
-	irq_domain_update_bus_token(mpic_domain, DOMAIN_BUS_WIRED);
+	irq_domain_update_bus_token(mpic->domain, DOMAIN_BUS_WIRED);
 
 	/*
-	 * Initialize parent_irq before calling any other functions, since it is
-	 * used to distinguish between IPI and non-IPI platforms.
+	 * Initialize mpic->parent_irq before calling any other functions, since
+	 * it is used to distinguish between IPI and non-IPI platforms.
 	 */
-	parent_irq = irq_of_parse_and_map(node, 0);
+	mpic->parent_irq = irq_of_parse_and_map(node, 0);
 
 	/* Setup for the boot CPU */
 	mpic_perf_init();
@@ -821,8 +842,8 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 		return err;
 	}
 
-	if (parent_irq <= 0) {
-		irq_set_default_host(mpic_domain);
+	if (mpic->parent_irq <= 0) {
+		irq_set_default_host(mpic->domain);
 		set_handle_irq(mpic_handle_irq);
 #ifdef CONFIG_SMP
 		err = mpic_ipi_init(node);
@@ -841,7 +862,7 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 					  "irqchip/armada/cascade:starting",
 					  mpic_cascaded_starting_cpu, NULL);
 #endif
-		irq_set_chained_handler(parent_irq, mpic_handle_cascade_irq);
+		irq_set_chained_handler(mpic->parent_irq, mpic_handle_cascade_irq);
 	}
 
 	register_syscore_ops(&mpic_syscore_ops);
Signature · 1 line
2.44.2
#6 lore raw

PATCH v2 6/12 irqchip/armada-370-xp: Put MSI doorbell limits into the mpic structure

In reply to Marek Behún

Put the MSI doorbell limits msi_doorbell_start, msi_doorbell_size and msi_doorbell_mask into the driver private structure and get rid of the corresponding functions.

---
 drivers/irqchip/irq-armada-370-xp.c | 44 ++++++++++++++---------------
 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +22 -22
index 00f38428d2ba..1c95a61c18cb 100644
@@ -161,6 +161,10 @@
  * @msi_used:		bitmap of used MSI numbers
  * @msi_lock:		mutex serializing access to @msi_used
  * @msi_doorbell_addr:	physical address of MSI doorbell register
+ * @msi_doorbell_mask:	mask of available doorbell bits for MSIs (either PCI_MSI_DOORBELL_MASK or
+ *			PCI_MSI_FULL_DOORBELL_MASK)
+ * @msi_doorbell_start:	first set bit in @msi_doorbell_mask
+ * @msi_doorbell_size:	number of set bits in @msi_doorbell_mask
  * @doorbell_mask:	doorbell mask of MSIs and IPIs, stored on suspend, restored on resume
  */
 struct mpic {
@@ -177,6 +181,8 @@ struct mpic {
 	DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR);
 	struct mutex msi_lock;
 	phys_addr_t msi_doorbell_addr;
+	u32 msi_doorbell_mask;
+	unsigned int msi_doorbell_start, msi_doorbell_size;
 #endif
 	u32 doorbell_mask;
 };
@@ -195,21 +201,6 @@ static inline bool mpic_is_ipi_available(void)
 	return mpic->parent_irq <= 0;
 }
 
-static inline u32 msi_doorbell_mask(void)
-{
-	return mpic_is_ipi_available() ? PCI_MSI_DOORBELL_MASK : PCI_MSI_FULL_DOORBELL_MASK;
-}
-
-static inline unsigned int msi_doorbell_start(void)
-{
-	return mpic_is_ipi_available() ? PCI_MSI_DOORBELL_START : PCI_MSI_FULL_DOORBELL_START;
-}
-
-static inline unsigned int msi_doorbell_size(void)
-{
-	return mpic_is_ipi_available() ? PCI_MSI_DOORBELL_NR : PCI_MSI_FULL_DOORBELL_NR;
-}
-
 static inline bool mpic_is_percpu_irq(irq_hw_number_t hwirq)
 {
 	return hwirq <= MPIC_MAX_PER_CPU_IRQS;
@@ -260,7 +251,7 @@ static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
 
 	msg->address_lo = lower_32_bits(mpic->msi_doorbell_addr);
 	msg->address_hi = upper_32_bits(mpic->msi_doorbell_addr);
-	msg->data = BIT(cpu + 8) | (d->hwirq + msi_doorbell_start());
+	msg->data = BIT(cpu + 8) | (d->hwirq + mpic->msi_doorbell_start);
 }
 
 static int mpic_msi_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force)
@@ -292,7 +283,7 @@ static int mpic_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned
 	int hwirq;
 
 	mutex_lock(&mpic->msi_lock);
-	hwirq = bitmap_find_free_region(mpic->msi_used, msi_doorbell_size(),
+	hwirq = bitmap_find_free_region(mpic->msi_used, mpic->msi_doorbell_size,
 					order_base_2(nr_irqs));
 	mutex_unlock(&mpic->msi_lock);
 
@@ -329,7 +320,7 @@ static void mpic_msi_reenable_percpu(void)
 
 	/* Enable MSI doorbell mask and combined cpu local interrupt */
 	reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
-	reg |= msi_doorbell_mask();
+	reg |= mpic->msi_doorbell_mask;
 	writel(reg, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
 	/* Unmask local doorbell interrupt */
@@ -342,7 +333,17 @@ static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_p
 
 	mutex_init(&mpic->msi_lock);
 
-	mpic->msi_inner_domain = irq_domain_add_linear(NULL, msi_doorbell_size(),
+	if (mpic_is_ipi_available()) {
+		mpic->msi_doorbell_start = PCI_MSI_DOORBELL_START;
+		mpic->msi_doorbell_size = PCI_MSI_DOORBELL_NR;
+		mpic->msi_doorbell_mask = PCI_MSI_DOORBELL_MASK;
+	} else {
+		mpic->msi_doorbell_start = PCI_MSI_FULL_DOORBELL_START;
+		mpic->msi_doorbell_size = PCI_MSI_FULL_DOORBELL_NR;
+		mpic->msi_doorbell_mask = PCI_MSI_FULL_DOORBELL_MASK;
+	}
+
+	mpic->msi_inner_domain = irq_domain_add_linear(NULL, mpic->msi_doorbell_size,
 						       &mpic_msi_domain_ops, NULL);
 	if (!mpic->msi_inner_domain)
 		return -ENOMEM;
@@ -620,12 +621,11 @@ static void mpic_handle_msi_irq(void)
 	unsigned int i;
 
 	cause = readl_relaxed(mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
-	cause &= msi_doorbell_mask();
+	cause &= mpic->msi_doorbell_mask;
 	writel(~cause, mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 
 	for_each_set_bit(i, &cause, BITS_PER_LONG)
-		generic_handle_domain_irq(mpic->msi_inner_domain,
-					  i - msi_doorbell_start());
+		generic_handle_domain_irq(mpic->msi_inner_domain, i - mpic->msi_doorbell_start);
 }
 #else
 static void mpic_handle_msi_irq(void) {}
Signature · 1 line
2.44.2
#7 lore raw

PATCH v2 7/12 irqchip/armada-370-xp: Pass around the driver private structure

In reply to Marek Behún

In continuation of converting the driver to modern style, drop the global pointer to the driver private structure and instead pass it around the functions and callbacks, wherever possible. (There are 3 cases where it is not possible: mpic_cascaded_starting_cpu() and the syscore operations mpic_suspend() and mpic_resume()).

---
 drivers/irqchip/irq-armada-370-xp.c | 115 +++++++++++++++++-----------
 1 file changed, 70 insertions(+), 45 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +70 -45
index 1c95a61c18cb..5710ce206cca 100644
@@ -188,9 +188,8 @@ struct mpic {
 };
 
 static struct mpic mpic_data;
-static struct mpic * const mpic = &mpic_data;
 
-static inline bool mpic_is_ipi_available(void)
+static inline bool mpic_is_ipi_available(struct mpic *mpic)
 {
 	/*
 	 * We distinguish IPI availability in the IC by the IC not having a
@@ -213,6 +212,7 @@ static inline bool mpic_is_percpu_irq(irq_hw_number_t hwirq)
  */
 static void mpic_irq_mask(struct irq_data *d)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
 	if (!mpic_is_percpu_irq(hwirq))
@@ -223,6 +223,7 @@ static void mpic_irq_mask(struct irq_data *d)
 
 static void mpic_irq_unmask(struct irq_data *d)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
 	if (!mpic_is_percpu_irq(hwirq))
@@ -248,6 +249,7 @@ static struct msi_domain_info mpic_msi_domain_info = {
 static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
 {
 	unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 
 	msg->address_lo = lower_32_bits(mpic->msi_doorbell_addr);
 	msg->address_hi = upper_32_bits(mpic->msi_doorbell_addr);
@@ -280,6 +282,7 @@ static struct irq_chip mpic_msi_bottom_irq_chip = {
 static int mpic_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs,
 			  void *args)
 {
+	struct mpic *mpic = domain->host_data;
 	int hwirq;
 
 	mutex_lock(&mpic->msi_lock);
@@ -303,6 +306,7 @@ static int mpic_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned
 static void mpic_msi_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs)
 {
 	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	struct mpic *mpic = domain->host_data;
 
 	mutex_lock(&mpic->msi_lock);
 	bitmap_release_region(mpic->msi_used, d->hwirq, order_base_2(nr_irqs));
@@ -314,7 +318,7 @@ static const struct irq_domain_ops mpic_msi_domain_ops = {
 	.free	= mpic_msi_free,
 };
 
-static void mpic_msi_reenable_percpu(void)
+static void mpic_msi_reenable_percpu(struct mpic *mpic)
 {
 	u32 reg;
 
@@ -327,13 +331,14 @@ static void mpic_msi_reenable_percpu(void)
 	writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 }
 
-static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_phys_base)
+static int __init mpic_msi_init(struct mpic *mpic, struct device_node *node,
+				phys_addr_t main_int_phys_base)
 {
 	mpic->msi_doorbell_addr = main_int_phys_base + MPIC_SW_TRIG_INT;
 
 	mutex_init(&mpic->msi_lock);
 
-	if (mpic_is_ipi_available()) {
+	if (mpic_is_ipi_available(mpic)) {
 		mpic->msi_doorbell_start = PCI_MSI_DOORBELL_START;
 		mpic->msi_doorbell_size = PCI_MSI_DOORBELL_NR;
 		mpic->msi_doorbell_mask = PCI_MSI_DOORBELL_MASK;
@@ -344,7 +349,7 @@ static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_p
 	}
 
 	mpic->msi_inner_domain = irq_domain_add_linear(NULL, mpic->msi_doorbell_size,
-						       &mpic_msi_domain_ops, NULL);
+						       &mpic_msi_domain_ops, mpic);
 	if (!mpic->msi_inner_domain)
 		return -ENOMEM;
 
@@ -355,25 +360,25 @@ static int __init mpic_msi_init(struct device_node *node, phys_addr_t main_int_p
 		return -ENOMEM;
 	}
 
-	mpic_msi_reenable_percpu();
+	mpic_msi_reenable_percpu(mpic);
 
 	/* Unmask low 16 MSI irqs on non-IPI platforms */
-	if (!mpic_is_ipi_available())
+	if (!mpic_is_ipi_available(mpic))
 		writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 
 	return 0;
 }
 #else
-static __maybe_unused void mpic_msi_reenable_percpu(void) {}
+static __maybe_unused void mpic_msi_reenable_percpu(struct mpic *mpic) {}
 
-static inline int mpic_msi_init(struct device_node *node,
+static inline int mpic_msi_init(struct mpic *mpic, struct device_node *node,
 				phys_addr_t main_int_phys_base)
 {
 	return 0;
 }
 #endif
 
-static void mpic_perf_init(void)
+static void mpic_perf_init(struct mpic *mpic)
 {
 	u32 cpuid;
 
@@ -393,6 +398,7 @@ static void mpic_perf_init(void)
 #ifdef CONFIG_SMP
 static void mpic_ipi_mask(struct irq_data *d)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 	u32 reg;
 
 	reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
@@ -402,6 +408,7 @@ static void mpic_ipi_mask(struct irq_data *d)
 
 static void mpic_ipi_unmask(struct irq_data *d)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 	u32 reg;
 
 	reg = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
@@ -411,6 +418,7 @@ static void mpic_ipi_unmask(struct irq_data *d)
 
 static void mpic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 	unsigned int cpu;
 	u32 map = 0;
 
@@ -430,6 +438,8 @@ static void mpic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 
 static void mpic_ipi_ack(struct irq_data *d)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
+
 	writel(~BIT(d->hwirq), mpic->per_cpu + MPIC_IN_DRBEL_CAUSE);
 }
 
@@ -464,7 +474,7 @@ static const struct irq_domain_ops mpic_ipi_domain_ops = {
 	.free	= mpic_ipi_free,
 };
 
-static void mpic_ipi_resume(void)
+static void mpic_ipi_resume(struct mpic *mpic)
 {
 	for (irq_hw_number_t i = 0; i < IPI_DOORBELL_NR; i++) {
 		unsigned int virq = irq_find_mapping(mpic->ipi_domain, i);
@@ -478,12 +488,12 @@ static void mpic_ipi_resume(void)
 	}
 }
 
-static int __init mpic_ipi_init(struct device_node *node)
+static int __init mpic_ipi_init(struct mpic *mpic, struct device_node *node)
 {
 	int base_ipi;
 
 	mpic->ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), IPI_DOORBELL_NR,
-						    &mpic_ipi_domain_ops, NULL);
+						    &mpic_ipi_domain_ops, mpic);
 	if (WARN_ON(!mpic->ipi_domain))
 		return -ENOMEM;
 
@@ -499,6 +509,7 @@ static int __init mpic_ipi_init(struct device_node *node)
 
 static int mpic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force)
 {
+	struct mpic *mpic = irq_data_get_irq_chip_data(d);
 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
 	unsigned int cpu;
 
@@ -513,12 +524,12 @@ static int mpic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 	return IRQ_SET_MASK_OK;
 }
 
-static void mpic_smp_cpu_init(void)
+static void mpic_smp_cpu_init(struct mpic *mpic)
 {
 	for (irq_hw_number_t i = 0; i < mpic->domain->hwirq_max; i++)
 		writel(i, mpic->per_cpu + MPIC_INT_SET_MASK);
 
-	if (!mpic_is_ipi_available())
+	if (!mpic_is_ipi_available(mpic))
 		return;
 
 	/* Disable all IPIs */
@@ -531,7 +542,7 @@ static void mpic_smp_cpu_init(void)
 	writel(0, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 }
 
-static void mpic_reenable_percpu(void)
+static void mpic_reenable_percpu(struct mpic *mpic)
 {
 	/* Re-enable per-CPU interrupts that were enabled before suspend */
 	for (irq_hw_number_t i = 0; i < MPIC_MAX_PER_CPU_IRQS; i++) {
@@ -545,32 +556,36 @@ static void mpic_reenable_percpu(void)
 		mpic_irq_unmask(d);
 	}
 
-	if (mpic_is_ipi_available())
-		mpic_ipi_resume();
+	if (mpic_is_ipi_available(mpic))
+		mpic_ipi_resume(mpic);
 
-	mpic_msi_reenable_percpu();
+	mpic_msi_reenable_percpu(mpic);
 }
 
 static int mpic_starting_cpu(unsigned int cpu)
 {
-	mpic_perf_init();
-	mpic_smp_cpu_init();
-	mpic_reenable_percpu();
+	struct mpic *mpic = irq_get_default_host()->host_data;
+
+	mpic_perf_init(mpic);
+	mpic_smp_cpu_init(mpic);
+	mpic_reenable_percpu(mpic);
 
 	return 0;
 }
 
 static int mpic_cascaded_starting_cpu(unsigned int cpu)
 {
-	mpic_perf_init();
-	mpic_reenable_percpu();
+	struct mpic *mpic = &mpic_data;
+
+	mpic_perf_init(mpic);
+	mpic_reenable_percpu(mpic);
 	enable_percpu_irq(mpic->parent_irq, IRQ_TYPE_NONE);
 
 	return 0;
 }
 #else
-static void mpic_smp_cpu_init(void) {}
-static void mpic_ipi_resume(void) {}
+static void mpic_smp_cpu_init(struct mpic *mpic) {}
+static void mpic_ipi_resume(struct mpic *mpic) {}
 #endif
 
 static struct irq_chip mpic_irq_chip = {
@@ -584,13 +599,16 @@ static struct irq_chip mpic_irq_chip = {
 	.flags		= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
 };
 
-static int mpic_irq_map(struct irq_domain *h, unsigned int virq,
-			irq_hw_number_t hwirq)
+static int mpic_irq_map(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq)
 {
+	struct mpic *mpic = domain->host_data;
+
 	/* IRQs 0 and 1 cannot be mapped, they are handled internally */
 	if (hwirq <= 1)
 		return -EINVAL;
 
+	irq_set_chip_data(virq, mpic);
+
 	mpic_irq_mask(irq_get_irq_data(virq));
 	if (!mpic_is_percpu_irq(hwirq))
 		writel(hwirq, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
@@ -615,7 +633,7 @@ static const struct irq_domain_ops mpic_irq_ops = {
 };
 
 #ifdef CONFIG_PCI_MSI
-static void mpic_handle_msi_irq(void)
+static void mpic_handle_msi_irq(struct mpic *mpic)
 {
 	unsigned long cause;
 	unsigned int i;
@@ -628,11 +646,11 @@ static void mpic_handle_msi_irq(void)
 		generic_handle_domain_irq(mpic->msi_inner_domain, i - mpic->msi_doorbell_start);
 }
 #else
-static void mpic_handle_msi_irq(void) {}
+static void mpic_handle_msi_irq(struct mpic *mpic) {}
 #endif
 
 #ifdef CONFIG_SMP
-static void mpic_handle_ipi_irq(void)
+static void mpic_handle_ipi_irq(struct mpic *mpic)
 {
 	unsigned long cause;
 	irq_hw_number_t i;
@@ -644,11 +662,12 @@ static void mpic_handle_ipi_irq(void)
 		generic_handle_domain_irq(mpic->ipi_domain, i);
 }
 #else
-static inline void mpic_handle_ipi_irq(void) {}
+static inline void mpic_handle_ipi_irq(struct mpic *mpic) {}
 #endif
 
 static void mpic_handle_cascade_irq(struct irq_desc *desc)
 {
+	struct mpic *mpic = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	unsigned long cause;
 	u32 irqsrc, cpuid;
@@ -669,7 +688,7 @@ static void mpic_handle_cascade_irq(struct irq_desc *desc)
 			continue;
 
 		if (i == 0 || i == 1) {
-			mpic_handle_msi_irq();
+			mpic_handle_msi_irq(mpic);
 			continue;
 		}
 
@@ -681,6 +700,7 @@ static void mpic_handle_cascade_irq(struct irq_desc *desc)
 
 static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs)
 {
+	struct mpic *mpic = irq_get_default_host()->host_data;
 	irq_hw_number_t i;
 	u32 irqstat;
 
@@ -696,16 +716,18 @@ static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs)
 
 		/* MSI handling */
 		if (i == 1)
-			mpic_handle_msi_irq();
+			mpic_handle_msi_irq(mpic);
 
 		/* IPI Handling */
 		if (i == 0)
-			mpic_handle_ipi_irq();
+			mpic_handle_ipi_irq(mpic);
 	} while (1);
 }
 
 static int mpic_suspend(void)
 {
+	struct mpic *mpic = &mpic_data;
+
 	mpic->doorbell_mask = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
 	return 0;
@@ -713,6 +735,7 @@ static int mpic_suspend(void)
 
 static void mpic_resume(void)
 {
+	struct mpic *mpic = &mpic_data;
 	bool src0, src1;
 
 	/* Re-enable interrupts */
@@ -746,7 +769,7 @@ static void mpic_resume(void)
 	/* Reconfigure doorbells for IPIs and MSIs */
 	writel(mpic->doorbell_mask, mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
-	if (mpic_is_ipi_available()) {
+	if (mpic_is_ipi_available(mpic)) {
 		src0 = mpic->doorbell_mask & IPI_DOORBELL_MASK;
 		src1 = mpic->doorbell_mask & PCI_MSI_DOORBELL_MASK;
 	} else {
@@ -759,8 +782,8 @@ static void mpic_resume(void)
 	if (src1)
 		writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK);
 
-	if (mpic_is_ipi_available())
-		mpic_ipi_resume();
+	if (mpic_is_ipi_available(mpic))
+		mpic_ipi_resume(mpic);
 }
 
 static struct syscore_ops mpic_syscore_ops = {
@@ -801,6 +824,7 @@ static int __init mpic_map_region(struct device_node *np, int index,
 
 static int __init mpic_of_init(struct device_node *node, struct device_node *parent)
 {
+	struct mpic *mpic = &mpic_data;
 	phys_addr_t phys_base;
 	unsigned int nr_irqs;
 	int err;
@@ -818,7 +842,7 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 	for (irq_hw_number_t i = 0; i < nr_irqs; i++)
 		writel(i, mpic->base + MPIC_INT_CLEAR_ENABLE);
 
-	mpic->domain = irq_domain_add_linear(node, nr_irqs, &mpic_irq_ops, NULL);
+	mpic->domain = irq_domain_add_linear(node, nr_irqs, &mpic_irq_ops, mpic);
 	if (!mpic->domain) {
 		pr_err("%pOF: Unable to add IRQ domain\n", node);
 		return -ENOMEM;
@@ -833,10 +857,10 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 	mpic->parent_irq = irq_of_parse_and_map(node, 0);
 
 	/* Setup for the boot CPU */
-	mpic_perf_init();
-	mpic_smp_cpu_init();
+	mpic_perf_init(mpic);
+	mpic_smp_cpu_init(mpic);
 
-	err = mpic_msi_init(node, phys_base);
+	err = mpic_msi_init(mpic, node, phys_base);
 	if (err) {
 		pr_err("%pOF: Unable to initialize MSI domain\n", node);
 		return err;
@@ -846,7 +870,7 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 		irq_set_default_host(mpic->domain);
 		set_handle_irq(mpic_handle_irq);
 #ifdef CONFIG_SMP
-		err = mpic_ipi_init(node);
+		err = mpic_ipi_init(mpic, node);
 		if (err) {
 			pr_err("%pOF: Unable to initialize IPI domain\n", node);
 			return err;
@@ -862,7 +886,8 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 					  "irqchip/armada/cascade:starting",
 					  mpic_cascaded_starting_cpu, NULL);
 #endif
-		irq_set_chained_handler(mpic->parent_irq, mpic_handle_cascade_irq);
+		irq_set_chained_handler_and_data(mpic->parent_irq,
+						 mpic_handle_cascade_irq, mpic);
 	}
 
 	register_syscore_ops(&mpic_syscore_ops);
Signature · 1 line
2.44.2
#8 lore raw

PATCH v2 8/12 irqchip/armada-370-xp: Dynamically allocate the driver private structure

In reply to Marek Behún

Dynamically allocate the driver private structure. This concludes the conversion of this driver to modern style.

---
 drivers/irqchip/irq-armada-370-xp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +11 -5
index 5710ce206cca..f8658a232f21 100644
@@ -187,7 +187,7 @@ struct mpic {
 	u32 doorbell_mask;
 };
 
-static struct mpic mpic_data;
+static struct mpic *mpic_data __ro_after_init;
 
 static inline bool mpic_is_ipi_available(struct mpic *mpic)
 {
@@ -575,7 +575,7 @@ static int mpic_starting_cpu(unsigned int cpu)
 
 static int mpic_cascaded_starting_cpu(unsigned int cpu)
 {
-	struct mpic *mpic = &mpic_data;
+	struct mpic *mpic = mpic_data;
 
 	mpic_perf_init(mpic);
 	mpic_reenable_percpu(mpic);
@@ -726,7 +726,7 @@ static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs)
 
 static int mpic_suspend(void)
 {
-	struct mpic *mpic = &mpic_data;
+	struct mpic *mpic = mpic_data;
 
 	mpic->doorbell_mask = readl(mpic->per_cpu + MPIC_IN_DRBEL_MASK);
 
@@ -735,7 +735,7 @@ static int mpic_suspend(void)
 
 static void mpic_resume(void)
 {
-	struct mpic *mpic = &mpic_data;
+	struct mpic *mpic = mpic_data;
 	bool src0, src1;
 
 	/* Re-enable interrupts */
@@ -824,11 +824,17 @@ static int __init mpic_map_region(struct device_node *np, int index,
 
 static int __init mpic_of_init(struct device_node *node, struct device_node *parent)
 {
-	struct mpic *mpic = &mpic_data;
 	phys_addr_t phys_base;
 	unsigned int nr_irqs;
+	struct mpic *mpic;
 	int err;
 
+	mpic = kzalloc(sizeof(*mpic), GFP_KERNEL);
+	if (WARN_ON(!mpic))
+		return -ENOMEM;
+
+	mpic_data = mpic;
+
 	err = mpic_map_region(node, 0, &mpic->base, &phys_base);
 	if (err)
 		return err;
Signature · 1 line
2.44.2
#9 lore raw

PATCH v2 9/12 irqchip/armada-370-xp: Fix reenabling last per-CPU interrupt

In reply to Marek Behún

The number of per-CPU interrupts is 29 (0 to 28). This is described by the constant MPIC_MAX_PER_CPU_IRQS, set to 28 (the maximum per-CPU interrupt).

Commit 0fa4ce746d1d ("irqchip/armada-370-xp: Re-enable per-CPU interrupts at resume time") used the constant incorrectly in the for-loop, it used the operator < instead of <=, causing it to iterate only the first 28 interrupts (0 to 27), ignoring the last, 28th, per-CPU interrupt.

To avoid this kind of confusions, fix this issue by renaming the constant to MPIC_PER_CPU_IRQS_NR and set it to 29, the number of per-CPU IRQs. Update its use in mpic_is_percpu_irq() accordingly.

Cc <[email protected]> # The 29th interrupt is not used in any device-tree
Fixes 0fa4ce746d1d ("irqchip/armada-370-xp: Re-enable per-CPU interrupts at resume time")

---
Thomas, I have added the stable+noautosel Cc so that this patch won't be autoselected for stable releases, as described in Documentation/process/stable-kernel-rules.rst. This way I can keep the Fixes tag.

---
 drivers/irqchip/irq-armada-370-xp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +3 -3
index f8658a232f21..83afc3a27812 100644
@@ -133,7 +133,7 @@
 #define MPIC_INT_FABRIC_MASK			0x54
 #define MPIC_INT_CAUSE_PERF(cpu)		BIT(cpu)
 
-#define MPIC_MAX_PER_CPU_IRQS			28
+#define MPIC_PER_CPU_IRQS_NR			29
 
 /* IPI and MSI interrupt definitions for IPI platforms */
 #define IPI_DOORBELL_NR				8
@@ -202,7 +202,7 @@ static inline bool mpic_is_ipi_available(struct mpic *mpic)
 
 static inline bool mpic_is_percpu_irq(irq_hw_number_t hwirq)
 {
-	return hwirq <= MPIC_MAX_PER_CPU_IRQS;
+	return hwirq < MPIC_PER_CPU_IRQS_NR;
 }
 
 /*
@@ -545,7 +545,7 @@ static void mpic_smp_cpu_init(struct mpic *mpic)
 static void mpic_reenable_percpu(struct mpic *mpic)
 {
 	/* Re-enable per-CPU interrupts that were enabled before suspend */
-	for (irq_hw_number_t i = 0; i < MPIC_MAX_PER_CPU_IRQS; i++) {
+	for (irq_hw_number_t i = 0; i < MPIC_PER_CPU_IRQS_NR; i++) {
 		unsigned int virq = irq_linear_revmap(mpic->domain, i);
 		struct irq_data *d;
 
Signature · 1 line
2.44.2
#10 lore raw

PATCH v2 10/12 irqchip/armada-370-xp: Iterate only valid bits of the per-CPU interrupt cause register

In reply to Marek Behún

Use MPIC_PER_CPU_IRQS_NR (29) bound instead of BITS_PER_LONG (32) when iterating the bits of the per-CPU interrupt cause register, since there are only 29 per-CPU interrupts. The top 3 bits are always zero anyway.

---
 drivers/irqchip/irq-armada-370-xp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +1 -1
index 83afc3a27812..36d1bac8a99f 100644
@@ -678,7 +678,7 @@ static void mpic_handle_cascade_irq(struct irq_desc *desc)
 	cause = readl_relaxed(mpic->per_cpu + MPIC_PPI_CAUSE);
 	cpuid = cpu_logical_map(smp_processor_id());
 
-	for_each_set_bit(i, &cause, BITS_PER_LONG) {
+	for_each_set_bit(i, &cause, MPIC_PER_CPU_IRQS_NR) {
 		irqsrc = readl_relaxed(mpic->base + MPIC_INT_SOURCE_CTL(i));
 
 		/* Check if the interrupt is not masked on current CPU.
Signature · 1 line
2.44.2
#11 lore raw

PATCH v2 11/12 irqchip/armada-370-xp: Allow mapping only per-CPU interrupts

In reply to Marek Behún

On platforms where MPIC is not the top-level interrupt controller the driver currently only supports handling of the per-CPU interrupts (the first 29 interrupts). This is obvious from the code of mpic_handle_cascade_irq(), which reads only one cause register.

Bound the number of available interrupts in the IRQ domain to 29 for these platforms.

The corresponding device-trees refer only to per-CPU interrupts via MPIC, the other interrupts are referred to via GIC.

---
 drivers/irqchip/irq-armada-370-xp.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/irqchip/irq-armada-370-xp.c +13 -6
index 36d1bac8a99f..4f3f99af12b2 100644
@@ -848,6 +848,19 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 	for (irq_hw_number_t i = 0; i < nr_irqs; i++)
 		writel(i, mpic->base + MPIC_INT_CLEAR_ENABLE);
 
+	/*
+	 * Initialize mpic->parent_irq before calling any other functions, since
+	 * it is used to distinguish between IPI and non-IPI platforms.
+	 */
+	mpic->parent_irq = irq_of_parse_and_map(node, 0);
+
+	/*
+	 * On non-IPI platforms the driver currently supports only the per-CPU
+	 * interrupts (the first 29 interrupts). See mpic_handle_cascade_irq().
+	 */
+	if (!mpic_is_ipi_available(mpic))
+		nr_irqs = MPIC_PER_CPU_IRQS_NR;
+
 	mpic->domain = irq_domain_add_linear(node, nr_irqs, &mpic_irq_ops, mpic);
 	if (!mpic->domain) {
 		pr_err("%pOF: Unable to add IRQ domain\n", node);
@@ -856,12 +869,6 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 
 	irq_domain_update_bus_token(mpic->domain, DOMAIN_BUS_WIRED);
 
-	/*
-	 * Initialize mpic->parent_irq before calling any other functions, since
-	 * it is used to distinguish between IPI and non-IPI platforms.
-	 */
-	mpic->parent_irq = irq_of_parse_and_map(node, 0);
-
 	/* Setup for the boot CPU */
 	mpic_perf_init(mpic);
 	mpic_smp_cpu_init(mpic);
Signature · 1 line
2.44.2
#12 lore raw

PATCH v2 12/12 irqchip/armada-370-xp: Use the mpic_is_ipi_available() helper in one more case

In reply to Marek Behún

There is one last case where we can use the helper function mpic_is_ipi_available() instead of hardcoding the condition.

---
 drivers/irqchip/irq-armada-370-xp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +1 -1
index 4f3f99af12b2..d7c5ef248474 100644
@@ -879,7 +879,7 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
 		return err;
 	}
 
-	if (mpic->parent_irq <= 0) {
+	if (mpic_is_ipi_available(mpic)) {
 		irq_set_default_host(mpic->domain);
 		set_handle_irq(mpic_handle_irq);
 #ifdef CONFIG_SMP
Signature · 1 line
2.44.2