Skip to content

Commit bc69b8a

Browse files
ezequielgarciaJason Cooper
authored andcommitted
irqchip: armada-370-xp: Setup a chained handler for the MPIC
The new Armada 375 and Armada 38x Marvell SoCs are based on Cortex-A9 CPU cores and use the ARM GIC as their main interrupt controller. However, for various purposes (wake-up from suspend, MSI interrupts), they have kept a separate MPIC interrupt controller, acting as a slave to the GIC. This MPIC was already used as the primary controller on previous Marvell SoCs, so this commit extends the existing driver to allow the MPIC to be used as a GIC slave. Reviewed-by: Gregory CLEMENT <[email protected]> Signed-off-by: Ezequiel Garcia <[email protected]> Signed-off-by: Jason Cooper <[email protected]>
1 parent 9b8cf77 commit bc69b8a

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Marvell Armada 370 and Armada XP Interrupt Controller
1+
Marvell Armada 370, 375, 38x, XP Interrupt Controller
22
-----------------------------------------------------
33

44
Required properties:
@@ -16,7 +16,13 @@ Required properties:
1616
automatically map to the interrupt controller registers of the
1717
current CPU)
1818

19+
Optional properties:
1920

21+
- interrupts: If defined, then it indicates that this MPIC is
22+
connected as a slave to another interrupt controller. This is
23+
typically the case on Armada 375 and Armada 38x, where the MPIC is
24+
connected as a slave to the Cortex-A9 GIC. The provided interrupt
25+
indicate to which GIC interrupt the MPIC output is connected.
2026

2127
Example:
2228

drivers/irqchip/irq-armada-370-xp.c

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/init.h>
1919
#include <linux/irq.h>
2020
#include <linux/interrupt.h>
21+
#include <linux/irqchip/chained_irq.h>
2122
#include <linux/io.h>
2223
#include <linux/of_address.h>
2324
#include <linux/of_irq.h>
@@ -42,6 +43,7 @@
4243
#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
4344

4445
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
46+
#define ARMADA_375_PPI_CAUSE (0x10)
4547

4648
#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
4749
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
@@ -353,7 +355,7 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
353355
};
354356

355357
#ifdef CONFIG_PCI_MSI
356-
static void armada_370_xp_handle_msi_irq(struct pt_regs *regs)
358+
static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
357359
{
358360
u32 msimask, msinr;
359361

@@ -373,13 +375,41 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs)
373375

374376
irq = irq_find_mapping(armada_370_xp_msi_domain,
375377
msinr - 16);
376-
handle_IRQ(irq, regs);
378+
379+
if (is_chained)
380+
generic_handle_irq(irq);
381+
else
382+
handle_IRQ(irq, regs);
377383
}
378384
}
379385
#else
380-
static void armada_370_xp_handle_msi_irq(struct pt_regs *r) {}
386+
static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
381387
#endif
382388

389+
static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
390+
struct irq_desc *desc)
391+
{
392+
struct irq_chip *chip = irq_get_chip(irq);
393+
unsigned long irqmap, irqn;
394+
unsigned int cascade_irq;
395+
396+
chained_irq_enter(chip, desc);
397+
398+
irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
399+
400+
if (irqmap & BIT(0)) {
401+
armada_370_xp_handle_msi_irq(NULL, true);
402+
irqmap &= ~BIT(0);
403+
}
404+
405+
for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
406+
cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
407+
generic_handle_irq(cascade_irq);
408+
}
409+
410+
chained_irq_exit(chip, desc);
411+
}
412+
383413
static asmlinkage void __exception_irq_entry
384414
armada_370_xp_handle_irq(struct pt_regs *regs)
385415
{
@@ -402,7 +432,7 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
402432

403433
/* MSI handling */
404434
if (irqnr == 1)
405-
armada_370_xp_handle_msi_irq(regs);
435+
armada_370_xp_handle_msi_irq(regs, false);
406436

407437
#ifdef CONFIG_SMP
408438
/* IPI Handling */
@@ -433,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
433463
struct device_node *parent)
434464
{
435465
struct resource main_int_res, per_cpu_int_res;
466+
int parent_irq;
436467
u32 control;
437468

438469
BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -461,8 +492,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
461492

462493
BUG_ON(!armada_370_xp_mpic_domain);
463494

464-
irq_set_default_host(armada_370_xp_mpic_domain);
465-
466495
#ifdef CONFIG_SMP
467496
armada_xp_mpic_smp_cpu_init();
468497

@@ -478,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
478507

479508
armada_370_xp_msi_init(node, main_int_res.start);
480509

481-
set_handle_irq(armada_370_xp_handle_irq);
510+
parent_irq = irq_of_parse_and_map(node, 0);
511+
if (parent_irq <= 0) {
512+
irq_set_default_host(armada_370_xp_mpic_domain);
513+
set_handle_irq(armada_370_xp_handle_irq);
514+
} else {
515+
irq_set_chained_handler(parent_irq,
516+
armada_370_xp_mpic_handle_cascade_irq);
517+
}
482518

483519
return 0;
484520
}

0 commit comments

Comments
 (0)