diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 333 |
1 files changed, 213 insertions, 120 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 9a95f16c19a5..7d31d7cc392d 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -340,27 +340,19 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) | |||
340 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 340 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
341 | 341 | ||
342 | 342 | ||
343 | #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | ||
344 | |||
343 | /* Find an mpic associated with a given linux interrupt */ | 345 | /* Find an mpic associated with a given linux interrupt */ |
344 | static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) | 346 | static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) |
345 | { | 347 | { |
346 | struct mpic *mpic = mpics; | 348 | unsigned int src = mpic_irq_to_hw(irq); |
347 | 349 | ||
348 | while(mpic) { | 350 | if (irq < NUM_ISA_INTERRUPTS) |
349 | /* search IPIs first since they may override the main interrupts */ | 351 | return NULL; |
350 | if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) { | 352 | if (is_ipi) |
351 | if (is_ipi) | 353 | *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3); |
352 | *is_ipi = 1; | 354 | |
353 | return mpic; | 355 | return irq_desc[irq].chip_data; |
354 | } | ||
355 | if (irq >= mpic->irq_offset && | ||
356 | irq < (mpic->irq_offset + mpic->irq_count)) { | ||
357 | if (is_ipi) | ||
358 | *is_ipi = 0; | ||
359 | return mpic; | ||
360 | } | ||
361 | mpic = mpic -> next; | ||
362 | } | ||
363 | return NULL; | ||
364 | } | 356 | } |
365 | 357 | ||
366 | /* Convert a cpu mask from logical to physical cpu numbers. */ | 358 | /* Convert a cpu mask from logical to physical cpu numbers. */ |
@@ -398,9 +390,7 @@ static inline void mpic_eoi(struct mpic *mpic) | |||
398 | #ifdef CONFIG_SMP | 390 | #ifdef CONFIG_SMP |
399 | static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | 391 | static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) |
400 | { | 392 | { |
401 | struct mpic *mpic = dev_id; | 393 | smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs); |
402 | |||
403 | smp_message_recv(irq - mpic->ipi_offset, regs); | ||
404 | return IRQ_HANDLED; | 394 | return IRQ_HANDLED; |
405 | } | 395 | } |
406 | #endif /* CONFIG_SMP */ | 396 | #endif /* CONFIG_SMP */ |
@@ -414,7 +404,7 @@ static void mpic_unmask_irq(unsigned int irq) | |||
414 | { | 404 | { |
415 | unsigned int loops = 100000; | 405 | unsigned int loops = 100000; |
416 | struct mpic *mpic = mpic_from_irq(irq); | 406 | struct mpic *mpic = mpic_from_irq(irq); |
417 | unsigned int src = irq - mpic->irq_offset; | 407 | unsigned int src = mpic_irq_to_hw(irq); |
418 | 408 | ||
419 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); | 409 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); |
420 | 410 | ||
@@ -435,7 +425,7 @@ static void mpic_mask_irq(unsigned int irq) | |||
435 | { | 425 | { |
436 | unsigned int loops = 100000; | 426 | unsigned int loops = 100000; |
437 | struct mpic *mpic = mpic_from_irq(irq); | 427 | struct mpic *mpic = mpic_from_irq(irq); |
438 | unsigned int src = irq - mpic->irq_offset; | 428 | unsigned int src = mpic_irq_to_hw(irq); |
439 | 429 | ||
440 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); | 430 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); |
441 | 431 | ||
@@ -472,7 +462,7 @@ static void mpic_end_irq(unsigned int irq) | |||
472 | static void mpic_unmask_ht_irq(unsigned int irq) | 462 | static void mpic_unmask_ht_irq(unsigned int irq) |
473 | { | 463 | { |
474 | struct mpic *mpic = mpic_from_irq(irq); | 464 | struct mpic *mpic = mpic_from_irq(irq); |
475 | unsigned int src = irq - mpic->irq_offset; | 465 | unsigned int src = mpic_irq_to_hw(irq); |
476 | 466 | ||
477 | mpic_unmask_irq(irq); | 467 | mpic_unmask_irq(irq); |
478 | 468 | ||
@@ -483,7 +473,7 @@ static void mpic_unmask_ht_irq(unsigned int irq) | |||
483 | static unsigned int mpic_startup_ht_irq(unsigned int irq) | 473 | static unsigned int mpic_startup_ht_irq(unsigned int irq) |
484 | { | 474 | { |
485 | struct mpic *mpic = mpic_from_irq(irq); | 475 | struct mpic *mpic = mpic_from_irq(irq); |
486 | unsigned int src = irq - mpic->irq_offset; | 476 | unsigned int src = mpic_irq_to_hw(irq); |
487 | 477 | ||
488 | mpic_unmask_irq(irq); | 478 | mpic_unmask_irq(irq); |
489 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | 479 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); |
@@ -494,7 +484,7 @@ static unsigned int mpic_startup_ht_irq(unsigned int irq) | |||
494 | static void mpic_shutdown_ht_irq(unsigned int irq) | 484 | static void mpic_shutdown_ht_irq(unsigned int irq) |
495 | { | 485 | { |
496 | struct mpic *mpic = mpic_from_irq(irq); | 486 | struct mpic *mpic = mpic_from_irq(irq); |
497 | unsigned int src = irq - mpic->irq_offset; | 487 | unsigned int src = mpic_irq_to_hw(irq); |
498 | 488 | ||
499 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | 489 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); |
500 | mpic_mask_irq(irq); | 490 | mpic_mask_irq(irq); |
@@ -503,7 +493,7 @@ static void mpic_shutdown_ht_irq(unsigned int irq) | |||
503 | static void mpic_end_ht_irq(unsigned int irq) | 493 | static void mpic_end_ht_irq(unsigned int irq) |
504 | { | 494 | { |
505 | struct mpic *mpic = mpic_from_irq(irq); | 495 | struct mpic *mpic = mpic_from_irq(irq); |
506 | unsigned int src = irq - mpic->irq_offset; | 496 | unsigned int src = mpic_irq_to_hw(irq); |
507 | 497 | ||
508 | #ifdef DEBUG_IRQ | 498 | #ifdef DEBUG_IRQ |
509 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 499 | DBG("%s: end_irq: %d\n", mpic->name, irq); |
@@ -525,7 +515,7 @@ static void mpic_end_ht_irq(unsigned int irq) | |||
525 | static void mpic_unmask_ipi(unsigned int irq) | 515 | static void mpic_unmask_ipi(unsigned int irq) |
526 | { | 516 | { |
527 | struct mpic *mpic = mpic_from_ipi(irq); | 517 | struct mpic *mpic = mpic_from_ipi(irq); |
528 | unsigned int src = irq - mpic->ipi_offset; | 518 | unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0; |
529 | 519 | ||
530 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); | 520 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); |
531 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); | 521 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); |
@@ -555,15 +545,46 @@ static void mpic_end_ipi(unsigned int irq) | |||
555 | static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) | 545 | static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) |
556 | { | 546 | { |
557 | struct mpic *mpic = mpic_from_irq(irq); | 547 | struct mpic *mpic = mpic_from_irq(irq); |
548 | unsigned int src = mpic_irq_to_hw(irq); | ||
558 | 549 | ||
559 | cpumask_t tmp; | 550 | cpumask_t tmp; |
560 | 551 | ||
561 | cpus_and(tmp, cpumask, cpu_online_map); | 552 | cpus_and(tmp, cpumask, cpu_online_map); |
562 | 553 | ||
563 | mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION, | 554 | mpic_irq_write(src, MPIC_IRQ_DESTINATION, |
564 | mpic_physmask(cpus_addr(tmp)[0])); | 555 | mpic_physmask(cpus_addr(tmp)[0])); |
565 | } | 556 | } |
566 | 557 | ||
558 | static unsigned int mpic_flags_to_vecpri(unsigned int flags, int *level) | ||
559 | { | ||
560 | unsigned int vecpri; | ||
561 | |||
562 | /* Now convert sense value */ | ||
563 | switch(flags & IRQ_TYPE_SENSE_MASK) { | ||
564 | case IRQ_TYPE_EDGE_RISING: | ||
565 | vecpri = MPIC_VECPRI_SENSE_EDGE | | ||
566 | MPIC_VECPRI_POLARITY_POSITIVE; | ||
567 | *level = 0; | ||
568 | break; | ||
569 | case IRQ_TYPE_EDGE_FALLING: | ||
570 | vecpri = MPIC_VECPRI_SENSE_EDGE | | ||
571 | MPIC_VECPRI_POLARITY_NEGATIVE; | ||
572 | *level = 0; | ||
573 | break; | ||
574 | case IRQ_TYPE_LEVEL_HIGH: | ||
575 | vecpri = MPIC_VECPRI_SENSE_LEVEL | | ||
576 | MPIC_VECPRI_POLARITY_POSITIVE; | ||
577 | *level = 1; | ||
578 | break; | ||
579 | case IRQ_TYPE_LEVEL_LOW: | ||
580 | default: | ||
581 | vecpri = MPIC_VECPRI_SENSE_LEVEL | | ||
582 | MPIC_VECPRI_POLARITY_NEGATIVE; | ||
583 | *level = 1; | ||
584 | } | ||
585 | return vecpri; | ||
586 | } | ||
587 | |||
567 | static struct irq_chip mpic_irq_chip = { | 588 | static struct irq_chip mpic_irq_chip = { |
568 | .mask = mpic_mask_irq, | 589 | .mask = mpic_mask_irq, |
569 | .unmask = mpic_unmask_irq, | 590 | .unmask = mpic_unmask_irq, |
@@ -589,19 +610,111 @@ static struct irq_chip mpic_irq_ht_chip = { | |||
589 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 610 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
590 | 611 | ||
591 | 612 | ||
613 | static int mpic_host_match(struct irq_host *h, struct device_node *node) | ||
614 | { | ||
615 | struct mpic *mpic = h->host_data; | ||
616 | |||
617 | /* Exact match, unless mpic node is NULL */ | ||
618 | return mpic->of_node == NULL || mpic->of_node == node; | ||
619 | } | ||
620 | |||
621 | static int mpic_host_map(struct irq_host *h, unsigned int virq, | ||
622 | irq_hw_number_t hw, unsigned int flags) | ||
623 | { | ||
624 | struct irq_desc *desc = get_irq_desc(virq); | ||
625 | struct irq_chip *chip; | ||
626 | struct mpic *mpic = h->host_data; | ||
627 | unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL | | ||
628 | MPIC_VECPRI_POLARITY_NEGATIVE; | ||
629 | int level; | ||
630 | |||
631 | pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", | ||
632 | virq, hw, flags); | ||
633 | |||
634 | if (hw == MPIC_VEC_SPURRIOUS) | ||
635 | return -EINVAL; | ||
636 | #ifdef CONFIG_SMP | ||
637 | else if (hw >= MPIC_VEC_IPI_0) { | ||
638 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | ||
639 | |||
640 | pr_debug("mpic: mapping as IPI\n"); | ||
641 | set_irq_chip_data(virq, mpic); | ||
642 | set_irq_chip_and_handler(virq, &mpic->hc_ipi, | ||
643 | handle_percpu_irq); | ||
644 | return 0; | ||
645 | } | ||
646 | #endif /* CONFIG_SMP */ | ||
647 | |||
648 | if (hw >= mpic->irq_count) | ||
649 | return -EINVAL; | ||
650 | |||
651 | /* If no sense provided, check default sense array */ | ||
652 | if (((flags & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE) && | ||
653 | mpic->senses && hw < mpic->senses_count) | ||
654 | flags |= mpic->senses[hw]; | ||
655 | |||
656 | vecpri = mpic_flags_to_vecpri(flags, &level); | ||
657 | if (level) | ||
658 | desc->status |= IRQ_LEVEL; | ||
659 | chip = &mpic->hc_irq; | ||
660 | |||
661 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
662 | /* Check for HT interrupts, override vecpri */ | ||
663 | if (mpic_is_ht_interrupt(mpic, hw)) { | ||
664 | vecpri &= ~(MPIC_VECPRI_SENSE_MASK | | ||
665 | MPIC_VECPRI_POLARITY_MASK); | ||
666 | vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; | ||
667 | chip = &mpic->hc_ht_irq; | ||
668 | } | ||
669 | #endif | ||
670 | |||
671 | /* Reconfigure irq */ | ||
672 | vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | ||
673 | mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri); | ||
674 | |||
675 | pr_debug("mpic: mapping as IRQ\n"); | ||
676 | |||
677 | set_irq_chip_data(virq, mpic); | ||
678 | set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | ||
683 | u32 *intspec, unsigned int intsize, | ||
684 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | ||
685 | |||
686 | { | ||
687 | static unsigned char map_mpic_senses[4] = { | ||
688 | IRQ_TYPE_EDGE_RISING, | ||
689 | IRQ_TYPE_LEVEL_LOW, | ||
690 | IRQ_TYPE_LEVEL_HIGH, | ||
691 | IRQ_TYPE_EDGE_FALLING, | ||
692 | }; | ||
693 | |||
694 | *out_hwirq = intspec[0]; | ||
695 | if (intsize > 1 && intspec[1] < 4) | ||
696 | *out_flags = map_mpic_senses[intspec[1]]; | ||
697 | else | ||
698 | *out_flags = IRQ_TYPE_NONE; | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static struct irq_host_ops mpic_host_ops = { | ||
704 | .match = mpic_host_match, | ||
705 | .map = mpic_host_map, | ||
706 | .xlate = mpic_host_xlate, | ||
707 | }; | ||
708 | |||
592 | /* | 709 | /* |
593 | * Exported functions | 710 | * Exported functions |
594 | */ | 711 | */ |
595 | 712 | ||
596 | 713 | struct mpic * __init mpic_alloc(struct device_node *node, | |
597 | struct mpic * __init mpic_alloc(unsigned long phys_addr, | 714 | unsigned long phys_addr, |
598 | unsigned int flags, | 715 | unsigned int flags, |
599 | unsigned int isu_size, | 716 | unsigned int isu_size, |
600 | unsigned int irq_offset, | ||
601 | unsigned int irq_count, | 717 | unsigned int irq_count, |
602 | unsigned int ipi_offset, | ||
603 | unsigned char *senses, | ||
604 | unsigned int senses_count, | ||
605 | const char *name) | 718 | const char *name) |
606 | { | 719 | { |
607 | struct mpic *mpic; | 720 | struct mpic *mpic; |
@@ -613,10 +726,19 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
613 | if (mpic == NULL) | 726 | if (mpic == NULL) |
614 | return NULL; | 727 | return NULL; |
615 | 728 | ||
616 | |||
617 | memset(mpic, 0, sizeof(struct mpic)); | 729 | memset(mpic, 0, sizeof(struct mpic)); |
618 | mpic->name = name; | 730 | mpic->name = name; |
731 | mpic->of_node = node ? of_node_get(node) : NULL; | ||
619 | 732 | ||
733 | mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256, | ||
734 | &mpic_host_ops, | ||
735 | MPIC_VEC_SPURRIOUS); | ||
736 | if (mpic->irqhost == NULL) { | ||
737 | of_node_put(node); | ||
738 | return NULL; | ||
739 | } | ||
740 | |||
741 | mpic->irqhost->host_data = mpic; | ||
620 | mpic->hc_irq = mpic_irq_chip; | 742 | mpic->hc_irq = mpic_irq_chip; |
621 | mpic->hc_irq.typename = name; | 743 | mpic->hc_irq.typename = name; |
622 | if (flags & MPIC_PRIMARY) | 744 | if (flags & MPIC_PRIMARY) |
@@ -628,18 +750,14 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
628 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | 750 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; |
629 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 751 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
630 | #ifdef CONFIG_SMP | 752 | #ifdef CONFIG_SMP |
631 | mpic->hc_ipi.typename = name; | ||
632 | mpic->hc_ipi = mpic_ipi_chip; | 753 | mpic->hc_ipi = mpic_ipi_chip; |
754 | mpic->hc_ipi.typename = name; | ||
633 | #endif /* CONFIG_SMP */ | 755 | #endif /* CONFIG_SMP */ |
634 | 756 | ||
635 | mpic->flags = flags; | 757 | mpic->flags = flags; |
636 | mpic->isu_size = isu_size; | 758 | mpic->isu_size = isu_size; |
637 | mpic->irq_offset = irq_offset; | ||
638 | mpic->irq_count = irq_count; | 759 | mpic->irq_count = irq_count; |
639 | mpic->ipi_offset = ipi_offset; | ||
640 | mpic->num_sources = 0; /* so far */ | 760 | mpic->num_sources = 0; /* so far */ |
641 | mpic->senses = senses; | ||
642 | mpic->senses_count = senses_count; | ||
643 | 761 | ||
644 | /* Map the global registers */ | 762 | /* Map the global registers */ |
645 | mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); | 763 | mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); |
@@ -707,8 +825,10 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
707 | mpic->next = mpics; | 825 | mpic->next = mpics; |
708 | mpics = mpic; | 826 | mpics = mpic; |
709 | 827 | ||
710 | if (flags & MPIC_PRIMARY) | 828 | if (flags & MPIC_PRIMARY) { |
711 | mpic_primary = mpic; | 829 | mpic_primary = mpic; |
830 | irq_set_default_host(mpic->irqhost); | ||
831 | } | ||
712 | 832 | ||
713 | return mpic; | 833 | return mpic; |
714 | } | 834 | } |
@@ -725,11 +845,22 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
725 | mpic->num_sources = isu_first + mpic->isu_size; | 845 | mpic->num_sources = isu_first + mpic->isu_size; |
726 | } | 846 | } |
727 | 847 | ||
848 | void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) | ||
849 | { | ||
850 | mpic->senses = senses; | ||
851 | mpic->senses_count = count; | ||
852 | } | ||
853 | |||
728 | void __init mpic_init(struct mpic *mpic) | 854 | void __init mpic_init(struct mpic *mpic) |
729 | { | 855 | { |
730 | int i; | 856 | int i; |
731 | 857 | ||
732 | BUG_ON(mpic->num_sources == 0); | 858 | BUG_ON(mpic->num_sources == 0); |
859 | WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0); | ||
860 | |||
861 | /* Sanitize source count */ | ||
862 | if (mpic->num_sources > MPIC_VEC_IPI_0) | ||
863 | mpic->num_sources = MPIC_VEC_IPI_0; | ||
733 | 864 | ||
734 | printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); | 865 | printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); |
735 | 866 | ||
@@ -753,14 +884,6 @@ void __init mpic_init(struct mpic *mpic) | |||
753 | MPIC_VECPRI_MASK | | 884 | MPIC_VECPRI_MASK | |
754 | (10 << MPIC_VECPRI_PRIORITY_SHIFT) | | 885 | (10 << MPIC_VECPRI_PRIORITY_SHIFT) | |
755 | (MPIC_VEC_IPI_0 + i)); | 886 | (MPIC_VEC_IPI_0 + i)); |
756 | #ifdef CONFIG_SMP | ||
757 | if (!(mpic->flags & MPIC_PRIMARY)) | ||
758 | continue; | ||
759 | set_irq_chip_data(mpic->ipi_offset+i, mpic); | ||
760 | set_irq_chip_and_handler(mpic->ipi_offset+i, | ||
761 | &mpic->hc_ipi, | ||
762 | handle_percpu_irq); | ||
763 | #endif /* CONFIG_SMP */ | ||
764 | } | 887 | } |
765 | 888 | ||
766 | /* Initialize interrupt sources */ | 889 | /* Initialize interrupt sources */ |
@@ -777,25 +900,15 @@ void __init mpic_init(struct mpic *mpic) | |||
777 | for (i = 0; i < mpic->num_sources; i++) { | 900 | for (i = 0; i < mpic->num_sources; i++) { |
778 | /* start with vector = source number, and masked */ | 901 | /* start with vector = source number, and masked */ |
779 | u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | 902 | u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); |
780 | int level = 0; | 903 | int level = 1; |
781 | 904 | ||
782 | /* if it's an IPI, we skip it */ | ||
783 | if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) && | ||
784 | (mpic->irq_offset + i) < (mpic->ipi_offset + i + 4)) | ||
785 | continue; | ||
786 | |||
787 | /* do senses munging */ | 905 | /* do senses munging */ |
788 | if (mpic->senses && i < mpic->senses_count) { | 906 | if (mpic->senses && i < mpic->senses_count) |
789 | if (mpic->senses[i] & IRQ_SENSE_LEVEL) | 907 | vecpri = mpic_flags_to_vecpri(mpic->senses[i], |
790 | vecpri |= MPIC_VECPRI_SENSE_LEVEL; | 908 | &level); |
791 | if (mpic->senses[i] & IRQ_POLARITY_POSITIVE) | 909 | else |
792 | vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; | ||
793 | } else | ||
794 | vecpri |= MPIC_VECPRI_SENSE_LEVEL; | 910 | vecpri |= MPIC_VECPRI_SENSE_LEVEL; |
795 | 911 | ||
796 | /* remember if it was a level interrupts */ | ||
797 | level = (vecpri & MPIC_VECPRI_SENSE_LEVEL); | ||
798 | |||
799 | /* deal with broken U3 */ | 912 | /* deal with broken U3 */ |
800 | if (mpic->flags & MPIC_BROKEN_U3) { | 913 | if (mpic->flags & MPIC_BROKEN_U3) { |
801 | #ifdef CONFIG_MPIC_BROKEN_U3 | 914 | #ifdef CONFIG_MPIC_BROKEN_U3 |
@@ -816,21 +929,6 @@ void __init mpic_init(struct mpic *mpic) | |||
816 | mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); | 929 | mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); |
817 | mpic_irq_write(i, MPIC_IRQ_DESTINATION, | 930 | mpic_irq_write(i, MPIC_IRQ_DESTINATION, |
818 | 1 << hard_smp_processor_id()); | 931 | 1 << hard_smp_processor_id()); |
819 | |||
820 | /* init linux descriptors */ | ||
821 | if (i < mpic->irq_count) { | ||
822 | struct irq_chip *chip = &mpic->hc_irq; | ||
823 | |||
824 | irq_desc[mpic->irq_offset+i].status |= | ||
825 | level ? IRQ_LEVEL : 0; | ||
826 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
827 | if (mpic_is_ht_interrupt(mpic, i)) | ||
828 | chip = &mpic->hc_ht_irq; | ||
829 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
830 | set_irq_chip_data(mpic->irq_offset+i, mpic); | ||
831 | set_irq_chip_and_handler(mpic->irq_offset+i, chip, | ||
832 | handle_fasteoi_irq); | ||
833 | } | ||
834 | } | 932 | } |
835 | 933 | ||
836 | /* Init spurrious vector */ | 934 | /* Init spurrious vector */ |
@@ -871,19 +969,20 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) | |||
871 | { | 969 | { |
872 | int is_ipi; | 970 | int is_ipi; |
873 | struct mpic *mpic = mpic_find(irq, &is_ipi); | 971 | struct mpic *mpic = mpic_find(irq, &is_ipi); |
972 | unsigned int src = mpic_irq_to_hw(irq); | ||
874 | unsigned long flags; | 973 | unsigned long flags; |
875 | u32 reg; | 974 | u32 reg; |
876 | 975 | ||
877 | spin_lock_irqsave(&mpic_lock, flags); | 976 | spin_lock_irqsave(&mpic_lock, flags); |
878 | if (is_ipi) { | 977 | if (is_ipi) { |
879 | reg = mpic_ipi_read(irq - mpic->ipi_offset) & | 978 | reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) & |
880 | ~MPIC_VECPRI_PRIORITY_MASK; | 979 | ~MPIC_VECPRI_PRIORITY_MASK; |
881 | mpic_ipi_write(irq - mpic->ipi_offset, | 980 | mpic_ipi_write(src - MPIC_VEC_IPI_0, |
882 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | 981 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); |
883 | } else { | 982 | } else { |
884 | reg = mpic_irq_read(irq - mpic->irq_offset,MPIC_IRQ_VECTOR_PRI) | 983 | reg = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
885 | & ~MPIC_VECPRI_PRIORITY_MASK; | 984 | & ~MPIC_VECPRI_PRIORITY_MASK; |
886 | mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI, | 985 | mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, |
887 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | 986 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); |
888 | } | 987 | } |
889 | spin_unlock_irqrestore(&mpic_lock, flags); | 988 | spin_unlock_irqrestore(&mpic_lock, flags); |
@@ -893,14 +992,15 @@ unsigned int mpic_irq_get_priority(unsigned int irq) | |||
893 | { | 992 | { |
894 | int is_ipi; | 993 | int is_ipi; |
895 | struct mpic *mpic = mpic_find(irq, &is_ipi); | 994 | struct mpic *mpic = mpic_find(irq, &is_ipi); |
995 | unsigned int src = mpic_irq_to_hw(irq); | ||
896 | unsigned long flags; | 996 | unsigned long flags; |
897 | u32 reg; | 997 | u32 reg; |
898 | 998 | ||
899 | spin_lock_irqsave(&mpic_lock, flags); | 999 | spin_lock_irqsave(&mpic_lock, flags); |
900 | if (is_ipi) | 1000 | if (is_ipi) |
901 | reg = mpic_ipi_read(irq - mpic->ipi_offset); | 1001 | reg = mpic_ipi_read(src = MPIC_VEC_IPI_0); |
902 | else | 1002 | else |
903 | reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI); | 1003 | reg = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI); |
904 | spin_unlock_irqrestore(&mpic_lock, flags); | 1004 | spin_unlock_irqrestore(&mpic_lock, flags); |
905 | return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; | 1005 | return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; |
906 | } | 1006 | } |
@@ -995,29 +1095,20 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) | |||
995 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); | 1095 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); |
996 | } | 1096 | } |
997 | 1097 | ||
998 | int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) | 1098 | unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) |
999 | { | 1099 | { |
1000 | u32 irq; | 1100 | u32 src; |
1001 | 1101 | ||
1002 | irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; | 1102 | src = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; |
1003 | #ifdef DEBUG_LOW | 1103 | #ifdef DEBUG_LOW |
1004 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); | 1104 | DBG("%s: get_one_irq(): %d\n", mpic->name, src); |
1005 | #endif | ||
1006 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) | ||
1007 | return -1; | ||
1008 | if (irq < MPIC_VEC_IPI_0) { | ||
1009 | #ifdef DEBUG_IRQ | ||
1010 | DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset); | ||
1011 | #endif | 1105 | #endif |
1012 | return irq + mpic->irq_offset; | 1106 | if (unlikely(src == MPIC_VEC_SPURRIOUS)) |
1013 | } | 1107 | return NO_IRQ; |
1014 | #ifdef DEBUG_IPI | 1108 | return irq_linear_revmap(mpic->irqhost, src); |
1015 | DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); | ||
1016 | #endif | ||
1017 | return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; | ||
1018 | } | 1109 | } |
1019 | 1110 | ||
1020 | int mpic_get_irq(struct pt_regs *regs) | 1111 | unsigned int mpic_get_irq(struct pt_regs *regs) |
1021 | { | 1112 | { |
1022 | struct mpic *mpic = mpic_primary; | 1113 | struct mpic *mpic = mpic_primary; |
1023 | 1114 | ||
@@ -1031,25 +1122,27 @@ int mpic_get_irq(struct pt_regs *regs) | |||
1031 | void mpic_request_ipis(void) | 1122 | void mpic_request_ipis(void) |
1032 | { | 1123 | { |
1033 | struct mpic *mpic = mpic_primary; | 1124 | struct mpic *mpic = mpic_primary; |
1034 | 1125 | int i; | |
1126 | static char *ipi_names[] = { | ||
1127 | "IPI0 (call function)", | ||
1128 | "IPI1 (reschedule)", | ||
1129 | "IPI2 (unused)", | ||
1130 | "IPI3 (debugger break)", | ||
1131 | }; | ||
1035 | BUG_ON(mpic == NULL); | 1132 | BUG_ON(mpic == NULL); |
1036 | |||
1037 | printk("requesting IPIs ... \n"); | ||
1038 | 1133 | ||
1039 | /* | 1134 | printk(KERN_INFO "mpic: requesting IPIs ... \n"); |
1040 | * IPIs are marked IRQF_DISABLED as they must run with irqs | 1135 | |
1041 | * disabled | 1136 | for (i = 0; i < 4; i++) { |
1042 | */ | 1137 | unsigned int vipi = irq_create_mapping(mpic->irqhost, |
1043 | request_irq(mpic->ipi_offset+0, mpic_ipi_action, IRQF_DISABLED, | 1138 | MPIC_VEC_IPI_0 + i, 0); |
1044 | "IPI0 (call function)", mpic); | 1139 | if (vipi == NO_IRQ) { |
1045 | request_irq(mpic->ipi_offset+1, mpic_ipi_action, IRQF_DISABLED, | 1140 | printk(KERN_ERR "Failed to map IPI %d\n", i); |
1046 | "IPI1 (reschedule)", mpic); | 1141 | break; |
1047 | request_irq(mpic->ipi_offset+2, mpic_ipi_action, IRQF_DISABLED, | 1142 | } |
1048 | "IPI2 (unused)", mpic); | 1143 | request_irq(vipi, mpic_ipi_action, IRQF_DISABLED, |
1049 | request_irq(mpic->ipi_offset+3, mpic_ipi_action, IRQF_DISABLED, | 1144 | ipi_names[i], mpic); |
1050 | "IPI3 (debugger break)", mpic); | 1145 | } |
1051 | |||
1052 | printk("IPIs requested... \n"); | ||
1053 | } | 1146 | } |
1054 | 1147 | ||
1055 | void smp_mpic_message_pass(int target, int msg) | 1148 | void smp_mpic_message_pass(int target, int msg) |