aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-05-19 23:43:47 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-05-19 23:43:47 -0400
commit3d07f0e83d4323d2cd45cc583f7cf1957aca3cac (patch)
tree279203d24b3a366ed6da93a3f9664409eb1a8488 /arch/powerpc/sysdev/mpic.c
parent593adf317cf165f7c66facf2285db9d4befbd1c0 (diff)
parentbbfff72ee3e76bd4712b87386af00bfe97114bc9 (diff)
Merge remote branch 'kumar/next' into next
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c129
1 files changed, 122 insertions, 7 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 53121f625068..57e954142c70 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
@@ -218,6 +219,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); 219 _mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
219} 220}
220 221
222static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
223{
224 unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
225 ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
226
227 if (tm >= 4)
228 offset += 0x1000 / 4;
229
230 return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
231}
232
233static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
234{
235 unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
236 ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
237
238 if (tm >= 4)
239 offset += 0x1000 / 4;
240
241 _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
242}
243
221static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 244static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
222{ 245{
223 unsigned int cpu = mpic_processor_id(mpic); 246 unsigned int cpu = mpic_processor_id(mpic);
@@ -268,6 +291,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)) 291#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)) 292#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i))
270#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 293#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v))
294#define mpic_tm_read(i) _mpic_tm_read(mpic,(i))
295#define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v))
271#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 296#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i))
272#define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 297#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)) 298#define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r))
@@ -624,6 +649,13 @@ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
624 return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); 649 return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
625} 650}
626 651
652/* Determine if the linux irq is a timer */
653static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq)
654{
655 unsigned int src = virq_to_hw(irq);
656
657 return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]);
658}
627 659
628/* Convert a cpu mask from logical to physical cpu numbers. */ 660/* Convert a cpu mask from logical to physical cpu numbers. */
629static inline u32 mpic_physmask(u32 cpumask) 661static inline u32 mpic_physmask(u32 cpumask)
@@ -810,6 +842,25 @@ static void mpic_end_ipi(struct irq_data *d)
810 842
811#endif /* CONFIG_SMP */ 843#endif /* CONFIG_SMP */
812 844
845static void mpic_unmask_tm(struct irq_data *d)
846{
847 struct mpic *mpic = mpic_from_irq_data(d);
848 unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0];
849
850 DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src);
851 mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK);
852 mpic_tm_read(src);
853}
854
855static void mpic_mask_tm(struct irq_data *d)
856{
857 struct mpic *mpic = mpic_from_irq_data(d);
858 unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0];
859
860 mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK);
861 mpic_tm_read(src);
862}
863
813int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 864int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
814 bool force) 865 bool force)
815{ 866{
@@ -936,6 +987,12 @@ static struct irq_chip mpic_ipi_chip = {
936}; 987};
937#endif /* CONFIG_SMP */ 988#endif /* CONFIG_SMP */
938 989
990static struct irq_chip mpic_tm_chip = {
991 .irq_mask = mpic_mask_tm,
992 .irq_unmask = mpic_unmask_tm,
993 .irq_eoi = mpic_end_irq,
994};
995
939#ifdef CONFIG_MPIC_U3_HT_IRQS 996#ifdef CONFIG_MPIC_U3_HT_IRQS
940static struct irq_chip mpic_irq_ht_chip = { 997static struct irq_chip mpic_irq_ht_chip = {
941 .irq_startup = mpic_startup_ht_irq, 998 .irq_startup = mpic_startup_ht_irq,
@@ -979,6 +1036,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
979 } 1036 }
980#endif /* CONFIG_SMP */ 1037#endif /* CONFIG_SMP */
981 1038
1039 if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) {
1040 WARN_ON(!(mpic->flags & MPIC_PRIMARY));
1041
1042 DBG("mpic: mapping as timer\n");
1043 irq_set_chip_data(virq, mpic);
1044 irq_set_chip_and_handler(virq, &mpic->hc_tm,
1045 handle_fasteoi_irq);
1046 return 0;
1047 }
1048
982 if (hw >= mpic->irq_count) 1049 if (hw >= mpic->irq_count)
983 return -EINVAL; 1050 return -EINVAL;
984 1051
@@ -1019,6 +1086,7 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
1019 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 1086 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
1020 1087
1021{ 1088{
1089 struct mpic *mpic = h->host_data;
1022 static unsigned char map_mpic_senses[4] = { 1090 static unsigned char map_mpic_senses[4] = {
1023 IRQ_TYPE_EDGE_RISING, 1091 IRQ_TYPE_EDGE_RISING,
1024 IRQ_TYPE_LEVEL_LOW, 1092 IRQ_TYPE_LEVEL_LOW,
@@ -1027,7 +1095,38 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
1027 }; 1095 };
1028 1096
1029 *out_hwirq = intspec[0]; 1097 *out_hwirq = intspec[0];
1030 if (intsize > 1) { 1098 if (intsize >= 4 && (mpic->flags & MPIC_FSL)) {
1099 /*
1100 * Freescale MPIC with extended intspec:
1101 * First two cells are as usual. Third specifies
1102 * an "interrupt type". Fourth is type-specific data.
1103 *
1104 * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
1105 */
1106 switch (intspec[2]) {
1107 case 0:
1108 case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
1109 break;
1110 case 2:
1111 if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
1112 return -EINVAL;
1113
1114 *out_hwirq = mpic->ipi_vecs[intspec[0]];
1115 break;
1116 case 3:
1117 if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs))
1118 return -EINVAL;
1119
1120 *out_hwirq = mpic->timer_vecs[intspec[0]];
1121 break;
1122 default:
1123 pr_debug("%s: unknown irq type %u\n",
1124 __func__, intspec[2]);
1125 return -EINVAL;
1126 }
1127
1128 *out_flags = map_mpic_senses[intspec[1] & 3];
1129 } else if (intsize > 1) {
1031 u32 mask = 0x3; 1130 u32 mask = 0x3;
1032 1131
1033 /* Apple invented a new race of encoding on machines with 1132 /* Apple invented a new race of encoding on machines with
@@ -1103,6 +1202,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1103 mpic->hc_ipi.name = name; 1202 mpic->hc_ipi.name = name;
1104#endif /* CONFIG_SMP */ 1203#endif /* CONFIG_SMP */
1105 1204
1205 mpic->hc_tm = mpic_tm_chip;
1206 mpic->hc_tm.name = name;
1207
1106 mpic->flags = flags; 1208 mpic->flags = flags;
1107 mpic->isu_size = isu_size; 1209 mpic->isu_size = isu_size;
1108 mpic->irq_count = irq_count; 1210 mpic->irq_count = irq_count;
@@ -1113,10 +1215,14 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1113 else 1215 else
1114 intvec_top = 255; 1216 intvec_top = 255;
1115 1217
1116 mpic->timer_vecs[0] = intvec_top - 8; 1218 mpic->timer_vecs[0] = intvec_top - 12;
1117 mpic->timer_vecs[1] = intvec_top - 7; 1219 mpic->timer_vecs[1] = intvec_top - 11;
1118 mpic->timer_vecs[2] = intvec_top - 6; 1220 mpic->timer_vecs[2] = intvec_top - 10;
1119 mpic->timer_vecs[3] = intvec_top - 5; 1221 mpic->timer_vecs[3] = intvec_top - 9;
1222 mpic->timer_vecs[4] = intvec_top - 8;
1223 mpic->timer_vecs[5] = intvec_top - 7;
1224 mpic->timer_vecs[6] = intvec_top - 6;
1225 mpic->timer_vecs[7] = intvec_top - 5;
1120 mpic->ipi_vecs[0] = intvec_top - 4; 1226 mpic->ipi_vecs[0] = intvec_top - 4;
1121 mpic->ipi_vecs[1] = intvec_top - 3; 1227 mpic->ipi_vecs[1] = intvec_top - 3;
1122 mpic->ipi_vecs[2] = intvec_top - 2; 1228 mpic->ipi_vecs[2] = intvec_top - 2;
@@ -1126,6 +1232,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1126 /* Check for "big-endian" in device-tree */ 1232 /* Check for "big-endian" in device-tree */
1127 if (node && of_get_property(node, "big-endian", NULL) != NULL) 1233 if (node && of_get_property(node, "big-endian", NULL) != NULL)
1128 mpic->flags |= MPIC_BIG_ENDIAN; 1234 mpic->flags |= MPIC_BIG_ENDIAN;
1235 if (node && of_device_is_compatible(node, "fsl,mpic"))
1236 mpic->flags |= MPIC_FSL;
1129 1237
1130 /* Look for protected sources */ 1238 /* Look for protected sources */
1131 if (node) { 1239 if (node) {
@@ -1317,15 +1425,17 @@ void __init mpic_init(struct mpic *mpic)
1317 /* Set current processor priority to max */ 1425 /* Set current processor priority to max */
1318 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 1426 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
1319 1427
1320 /* Initialize timers: just disable them all */ 1428 /* Initialize timers to our reserved vectors and mask them for now */
1321 for (i = 0; i < 4; i++) { 1429 for (i = 0; i < 4; i++) {
1322 mpic_write(mpic->tmregs, 1430 mpic_write(mpic->tmregs,
1323 i * MPIC_INFO(TIMER_STRIDE) + 1431 i * MPIC_INFO(TIMER_STRIDE) +
1324 MPIC_INFO(TIMER_DESTINATION), 0); 1432 MPIC_INFO(TIMER_DESTINATION),
1433 1 << hard_smp_processor_id());
1325 mpic_write(mpic->tmregs, 1434 mpic_write(mpic->tmregs,
1326 i * MPIC_INFO(TIMER_STRIDE) + 1435 i * MPIC_INFO(TIMER_STRIDE) +
1327 MPIC_INFO(TIMER_VECTOR_PRI), 1436 MPIC_INFO(TIMER_VECTOR_PRI),
1328 MPIC_VECPRI_MASK | 1437 MPIC_VECPRI_MASK |
1438 (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
1329 (mpic->timer_vecs[0] + i)); 1439 (mpic->timer_vecs[0] + i));
1330 } 1440 }
1331 1441
@@ -1434,6 +1544,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
1434 ~MPIC_VECPRI_PRIORITY_MASK; 1544 ~MPIC_VECPRI_PRIORITY_MASK;
1435 mpic_ipi_write(src - mpic->ipi_vecs[0], 1545 mpic_ipi_write(src - mpic->ipi_vecs[0],
1436 reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 1546 reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
1547 } else if (mpic_is_tm(mpic, irq)) {
1548 reg = mpic_tm_read(src - mpic->timer_vecs[0]) &
1549 ~MPIC_VECPRI_PRIORITY_MASK;
1550 mpic_tm_write(src - mpic->timer_vecs[0],
1551 reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
1437 } else { 1552 } else {
1438 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1553 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
1439 & ~MPIC_VECPRI_PRIORITY_MASK; 1554 & ~MPIC_VECPRI_PRIORITY_MASK;