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.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;