Commit d0e3a971 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-mvebu-3.15' of git://git.infradead.org/linux-mvebu into irq/core

irqchip mvebu changes for v3.15

 - armada-370-xp
    - add MSI helper
    - MPIC chained handler
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parents b04c644e bc69b8ad
Marvell Armada 370 and Armada XP Interrupt Controller
Marvell Armada 370, 375, 38x, XP Interrupt Controller
-----------------------------------------------------
Required properties:
......@@ -16,7 +16,13 @@ Required properties:
automatically map to the interrupt controller registers of the
current CPU)
Optional properties:
- interrupts: If defined, then it indicates that this MPIC is
connected as a slave to another interrupt controller. This is
typically the case on Armada 375 and Armada 38x, where the MPIC is
connected as a slave to the Cortex-A9 GIC. The provided interrupt
indicate to which GIC interrupt the MPIC output is connected.
Example:
......
......@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
......@@ -42,6 +43,7 @@
#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
#define ARMADA_375_PPI_CAUSE (0x10)
#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
......@@ -352,6 +354,62 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
.xlate = irq_domain_xlate_onecell,
};
#ifdef CONFIG_PCI_MSI
static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
{
u32 msimask, msinr;
msimask = readl_relaxed(per_cpu_int_base +
ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
& PCI_MSI_DOORBELL_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++) {
int irq;
if (!(msimask & BIT(msinr)))
continue;
irq = irq_find_mapping(armada_370_xp_msi_domain,
msinr - 16);
if (is_chained)
generic_handle_irq(irq);
else
handle_IRQ(irq, regs);
}
}
#else
static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
#endif
static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
struct irq_desc *desc)
{
struct irq_chip *chip = irq_get_chip(irq);
unsigned long irqmap, irqn;
unsigned int cascade_irq;
chained_irq_enter(chip, desc);
irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
if (irqmap & BIT(0)) {
armada_370_xp_handle_msi_irq(NULL, true);
irqmap &= ~BIT(0);
}
for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
generic_handle_irq(cascade_irq);
}
chained_irq_exit(chip, desc);
}
static asmlinkage void __exception_irq_entry
armada_370_xp_handle_irq(struct pt_regs *regs)
{
......@@ -372,31 +430,9 @@ armada_370_xp_handle_irq(struct pt_regs *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(~msimask, 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
if (irqnr == 1)
armada_370_xp_handle_msi_irq(regs, false);
#ifdef CONFIG_SMP
/* IPI Handling */
......@@ -427,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
struct device_node *parent)
{
struct resource main_int_res, per_cpu_int_res;
int parent_irq;
u32 control;
BUG_ON(of_address_to_resource(node, 0, &main_int_res));
......@@ -455,8 +492,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
BUG_ON(!armada_370_xp_mpic_domain);
irq_set_default_host(armada_370_xp_mpic_domain);
#ifdef CONFIG_SMP
armada_xp_mpic_smp_cpu_init();
......@@ -472,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_msi_init(node, main_int_res.start);
set_handle_irq(armada_370_xp_handle_irq);
parent_irq = irq_of_parse_and_map(node, 0);
if (parent_irq <= 0) {
irq_set_default_host(armada_370_xp_mpic_domain);
set_handle_irq(armada_370_xp_handle_irq);
} else {
irq_set_chained_handler(parent_irq,
armada_370_xp_mpic_handle_cascade_irq);
}
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment