aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2011-03-24 17:43:55 -0400
committerKumar Gala <galak@kernel.crashing.org>2011-05-19 02:14:28 -0400
commitea94187face757e723aa461a60698ca43c09fbb9 (patch)
tree0be763512d05cbace1098837d0019703bf517dc9 /arch/powerpc/sysdev
parent22d168ce60272ca112e86e58c5ebde82f20f9c83 (diff)
powerpc/mpic: add the mpic global timer support
Add support for MPIC timers as requestable interrupt sources. Based on http://patchwork.ozlabs.org/patch/20941/ by Dave Liu. Signed-off-by: Dave Liu <daveliu@freescale.com> Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/mpic.c92
1 files changed, 86 insertions, 6 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 0a3c1c20115c..0e47bce5f696 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -219,6 +219,28 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
219 _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 219 _mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
220} 220}
221 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
222static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 244static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
223{ 245{
224 unsigned int cpu = mpic_processor_id(mpic); 246 unsigned int cpu = mpic_processor_id(mpic);
@@ -269,6 +291,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
269#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))
270#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 292#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i))
271#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))
272#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 296#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i))
273#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))
274#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))
@@ -625,6 +649,13 @@ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
625 return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); 649 return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
626} 650}
627 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}
628 659
629/* Convert a cpu mask from logical to physical cpu numbers. */ 660/* Convert a cpu mask from logical to physical cpu numbers. */
630static inline u32 mpic_physmask(u32 cpumask) 661static inline u32 mpic_physmask(u32 cpumask)
@@ -811,6 +842,25 @@ static void mpic_end_ipi(struct irq_data *d)
811 842
812#endif /* CONFIG_SMP */ 843#endif /* CONFIG_SMP */
813 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
814int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 864int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
815 bool force) 865 bool force)
816{ 866{
@@ -941,6 +991,12 @@ static struct irq_chip mpic_ipi_chip = {
941}; 991};
942#endif /* CONFIG_SMP */ 992#endif /* CONFIG_SMP */
943 993
994static struct irq_chip mpic_tm_chip = {
995 .irq_mask = mpic_mask_tm,
996 .irq_unmask = mpic_unmask_tm,
997 .irq_eoi = mpic_end_irq,
998};
999
944#ifdef CONFIG_MPIC_U3_HT_IRQS 1000#ifdef CONFIG_MPIC_U3_HT_IRQS
945static struct irq_chip mpic_irq_ht_chip = { 1001static struct irq_chip mpic_irq_ht_chip = {
946 .irq_startup = mpic_startup_ht_irq, 1002 .irq_startup = mpic_startup_ht_irq,
@@ -984,6 +1040,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
984 } 1040 }
985#endif /* CONFIG_SMP */ 1041#endif /* CONFIG_SMP */
986 1042
1043 if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) {
1044 WARN_ON(!(mpic->flags & MPIC_PRIMARY));
1045
1046 DBG("mpic: mapping as timer\n");
1047 irq_set_chip_data(virq, mpic);
1048 irq_set_chip_and_handler(virq, &mpic->hc_tm,
1049 handle_fasteoi_irq);
1050 return 0;
1051 }
1052
987 if (hw >= mpic->irq_count) 1053 if (hw >= mpic->irq_count)
988 return -EINVAL; 1054 return -EINVAL;
989 1055
@@ -1140,6 +1206,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1140 mpic->hc_ipi.name = name; 1206 mpic->hc_ipi.name = name;
1141#endif /* CONFIG_SMP */ 1207#endif /* CONFIG_SMP */
1142 1208
1209 mpic->hc_tm = mpic_tm_chip;
1210 mpic->hc_tm.name = name;
1211
1143 mpic->flags = flags; 1212 mpic->flags = flags;
1144 mpic->isu_size = isu_size; 1213 mpic->isu_size = isu_size;
1145 mpic->irq_count = irq_count; 1214 mpic->irq_count = irq_count;
@@ -1150,10 +1219,14 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1150 else 1219 else
1151 intvec_top = 255; 1220 intvec_top = 255;
1152 1221
1153 mpic->timer_vecs[0] = intvec_top - 8; 1222 mpic->timer_vecs[0] = intvec_top - 12;
1154 mpic->timer_vecs[1] = intvec_top - 7; 1223 mpic->timer_vecs[1] = intvec_top - 11;
1155 mpic->timer_vecs[2] = intvec_top - 6; 1224 mpic->timer_vecs[2] = intvec_top - 10;
1156 mpic->timer_vecs[3] = intvec_top - 5; 1225 mpic->timer_vecs[3] = intvec_top - 9;
1226 mpic->timer_vecs[4] = intvec_top - 8;
1227 mpic->timer_vecs[5] = intvec_top - 7;
1228 mpic->timer_vecs[6] = intvec_top - 6;
1229 mpic->timer_vecs[7] = intvec_top - 5;
1157 mpic->ipi_vecs[0] = intvec_top - 4; 1230 mpic->ipi_vecs[0] = intvec_top - 4;
1158 mpic->ipi_vecs[1] = intvec_top - 3; 1231 mpic->ipi_vecs[1] = intvec_top - 3;
1159 mpic->ipi_vecs[2] = intvec_top - 2; 1232 mpic->ipi_vecs[2] = intvec_top - 2;
@@ -1356,15 +1429,17 @@ void __init mpic_init(struct mpic *mpic)
1356 /* Set current processor priority to max */ 1429 /* Set current processor priority to max */
1357 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 1430 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
1358 1431
1359 /* Initialize timers: just disable them all */ 1432 /* Initialize timers to our reserved vectors and mask them for now */
1360 for (i = 0; i < 4; i++) { 1433 for (i = 0; i < 4; i++) {
1361 mpic_write(mpic->tmregs, 1434 mpic_write(mpic->tmregs,
1362 i * MPIC_INFO(TIMER_STRIDE) + 1435 i * MPIC_INFO(TIMER_STRIDE) +
1363 MPIC_INFO(TIMER_DESTINATION), 0); 1436 MPIC_INFO(TIMER_DESTINATION),
1437 1 << hard_smp_processor_id());
1364 mpic_write(mpic->tmregs, 1438 mpic_write(mpic->tmregs,
1365 i * MPIC_INFO(TIMER_STRIDE) + 1439 i * MPIC_INFO(TIMER_STRIDE) +
1366 MPIC_INFO(TIMER_VECTOR_PRI), 1440 MPIC_INFO(TIMER_VECTOR_PRI),
1367 MPIC_VECPRI_MASK | 1441 MPIC_VECPRI_MASK |
1442 (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
1368 (mpic->timer_vecs[0] + i)); 1443 (mpic->timer_vecs[0] + i));
1369 } 1444 }
1370 1445
@@ -1473,6 +1548,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
1473 ~MPIC_VECPRI_PRIORITY_MASK; 1548 ~MPIC_VECPRI_PRIORITY_MASK;
1474 mpic_ipi_write(src - mpic->ipi_vecs[0], 1549 mpic_ipi_write(src - mpic->ipi_vecs[0],
1475 reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 1550 reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
1551 } else if (mpic_is_tm(mpic, irq)) {
1552 reg = mpic_tm_read(src - mpic->timer_vecs[0]) &
1553 ~MPIC_VECPRI_PRIORITY_MASK;
1554 mpic_tm_write(src - mpic->timer_vecs[0],
1555 reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
1476 } else { 1556 } else {
1477 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1557 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
1478 & ~MPIC_VECPRI_PRIORITY_MASK; 1558 & ~MPIC_VECPRI_PRIORITY_MASK;