diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 128 |
1 files changed, 82 insertions, 46 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index eb7021815e2d..f91c065bed5a 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -147,6 +147,16 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
147 | 147 | ||
148 | #endif /* CONFIG_MPIC_WEIRD */ | 148 | #endif /* CONFIG_MPIC_WEIRD */ |
149 | 149 | ||
150 | static inline unsigned int mpic_processor_id(struct mpic *mpic) | ||
151 | { | ||
152 | unsigned int cpu = 0; | ||
153 | |||
154 | if (mpic->flags & MPIC_PRIMARY) | ||
155 | cpu = hard_smp_processor_id(); | ||
156 | |||
157 | return cpu; | ||
158 | } | ||
159 | |||
150 | /* | 160 | /* |
151 | * Register accessor functions | 161 | * Register accessor functions |
152 | */ | 162 | */ |
@@ -210,19 +220,14 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu | |||
210 | 220 | ||
211 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | 221 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) |
212 | { | 222 | { |
213 | unsigned int cpu = 0; | 223 | unsigned int cpu = mpic_processor_id(mpic); |
214 | 224 | ||
215 | if (mpic->flags & MPIC_PRIMARY) | ||
216 | cpu = hard_smp_processor_id(); | ||
217 | return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); | 225 | return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); |
218 | } | 226 | } |
219 | 227 | ||
220 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) | 228 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) |
221 | { | 229 | { |
222 | unsigned int cpu = 0; | 230 | unsigned int cpu = mpic_processor_id(mpic); |
223 | |||
224 | if (mpic->flags & MPIC_PRIMARY) | ||
225 | cpu = hard_smp_processor_id(); | ||
226 | 231 | ||
227 | _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); | 232 | _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); |
228 | } | 233 | } |
@@ -356,7 +361,7 @@ static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) | |||
356 | } | 361 | } |
357 | 362 | ||
358 | static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | 363 | static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, |
359 | unsigned int irqflags) | 364 | bool level) |
360 | { | 365 | { |
361 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; | 366 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; |
362 | unsigned long flags; | 367 | unsigned long flags; |
@@ -365,14 +370,14 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
365 | if (fixup->base == NULL) | 370 | if (fixup->base == NULL) |
366 | return; | 371 | return; |
367 | 372 | ||
368 | DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n", | 373 | DBG("startup_ht_interrupt(0x%x) index: %d\n", |
369 | source, irqflags, fixup->index); | 374 | source, fixup->index); |
370 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); | 375 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); |
371 | /* Enable and configure */ | 376 | /* Enable and configure */ |
372 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); | 377 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); |
373 | tmp = readl(fixup->base + 4); | 378 | tmp = readl(fixup->base + 4); |
374 | tmp &= ~(0x23U); | 379 | tmp &= ~(0x23U); |
375 | if (irqflags & IRQ_LEVEL) | 380 | if (level) |
376 | tmp |= 0x22; | 381 | tmp |= 0x22; |
377 | writel(tmp, fixup->base + 4); | 382 | writel(tmp, fixup->base + 4); |
378 | raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); | 383 | raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); |
@@ -384,8 +389,7 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
384 | #endif | 389 | #endif |
385 | } | 390 | } |
386 | 391 | ||
387 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | 392 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source) |
388 | unsigned int irqflags) | ||
389 | { | 393 | { |
390 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; | 394 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; |
391 | unsigned long flags; | 395 | unsigned long flags; |
@@ -394,7 +398,7 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
394 | if (fixup->base == NULL) | 398 | if (fixup->base == NULL) |
395 | return; | 399 | return; |
396 | 400 | ||
397 | DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags); | 401 | DBG("shutdown_ht_interrupt(0x%x)\n", source); |
398 | 402 | ||
399 | /* Disable */ | 403 | /* Disable */ |
400 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); | 404 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); |
@@ -611,7 +615,7 @@ static struct mpic *mpic_find(unsigned int irq) | |||
611 | if (irq < NUM_ISA_INTERRUPTS) | 615 | if (irq < NUM_ISA_INTERRUPTS) |
612 | return NULL; | 616 | return NULL; |
613 | 617 | ||
614 | return get_irq_chip_data(irq); | 618 | return irq_get_chip_data(irq); |
615 | } | 619 | } |
616 | 620 | ||
617 | /* Determine if the linux irq is an IPI */ | 621 | /* Determine if the linux irq is an IPI */ |
@@ -645,7 +649,7 @@ static inline struct mpic * mpic_from_ipi(struct irq_data *d) | |||
645 | /* Get the mpic structure from the irq number */ | 649 | /* Get the mpic structure from the irq number */ |
646 | static inline struct mpic * mpic_from_irq(unsigned int irq) | 650 | static inline struct mpic * mpic_from_irq(unsigned int irq) |
647 | { | 651 | { |
648 | return get_irq_chip_data(irq); | 652 | return irq_get_chip_data(irq); |
649 | } | 653 | } |
650 | 654 | ||
651 | /* Get the mpic structure from the irq data */ | 655 | /* Get the mpic structure from the irq data */ |
@@ -733,7 +737,7 @@ static void mpic_unmask_ht_irq(struct irq_data *d) | |||
733 | 737 | ||
734 | mpic_unmask_irq(d); | 738 | mpic_unmask_irq(d); |
735 | 739 | ||
736 | if (irq_to_desc(d->irq)->status & IRQ_LEVEL) | 740 | if (irqd_is_level_type(d)) |
737 | mpic_ht_end_irq(mpic, src); | 741 | mpic_ht_end_irq(mpic, src); |
738 | } | 742 | } |
739 | 743 | ||
@@ -743,7 +747,7 @@ static unsigned int mpic_startup_ht_irq(struct irq_data *d) | |||
743 | unsigned int src = mpic_irq_to_hw(d->irq); | 747 | unsigned int src = mpic_irq_to_hw(d->irq); |
744 | 748 | ||
745 | mpic_unmask_irq(d); | 749 | mpic_unmask_irq(d); |
746 | mpic_startup_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status); | 750 | mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); |
747 | 751 | ||
748 | return 0; | 752 | return 0; |
749 | } | 753 | } |
@@ -753,7 +757,7 @@ static void mpic_shutdown_ht_irq(struct irq_data *d) | |||
753 | struct mpic *mpic = mpic_from_irq_data(d); | 757 | struct mpic *mpic = mpic_from_irq_data(d); |
754 | unsigned int src = mpic_irq_to_hw(d->irq); | 758 | unsigned int src = mpic_irq_to_hw(d->irq); |
755 | 759 | ||
756 | mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status); | 760 | mpic_shutdown_ht_interrupt(mpic, src); |
757 | mpic_mask_irq(d); | 761 | mpic_mask_irq(d); |
758 | } | 762 | } |
759 | 763 | ||
@@ -770,7 +774,7 @@ static void mpic_end_ht_irq(struct irq_data *d) | |||
770 | * latched another edge interrupt coming in anyway | 774 | * latched another edge interrupt coming in anyway |
771 | */ | 775 | */ |
772 | 776 | ||
773 | if (irq_to_desc(d->irq)->status & IRQ_LEVEL) | 777 | if (irqd_is_level_type(d)) |
774 | mpic_ht_end_irq(mpic, src); | 778 | mpic_ht_end_irq(mpic, src); |
775 | mpic_eoi(mpic); | 779 | mpic_eoi(mpic); |
776 | } | 780 | } |
@@ -859,7 +863,6 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | |||
859 | { | 863 | { |
860 | struct mpic *mpic = mpic_from_irq_data(d); | 864 | struct mpic *mpic = mpic_from_irq_data(d); |
861 | unsigned int src = mpic_irq_to_hw(d->irq); | 865 | unsigned int src = mpic_irq_to_hw(d->irq); |
862 | struct irq_desc *desc = irq_to_desc(d->irq); | ||
863 | unsigned int vecpri, vold, vnew; | 866 | unsigned int vecpri, vold, vnew; |
864 | 867 | ||
865 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", | 868 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", |
@@ -874,10 +877,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | |||
874 | if (flow_type == IRQ_TYPE_NONE) | 877 | if (flow_type == IRQ_TYPE_NONE) |
875 | flow_type = IRQ_TYPE_LEVEL_LOW; | 878 | flow_type = IRQ_TYPE_LEVEL_LOW; |
876 | 879 | ||
877 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 880 | irqd_set_trigger_type(d, flow_type); |
878 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
879 | if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) | ||
880 | desc->status |= IRQ_LEVEL; | ||
881 | 881 | ||
882 | if (mpic_is_ht_interrupt(mpic, src)) | 882 | if (mpic_is_ht_interrupt(mpic, src)) |
883 | vecpri = MPIC_VECPRI_POLARITY_POSITIVE | | 883 | vecpri = MPIC_VECPRI_POLARITY_POSITIVE | |
@@ -892,7 +892,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | |||
892 | if (vold != vnew) | 892 | if (vold != vnew) |
893 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); | 893 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); |
894 | 894 | ||
895 | return 0; | 895 | return IRQ_SET_MASK_OK_NOCOPY;; |
896 | } | 896 | } |
897 | 897 | ||
898 | void mpic_set_vector(unsigned int virq, unsigned int vector) | 898 | void mpic_set_vector(unsigned int virq, unsigned int vector) |
@@ -913,6 +913,20 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) | |||
913 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); | 913 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); |
914 | } | 914 | } |
915 | 915 | ||
916 | void mpic_set_destination(unsigned int virq, unsigned int cpuid) | ||
917 | { | ||
918 | struct mpic *mpic = mpic_from_irq(virq); | ||
919 | unsigned int src = mpic_irq_to_hw(virq); | ||
920 | |||
921 | DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", | ||
922 | mpic, virq, src, cpuid); | ||
923 | |||
924 | if (src >= mpic->irq_count) | ||
925 | return; | ||
926 | |||
927 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); | ||
928 | } | ||
929 | |||
916 | static struct irq_chip mpic_irq_chip = { | 930 | static struct irq_chip mpic_irq_chip = { |
917 | .irq_mask = mpic_mask_irq, | 931 | .irq_mask = mpic_mask_irq, |
918 | .irq_unmask = mpic_unmask_irq, | 932 | .irq_unmask = mpic_unmask_irq, |
@@ -964,8 +978,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
964 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | 978 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); |
965 | 979 | ||
966 | DBG("mpic: mapping as IPI\n"); | 980 | DBG("mpic: mapping as IPI\n"); |
967 | set_irq_chip_data(virq, mpic); | 981 | irq_set_chip_data(virq, mpic); |
968 | set_irq_chip_and_handler(virq, &mpic->hc_ipi, | 982 | irq_set_chip_and_handler(virq, &mpic->hc_ipi, |
969 | handle_percpu_irq); | 983 | handle_percpu_irq); |
970 | return 0; | 984 | return 0; |
971 | } | 985 | } |
@@ -987,11 +1001,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
987 | 1001 | ||
988 | DBG("mpic: mapping to irq chip @%p\n", chip); | 1002 | DBG("mpic: mapping to irq chip @%p\n", chip); |
989 | 1003 | ||
990 | set_irq_chip_data(virq, mpic); | 1004 | irq_set_chip_data(virq, mpic); |
991 | set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); | 1005 | irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq); |
992 | 1006 | ||
993 | /* Set default irq type */ | 1007 | /* Set default irq type */ |
994 | set_irq_type(virq, IRQ_TYPE_NONE); | 1008 | irq_set_irq_type(virq, IRQ_TYPE_NONE); |
1009 | |||
1010 | /* If the MPIC was reset, then all vectors have already been | ||
1011 | * initialized. Otherwise, a per source lazy initialization | ||
1012 | * is done here. | ||
1013 | */ | ||
1014 | if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { | ||
1015 | mpic_set_vector(virq, hw); | ||
1016 | mpic_set_destination(virq, mpic_processor_id(mpic)); | ||
1017 | mpic_irq_set_priority(virq, 8); | ||
1018 | } | ||
995 | 1019 | ||
996 | return 0; | 1020 | return 0; |
997 | } | 1021 | } |
@@ -1040,6 +1064,11 @@ static struct irq_host_ops mpic_host_ops = { | |||
1040 | .xlate = mpic_host_xlate, | 1064 | .xlate = mpic_host_xlate, |
1041 | }; | 1065 | }; |
1042 | 1066 | ||
1067 | static int mpic_reset_prohibited(struct device_node *node) | ||
1068 | { | ||
1069 | return node && of_get_property(node, "pic-no-reset", NULL); | ||
1070 | } | ||
1071 | |||
1043 | /* | 1072 | /* |
1044 | * Exported functions | 1073 | * Exported functions |
1045 | */ | 1074 | */ |
@@ -1160,7 +1189,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1160 | mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); | 1189 | mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); |
1161 | 1190 | ||
1162 | /* Reset */ | 1191 | /* Reset */ |
1163 | if (flags & MPIC_WANTS_RESET) { | 1192 | |
1193 | /* When using a device-node, reset requests are only honored if the MPIC | ||
1194 | * is allowed to reset. | ||
1195 | */ | ||
1196 | if (mpic_reset_prohibited(node)) | ||
1197 | mpic->flags |= MPIC_NO_RESET; | ||
1198 | |||
1199 | if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { | ||
1200 | printk(KERN_DEBUG "mpic: Resetting\n"); | ||
1164 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | 1201 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), |
1165 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | 1202 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) |
1166 | | MPIC_GREG_GCONF_RESET); | 1203 | | MPIC_GREG_GCONF_RESET); |
@@ -1320,22 +1357,21 @@ void __init mpic_init(struct mpic *mpic) | |||
1320 | 1357 | ||
1321 | mpic_pasemi_msi_init(mpic); | 1358 | mpic_pasemi_msi_init(mpic); |
1322 | 1359 | ||
1323 | if (mpic->flags & MPIC_PRIMARY) | 1360 | cpu = mpic_processor_id(mpic); |
1324 | cpu = hard_smp_processor_id(); | ||
1325 | else | ||
1326 | cpu = 0; | ||
1327 | 1361 | ||
1328 | for (i = 0; i < mpic->num_sources; i++) { | 1362 | if (!(mpic->flags & MPIC_NO_RESET)) { |
1329 | /* start with vector = source number, and masked */ | 1363 | for (i = 0; i < mpic->num_sources; i++) { |
1330 | u32 vecpri = MPIC_VECPRI_MASK | i | | 1364 | /* start with vector = source number, and masked */ |
1331 | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | 1365 | u32 vecpri = MPIC_VECPRI_MASK | i | |
1366 | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | ||
1332 | 1367 | ||
1333 | /* check if protected */ | 1368 | /* check if protected */ |
1334 | if (mpic->protected && test_bit(i, mpic->protected)) | 1369 | if (mpic->protected && test_bit(i, mpic->protected)) |
1335 | continue; | 1370 | continue; |
1336 | /* init hw */ | 1371 | /* init hw */ |
1337 | mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); | 1372 | mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); |
1338 | mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); | 1373 | mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); |
1374 | } | ||
1339 | } | 1375 | } |
1340 | 1376 | ||
1341 | /* Init spurious vector */ | 1377 | /* Init spurious vector */ |