aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c210
1 files changed, 104 insertions, 106 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 9cecebaa0360..6e0281afa6c3 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -204,7 +204,7 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
204 if (fixup->base == NULL) 204 if (fixup->base == NULL)
205 return; 205 return;
206 206
207 DBG("startup_ht_interrupt(%u, %u) index: %d\n", 207 DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n",
208 source, irqflags, fixup->index); 208 source, irqflags, fixup->index);
209 spin_lock_irqsave(&mpic->fixup_lock, flags); 209 spin_lock_irqsave(&mpic->fixup_lock, flags);
210 /* Enable and configure */ 210 /* Enable and configure */
@@ -227,7 +227,7 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
227 if (fixup->base == NULL) 227 if (fixup->base == NULL)
228 return; 228 return;
229 229
230 DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags); 230 DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags);
231 231
232 /* Disable */ 232 /* Disable */
233 spin_lock_irqsave(&mpic->fixup_lock, flags); 233 spin_lock_irqsave(&mpic->fixup_lock, flags);
@@ -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 DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,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,26 +656,21 @@ 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 DBG("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;
668
642#ifdef CONFIG_SMP 669#ifdef CONFIG_SMP
643 else if (hw >= MPIC_VEC_IPI_0) { 670 else if (hw >= MPIC_VEC_IPI_0) {
644 WARN_ON(!(mpic->flags & MPIC_PRIMARY)); 671 WARN_ON(!(mpic->flags & MPIC_PRIMARY));
645 672
646 pr_debug("mpic: mapping as IPI\n"); 673 DBG("mpic: mapping as IPI\n");
647 set_irq_chip_data(virq, mpic); 674 set_irq_chip_data(virq, mpic);
648 set_irq_chip_and_handler(virq, &mpic->hc_ipi, 675 set_irq_chip_and_handler(virq, &mpic->hc_ipi,
649 handle_percpu_irq); 676 handle_percpu_irq);
@@ -654,44 +681,23 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
654 if (hw >= mpic->irq_count) 681 if (hw >= mpic->irq_count)
655 return -EINVAL; 682 return -EINVAL;
656 683
657 /* If no sense provided, check default sense array */ 684 /* 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; 685 chip = &mpic->hc_irq;
666 686
667#ifdef CONFIG_MPIC_BROKEN_U3 687#ifdef CONFIG_MPIC_BROKEN_U3
668 /* Check for HT interrupts, override vecpri */ 688 /* Check for HT interrupts, override vecpri */
669 if (mpic_is_ht_interrupt(mpic, hw)) { 689 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; 690 chip = &mpic->hc_ht_irq;
674 } 691#endif /* CONFIG_MPIC_BROKEN_U3 */
675#endif
676 692
677 /* Reconfigure irq. We must preserve the mask bit as we can be called 693 DBG("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 694
693 set_irq_chip_data(virq, mpic); 695 set_irq_chip_data(virq, mpic);
694 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); 696 set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
697
698 /* Set default irq type */
699 set_irq_type(virq, IRQ_TYPE_NONE);
700
695 return 0; 701 return 0;
696} 702}
697 703
@@ -708,11 +714,28 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
708 }; 714 };
709 715
710 *out_hwirq = intspec[0]; 716 *out_hwirq = intspec[0];
711 if (intsize > 1 && intspec[1] < 4) 717 if (intsize > 1) {
712 *out_flags = map_mpic_senses[intspec[1]]; 718 u32 mask = 0x3;
713 else 719
720 /* Apple invented a new race of encoding on machines with
721 * an HT APIC. They encode, among others, the index within
722 * the HT APIC. We don't care about it here since thankfully,
723 * it appears that they have the APIC already properly
724 * configured, and thus our current fixup code that reads the
725 * APIC config works fine. However, we still need to mask out
726 * bits in the specifier to make sure we only get bit 0 which
727 * is the level/edge bit (the only sense bit exposed by Apple),
728 * as their bit 1 means something else.
729 */
730 if (machine_is(powermac))
731 mask = 0x1;
732 *out_flags = map_mpic_senses[intspec[1] & mask];
733 } else
714 *out_flags = IRQ_TYPE_NONE; 734 *out_flags = IRQ_TYPE_NONE;
715 735
736 DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n",
737 intsize, intspec[0], intspec[1], *out_hwirq, *out_flags);
738
716 return 0; 739 return 0;
717} 740}
718 741
@@ -906,41 +929,16 @@ void __init mpic_init(struct mpic *mpic)
906 if (mpic->irq_count == 0) 929 if (mpic->irq_count == 0)
907 mpic->irq_count = mpic->num_sources; 930 mpic->irq_count = mpic->num_sources;
908 931
909#ifdef CONFIG_MPIC_BROKEN_U3
910 /* Do the HT PIC fixups on U3 broken mpic */ 932 /* Do the HT PIC fixups on U3 broken mpic */
911 DBG("MPIC flags: %x\n", mpic->flags); 933 DBG("MPIC flags: %x\n", mpic->flags);
912 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) 934 if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
913 mpic_scan_ht_pics(mpic); 935 mpic_scan_ht_pics(mpic);
914#endif /* CONFIG_MPIC_BROKEN_U3 */
915 936
916 for (i = 0; i < mpic->num_sources; i++) { 937 for (i = 0; i < mpic->num_sources; i++) {
917 /* start with vector = source number, and masked */ 938 /* start with vector = source number, and masked */
918 u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); 939 u32 vecpri = MPIC_VECPRI_MASK | i |
919 int level = 1; 940 (8 << MPIC_VECPRI_PRIORITY_SHIFT);
920 941
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 */ 942 /* init hw */
945 mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); 943 mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
946 mpic_irq_write(i, MPIC_IRQ_DESTINATION, 944 mpic_irq_write(i, MPIC_IRQ_DESTINATION,
@@ -1154,7 +1152,7 @@ void mpic_request_ipis(void)
1154 1152
1155 for (i = 0; i < 4; i++) { 1153 for (i = 0; i < 4; i++) {
1156 unsigned int vipi = irq_create_mapping(mpic->irqhost, 1154 unsigned int vipi = irq_create_mapping(mpic->irqhost,
1157 MPIC_VEC_IPI_0 + i, 0); 1155 MPIC_VEC_IPI_0 + i);
1158 if (vipi == NO_IRQ) { 1156 if (vipi == NO_IRQ) {
1159 printk(KERN_ERR "Failed to map IPI %d\n", i); 1157 printk(KERN_ERR "Failed to map IPI %d\n", i);
1160 break; 1158 break;