diff options
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-armada-370-xp.c | 96 |
1 files changed, 69 insertions, 27 deletions
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 540956465ed2..cd79503abea9 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,6 +354,62 @@ 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 | ||
357 | #ifdef CONFIG_PCI_MSI | ||
358 | static 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 | ||
386 | static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} | ||
387 | #endif | ||
388 | |||
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 | |||
355 | static asmlinkage void __exception_irq_entry | 413 | static asmlinkage void __exception_irq_entry |
356 | armada_370_xp_handle_irq(struct pt_regs *regs) | 414 | armada_370_xp_handle_irq(struct pt_regs *regs) |
357 | { | 415 | { |
@@ -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 | } |