diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 193 |
1 files changed, 101 insertions, 92 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 7e469358895f..9a95f16c19a5 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -100,8 +100,8 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | |||
100 | 100 | ||
101 | if (mpic->flags & MPIC_PRIMARY) | 101 | if (mpic->flags & MPIC_PRIMARY) |
102 | cpu = hard_smp_processor_id(); | 102 | cpu = hard_smp_processor_id(); |
103 | 103 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, | |
104 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg); | 104 | mpic->cpuregs[cpu], reg); |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) | 107 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) |
@@ -378,14 +378,14 @@ static inline u32 mpic_physmask(u32 cpumask) | |||
378 | /* Get the mpic structure from the IPI number */ | 378 | /* Get the mpic structure from the IPI number */ |
379 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) | 379 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) |
380 | { | 380 | { |
381 | return container_of(irq_desc[ipi].chip, struct mpic, hc_ipi); | 381 | return irq_desc[ipi].chip_data; |
382 | } | 382 | } |
383 | #endif | 383 | #endif |
384 | 384 | ||
385 | /* Get the mpic structure from the irq number */ | 385 | /* Get the mpic structure from the irq number */ |
386 | static inline struct mpic * mpic_from_irq(unsigned int irq) | 386 | static inline struct mpic * mpic_from_irq(unsigned int irq) |
387 | { | 387 | { |
388 | return container_of(irq_desc[irq].chip, struct mpic, hc_irq); | 388 | return irq_desc[irq].chip_data; |
389 | } | 389 | } |
390 | 390 | ||
391 | /* Send an EOI */ | 391 | /* Send an EOI */ |
@@ -410,7 +410,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | |||
410 | */ | 410 | */ |
411 | 411 | ||
412 | 412 | ||
413 | static void mpic_enable_irq(unsigned int irq) | 413 | static void mpic_unmask_irq(unsigned int irq) |
414 | { | 414 | { |
415 | unsigned int loops = 100000; | 415 | unsigned int loops = 100000; |
416 | struct mpic *mpic = mpic_from_irq(irq); | 416 | struct mpic *mpic = mpic_from_irq(irq); |
@@ -429,35 +429,9 @@ static void mpic_enable_irq(unsigned int irq) | |||
429 | break; | 429 | break; |
430 | } | 430 | } |
431 | } 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); |
432 | |||
433 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
434 | if (mpic->flags & MPIC_BROKEN_U3) { | ||
435 | unsigned int src = irq - mpic->irq_offset; | ||
436 | if (mpic_is_ht_interrupt(mpic, src) && | ||
437 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
438 | mpic_ht_end_irq(mpic, src); | ||
439 | } | ||
440 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
441 | } | ||
442 | |||
443 | static unsigned int mpic_startup_irq(unsigned int irq) | ||
444 | { | ||
445 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
446 | struct mpic *mpic = mpic_from_irq(irq); | ||
447 | unsigned int src = irq - mpic->irq_offset; | ||
448 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
449 | |||
450 | mpic_enable_irq(irq); | ||
451 | |||
452 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
453 | if (mpic_is_ht_interrupt(mpic, src)) | ||
454 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
455 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
456 | |||
457 | return 0; | ||
458 | } | 432 | } |
459 | 433 | ||
460 | static void mpic_disable_irq(unsigned int irq) | 434 | static void mpic_mask_irq(unsigned int irq) |
461 | { | 435 | { |
462 | unsigned int loops = 100000; | 436 | unsigned int loops = 100000; |
463 | struct mpic *mpic = mpic_from_irq(irq); | 437 | struct mpic *mpic = mpic_from_irq(irq); |
@@ -478,23 +452,58 @@ static void mpic_disable_irq(unsigned int irq) | |||
478 | } 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)); |
479 | } | 453 | } |
480 | 454 | ||
481 | static void mpic_shutdown_irq(unsigned int irq) | 455 | static void mpic_end_irq(unsigned int irq) |
482 | { | 456 | { |
457 | struct mpic *mpic = mpic_from_irq(irq); | ||
458 | |||
459 | #ifdef DEBUG_IRQ | ||
460 | DBG("%s: end_irq: %d\n", mpic->name, irq); | ||
461 | #endif | ||
462 | /* We always EOI on end_irq() even for edge interrupts since that | ||
463 | * should only lower the priority, the MPIC should have properly | ||
464 | * latched another edge interrupt coming in anyway | ||
465 | */ | ||
466 | |||
467 | mpic_eoi(mpic); | ||
468 | } | ||
469 | |||
483 | #ifdef CONFIG_MPIC_BROKEN_U3 | 470 | #ifdef CONFIG_MPIC_BROKEN_U3 |
471 | |||
472 | static void mpic_unmask_ht_irq(unsigned int irq) | ||
473 | { | ||
484 | struct mpic *mpic = mpic_from_irq(irq); | 474 | struct mpic *mpic = mpic_from_irq(irq); |
485 | unsigned int src = irq - mpic->irq_offset; | 475 | unsigned int src = irq - mpic->irq_offset; |
486 | 476 | ||
487 | if (mpic_is_ht_interrupt(mpic, src)) | 477 | mpic_unmask_irq(irq); |
488 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
489 | 478 | ||
490 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 479 | if (irq_desc[irq].status & IRQ_LEVEL) |
480 | mpic_ht_end_irq(mpic, src); | ||
481 | } | ||
482 | |||
483 | static unsigned int mpic_startup_ht_irq(unsigned int irq) | ||
484 | { | ||
485 | struct mpic *mpic = mpic_from_irq(irq); | ||
486 | unsigned int src = irq - mpic->irq_offset; | ||
491 | 487 | ||
492 | mpic_disable_irq(irq); | 488 | mpic_unmask_irq(irq); |
489 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
490 | |||
491 | return 0; | ||
493 | } | 492 | } |
494 | 493 | ||
495 | static void mpic_end_irq(unsigned int irq) | 494 | static void mpic_shutdown_ht_irq(unsigned int irq) |
495 | { | ||
496 | struct mpic *mpic = mpic_from_irq(irq); | ||
497 | unsigned int src = irq - mpic->irq_offset; | ||
498 | |||
499 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
500 | mpic_mask_irq(irq); | ||
501 | } | ||
502 | |||
503 | static void mpic_end_ht_irq(unsigned int irq) | ||
496 | { | 504 | { |
497 | struct mpic *mpic = mpic_from_irq(irq); | 505 | struct mpic *mpic = mpic_from_irq(irq); |
506 | unsigned int src = irq - mpic->irq_offset; | ||
498 | 507 | ||
499 | #ifdef DEBUG_IRQ | 508 | #ifdef DEBUG_IRQ |
500 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 509 | DBG("%s: end_irq: %d\n", mpic->name, irq); |
@@ -504,21 +513,16 @@ static void mpic_end_irq(unsigned int irq) | |||
504 | * latched another edge interrupt coming in anyway | 513 | * latched another edge interrupt coming in anyway |
505 | */ | 514 | */ |
506 | 515 | ||
507 | #ifdef CONFIG_MPIC_BROKEN_U3 | 516 | if (irq_desc[irq].status & IRQ_LEVEL) |
508 | if (mpic->flags & MPIC_BROKEN_U3) { | 517 | mpic_ht_end_irq(mpic, src); |
509 | unsigned int src = irq - mpic->irq_offset; | ||
510 | if (mpic_is_ht_interrupt(mpic, src) && | ||
511 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
512 | mpic_ht_end_irq(mpic, src); | ||
513 | } | ||
514 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
515 | |||
516 | mpic_eoi(mpic); | 518 | mpic_eoi(mpic); |
517 | } | 519 | } |
518 | 520 | ||
521 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
522 | |||
519 | #ifdef CONFIG_SMP | 523 | #ifdef CONFIG_SMP |
520 | 524 | ||
521 | static void mpic_enable_ipi(unsigned int irq) | 525 | static void mpic_unmask_ipi(unsigned int irq) |
522 | { | 526 | { |
523 | struct mpic *mpic = mpic_from_ipi(irq); | 527 | struct mpic *mpic = mpic_from_ipi(irq); |
524 | unsigned int src = irq - mpic->ipi_offset; | 528 | unsigned int src = irq - mpic->ipi_offset; |
@@ -527,7 +531,7 @@ static void mpic_enable_ipi(unsigned int irq) | |||
527 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); | 531 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); |
528 | } | 532 | } |
529 | 533 | ||
530 | static void mpic_disable_ipi(unsigned int irq) | 534 | static void mpic_mask_ipi(unsigned int irq) |
531 | { | 535 | { |
532 | /* NEVER disable an IPI... that's just plain wrong! */ | 536 | /* NEVER disable an IPI... that's just plain wrong! */ |
533 | } | 537 | } |
@@ -560,6 +564,30 @@ 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 | ||
567 | static struct irq_chip mpic_irq_chip = { | ||
568 | .mask = mpic_mask_irq, | ||
569 | .unmask = mpic_unmask_irq, | ||
570 | .eoi = mpic_end_irq, | ||
571 | }; | ||
572 | |||
573 | #ifdef CONFIG_SMP | ||
574 | static struct irq_chip mpic_ipi_chip = { | ||
575 | .mask = mpic_mask_ipi, | ||
576 | .unmask = mpic_unmask_ipi, | ||
577 | .eoi = mpic_end_ipi, | ||
578 | }; | ||
579 | #endif /* CONFIG_SMP */ | ||
580 | |||
581 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
582 | static struct irq_chip mpic_irq_ht_chip = { | ||
583 | .startup = mpic_startup_ht_irq, | ||
584 | .shutdown = mpic_shutdown_ht_irq, | ||
585 | .mask = mpic_mask_irq, | ||
586 | .unmask = mpic_unmask_ht_irq, | ||
587 | .eoi = mpic_end_ht_irq, | ||
588 | }; | ||
589 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
590 | |||
563 | 591 | ||
564 | /* | 592 | /* |
565 | * Exported functions | 593 | * Exported functions |
@@ -589,19 +617,19 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
589 | memset(mpic, 0, sizeof(struct mpic)); | 617 | memset(mpic, 0, sizeof(struct mpic)); |
590 | mpic->name = name; | 618 | mpic->name = name; |
591 | 619 | ||
620 | mpic->hc_irq = mpic_irq_chip; | ||
592 | mpic->hc_irq.typename = name; | 621 | mpic->hc_irq.typename = name; |
593 | mpic->hc_irq.startup = mpic_startup_irq; | ||
594 | mpic->hc_irq.shutdown = mpic_shutdown_irq; | ||
595 | mpic->hc_irq.enable = mpic_enable_irq; | ||
596 | mpic->hc_irq.disable = mpic_disable_irq; | ||
597 | mpic->hc_irq.end = mpic_end_irq; | ||
598 | if (flags & MPIC_PRIMARY) | 622 | if (flags & MPIC_PRIMARY) |
599 | mpic->hc_irq.set_affinity = mpic_set_affinity; | 623 | mpic->hc_irq.set_affinity = mpic_set_affinity; |
624 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
625 | mpic->hc_ht_irq = mpic_irq_ht_chip; | ||
626 | mpic->hc_ht_irq.typename = name; | ||
627 | if (flags & MPIC_PRIMARY) | ||
628 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | ||
629 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
600 | #ifdef CONFIG_SMP | 630 | #ifdef CONFIG_SMP |
601 | mpic->hc_ipi.typename = name; | 631 | mpic->hc_ipi.typename = name; |
602 | mpic->hc_ipi.enable = mpic_enable_ipi; | 632 | mpic->hc_ipi = mpic_ipi_chip; |
603 | mpic->hc_ipi.disable = mpic_disable_ipi; | ||
604 | mpic->hc_ipi.end = mpic_end_ipi; | ||
605 | #endif /* CONFIG_SMP */ | 633 | #endif /* CONFIG_SMP */ |
606 | 634 | ||
607 | mpic->flags = flags; | 635 | mpic->flags = flags; |
@@ -697,28 +725,6 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
697 | mpic->num_sources = isu_first + mpic->isu_size; | 725 | mpic->num_sources = isu_first + mpic->isu_size; |
698 | } | 726 | } |
699 | 727 | ||
700 | void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler, | ||
701 | void *data) | ||
702 | { | ||
703 | struct mpic *mpic = mpic_find(irq, NULL); | ||
704 | unsigned long flags; | ||
705 | |||
706 | /* Synchronization here is a bit dodgy, so don't try to replace cascade | ||
707 | * interrupts on the fly too often ... but normally it's set up at boot. | ||
708 | */ | ||
709 | spin_lock_irqsave(&mpic_lock, flags); | ||
710 | if (mpic->cascade) | ||
711 | mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset); | ||
712 | mpic->cascade = NULL; | ||
713 | wmb(); | ||
714 | mpic->cascade_vec = irq - mpic->irq_offset; | ||
715 | mpic->cascade_data = data; | ||
716 | wmb(); | ||
717 | mpic->cascade = handler; | ||
718 | mpic_enable_irq(irq); | ||
719 | spin_unlock_irqrestore(&mpic_lock, flags); | ||
720 | } | ||
721 | |||
722 | void __init mpic_init(struct mpic *mpic) | 728 | void __init mpic_init(struct mpic *mpic) |
723 | { | 729 | { |
724 | int i; | 730 | int i; |
@@ -750,8 +756,10 @@ void __init mpic_init(struct mpic *mpic) | |||
750 | #ifdef CONFIG_SMP | 756 | #ifdef CONFIG_SMP |
751 | if (!(mpic->flags & MPIC_PRIMARY)) | 757 | if (!(mpic->flags & MPIC_PRIMARY)) |
752 | continue; | 758 | continue; |
753 | irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; | 759 | set_irq_chip_data(mpic->ipi_offset+i, mpic); |
754 | irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi; | 760 | set_irq_chip_and_handler(mpic->ipi_offset+i, |
761 | &mpic->hc_ipi, | ||
762 | handle_percpu_irq); | ||
755 | #endif /* CONFIG_SMP */ | 763 | #endif /* CONFIG_SMP */ |
756 | } | 764 | } |
757 | 765 | ||
@@ -763,7 +771,7 @@ void __init mpic_init(struct mpic *mpic) | |||
763 | /* Do the HT PIC fixups on U3 broken mpic */ | 771 | /* Do the HT PIC fixups on U3 broken mpic */ |
764 | DBG("MPIC flags: %x\n", mpic->flags); | 772 | DBG("MPIC flags: %x\n", mpic->flags); |
765 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) | 773 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) |
766 | mpic_scan_ht_pics(mpic); | 774 | mpic_scan_ht_pics(mpic); |
767 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 775 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
768 | 776 | ||
769 | for (i = 0; i < mpic->num_sources; i++) { | 777 | for (i = 0; i < mpic->num_sources; i++) { |
@@ -811,8 +819,17 @@ void __init mpic_init(struct mpic *mpic) | |||
811 | 819 | ||
812 | /* init linux descriptors */ | 820 | /* init linux descriptors */ |
813 | if (i < mpic->irq_count) { | 821 | if (i < mpic->irq_count) { |
814 | irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0; | 822 | struct irq_chip *chip = &mpic->hc_irq; |
815 | irq_desc[mpic->irq_offset+i].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); | ||
816 | } | 833 | } |
817 | } | 834 | } |
818 | 835 | ||
@@ -986,14 +1003,6 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) | |||
986 | #ifdef DEBUG_LOW | 1003 | #ifdef DEBUG_LOW |
987 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); | 1004 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); |
988 | #endif | 1005 | #endif |
989 | if (mpic->cascade && irq == mpic->cascade_vec) { | ||
990 | #ifdef DEBUG_LOW | ||
991 | DBG("%s: cascading ...\n", mpic->name); | ||
992 | #endif | ||
993 | irq = mpic->cascade(regs, mpic->cascade_data); | ||
994 | mpic_eoi(mpic); | ||
995 | return irq; | ||
996 | } | ||
997 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) | 1006 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) |
998 | return -1; | 1007 | return -1; |
999 | if (irq < MPIC_VEC_IPI_0) { | 1008 | if (irq < MPIC_VEC_IPI_0) { |