From adf4ef16f1869c4f8a35bfb95ce95e0d418f72b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 11 Aug 2022 13:16:26 +0200 Subject: [PATCH 66/90] irqchip/armada-370-xp: Add support for 32 MSI interrupts on non-IPI platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently only upper 16 MSI interrupts on non-IPI platforms are used. Low 16 MSI interrupts on non-IPI platforms are mapped into IPI registers. Implement support also for low 16 MSI interrupts which allow increase number of MSI interrupts on non-IPI platforms from 16 to 32. Signed-off-by: Pali Rohár --- drivers/irqchip/irq-armada-370-xp.c | 54 +++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 397bacf638a2..8abc70ed30c1 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -135,6 +135,7 @@ #define ARMADA_370_XP_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_MASK 0xFF @@ -143,6 +144,12 @@ #define PCI_MSI_DOORBELL_END (32) #define PCI_MSI_DOORBELL_MASK 0xFFFF0000 +/* 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 (0xFFFFFFFF) + static void __iomem *per_cpu_int_base; static void __iomem *main_int_base; static struct irq_domain *armada_370_xp_mpic_domain; @@ -151,7 +158,7 @@ static int parent_irq; #ifdef CONFIG_PCI_MSI static struct irq_domain *armada_370_xp_msi_domain; static struct irq_domain *armada_370_xp_msi_inner_domain; -static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); +static DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR); static DEFINE_MUTEX(msi_used_lock); static phys_addr_t msi_doorbell_addr; #endif @@ -209,9 +216,10 @@ static struct msi_domain_info armada_370_xp_msi_domain_info = { static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { + u32 msi_start = (parent_irq <= 0) ? PCI_MSI_DOORBELL_START : PCI_MSI_FULL_DOORBELL_START; msg->address_lo = lower_32_bits(msi_doorbell_addr); msg->address_hi = upper_32_bits(msi_doorbell_addr); - msg->data = 0xf00 | (data->hwirq + PCI_MSI_DOORBELL_START); + msg->data = 0xf00 | (data->hwirq + msi_start); } static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data, @@ -229,10 +237,11 @@ static struct irq_chip armada_370_xp_msi_bottom_irq_chip = { static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { + unsigned int msi_nr = (parent_irq <= 0) ? PCI_MSI_DOORBELL_NR : PCI_MSI_FULL_DOORBELL_NR; int hwirq, i; mutex_lock(&msi_used_lock); - hwirq = bitmap_find_free_region(msi_used, PCI_MSI_DOORBELL_NR, + hwirq = bitmap_find_free_region(msi_used, msi_nr, order_base_2(nr_irqs)); mutex_unlock(&msi_used_lock); @@ -267,13 +276,15 @@ static const struct irq_domain_ops armada_370_xp_msi_domain_ops = { static int armada_370_xp_msi_init(struct device_node *node, phys_addr_t main_int_phys_base) { + unsigned int msi_nr = (parent_irq <= 0) ? PCI_MSI_DOORBELL_NR : PCI_MSI_FULL_DOORBELL_NR; + u32 msi_mask = (parent_irq <= 0) ? PCI_MSI_DOORBELL_MASK: PCI_MSI_FULL_DOORBELL_MASK; u32 reg; msi_doorbell_addr = main_int_phys_base + ARMADA_370_XP_SW_TRIG_INT_OFFS; armada_370_xp_msi_inner_domain = - irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR, + irq_domain_add_linear(NULL, msi_nr, &armada_370_xp_msi_domain_ops, NULL); if (!armada_370_xp_msi_inner_domain) return -ENOMEM; @@ -288,7 +299,7 @@ static int armada_370_xp_msi_init(struct device_node *node, } reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS) - | PCI_MSI_DOORBELL_MASK; + | msi_mask; writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); @@ -296,6 +307,10 @@ static int armada_370_xp_msi_init(struct device_node *node, /* Unmask MSI interrupt */ writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + /* Unmask low 16 MSI irqs on non-IPI platforms */ + if (parent_irq > 0) + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + return 0; } #else @@ -586,23 +601,25 @@ static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = { #ifdef CONFIG_PCI_MSI static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained) { + u32 msi_start = (parent_irq <= 0) ? PCI_MSI_DOORBELL_START : PCI_MSI_FULL_DOORBELL_START; + u32 msi_end = (parent_irq <= 0) ? PCI_MSI_DOORBELL_END : PCI_MSI_FULL_DOORBELL_END; + u32 msi_mask = (parent_irq <= 0) ? PCI_MSI_DOORBELL_MASK: PCI_MSI_FULL_DOORBELL_MASK; u32 msimask, msinr; msimask = readl_relaxed(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) - & PCI_MSI_DOORBELL_MASK; + & msi_mask; writel(~msimask, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); - for (msinr = PCI_MSI_DOORBELL_START; - msinr < PCI_MSI_DOORBELL_END; msinr++) { + for (msinr = msi_start; msinr < msi_end; msinr++) { unsigned int irq; if (!(msimask & BIT(msinr))) continue; - irq = msinr - PCI_MSI_DOORBELL_START; + irq = msinr - msi_start; if (is_chained) generic_handle_domain_irq(armada_370_xp_msi_inner_domain, @@ -636,7 +653,7 @@ static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc) if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid))) continue; - if (irqn == 1) { + if (irqn == 0 || irqn == 1) { armada_370_xp_handle_msi_irq(NULL, true); continue; } @@ -737,10 +754,19 @@ static void armada_370_xp_mpic_resume(void) writel(doorbell_mask_reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); /* IPI is used only when we do not have parent irq */ - if (parent_irq <= 0 && (doorbell_mask_reg & IPI_DOORBELL_MASK)) - writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); - if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK) - writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + if (parent_irq <= 0) { + /* On IPI platforms is source 0 used for IPI and source 1 for MSI */ + if (doorbell_mask_reg & IPI_DOORBELL_MASK) + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK) + writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + } else { + /* On non-IPI platforms is source 0 used for MSI 0-15 and 1 for MSI 16-31 */ + if (doorbell_mask_reg & GENMASK(15, 0)) + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + if (doorbell_mask_reg & GENMASK(31, 16)) + writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + } /* IPI is used only when we do not have parent irq */ if (parent_irq <= 0) -- 2.34.1