diff options
author | Jason Cooper <jason@lakedaemon.net> | 2015-03-14 21:46:04 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2015-03-14 21:46:04 -0400 |
commit | 9df5126b69294788f5ca3dc7aeafc80a42c6d4a7 (patch) | |
tree | f577adbc91229110f692732a6ea2ece28128a003 /drivers/irqchip | |
parent | 6e3aca4419e1363ff9abb3e1710c52858fc45b66 (diff) | |
parent | 28da06dfd9e4b04577c517f9c4b52aaa73e3d1c7 (diff) |
Merge branch 'irqchip/mvebu' into irqchip/core
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-armada-370-xp.c | 105 |
1 files changed, 75 insertions, 30 deletions
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 463c235acbdc..b36373c019ba 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c | |||
@@ -38,6 +38,8 @@ | |||
38 | /* Interrupt Controller Registers Map */ | 38 | /* Interrupt Controller Registers Map */ |
39 | #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) | 39 | #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) |
40 | #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) | 40 | #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) |
41 | #define ARMADA_370_XP_INT_FABRIC_MASK_OFFS (0x54) | ||
42 | #define ARMADA_370_XP_INT_CAUSE_PERF(cpu) (1 << cpu) | ||
41 | 43 | ||
42 | #define ARMADA_370_XP_INT_CONTROL (0x00) | 44 | #define ARMADA_370_XP_INT_CONTROL (0x00) |
43 | #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) | 45 | #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) |
@@ -56,6 +58,7 @@ | |||
56 | #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) | 58 | #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) |
57 | 59 | ||
58 | #define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) | 60 | #define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) |
61 | #define ARMADA_370_XP_FABRIC_IRQ (3) | ||
59 | 62 | ||
60 | #define IPI_DOORBELL_START (0) | 63 | #define IPI_DOORBELL_START (0) |
61 | #define IPI_DOORBELL_END (8) | 64 | #define IPI_DOORBELL_END (8) |
@@ -69,6 +72,7 @@ static void __iomem *per_cpu_int_base; | |||
69 | static void __iomem *main_int_base; | 72 | static void __iomem *main_int_base; |
70 | static struct irq_domain *armada_370_xp_mpic_domain; | 73 | static struct irq_domain *armada_370_xp_mpic_domain; |
71 | static u32 doorbell_mask_reg; | 74 | static u32 doorbell_mask_reg; |
75 | static int parent_irq; | ||
72 | #ifdef CONFIG_PCI_MSI | 76 | #ifdef CONFIG_PCI_MSI |
73 | static struct irq_domain *armada_370_xp_msi_domain; | 77 | static struct irq_domain *armada_370_xp_msi_domain; |
74 | static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); | 78 | static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); |
@@ -76,6 +80,17 @@ static DEFINE_MUTEX(msi_used_lock); | |||
76 | static phys_addr_t msi_doorbell_addr; | 80 | static phys_addr_t msi_doorbell_addr; |
77 | #endif | 81 | #endif |
78 | 82 | ||
83 | static inline bool is_percpu_irq(irq_hw_number_t irq) | ||
84 | { | ||
85 | switch (irq) { | ||
86 | case ARMADA_370_XP_TIMER0_PER_CPU_IRQ: | ||
87 | case ARMADA_370_XP_FABRIC_IRQ: | ||
88 | return true; | ||
89 | default: | ||
90 | return false; | ||
91 | } | ||
92 | } | ||
93 | |||
79 | /* | 94 | /* |
80 | * In SMP mode: | 95 | * In SMP mode: |
81 | * For shared global interrupts, mask/unmask global enable bit | 96 | * For shared global interrupts, mask/unmask global enable bit |
@@ -85,7 +100,7 @@ static void armada_370_xp_irq_mask(struct irq_data *d) | |||
85 | { | 100 | { |
86 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | 101 | irq_hw_number_t hwirq = irqd_to_hwirq(d); |
87 | 102 | ||
88 | if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) | 103 | if (!is_percpu_irq(hwirq)) |
89 | writel(hwirq, main_int_base + | 104 | writel(hwirq, main_int_base + |
90 | ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); | 105 | ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); |
91 | else | 106 | else |
@@ -97,7 +112,7 @@ static void armada_370_xp_irq_unmask(struct irq_data *d) | |||
97 | { | 112 | { |
98 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | 113 | irq_hw_number_t hwirq = irqd_to_hwirq(d); |
99 | 114 | ||
100 | if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) | 115 | if (!is_percpu_irq(hwirq)) |
101 | writel(hwirq, main_int_base + | 116 | writel(hwirq, main_int_base + |
102 | ARMADA_370_XP_INT_SET_ENABLE_OFFS); | 117 | ARMADA_370_XP_INT_SET_ENABLE_OFFS); |
103 | else | 118 | else |
@@ -286,14 +301,14 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, | |||
286 | unsigned int virq, irq_hw_number_t hw) | 301 | unsigned int virq, irq_hw_number_t hw) |
287 | { | 302 | { |
288 | armada_370_xp_irq_mask(irq_get_irq_data(virq)); | 303 | armada_370_xp_irq_mask(irq_get_irq_data(virq)); |
289 | if (hw != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) | 304 | if (!is_percpu_irq(hw)) |
290 | writel(hw, per_cpu_int_base + | 305 | writel(hw, per_cpu_int_base + |
291 | ARMADA_370_XP_INT_CLEAR_MASK_OFFS); | 306 | ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
292 | else | 307 | else |
293 | writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); | 308 | writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); |
294 | irq_set_status_flags(virq, IRQ_LEVEL); | 309 | irq_set_status_flags(virq, IRQ_LEVEL); |
295 | 310 | ||
296 | if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) { | 311 | if (is_percpu_irq(hw)) { |
297 | irq_set_percpu_devid(virq); | 312 | irq_set_percpu_devid(virq); |
298 | irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, | 313 | irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, |
299 | handle_percpu_devid_irq); | 314 | handle_percpu_devid_irq); |
@@ -307,28 +322,6 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, | |||
307 | return 0; | 322 | return 0; |
308 | } | 323 | } |
309 | 324 | ||
310 | #ifdef CONFIG_SMP | ||
311 | static void armada_mpic_send_doorbell(const struct cpumask *mask, | ||
312 | unsigned int irq) | ||
313 | { | ||
314 | int cpu; | ||
315 | unsigned long map = 0; | ||
316 | |||
317 | /* Convert our logical CPU mask into a physical one. */ | ||
318 | for_each_cpu(cpu, mask) | ||
319 | map |= 1 << cpu_logical_map(cpu); | ||
320 | |||
321 | /* | ||
322 | * Ensure that stores to Normal memory are visible to the | ||
323 | * other CPUs before issuing the IPI. | ||
324 | */ | ||
325 | dsb(); | ||
326 | |||
327 | /* submit softirq */ | ||
328 | writel((map << 8) | irq, main_int_base + | ||
329 | ARMADA_370_XP_SW_TRIG_INT_OFFS); | ||
330 | } | ||
331 | |||
332 | static void armada_xp_mpic_smp_cpu_init(void) | 325 | static void armada_xp_mpic_smp_cpu_init(void) |
333 | { | 326 | { |
334 | u32 control; | 327 | u32 control; |
@@ -351,11 +344,45 @@ static void armada_xp_mpic_smp_cpu_init(void) | |||
351 | writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); | 344 | writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
352 | } | 345 | } |
353 | 346 | ||
347 | static void armada_xp_mpic_perf_init(void) | ||
348 | { | ||
349 | unsigned long cpuid = cpu_logical_map(smp_processor_id()); | ||
350 | |||
351 | /* Enable Performance Counter Overflow interrupts */ | ||
352 | writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), | ||
353 | per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); | ||
354 | } | ||
355 | |||
356 | #ifdef CONFIG_SMP | ||
357 | static void armada_mpic_send_doorbell(const struct cpumask *mask, | ||
358 | unsigned int irq) | ||
359 | { | ||
360 | int cpu; | ||
361 | unsigned long map = 0; | ||
362 | |||
363 | /* Convert our logical CPU mask into a physical one. */ | ||
364 | for_each_cpu(cpu, mask) | ||
365 | map |= 1 << cpu_logical_map(cpu); | ||
366 | |||
367 | /* | ||
368 | * Ensure that stores to Normal memory are visible to the | ||
369 | * other CPUs before issuing the IPI. | ||
370 | */ | ||
371 | dsb(); | ||
372 | |||
373 | /* submit softirq */ | ||
374 | writel((map << 8) | irq, main_int_base + | ||
375 | ARMADA_370_XP_SW_TRIG_INT_OFFS); | ||
376 | } | ||
377 | |||
354 | static int armada_xp_mpic_secondary_init(struct notifier_block *nfb, | 378 | static int armada_xp_mpic_secondary_init(struct notifier_block *nfb, |
355 | unsigned long action, void *hcpu) | 379 | unsigned long action, void *hcpu) |
356 | { | 380 | { |
357 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) | 381 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) { |
382 | armada_xp_mpic_perf_init(); | ||
358 | armada_xp_mpic_smp_cpu_init(); | 383 | armada_xp_mpic_smp_cpu_init(); |
384 | } | ||
385 | |||
359 | return NOTIFY_OK; | 386 | return NOTIFY_OK; |
360 | } | 387 | } |
361 | 388 | ||
@@ -364,6 +391,21 @@ static struct notifier_block armada_370_xp_mpic_cpu_notifier = { | |||
364 | .priority = 100, | 391 | .priority = 100, |
365 | }; | 392 | }; |
366 | 393 | ||
394 | static int mpic_cascaded_secondary_init(struct notifier_block *nfb, | ||
395 | unsigned long action, void *hcpu) | ||
396 | { | ||
397 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) { | ||
398 | armada_xp_mpic_perf_init(); | ||
399 | enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); | ||
400 | } | ||
401 | |||
402 | return NOTIFY_OK; | ||
403 | } | ||
404 | |||
405 | static struct notifier_block mpic_cascaded_cpu_notifier = { | ||
406 | .notifier_call = mpic_cascaded_secondary_init, | ||
407 | .priority = 100, | ||
408 | }; | ||
367 | #endif /* CONFIG_SMP */ | 409 | #endif /* CONFIG_SMP */ |
368 | 410 | ||
369 | static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { | 411 | static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { |
@@ -539,7 +581,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, | |||
539 | struct device_node *parent) | 581 | struct device_node *parent) |
540 | { | 582 | { |
541 | struct resource main_int_res, per_cpu_int_res; | 583 | struct resource main_int_res, per_cpu_int_res; |
542 | int parent_irq, nr_irqs, i; | 584 | int nr_irqs, i; |
543 | u32 control; | 585 | u32 control; |
544 | 586 | ||
545 | BUG_ON(of_address_to_resource(node, 0, &main_int_res)); | 587 | BUG_ON(of_address_to_resource(node, 0, &main_int_res)); |
@@ -572,9 +614,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, | |||
572 | 614 | ||
573 | BUG_ON(!armada_370_xp_mpic_domain); | 615 | BUG_ON(!armada_370_xp_mpic_domain); |
574 | 616 | ||
575 | #ifdef CONFIG_SMP | 617 | /* Setup for the boot CPU */ |
618 | armada_xp_mpic_perf_init(); | ||
576 | armada_xp_mpic_smp_cpu_init(); | 619 | armada_xp_mpic_smp_cpu_init(); |
577 | #endif | ||
578 | 620 | ||
579 | armada_370_xp_msi_init(node, main_int_res.start); | 621 | armada_370_xp_msi_init(node, main_int_res.start); |
580 | 622 | ||
@@ -587,6 +629,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, | |||
587 | register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier); | 629 | register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier); |
588 | #endif | 630 | #endif |
589 | } else { | 631 | } else { |
632 | #ifdef CONFIG_SMP | ||
633 | register_cpu_notifier(&mpic_cascaded_cpu_notifier); | ||
634 | #endif | ||
590 | irq_set_chained_handler(parent_irq, | 635 | irq_set_chained_handler(parent_irq, |
591 | armada_370_xp_mpic_handle_cascade_irq); | 636 | armada_370_xp_mpic_handle_cascade_irq); |
592 | } | 637 | } |