aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-armada-370-xp.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-01 14:22:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-01 14:22:57 -0400
commit683b6c6f82a60fabf47012581c2cfbf1b037ab95 (patch)
tree6a3fdf26b98aebf4b0b9eca8d242ba89e0565d8b /drivers/irqchip/irq-armada-370-xp.c
parent1ead65812486cda65093683a99b8907a7242fa93 (diff)
parent1b422ecd27866985b9f35d0d2b5ae6e9122dd4c0 (diff)
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq code updates from Thomas Gleixner: "The irq department proudly presents: - Another tree wide sweep of irq infrastructure abuse. Clear winner of the trainwreck engineering contest was: #include "../../../kernel/irq/settings.h" - Tree wide update of irq_set_affinity() callbacks which miss a cpu online check when picking a single cpu out of the affinity mask. - Tree wide consolidation of interrupt statistics. - Updates to the threaded interrupt infrastructure to allow explicit wakeup of the interrupt thread and a variant of synchronize_irq() which synchronizes only the hard interrupt handler. Both are needed to replace the homebrewn thread handling in the mmc/sdhci code. - New irq chip callbacks to allow proper support for GPIO based irqs. The GPIO based interrupts need to request/release GPIO resources from request/free_irq. - A few new ARM interrupt chips. No revolutionary new hardware, just differently wreckaged variations of the scheme. - Small improvments, cleanups and updates all over the place" I was hoping that that trainwreck engineering contest was a April Fools' joke. But no. * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (68 commits) irqchip: sun7i/sun6i: Disable NMI before registering the handler ARM: sun7i/sun6i: dts: Fix IRQ number for sun6i NMI controller ARM: sun7i/sun6i: irqchip: Update the documentation ARM: sun7i/sun6i: dts: Add NMI irqchip support ARM: sun7i/sun6i: irqchip: Add irqchip driver for NMI controller genirq: Export symbol no_action() arm: omap: Fix typo in ams-delta-fiq.c m68k: atari: Fix the last kernel_stat.h fallout irqchip: sun4i: Simplify sun4i_irq_ack irqchip: sun4i: Use handle_fasteoi_irq for all interrupts genirq: procfs: Make smp_affinity values go+r softirq: Add linux/irq.h to make it compile again m68k: amiga: Add linux/irq.h to make it compile again irqchip: sun4i: Don't ack IRQs > 0, fix acking of IRQ 0 irqchip: sun4i: Fix a comment about mask register initialization irqchip: sun4i: Fix irq 0 not working genirq: Add a new IRQCHIP_EOI_THREADED flag genirq: Document IRQCHIP_ONESHOT_SAFE flag ARM: sunxi: dt: Convert to the new irq controller compatibles irqchip: sunxi: Change compatibles ...
Diffstat (limited to 'drivers/irqchip/irq-armada-370-xp.c')
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c98
1 files changed, 70 insertions, 28 deletions
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 540956465ed2..41be897df8d5 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -18,6 +18,7 @@
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/irq.h> 19#include <linux/irq.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irqchip/chained_irq.h>
21#include <linux/io.h> 22#include <linux/io.h>
22#include <linux/of_address.h> 23#include <linux/of_address.h>
23#include <linux/of_irq.h> 24#include <linux/of_irq.h>
@@ -42,6 +43,7 @@
42#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) 43#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
43 44
44#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) 45#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
46#define ARMADA_375_PPI_CAUSE (0x10)
45 47
46#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4) 48#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
47#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc) 49#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
@@ -352,7 +354,63 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
352 .xlate = irq_domain_xlate_onecell, 354 .xlate = irq_domain_xlate_onecell,
353}; 355};
354 356
355static asmlinkage void __exception_irq_entry 357#ifdef CONFIG_PCI_MSI
358static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
359{
360 u32 msimask, msinr;
361
362 msimask = readl_relaxed(per_cpu_int_base +
363 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
364 & PCI_MSI_DOORBELL_MASK;
365
366 writel(~msimask, per_cpu_int_base +
367 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
368
369 for (msinr = PCI_MSI_DOORBELL_START;
370 msinr < PCI_MSI_DOORBELL_END; msinr++) {
371 int irq;
372
373 if (!(msimask & BIT(msinr)))
374 continue;
375
376 irq = irq_find_mapping(armada_370_xp_msi_domain,
377 msinr - 16);
378
379 if (is_chained)
380 generic_handle_irq(irq);
381 else
382 handle_IRQ(irq, regs);
383 }
384}
385#else
386static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
387#endif
388
389static 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
413static void __exception_irq_entry
356armada_370_xp_handle_irq(struct pt_regs *regs) 414armada_370_xp_handle_irq(struct pt_regs *regs)
357{ 415{
358 u32 irqstat, irqnr; 416 u32 irqstat, irqnr;
@@ -372,31 +430,9 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
372 continue; 430 continue;
373 } 431 }
374 432
375#ifdef CONFIG_PCI_MSI
376 /* MSI handling */ 433 /* MSI handling */
377 if (irqnr == 1) { 434 if (irqnr == 1)
378 u32 msimask, msinr; 435 armada_370_xp_handle_msi_irq(regs, false);
379
380 msimask = readl_relaxed(per_cpu_int_base +
381 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
382 & PCI_MSI_DOORBELL_MASK;
383
384 writel(~msimask, per_cpu_int_base +
385 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
386
387 for (msinr = PCI_MSI_DOORBELL_START;
388 msinr < PCI_MSI_DOORBELL_END; msinr++) {
389 int irq;
390
391 if (!(msimask & BIT(msinr)))
392 continue;
393
394 irq = irq_find_mapping(armada_370_xp_msi_domain,
395 msinr - 16);
396 handle_IRQ(irq, regs);
397 }
398 }
399#endif
400 436
401#ifdef CONFIG_SMP 437#ifdef CONFIG_SMP
402 /* IPI Handling */ 438 /* IPI Handling */
@@ -427,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
427 struct device_node *parent) 463 struct device_node *parent)
428{ 464{
429 struct resource main_int_res, per_cpu_int_res; 465 struct resource main_int_res, per_cpu_int_res;
466 int parent_irq;
430 u32 control; 467 u32 control;
431 468
432 BUG_ON(of_address_to_resource(node, 0, &main_int_res)); 469 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,
455 492
456 BUG_ON(!armada_370_xp_mpic_domain); 493 BUG_ON(!armada_370_xp_mpic_domain);
457 494
458 irq_set_default_host(armada_370_xp_mpic_domain);
459
460#ifdef CONFIG_SMP 495#ifdef CONFIG_SMP
461 armada_xp_mpic_smp_cpu_init(); 496 armada_xp_mpic_smp_cpu_init();
462 497
@@ -472,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
472 507
473 armada_370_xp_msi_init(node, main_int_res.start); 508 armada_370_xp_msi_init(node, main_int_res.start);
474 509
475 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 }
476 518
477 return 0; 519 return 0;
478} 520}