diff options
author | Scott Wood <scottwood@freescale.com> | 2011-03-24 17:43:55 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2011-05-19 02:14:28 -0400 |
commit | ea94187face757e723aa461a60698ca43c09fbb9 (patch) | |
tree | 0be763512d05cbace1098837d0019703bf517dc9 /arch/powerpc/sysdev | |
parent | 22d168ce60272ca112e86e58c5ebde82f20f9c83 (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.c | 92 |
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 | ||
222 | static 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 | |||
233 | static 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 | |||
222 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | 244 | static 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 */ | ||
653 | static 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. */ |
630 | static inline u32 mpic_physmask(u32 cpumask) | 661 | static 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 | ||
845 | static 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 | |||
855 | static 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 | |||
814 | int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, | 864 | int 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 | ||
994 | static 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 |
945 | static struct irq_chip mpic_irq_ht_chip = { | 1001 | static 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; |