This commit introduces the support for the MSI interrupts in the armada-370-xp interrupt controller driver. It registers an IRQ domain associated with the 'msi' node in the Device Tree, which the PCI controller will refer to in a followup commit. The MSI interrupts use the 16 high doorbells, and are therefore notified using IRQ1 of the main interrupt controller. The Device Tree binding documentation for the armada-370-xp driver is also updated in the process. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxxxxxxxxx> --- .../devicetree/bindings/arm/armada-370-xp-mpic.txt | 39 +++++++-- arch/arm/boot/dts/armada-370-xp.dtsi | 6 ++ arch/arm/mach-mvebu/Kconfig | 1 + drivers/irqchip/irq-armada-370-xp.c | 91 +++++++++++++++++++- 4 files changed, 130 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt index 61df564..2233d20 100644 --- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt +++ b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt @@ -4,8 +4,6 @@ Marvell Armada 370 and Armada XP Interrupt Controller Required properties: - compatible: Should be "marvell,mpic" - interrupt-controller: Identifies the node as an interrupt controller. -- #interrupt-cells: The number of cells to define the interrupts. Should be 1. - The cell is the IRQ number - reg: Should contain PMIC registers location and length. First pair for the main interrupt registers, second pair for the per-CPU @@ -14,16 +12,45 @@ Required properties: automatically map to the interrupt controller registers of the current CPU) +The node should have two sub-nodes, each describing one aspect of the +interrupt controller: + * A first node named main-intc that describes the main interrupt + controller itself, receiving interrupts from all devices. + + This sub-node should have the following properties: + - interrupt-controller: identifies the code as an interrupt + controller. + - #interrupt-cells: The number of cells to define the + interrupts. Should be 1. The cell is the IRQ number + + * A second node named msi-intc that is used for Message Signaled + Interrupts of the PCIe bus. + + This sub-node should have the following properties: + - interrupt-controller: identifies the code as an interrupt + controller. + - #interrupt-cells: The number of cells to define the + interrupts. Should be 1. The cell is the IRQ number + - marvell,doorbell: Gives the physical address at which PCIe + devices should write to signal an MSI interrupt. Example: - mpic: interrupt-controller@d0020000 { + interrupt-controller@d0020000 { compatible = "marvell,mpic"; - #interrupt-cells = <1>; - #address-cells = <1>; - #size-cells = <1>; interrupt-controller; reg = <0xd0020a00 0x1d0>, <0xd0021070 0x58>; + + mpic: main-intc@d0020000 { + #interrupt-cells = <1>; + interrupt-controller; + }; + + msi: msi-intc@d0020000 { + #interrupt-cells = <1>; + interrupt-controller; + marvell,doorbell = <0xd0020a04>; + }; }; diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index de054ed..de6569cd 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -36,6 +36,12 @@ #interrupt-cells = <1>; interrupt-controller; }; + + msi: msi-intc@d0020000 { + #interrupt-cells = <1>; + interrupt-controller; + marvell,doorbell = <0xd0020a04>; + }; }; coherency-fabric@d0020200 { diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index d353249..3254b77 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -16,6 +16,7 @@ config ARCH_MVEBU select MVEBU_MBUS select MIGHT_HAVE_PCI select PCI_QUIRKS if PCI + select ARCH_SUPPORTS_MSI if PCI if ARCH_MVEBU diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 4b2a6d7..3180797 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -22,6 +22,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/irqdomain.h> +#include <linux/msi.h> #include <asm/mach/arch.h> #include <asm/exception.h> #include <asm/smp_plat.h> @@ -51,6 +52,10 @@ #define IPI_DOORBELL_START (0) #define IPI_DOORBELL_END (8) #define IPI_DOORBELL_MASK 0xFF +#define PCI_MSI_DOORBELL_START (16) +#define PCI_MSI_DOORBELL_NR (16) +#define PCI_MSI_DOORBELL_END (32) +#define PCI_MSI_DOORBELL_MASK 0xFFFF0000 static DEFINE_RAW_SPINLOCK(irq_controller_lock); @@ -58,6 +63,10 @@ static void __iomem *per_cpu_int_base; static void __iomem *main_int_base; static struct irq_domain *armada_370_xp_mpic_domain; +#ifdef CONFIG_PCI_MSI +static struct irq_domain *armada_370_xp_msi_domain; +#endif + /* * In SMP mode: * For shared global interrupts, mask/unmask global enable bit @@ -167,6 +176,57 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, return 0; } +#ifdef CONFIG_PCI_MSI +static struct irq_chip armada_370_xp_msi_irq_chip = { + .name = "armada_370_xp_msi_irq", + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, +}; + +static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + + return 0; +} + +static const struct irq_domain_ops armada_370_xp_msi_irq_ops = { + .map = armada_370_xp_msi_map, +}; + +void armada_370_xp_msi_init(struct device_node *node) +{ + struct device_node *msi_node; + u32 reg; + + msi_node = of_get_child_by_name(node, "msi-intc"); + if (!msi_node) + return; + + armada_370_xp_msi_domain = + irq_domain_add_linear(msi_node, PCI_MSI_DOORBELL_NR, + &armada_370_xp_msi_irq_ops, NULL); + if (!armada_370_xp_msi_domain) + panic("Unable to add Armada 370/XP MSI irq domain\n"); + + reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS) + | PCI_MSI_DOORBELL_MASK; + + writel(reg, per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); + + /* Unmask IPI interrupt */ + writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); +} +#else +static void armada_370_xp_msi_init(struct device_node *node) { } +#endif /* CONFIG_PCI_MSI */ + #ifdef CONFIG_SMP void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq) { @@ -220,12 +280,39 @@ armada_370_xp_handle_irq(struct pt_regs *regs) if (irqnr > 1022) break; - if (irqnr > 0) { + if (irqnr > 1) { irqnr = irq_find_mapping(armada_370_xp_mpic_domain, irqnr); handle_IRQ(irqnr, regs); continue; } + +#ifdef CONFIG_PCI_MSI + /* MSI handling */ + if (irqnr == 1) { + u32 msimask, msinr; + + msimask = readl_relaxed(per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) + & PCI_MSI_DOORBELL_MASK; + + writel(~PCI_MSI_DOORBELL_MASK, per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); + + for (msinr = PCI_MSI_DOORBELL_START; + msinr < PCI_MSI_DOORBELL_END; msinr++) { + int irq; + + if (!(msimask & BIT(msinr))) + continue; + + irq = irq_find_mapping(armada_370_xp_msi_domain, + msinr - 16); + handle_IRQ(irq, regs); + } + } +#endif + #ifdef CONFIG_SMP /* IPI Handling */ if (irqnr == 0) { @@ -291,6 +378,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, #endif + armada_370_xp_msi_init(node); + set_handle_irq(armada_370_xp_handle_irq); return 0; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html