diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 257 |
1 files changed, 176 insertions, 81 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index f91c065bed5a..3a8de5bb628a 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * with various broken implementations of this HW. | 6 | * with various broken implementations of this HW. |
7 | * | 7 | * |
8 | * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. | 8 | * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. |
9 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||
9 | * | 10 | * |
10 | * This file is subject to the terms and conditions of the GNU General Public | 11 | * This file is subject to the terms and conditions of the GNU General Public |
11 | * License. See the file COPYING in the main directory of this archive | 12 | * License. See the file COPYING in the main directory of this archive |
@@ -27,6 +28,7 @@ | |||
27 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
28 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/syscore_ops.h> | ||
30 | 32 | ||
31 | #include <asm/ptrace.h> | 33 | #include <asm/ptrace.h> |
32 | #include <asm/signal.h> | 34 | #include <asm/signal.h> |
@@ -218,6 +220,28 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu | |||
218 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); | 220 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); |
219 | } | 221 | } |
220 | 222 | ||
223 | static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) | ||
224 | { | ||
225 | unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + | ||
226 | ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); | ||
227 | |||
228 | if (tm >= 4) | ||
229 | offset += 0x1000 / 4; | ||
230 | |||
231 | return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); | ||
232 | } | ||
233 | |||
234 | static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) | ||
235 | { | ||
236 | unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + | ||
237 | ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); | ||
238 | |||
239 | if (tm >= 4) | ||
240 | offset += 0x1000 / 4; | ||
241 | |||
242 | _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); | ||
243 | } | ||
244 | |||
221 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | 245 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) |
222 | { | 246 | { |
223 | unsigned int cpu = mpic_processor_id(mpic); | 247 | unsigned int cpu = mpic_processor_id(mpic); |
@@ -268,6 +292,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, | |||
268 | #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) | 292 | #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) |
269 | #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) | 293 | #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) |
270 | #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) | 294 | #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) |
295 | #define mpic_tm_read(i) _mpic_tm_read(mpic,(i)) | ||
296 | #define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v)) | ||
271 | #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) | 297 | #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) |
272 | #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) | 298 | #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) |
273 | #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) | 299 | #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) |
@@ -607,8 +633,6 @@ static int irq_choose_cpu(const struct cpumask *mask) | |||
607 | } | 633 | } |
608 | #endif | 634 | #endif |
609 | 635 | ||
610 | #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | ||
611 | |||
612 | /* Find an mpic associated with a given linux interrupt */ | 636 | /* Find an mpic associated with a given linux interrupt */ |
613 | static struct mpic *mpic_find(unsigned int irq) | 637 | static struct mpic *mpic_find(unsigned int irq) |
614 | { | 638 | { |
@@ -621,11 +645,18 @@ static struct mpic *mpic_find(unsigned int irq) | |||
621 | /* Determine if the linux irq is an IPI */ | 645 | /* Determine if the linux irq is an IPI */ |
622 | static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) | 646 | static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) |
623 | { | 647 | { |
624 | unsigned int src = mpic_irq_to_hw(irq); | 648 | unsigned int src = virq_to_hw(irq); |
625 | 649 | ||
626 | return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); | 650 | return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); |
627 | } | 651 | } |
628 | 652 | ||
653 | /* Determine if the linux irq is a timer */ | ||
654 | static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq) | ||
655 | { | ||
656 | unsigned int src = virq_to_hw(irq); | ||
657 | |||
658 | return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]); | ||
659 | } | ||
629 | 660 | ||
630 | /* Convert a cpu mask from logical to physical cpu numbers. */ | 661 | /* Convert a cpu mask from logical to physical cpu numbers. */ |
631 | static inline u32 mpic_physmask(u32 cpumask) | 662 | static inline u32 mpic_physmask(u32 cpumask) |
@@ -633,7 +664,7 @@ static inline u32 mpic_physmask(u32 cpumask) | |||
633 | int i; | 664 | int i; |
634 | u32 mask = 0; | 665 | u32 mask = 0; |
635 | 666 | ||
636 | for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) | 667 | for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) |
637 | mask |= (cpumask & 1) << get_hard_smp_processor_id(i); | 668 | mask |= (cpumask & 1) << get_hard_smp_processor_id(i); |
638 | return mask; | 669 | return mask; |
639 | } | 670 | } |
@@ -674,7 +705,7 @@ void mpic_unmask_irq(struct irq_data *d) | |||
674 | { | 705 | { |
675 | unsigned int loops = 100000; | 706 | unsigned int loops = 100000; |
676 | struct mpic *mpic = mpic_from_irq_data(d); | 707 | struct mpic *mpic = mpic_from_irq_data(d); |
677 | unsigned int src = mpic_irq_to_hw(d->irq); | 708 | unsigned int src = irqd_to_hwirq(d); |
678 | 709 | ||
679 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); | 710 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); |
680 | 711 | ||
@@ -695,7 +726,7 @@ void mpic_mask_irq(struct irq_data *d) | |||
695 | { | 726 | { |
696 | unsigned int loops = 100000; | 727 | unsigned int loops = 100000; |
697 | struct mpic *mpic = mpic_from_irq_data(d); | 728 | struct mpic *mpic = mpic_from_irq_data(d); |
698 | unsigned int src = mpic_irq_to_hw(d->irq); | 729 | unsigned int src = irqd_to_hwirq(d); |
699 | 730 | ||
700 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); | 731 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); |
701 | 732 | ||
@@ -733,7 +764,7 @@ void mpic_end_irq(struct irq_data *d) | |||
733 | static void mpic_unmask_ht_irq(struct irq_data *d) | 764 | static void mpic_unmask_ht_irq(struct irq_data *d) |
734 | { | 765 | { |
735 | struct mpic *mpic = mpic_from_irq_data(d); | 766 | struct mpic *mpic = mpic_from_irq_data(d); |
736 | unsigned int src = mpic_irq_to_hw(d->irq); | 767 | unsigned int src = irqd_to_hwirq(d); |
737 | 768 | ||
738 | mpic_unmask_irq(d); | 769 | mpic_unmask_irq(d); |
739 | 770 | ||
@@ -744,7 +775,7 @@ static void mpic_unmask_ht_irq(struct irq_data *d) | |||
744 | static unsigned int mpic_startup_ht_irq(struct irq_data *d) | 775 | static unsigned int mpic_startup_ht_irq(struct irq_data *d) |
745 | { | 776 | { |
746 | struct mpic *mpic = mpic_from_irq_data(d); | 777 | struct mpic *mpic = mpic_from_irq_data(d); |
747 | unsigned int src = mpic_irq_to_hw(d->irq); | 778 | unsigned int src = irqd_to_hwirq(d); |
748 | 779 | ||
749 | mpic_unmask_irq(d); | 780 | mpic_unmask_irq(d); |
750 | mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); | 781 | mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); |
@@ -755,7 +786,7 @@ static unsigned int mpic_startup_ht_irq(struct irq_data *d) | |||
755 | static void mpic_shutdown_ht_irq(struct irq_data *d) | 786 | static void mpic_shutdown_ht_irq(struct irq_data *d) |
756 | { | 787 | { |
757 | struct mpic *mpic = mpic_from_irq_data(d); | 788 | struct mpic *mpic = mpic_from_irq_data(d); |
758 | unsigned int src = mpic_irq_to_hw(d->irq); | 789 | unsigned int src = irqd_to_hwirq(d); |
759 | 790 | ||
760 | mpic_shutdown_ht_interrupt(mpic, src); | 791 | mpic_shutdown_ht_interrupt(mpic, src); |
761 | mpic_mask_irq(d); | 792 | mpic_mask_irq(d); |
@@ -764,7 +795,7 @@ static void mpic_shutdown_ht_irq(struct irq_data *d) | |||
764 | static void mpic_end_ht_irq(struct irq_data *d) | 795 | static void mpic_end_ht_irq(struct irq_data *d) |
765 | { | 796 | { |
766 | struct mpic *mpic = mpic_from_irq_data(d); | 797 | struct mpic *mpic = mpic_from_irq_data(d); |
767 | unsigned int src = mpic_irq_to_hw(d->irq); | 798 | unsigned int src = irqd_to_hwirq(d); |
768 | 799 | ||
769 | #ifdef DEBUG_IRQ | 800 | #ifdef DEBUG_IRQ |
770 | DBG("%s: end_irq: %d\n", mpic->name, d->irq); | 801 | DBG("%s: end_irq: %d\n", mpic->name, d->irq); |
@@ -785,7 +816,7 @@ static void mpic_end_ht_irq(struct irq_data *d) | |||
785 | static void mpic_unmask_ipi(struct irq_data *d) | 816 | static void mpic_unmask_ipi(struct irq_data *d) |
786 | { | 817 | { |
787 | struct mpic *mpic = mpic_from_ipi(d); | 818 | struct mpic *mpic = mpic_from_ipi(d); |
788 | unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0]; | 819 | unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; |
789 | 820 | ||
790 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); | 821 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); |
791 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); | 822 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); |
@@ -812,27 +843,42 @@ static void mpic_end_ipi(struct irq_data *d) | |||
812 | 843 | ||
813 | #endif /* CONFIG_SMP */ | 844 | #endif /* CONFIG_SMP */ |
814 | 845 | ||
846 | static void mpic_unmask_tm(struct irq_data *d) | ||
847 | { | ||
848 | struct mpic *mpic = mpic_from_irq_data(d); | ||
849 | unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; | ||
850 | |||
851 | DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src); | ||
852 | mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); | ||
853 | mpic_tm_read(src); | ||
854 | } | ||
855 | |||
856 | static void mpic_mask_tm(struct irq_data *d) | ||
857 | { | ||
858 | struct mpic *mpic = mpic_from_irq_data(d); | ||
859 | unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; | ||
860 | |||
861 | mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK); | ||
862 | mpic_tm_read(src); | ||
863 | } | ||
864 | |||
815 | int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, | 865 | int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, |
816 | bool force) | 866 | bool force) |
817 | { | 867 | { |
818 | struct mpic *mpic = mpic_from_irq_data(d); | 868 | struct mpic *mpic = mpic_from_irq_data(d); |
819 | unsigned int src = mpic_irq_to_hw(d->irq); | 869 | unsigned int src = irqd_to_hwirq(d); |
820 | 870 | ||
821 | if (mpic->flags & MPIC_SINGLE_DEST_CPU) { | 871 | if (mpic->flags & MPIC_SINGLE_DEST_CPU) { |
822 | int cpuid = irq_choose_cpu(cpumask); | 872 | int cpuid = irq_choose_cpu(cpumask); |
823 | 873 | ||
824 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); | 874 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); |
825 | } else { | 875 | } else { |
826 | cpumask_var_t tmp; | 876 | u32 mask = cpumask_bits(cpumask)[0]; |
827 | |||
828 | alloc_cpumask_var(&tmp, GFP_KERNEL); | ||
829 | 877 | ||
830 | cpumask_and(tmp, cpumask, cpu_online_mask); | 878 | mask &= cpumask_bits(cpu_online_mask)[0]; |
831 | 879 | ||
832 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), | 880 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), |
833 | mpic_physmask(cpumask_bits(tmp)[0])); | 881 | mpic_physmask(mask)); |
834 | |||
835 | free_cpumask_var(tmp); | ||
836 | } | 882 | } |
837 | 883 | ||
838 | return 0; | 884 | return 0; |
@@ -862,7 +908,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) | |||
862 | int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | 908 | int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) |
863 | { | 909 | { |
864 | struct mpic *mpic = mpic_from_irq_data(d); | 910 | struct mpic *mpic = mpic_from_irq_data(d); |
865 | unsigned int src = mpic_irq_to_hw(d->irq); | 911 | unsigned int src = irqd_to_hwirq(d); |
866 | unsigned int vecpri, vold, vnew; | 912 | unsigned int vecpri, vold, vnew; |
867 | 913 | ||
868 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", | 914 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", |
@@ -898,7 +944,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | |||
898 | void mpic_set_vector(unsigned int virq, unsigned int vector) | 944 | void mpic_set_vector(unsigned int virq, unsigned int vector) |
899 | { | 945 | { |
900 | struct mpic *mpic = mpic_from_irq(virq); | 946 | struct mpic *mpic = mpic_from_irq(virq); |
901 | unsigned int src = mpic_irq_to_hw(virq); | 947 | unsigned int src = virq_to_hw(virq); |
902 | unsigned int vecpri; | 948 | unsigned int vecpri; |
903 | 949 | ||
904 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", | 950 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", |
@@ -916,7 +962,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) | |||
916 | void mpic_set_destination(unsigned int virq, unsigned int cpuid) | 962 | void mpic_set_destination(unsigned int virq, unsigned int cpuid) |
917 | { | 963 | { |
918 | struct mpic *mpic = mpic_from_irq(virq); | 964 | struct mpic *mpic = mpic_from_irq(virq); |
919 | unsigned int src = mpic_irq_to_hw(virq); | 965 | unsigned int src = virq_to_hw(virq); |
920 | 966 | ||
921 | DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", | 967 | DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", |
922 | mpic, virq, src, cpuid); | 968 | mpic, virq, src, cpuid); |
@@ -942,6 +988,12 @@ static struct irq_chip mpic_ipi_chip = { | |||
942 | }; | 988 | }; |
943 | #endif /* CONFIG_SMP */ | 989 | #endif /* CONFIG_SMP */ |
944 | 990 | ||
991 | static struct irq_chip mpic_tm_chip = { | ||
992 | .irq_mask = mpic_mask_tm, | ||
993 | .irq_unmask = mpic_unmask_tm, | ||
994 | .irq_eoi = mpic_end_irq, | ||
995 | }; | ||
996 | |||
945 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 997 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
946 | static struct irq_chip mpic_irq_ht_chip = { | 998 | static struct irq_chip mpic_irq_ht_chip = { |
947 | .irq_startup = mpic_startup_ht_irq, | 999 | .irq_startup = mpic_startup_ht_irq, |
@@ -985,6 +1037,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
985 | } | 1037 | } |
986 | #endif /* CONFIG_SMP */ | 1038 | #endif /* CONFIG_SMP */ |
987 | 1039 | ||
1040 | if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { | ||
1041 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | ||
1042 | |||
1043 | DBG("mpic: mapping as timer\n"); | ||
1044 | irq_set_chip_data(virq, mpic); | ||
1045 | irq_set_chip_and_handler(virq, &mpic->hc_tm, | ||
1046 | handle_fasteoi_irq); | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
988 | if (hw >= mpic->irq_count) | 1050 | if (hw >= mpic->irq_count) |
989 | return -EINVAL; | 1051 | return -EINVAL; |
990 | 1052 | ||
@@ -1025,6 +1087,7 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
1025 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 1087 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
1026 | 1088 | ||
1027 | { | 1089 | { |
1090 | struct mpic *mpic = h->host_data; | ||
1028 | static unsigned char map_mpic_senses[4] = { | 1091 | static unsigned char map_mpic_senses[4] = { |
1029 | IRQ_TYPE_EDGE_RISING, | 1092 | IRQ_TYPE_EDGE_RISING, |
1030 | IRQ_TYPE_LEVEL_LOW, | 1093 | IRQ_TYPE_LEVEL_LOW, |
@@ -1033,7 +1096,38 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
1033 | }; | 1096 | }; |
1034 | 1097 | ||
1035 | *out_hwirq = intspec[0]; | 1098 | *out_hwirq = intspec[0]; |
1036 | if (intsize > 1) { | 1099 | if (intsize >= 4 && (mpic->flags & MPIC_FSL)) { |
1100 | /* | ||
1101 | * Freescale MPIC with extended intspec: | ||
1102 | * First two cells are as usual. Third specifies | ||
1103 | * an "interrupt type". Fourth is type-specific data. | ||
1104 | * | ||
1105 | * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt | ||
1106 | */ | ||
1107 | switch (intspec[2]) { | ||
1108 | case 0: | ||
1109 | case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ | ||
1110 | break; | ||
1111 | case 2: | ||
1112 | if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | *out_hwirq = mpic->ipi_vecs[intspec[0]]; | ||
1116 | break; | ||
1117 | case 3: | ||
1118 | if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs)) | ||
1119 | return -EINVAL; | ||
1120 | |||
1121 | *out_hwirq = mpic->timer_vecs[intspec[0]]; | ||
1122 | break; | ||
1123 | default: | ||
1124 | pr_debug("%s: unknown irq type %u\n", | ||
1125 | __func__, intspec[2]); | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | *out_flags = map_mpic_senses[intspec[1] & 3]; | ||
1130 | } else if (intsize > 1) { | ||
1037 | u32 mask = 0x3; | 1131 | u32 mask = 0x3; |
1038 | 1132 | ||
1039 | /* Apple invented a new race of encoding on machines with | 1133 | /* Apple invented a new race of encoding on machines with |
@@ -1109,6 +1203,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1109 | mpic->hc_ipi.name = name; | 1203 | mpic->hc_ipi.name = name; |
1110 | #endif /* CONFIG_SMP */ | 1204 | #endif /* CONFIG_SMP */ |
1111 | 1205 | ||
1206 | mpic->hc_tm = mpic_tm_chip; | ||
1207 | mpic->hc_tm.name = name; | ||
1208 | |||
1112 | mpic->flags = flags; | 1209 | mpic->flags = flags; |
1113 | mpic->isu_size = isu_size; | 1210 | mpic->isu_size = isu_size; |
1114 | mpic->irq_count = irq_count; | 1211 | mpic->irq_count = irq_count; |
@@ -1119,10 +1216,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1119 | else | 1216 | else |
1120 | intvec_top = 255; | 1217 | intvec_top = 255; |
1121 | 1218 | ||
1122 | mpic->timer_vecs[0] = intvec_top - 8; | 1219 | mpic->timer_vecs[0] = intvec_top - 12; |
1123 | mpic->timer_vecs[1] = intvec_top - 7; | 1220 | mpic->timer_vecs[1] = intvec_top - 11; |
1124 | mpic->timer_vecs[2] = intvec_top - 6; | 1221 | mpic->timer_vecs[2] = intvec_top - 10; |
1125 | mpic->timer_vecs[3] = intvec_top - 5; | 1222 | mpic->timer_vecs[3] = intvec_top - 9; |
1223 | mpic->timer_vecs[4] = intvec_top - 8; | ||
1224 | mpic->timer_vecs[5] = intvec_top - 7; | ||
1225 | mpic->timer_vecs[6] = intvec_top - 6; | ||
1226 | mpic->timer_vecs[7] = intvec_top - 5; | ||
1126 | mpic->ipi_vecs[0] = intvec_top - 4; | 1227 | mpic->ipi_vecs[0] = intvec_top - 4; |
1127 | mpic->ipi_vecs[1] = intvec_top - 3; | 1228 | mpic->ipi_vecs[1] = intvec_top - 3; |
1128 | mpic->ipi_vecs[2] = intvec_top - 2; | 1229 | mpic->ipi_vecs[2] = intvec_top - 2; |
@@ -1132,6 +1233,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1132 | /* Check for "big-endian" in device-tree */ | 1233 | /* Check for "big-endian" in device-tree */ |
1133 | if (node && of_get_property(node, "big-endian", NULL) != NULL) | 1234 | if (node && of_get_property(node, "big-endian", NULL) != NULL) |
1134 | mpic->flags |= MPIC_BIG_ENDIAN; | 1235 | mpic->flags |= MPIC_BIG_ENDIAN; |
1236 | if (node && of_device_is_compatible(node, "fsl,mpic")) | ||
1237 | mpic->flags |= MPIC_FSL; | ||
1135 | 1238 | ||
1136 | /* Look for protected sources */ | 1239 | /* Look for protected sources */ |
1137 | if (node) { | 1240 | if (node) { |
@@ -1323,15 +1426,17 @@ void __init mpic_init(struct mpic *mpic) | |||
1323 | /* Set current processor priority to max */ | 1426 | /* Set current processor priority to max */ |
1324 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); | 1427 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); |
1325 | 1428 | ||
1326 | /* Initialize timers: just disable them all */ | 1429 | /* Initialize timers to our reserved vectors and mask them for now */ |
1327 | for (i = 0; i < 4; i++) { | 1430 | for (i = 0; i < 4; i++) { |
1328 | mpic_write(mpic->tmregs, | 1431 | mpic_write(mpic->tmregs, |
1329 | i * MPIC_INFO(TIMER_STRIDE) + | 1432 | i * MPIC_INFO(TIMER_STRIDE) + |
1330 | MPIC_INFO(TIMER_DESTINATION), 0); | 1433 | MPIC_INFO(TIMER_DESTINATION), |
1434 | 1 << hard_smp_processor_id()); | ||
1331 | mpic_write(mpic->tmregs, | 1435 | mpic_write(mpic->tmregs, |
1332 | i * MPIC_INFO(TIMER_STRIDE) + | 1436 | i * MPIC_INFO(TIMER_STRIDE) + |
1333 | MPIC_INFO(TIMER_VECTOR_PRI), | 1437 | MPIC_INFO(TIMER_VECTOR_PRI), |
1334 | MPIC_VECPRI_MASK | | 1438 | MPIC_VECPRI_MASK | |
1439 | (9 << MPIC_VECPRI_PRIORITY_SHIFT) | | ||
1335 | (mpic->timer_vecs[0] + i)); | 1440 | (mpic->timer_vecs[0] + i)); |
1336 | } | 1441 | } |
1337 | 1442 | ||
@@ -1427,7 +1532,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable) | |||
1427 | void mpic_irq_set_priority(unsigned int irq, unsigned int pri) | 1532 | void mpic_irq_set_priority(unsigned int irq, unsigned int pri) |
1428 | { | 1533 | { |
1429 | struct mpic *mpic = mpic_find(irq); | 1534 | struct mpic *mpic = mpic_find(irq); |
1430 | unsigned int src = mpic_irq_to_hw(irq); | 1535 | unsigned int src = virq_to_hw(irq); |
1431 | unsigned long flags; | 1536 | unsigned long flags; |
1432 | u32 reg; | 1537 | u32 reg; |
1433 | 1538 | ||
@@ -1440,6 +1545,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) | |||
1440 | ~MPIC_VECPRI_PRIORITY_MASK; | 1545 | ~MPIC_VECPRI_PRIORITY_MASK; |
1441 | mpic_ipi_write(src - mpic->ipi_vecs[0], | 1546 | mpic_ipi_write(src - mpic->ipi_vecs[0], |
1442 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | 1547 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); |
1548 | } else if (mpic_is_tm(mpic, irq)) { | ||
1549 | reg = mpic_tm_read(src - mpic->timer_vecs[0]) & | ||
1550 | ~MPIC_VECPRI_PRIORITY_MASK; | ||
1551 | mpic_tm_write(src - mpic->timer_vecs[0], | ||
1552 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | ||
1443 | } else { | 1553 | } else { |
1444 | reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 1554 | reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
1445 | & ~MPIC_VECPRI_PRIORITY_MASK; | 1555 | & ~MPIC_VECPRI_PRIORITY_MASK; |
@@ -1619,46 +1729,28 @@ void mpic_request_ipis(void) | |||
1619 | } | 1729 | } |
1620 | } | 1730 | } |
1621 | 1731 | ||
1622 | static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) | 1732 | void smp_mpic_message_pass(int cpu, int msg) |
1623 | { | 1733 | { |
1624 | struct mpic *mpic = mpic_primary; | 1734 | struct mpic *mpic = mpic_primary; |
1735 | u32 physmask; | ||
1625 | 1736 | ||
1626 | BUG_ON(mpic == NULL); | 1737 | BUG_ON(mpic == NULL); |
1627 | 1738 | ||
1628 | #ifdef DEBUG_IPI | ||
1629 | DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); | ||
1630 | #endif | ||
1631 | |||
1632 | mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + | ||
1633 | ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), | ||
1634 | mpic_physmask(cpumask_bits(cpu_mask)[0])); | ||
1635 | } | ||
1636 | |||
1637 | void smp_mpic_message_pass(int target, int msg) | ||
1638 | { | ||
1639 | cpumask_var_t tmp; | ||
1640 | |||
1641 | /* make sure we're sending something that translates to an IPI */ | 1739 | /* make sure we're sending something that translates to an IPI */ |
1642 | if ((unsigned int)msg > 3) { | 1740 | if ((unsigned int)msg > 3) { |
1643 | printk("SMP %d: smp_message_pass: unknown msg %d\n", | 1741 | printk("SMP %d: smp_message_pass: unknown msg %d\n", |
1644 | smp_processor_id(), msg); | 1742 | smp_processor_id(), msg); |
1645 | return; | 1743 | return; |
1646 | } | 1744 | } |
1647 | switch (target) { | 1745 | |
1648 | case MSG_ALL: | 1746 | #ifdef DEBUG_IPI |
1649 | mpic_send_ipi(msg, cpu_online_mask); | 1747 | DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg); |
1650 | break; | 1748 | #endif |
1651 | case MSG_ALL_BUT_SELF: | 1749 | |
1652 | alloc_cpumask_var(&tmp, GFP_NOWAIT); | 1750 | physmask = 1 << get_hard_smp_processor_id(cpu); |
1653 | cpumask_andnot(tmp, cpu_online_mask, | 1751 | |
1654 | cpumask_of(smp_processor_id())); | 1752 | mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + |
1655 | mpic_send_ipi(msg, tmp); | 1753 | msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask); |
1656 | free_cpumask_var(tmp); | ||
1657 | break; | ||
1658 | default: | ||
1659 | mpic_send_ipi(msg, cpumask_of(target)); | ||
1660 | break; | ||
1661 | } | ||
1662 | } | 1754 | } |
1663 | 1755 | ||
1664 | int __init smp_mpic_probe(void) | 1756 | int __init smp_mpic_probe(void) |
@@ -1702,9 +1794,8 @@ void mpic_reset_core(int cpu) | |||
1702 | #endif /* CONFIG_SMP */ | 1794 | #endif /* CONFIG_SMP */ |
1703 | 1795 | ||
1704 | #ifdef CONFIG_PM | 1796 | #ifdef CONFIG_PM |
1705 | static int mpic_suspend(struct sys_device *dev, pm_message_t state) | 1797 | static void mpic_suspend_one(struct mpic *mpic) |
1706 | { | 1798 | { |
1707 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
1708 | int i; | 1799 | int i; |
1709 | 1800 | ||
1710 | for (i = 0; i < mpic->num_sources; i++) { | 1801 | for (i = 0; i < mpic->num_sources; i++) { |
@@ -1713,13 +1804,22 @@ static int mpic_suspend(struct sys_device *dev, pm_message_t state) | |||
1713 | mpic->save_data[i].dest = | 1804 | mpic->save_data[i].dest = |
1714 | mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); | 1805 | mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); |
1715 | } | 1806 | } |
1807 | } | ||
1808 | |||
1809 | static int mpic_suspend(void) | ||
1810 | { | ||
1811 | struct mpic *mpic = mpics; | ||
1812 | |||
1813 | while (mpic) { | ||
1814 | mpic_suspend_one(mpic); | ||
1815 | mpic = mpic->next; | ||
1816 | } | ||
1716 | 1817 | ||
1717 | return 0; | 1818 | return 0; |
1718 | } | 1819 | } |
1719 | 1820 | ||
1720 | static int mpic_resume(struct sys_device *dev) | 1821 | static void mpic_resume_one(struct mpic *mpic) |
1721 | { | 1822 | { |
1722 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
1723 | int i; | 1823 | int i; |
1724 | 1824 | ||
1725 | for (i = 0; i < mpic->num_sources; i++) { | 1825 | for (i = 0; i < mpic->num_sources; i++) { |
@@ -1746,33 +1846,28 @@ static int mpic_resume(struct sys_device *dev) | |||
1746 | } | 1846 | } |
1747 | #endif | 1847 | #endif |
1748 | } /* end for loop */ | 1848 | } /* end for loop */ |
1849 | } | ||
1749 | 1850 | ||
1750 | return 0; | 1851 | static void mpic_resume(void) |
1852 | { | ||
1853 | struct mpic *mpic = mpics; | ||
1854 | |||
1855 | while (mpic) { | ||
1856 | mpic_resume_one(mpic); | ||
1857 | mpic = mpic->next; | ||
1858 | } | ||
1751 | } | 1859 | } |
1752 | #endif | ||
1753 | 1860 | ||
1754 | static struct sysdev_class mpic_sysclass = { | 1861 | static struct syscore_ops mpic_syscore_ops = { |
1755 | #ifdef CONFIG_PM | ||
1756 | .resume = mpic_resume, | 1862 | .resume = mpic_resume, |
1757 | .suspend = mpic_suspend, | 1863 | .suspend = mpic_suspend, |
1758 | #endif | ||
1759 | .name = "mpic", | ||
1760 | }; | 1864 | }; |
1761 | 1865 | ||
1762 | static int mpic_init_sys(void) | 1866 | static int mpic_init_sys(void) |
1763 | { | 1867 | { |
1764 | struct mpic *mpic = mpics; | 1868 | register_syscore_ops(&mpic_syscore_ops); |
1765 | int error, id = 0; | 1869 | return 0; |
1766 | |||
1767 | error = sysdev_class_register(&mpic_sysclass); | ||
1768 | |||
1769 | while (mpic && !error) { | ||
1770 | mpic->sysdev.cls = &mpic_sysclass; | ||
1771 | mpic->sysdev.id = id++; | ||
1772 | error = sysdev_register(&mpic->sysdev); | ||
1773 | mpic = mpic->next; | ||
1774 | } | ||
1775 | return error; | ||
1776 | } | 1870 | } |
1777 | 1871 | ||
1778 | device_initcall(mpic_init_sys); | 1872 | device_initcall(mpic_init_sys); |
1873 | #endif | ||