aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-10 07:44:42 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-10 16:24:20 -0400
commit6e99e4582861578fb00d84d085f8f283569f51dd (patch)
tree8890d540932f02fa47e49248adcc918b42c335b8 /arch/powerpc/sysdev/mpic.c
parent50099328e4fe7c9f8981f408071a1ff82d59ddf8 (diff)
[PATCH] powerpc: fix trigger handling in the new irq code
This patch slightly reworks the new irq code to fix a small design error. I removed the passing of the trigger to the map() calls entirely, it was not a good idea to have one call do two different things. It also fixes a couple of corner cases. Mapping a linux virtual irq to a physical irq now does only that. Setting the trigger is a different action which has a different call. The main changes are: - I no longer call host->ops->map() for an already mapped irq, I just return the virtual number that was already mapped. It was called before to give an opportunity to change the trigger, but that was causing issues as that could happen while the interrupt was in use by a device, and because of the trigger change, map would potentially muck around with things in a racy way. That was causing much burden on a given's controller implementation of map() to get it right. This is much simpler now. map() is only called on the initial mapping of an irq, meaning that you know that this irq is _not_ being used. You can initialize the hardware if you want (though you don't have to). - Controllers that can handle different type of triggers (level/edge/etc...) now implement the standard irq_chip->set_type() call as defined by the generic code. That means that you can use the standard set_irq_type() to configure an irq line manually if you wish or (though I don't like that interface), pass explicit trigger flags to request_irq() as defined by the generic kernel interfaces. Also, using those interfaces guarantees that your controller set_type callback is called with the descriptor lock held, thus providing locking against activity on the same interrupt (including mask/unmask/etc...) automatically. A result is that, for example, MPIC's own map() implementation calls irq_set_type(NONE) to configure the hardware to the default triggers. - To allow the above, the irq_map array entry for the new mapped interrupt is now set before map() callback is called for the controller. - The irq_create_of_mapping() (also used by irq_of_parse_and_map()) function for mapping interrupts from the device-tree now also call the separate set_irq_type(), and only does so if there is a change in the trigger type. - While I was at it, I changed pci_read_irq_line() (which is the helper I would expect most archs to use in their pcibios_fixup() to get the PCI interrupt routing from the device tree) to also handle a fallback when the DT mapping fails consisting of reading the PCI_INTERRUPT_PIN to know wether the device has an interrupt at all, and the the PCI_INTERRUPT_LINE to get an interrupt number from the device. That number is then mapped using the default controller, and the trigger is set to level low. That default behaviour works for several platforms that don't have a proper interrupt tree like Pegasos. If it doesn't work for your platform, then either provide a proper interrupt tree from the firmware so that fallback isn't needed, or don't call pci_read_irq_line() - Add back a bit that got dropped by my main rework patch for properly clearing pending IPIs on pSeries when using a kexec Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c180
1 files changed, 80 insertions, 100 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 9cecebaa0360..c39c4a0b1cda 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -337,6 +337,17 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
337 } 337 }
338} 338}
339 339
340#else /* CONFIG_MPIC_BROKEN_U3 */
341
342static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
343{
344 return 0;
345}
346
347static void __init mpic_scan_ht_pics(struct mpic *mpic)
348{
349}
350
340#endif /* CONFIG_MPIC_BROKEN_U3 */ 351#endif /* CONFIG_MPIC_BROKEN_U3 */
341 352
342 353
@@ -405,11 +416,9 @@ static void mpic_unmask_irq(unsigned int irq)
405 unsigned int loops = 100000; 416 unsigned int loops = 100000;
406 struct mpic *mpic = mpic_from_irq(irq); 417 struct mpic *mpic = mpic_from_irq(irq);
407 unsigned int src = mpic_irq_to_hw(irq); 418 unsigned int src = mpic_irq_to_hw(irq);
408 unsigned long flags;
409 419
410 DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 420 DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
411 421
412 spin_lock_irqsave(&mpic_lock, flags);
413 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 422 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
414 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & 423 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
415 ~MPIC_VECPRI_MASK); 424 ~MPIC_VECPRI_MASK);
@@ -420,7 +429,6 @@ static void mpic_unmask_irq(unsigned int irq)
420 break; 429 break;
421 } 430 }
422 } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); 431 } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
423 spin_unlock_irqrestore(&mpic_lock, flags);
424} 432}
425 433
426static void mpic_mask_irq(unsigned int irq) 434static void mpic_mask_irq(unsigned int irq)
@@ -428,11 +436,9 @@ static void mpic_mask_irq(unsigned int irq)
428 unsigned int loops = 100000; 436 unsigned int loops = 100000;
429 struct mpic *mpic = mpic_from_irq(irq); 437 struct mpic *mpic = mpic_from_irq(irq);
430 unsigned int src = mpic_irq_to_hw(irq); 438 unsigned int src = mpic_irq_to_hw(irq);
431 unsigned long flags;
432 439
433 DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 440 DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
434 441
435 spin_lock_irqsave(&mpic_lock, flags);
436 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, 442 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
437 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | 443 mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
438 MPIC_VECPRI_MASK); 444 MPIC_VECPRI_MASK);
@@ -444,7 +450,6 @@ static void mpic_mask_irq(unsigned int irq)
444 break; 450 break;
445 } 451 }
446 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); 452 } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
447 spin_unlock_irqrestore(&mpic_lock, flags);
448} 453}
449 454
450static void mpic_end_irq(unsigned int irq) 455static void mpic_end_irq(unsigned int irq)
@@ -512,8 +517,7 @@ static void mpic_end_ht_irq(unsigned int irq)
512 mpic_ht_end_irq(mpic, src); 517 mpic_ht_end_irq(mpic, src);
513 mpic_eoi(mpic); 518 mpic_eoi(mpic);
514} 519}
515 520#endif /* !CONFIG_MPIC_BROKEN_U3 */
516#endif /* CONFIG_MPIC_BROKEN_U3 */
517 521
518#ifdef CONFIG_SMP 522#ifdef CONFIG_SMP
519 523
@@ -560,47 +564,74 @@ static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
560 mpic_physmask(cpus_addr(tmp)[0])); 564 mpic_physmask(cpus_addr(tmp)[0]));
561} 565}
562 566
563static unsigned int mpic_flags_to_vecpri(unsigned int flags, int *level) 567static unsigned int mpic_type_to_vecpri(unsigned int type)
564{ 568{
565 unsigned int vecpri;
566
567 /* Now convert sense value */ 569 /* Now convert sense value */
568 switch(flags & IRQ_TYPE_SENSE_MASK) { 570 switch(type & IRQ_TYPE_SENSE_MASK) {
569 case IRQ_TYPE_EDGE_RISING: 571 case IRQ_TYPE_EDGE_RISING:
570 vecpri = MPIC_VECPRI_SENSE_EDGE | 572 return MPIC_VECPRI_SENSE_EDGE | MPIC_VECPRI_POLARITY_POSITIVE;
571 MPIC_VECPRI_POLARITY_POSITIVE;
572 *level = 0;
573 break;
574 case IRQ_TYPE_EDGE_FALLING: 573 case IRQ_TYPE_EDGE_FALLING:
575 vecpri = MPIC_VECPRI_SENSE_EDGE | 574 case IRQ_TYPE_EDGE_BOTH:
576 MPIC_VECPRI_POLARITY_NEGATIVE; 575 return MPIC_VECPRI_SENSE_EDGE | MPIC_VECPRI_POLARITY_NEGATIVE;
577 *level = 0;
578 break;
579 case IRQ_TYPE_LEVEL_HIGH: 576 case IRQ_TYPE_LEVEL_HIGH:
580 vecpri = MPIC_VECPRI_SENSE_LEVEL | 577 return MPIC_VECPRI_SENSE_LEVEL | MPIC_VECPRI_POLARITY_POSITIVE;
581 MPIC_VECPRI_POLARITY_POSITIVE;
582 *level = 1;
583 break;
584 case IRQ_TYPE_LEVEL_LOW: 578 case IRQ_TYPE_LEVEL_LOW:
585 default: 579 default:
586 vecpri = MPIC_VECPRI_SENSE_LEVEL | 580 return MPIC_VECPRI_SENSE_LEVEL | MPIC_VECPRI_POLARITY_NEGATIVE;
587 MPIC_VECPRI_POLARITY_NEGATIVE;
588 *level = 1;
589 } 581 }
590 return vecpri; 582}
583
584static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
585{
586 struct mpic *mpic = mpic_from_irq(virq);
587 unsigned int src = mpic_irq_to_hw(virq);
588 struct irq_desc *desc = get_irq_desc(virq);
589 unsigned int vecpri, vold, vnew;
590
591 pr_debug("mpic: set_irq_type(mpic:@%p,virq:%d,src:%d,type:0x%x)\n",
592 mpic, virq, src, flow_type);
593
594 if (src >= mpic->irq_count)
595 return -EINVAL;
596
597 if (flow_type == IRQ_TYPE_NONE)
598 if (mpic->senses && src < mpic->senses_count)
599 flow_type = mpic->senses[src];
600 if (flow_type == IRQ_TYPE_NONE)
601 flow_type = IRQ_TYPE_LEVEL_LOW;
602
603 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
604 desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
605 if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
606 desc->status |= IRQ_LEVEL;
607
608 if (mpic_is_ht_interrupt(mpic, src))
609 vecpri = MPIC_VECPRI_POLARITY_POSITIVE |
610 MPIC_VECPRI_SENSE_EDGE;
611 else
612 vecpri = mpic_type_to_vecpri(flow_type);
613
614 vold = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI);
615 vnew = vold & ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK);
616 vnew |= vecpri;
617 if (vold != vnew)
618 mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, vnew);
619
620 return 0;
591} 621}
592 622
593static struct irq_chip mpic_irq_chip = { 623static struct irq_chip mpic_irq_chip = {
594 .mask = mpic_mask_irq, 624 .mask = mpic_mask_irq,
595 .unmask = mpic_unmask_irq, 625 .unmask = mpic_unmask_irq,
596 .eoi = mpic_end_irq, 626 .eoi = mpic_end_irq,
627 .set_type = mpic_set_irq_type,
597}; 628};
598 629
599#ifdef CONFIG_SMP 630#ifdef CONFIG_SMP
600static struct irq_chip mpic_ipi_chip = { 631static struct irq_chip mpic_ipi_chip = {
601 .mask = mpic_mask_ipi, 632 .mask = mpic_mask_ipi,
602 .unmask = mpic_unmask_ipi, 633 .unmask = mpic_unmask_ipi,
603 .eoi = mpic_end_ipi, 634 .eoi = mpic_end_ipi,
604}; 635};
605#endif /* CONFIG_SMP */ 636#endif /* CONFIG_SMP */
606 637
@@ -611,6 +642,7 @@ static struct irq_chip mpic_irq_ht_chip = {
611 .mask = mpic_mask_irq, 642 .mask = mpic_mask_irq,
612 .unmask = mpic_unmask_ht_irq, 643 .unmask = mpic_unmask_ht_irq,
613 .eoi = mpic_end_ht_irq, 644 .eoi = mpic_end_ht_irq,
645 .set_type = mpic_set_irq_type,
614}; 646};
615#endif /* CONFIG_MPIC_BROKEN_U3 */ 647#endif /* CONFIG_MPIC_BROKEN_U3 */
616 648
@@ -624,18 +656,12 @@ static int mpic_host_match(struct irq_host *h, struct device_node *node)
624} 656}
625 657
626static int mpic_host_map(struct irq_host *h, unsigned int virq, 658static int mpic_host_map(struct irq_host *h, unsigned int virq,
627 irq_hw_number_t hw, unsigned int flags) 659 irq_hw_number_t hw)
628{ 660{
629 struct irq_desc *desc = get_irq_desc(virq);
630 struct irq_chip *chip;
631 struct mpic *mpic = h->host_data; 661 struct mpic *mpic = h->host_data;
632 u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL | 662 struct irq_chip *chip;
633 MPIC_VECPRI_POLARITY_NEGATIVE;
634 int level;
635 unsigned long iflags;
636 663
637 pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", 664 pr_debug("mpic: map virq %d, hwirq 0x%lx\n", virq, hw);
638 virq, hw, flags);
639 665
640 if (hw == MPIC_VEC_SPURRIOUS) 666 if (hw == MPIC_VEC_SPURRIOUS)
641 return -EINVAL; 667 return -EINVAL;
@@ -654,44 +680,23 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
654 if (hw >= mpic->irq_count) 680 if (hw >= mpic->irq_count)
655 return -EINVAL; 681 return -EINVAL;
656 682
657 /* If no sense provided, check default sense array */ 683 /* Default chip */
658 if (((flags & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE) &&
659 mpic->senses && hw < mpic->senses_count)
660 flags |= mpic->senses[hw];
661
662 vecpri = mpic_flags_to_vecpri(flags, &level);
663 if (level)
664 desc->status |= IRQ_LEVEL;
665 chip = &mpic->hc_irq; 684 chip = &mpic->hc_irq;
666 685
667#ifdef CONFIG_MPIC_BROKEN_U3 686#ifdef CONFIG_MPIC_BROKEN_U3
668 /* Check for HT interrupts, override vecpri */ 687 /* Check for HT interrupts, override vecpri */
669 if (mpic_is_ht_interrupt(mpic, hw)) { 688 if (mpic_is_ht_interrupt(mpic, hw))
670 vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
671 MPIC_VECPRI_POLARITY_MASK);
672 vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
673 chip = &mpic->hc_ht_irq; 689 chip = &mpic->hc_ht_irq;
674 } 690#endif /* CONFIG_MPIC_BROKEN_U3 */
675#endif
676 691
677 /* Reconfigure irq. We must preserve the mask bit as we can be called 692 pr_debug("mpic: mapping to irq chip @%p\n", chip);
678 * while the interrupt is still active (This may change in the future
679 * but for now, it is the case).
680 */
681 spin_lock_irqsave(&mpic_lock, iflags);
682 v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
683 vecpri = (v &
684 ~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
685 vecpri;
686 if (vecpri != v)
687 mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
688 spin_unlock_irqrestore(&mpic_lock, iflags);
689
690 pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
691 vecpri, v);
692 693
693 set_irq_chip_data(virq, mpic); 694 set_irq_chip_data(virq, mpic);
694 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); 695 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
696
697 /* Set default irq type */
698 set_irq_type(virq, IRQ_TYPE_NONE);
699
695 return 0; 700 return 0;
696} 701}
697 702
@@ -906,41 +911,16 @@ void __init mpic_init(struct mpic *mpic)
906 if (mpic->irq_count == 0) 911 if (mpic->irq_count == 0)
907 mpic->irq_count = mpic->num_sources; 912 mpic->irq_count = mpic->num_sources;
908 913
909#ifdef CONFIG_MPIC_BROKEN_U3
910 /* Do the HT PIC fixups on U3 broken mpic */ 914 /* Do the HT PIC fixups on U3 broken mpic */
911 DBG("MPIC flags: %x\n", mpic->flags); 915 DBG("MPIC flags: %x\n", mpic->flags);
912 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) 916 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
913 mpic_scan_ht_pics(mpic); 917 mpic_scan_ht_pics(mpic);
914#endif /* CONFIG_MPIC_BROKEN_U3 */
915 918
916 for (i = 0; i < mpic->num_sources; i++) { 919 for (i = 0; i < mpic->num_sources; i++) {
917 /* start with vector = source number, and masked */ 920 /* start with vector = source number, and masked */
918 u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); 921 u32 vecpri = MPIC_VECPRI_MASK | i |
919 int level = 1; 922 (8 << MPIC_VECPRI_PRIORITY_SHIFT);
920 923
921 /* do senses munging */
922 if (mpic->senses && i < mpic->senses_count)
923 vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
924 &level);
925 else
926 vecpri |= MPIC_VECPRI_SENSE_LEVEL;
927
928 /* deal with broken U3 */
929 if (mpic->flags & MPIC_BROKEN_U3) {
930#ifdef CONFIG_MPIC_BROKEN_U3
931 if (mpic_is_ht_interrupt(mpic, i)) {
932 vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
933 MPIC_VECPRI_POLARITY_MASK);
934 vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
935 }
936#else
937 printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n");
938#endif
939 }
940
941 DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri,
942 (level != 0));
943
944 /* init hw */ 924 /* init hw */
945 mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); 925 mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
946 mpic_irq_write(i, MPIC_IRQ_DESTINATION, 926 mpic_irq_write(i, MPIC_IRQ_DESTINATION,
@@ -1154,7 +1134,7 @@ void mpic_request_ipis(void)
1154 1134
1155 for (i = 0; i < 4; i++) { 1135 for (i = 0; i < 4; i++) {
1156 unsigned int vipi = irq_create_mapping(mpic->irqhost, 1136 unsigned int vipi = irq_create_mapping(mpic->irqhost,
1157 MPIC_VEC_IPI_0 + i, 0); 1137 MPIC_VEC_IPI_0 + i);
1158 if (vipi == NO_IRQ) { 1138 if (vipi == NO_IRQ) {
1159 printk(KERN_ERR "Failed to map IPI %d\n", i); 1139 printk(KERN_ERR "Failed to map IPI %d\n", i);
1160 break; 1140 break;