Skip to content

Commit

Permalink
Merge tag 'irqchip-mvebu-3.15' of git://git.infradead.org/linux-mvebu…
Browse files Browse the repository at this point in the history
… into irq/core

irqchip mvebu changes for v3.15

 - armada-370-xp
    - add MSI helper
    - MPIC chained handler

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Feb 22, 2014
2 parents b04c644 + bc69b8a commit d0e3a97
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 28 deletions.
8 changes: 7 additions & 1 deletion Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Marvell Armada 370 and Armada XP Interrupt Controller
Marvell Armada 370, 375, 38x, XP Interrupt Controller
-----------------------------------------------------

Required properties:
Expand All @@ -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:

Expand Down
96 changes: 69 additions & 27 deletions drivers/irqchip/irq-armada-370-xp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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 */
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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();

Expand All @@ -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;
}
Expand Down

0 comments on commit d0e3a97

Please sign in to comment.