diff options
Diffstat (limited to 'arch/mips/kernel/smtc.c')
-rw-r--r-- | arch/mips/kernel/smtc.c | 65 |
1 files changed, 53 insertions, 12 deletions
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index f253eda27fa3..5dcfab6b288e 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/sched.h> | 4 | #include <linux/sched.h> |
5 | #include <linux/cpumask.h> | 5 | #include <linux/cpumask.h> |
6 | #include <linux/interrupt.h> | 6 | #include <linux/interrupt.h> |
7 | #include <linux/kernel_stat.h> | ||
7 | #include <linux/module.h> | 8 | #include <linux/module.h> |
8 | 9 | ||
9 | #include <asm/cpu.h> | 10 | #include <asm/cpu.h> |
@@ -14,6 +15,7 @@ | |||
14 | #include <asm/hazards.h> | 15 | #include <asm/hazards.h> |
15 | #include <asm/mmu_context.h> | 16 | #include <asm/mmu_context.h> |
16 | #include <asm/smp.h> | 17 | #include <asm/smp.h> |
18 | #include <asm/mips-boards/maltaint.h> | ||
17 | #include <asm/mipsregs.h> | 19 | #include <asm/mipsregs.h> |
18 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
19 | #include <asm/time.h> | 21 | #include <asm/time.h> |
@@ -75,7 +77,7 @@ static struct smtc_ipi_q freeIPIq; | |||
75 | 77 | ||
76 | void ipi_decode(struct smtc_ipi *); | 78 | void ipi_decode(struct smtc_ipi *); |
77 | static void post_direct_ipi(int cpu, struct smtc_ipi *pipi); | 79 | static void post_direct_ipi(int cpu, struct smtc_ipi *pipi); |
78 | static void setup_cross_vpe_interrupts(void); | 80 | static void setup_cross_vpe_interrupts(unsigned int nvpe); |
79 | void init_smtc_stats(void); | 81 | void init_smtc_stats(void); |
80 | 82 | ||
81 | /* Global SMTC Status */ | 83 | /* Global SMTC Status */ |
@@ -168,7 +170,10 @@ __setup("tintq=", tintq); | |||
168 | 170 | ||
169 | int imstuckcount[2][8]; | 171 | int imstuckcount[2][8]; |
170 | /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */ | 172 | /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */ |
171 | int vpemask[2][8] = {{0,1,1,0,0,0,0,1},{0,1,0,0,0,0,0,1}}; | 173 | int vpemask[2][8] = { |
174 | {0, 0, 1, 0, 0, 0, 0, 1}, | ||
175 | {0, 0, 0, 0, 0, 0, 0, 1} | ||
176 | }; | ||
172 | int tcnoprog[NR_CPUS]; | 177 | int tcnoprog[NR_CPUS]; |
173 | static atomic_t idle_hook_initialized = {0}; | 178 | static atomic_t idle_hook_initialized = {0}; |
174 | static int clock_hang_reported[NR_CPUS]; | 179 | static int clock_hang_reported[NR_CPUS]; |
@@ -501,8 +506,7 @@ void mipsmt_prepare_cpus(void) | |||
501 | 506 | ||
502 | /* If we have multiple VPEs running, set up the cross-VPE interrupt */ | 507 | /* If we have multiple VPEs running, set up the cross-VPE interrupt */ |
503 | 508 | ||
504 | if (nvpe > 1) | 509 | setup_cross_vpe_interrupts(nvpe); |
505 | setup_cross_vpe_interrupts(); | ||
506 | 510 | ||
507 | /* Set up queue of free IPI "messages". */ | 511 | /* Set up queue of free IPI "messages". */ |
508 | nipi = NR_CPUS * IPIBUF_PER_CPU; | 512 | nipi = NR_CPUS * IPIBUF_PER_CPU; |
@@ -607,7 +611,12 @@ void smtc_cpus_done(void) | |||
607 | int setup_irq_smtc(unsigned int irq, struct irqaction * new, | 611 | int setup_irq_smtc(unsigned int irq, struct irqaction * new, |
608 | unsigned long hwmask) | 612 | unsigned long hwmask) |
609 | { | 613 | { |
614 | unsigned int vpe = current_cpu_data.vpe_id; | ||
615 | |||
610 | irq_hwmask[irq] = hwmask; | 616 | irq_hwmask[irq] = hwmask; |
617 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | ||
618 | vpemask[vpe][irq - MIPSCPU_INT_BASE] = 1; | ||
619 | #endif | ||
611 | 620 | ||
612 | return setup_irq(irq, new); | 621 | return setup_irq(irq, new); |
613 | } | 622 | } |
@@ -812,12 +821,15 @@ void ipi_decode(struct smtc_ipi *pipi) | |||
812 | smtc_ipi_nq(&freeIPIq, pipi); | 821 | smtc_ipi_nq(&freeIPIq, pipi); |
813 | switch (type_copy) { | 822 | switch (type_copy) { |
814 | case SMTC_CLOCK_TICK: | 823 | case SMTC_CLOCK_TICK: |
824 | irq_enter(); | ||
825 | kstat_this_cpu.irqs[MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR]++; | ||
815 | /* Invoke Clock "Interrupt" */ | 826 | /* Invoke Clock "Interrupt" */ |
816 | ipi_timer_latch[dest_copy] = 0; | 827 | ipi_timer_latch[dest_copy] = 0; |
817 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | 828 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG |
818 | clock_hang_reported[dest_copy] = 0; | 829 | clock_hang_reported[dest_copy] = 0; |
819 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | 830 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ |
820 | local_timer_interrupt(0, NULL); | 831 | local_timer_interrupt(0, NULL); |
832 | irq_exit(); | ||
821 | break; | 833 | break; |
822 | case LINUX_SMP_IPI: | 834 | case LINUX_SMP_IPI: |
823 | switch ((int)arg_copy) { | 835 | switch ((int)arg_copy) { |
@@ -965,8 +977,11 @@ static void ipi_irq_dispatch(void) | |||
965 | 977 | ||
966 | static struct irqaction irq_ipi; | 978 | static struct irqaction irq_ipi; |
967 | 979 | ||
968 | static void setup_cross_vpe_interrupts(void) | 980 | static void setup_cross_vpe_interrupts(unsigned int nvpe) |
969 | { | 981 | { |
982 | if (nvpe < 1) | ||
983 | return; | ||
984 | |||
970 | if (!cpu_has_vint) | 985 | if (!cpu_has_vint) |
971 | panic("SMTC Kernel requires Vectored Interupt support"); | 986 | panic("SMTC Kernel requires Vectored Interupt support"); |
972 | 987 | ||
@@ -984,10 +999,17 @@ static void setup_cross_vpe_interrupts(void) | |||
984 | 999 | ||
985 | /* | 1000 | /* |
986 | * SMTC-specific hacks invoked from elsewhere in the kernel. | 1001 | * SMTC-specific hacks invoked from elsewhere in the kernel. |
1002 | * | ||
1003 | * smtc_ipi_replay is called from raw_local_irq_restore which is only ever | ||
1004 | * called with interrupts disabled. We do rely on interrupts being disabled | ||
1005 | * here because using spin_lock_irqsave()/spin_unlock_irqrestore() would | ||
1006 | * result in a recursive call to raw_local_irq_restore(). | ||
987 | */ | 1007 | */ |
988 | 1008 | ||
989 | void smtc_ipi_replay(void) | 1009 | static void __smtc_ipi_replay(void) |
990 | { | 1010 | { |
1011 | unsigned int cpu = smp_processor_id(); | ||
1012 | |||
991 | /* | 1013 | /* |
992 | * To the extent that we've ever turned interrupts off, | 1014 | * To the extent that we've ever turned interrupts off, |
993 | * we may have accumulated deferred IPIs. This is subtle. | 1015 | * we may have accumulated deferred IPIs. This is subtle. |
@@ -1002,17 +1024,30 @@ void smtc_ipi_replay(void) | |||
1002 | * is clear, and we'll handle it as a real pseudo-interrupt | 1024 | * is clear, and we'll handle it as a real pseudo-interrupt |
1003 | * and not a pseudo-pseudo interrupt. | 1025 | * and not a pseudo-pseudo interrupt. |
1004 | */ | 1026 | */ |
1005 | if (IPIQ[smp_processor_id()].depth > 0) { | 1027 | if (IPIQ[cpu].depth > 0) { |
1006 | struct smtc_ipi *pipi; | 1028 | while (1) { |
1007 | extern void self_ipi(struct smtc_ipi *); | 1029 | struct smtc_ipi_q *q = &IPIQ[cpu]; |
1030 | struct smtc_ipi *pipi; | ||
1031 | extern void self_ipi(struct smtc_ipi *); | ||
1032 | |||
1033 | spin_lock(&q->lock); | ||
1034 | pipi = __smtc_ipi_dq(q); | ||
1035 | spin_unlock(&q->lock); | ||
1036 | if (!pipi) | ||
1037 | break; | ||
1008 | 1038 | ||
1009 | while ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()]))) { | ||
1010 | self_ipi(pipi); | 1039 | self_ipi(pipi); |
1011 | smtc_cpu_stats[smp_processor_id()].selfipis++; | 1040 | smtc_cpu_stats[cpu].selfipis++; |
1012 | } | 1041 | } |
1013 | } | 1042 | } |
1014 | } | 1043 | } |
1015 | 1044 | ||
1045 | void smtc_ipi_replay(void) | ||
1046 | { | ||
1047 | raw_local_irq_disable(); | ||
1048 | __smtc_ipi_replay(); | ||
1049 | } | ||
1050 | |||
1016 | EXPORT_SYMBOL(smtc_ipi_replay); | 1051 | EXPORT_SYMBOL(smtc_ipi_replay); |
1017 | 1052 | ||
1018 | void smtc_idle_loop_hook(void) | 1053 | void smtc_idle_loop_hook(void) |
@@ -1117,7 +1152,13 @@ void smtc_idle_loop_hook(void) | |||
1117 | * is in use, there should never be any. | 1152 | * is in use, there should never be any. |
1118 | */ | 1153 | */ |
1119 | #ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY | 1154 | #ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY |
1120 | smtc_ipi_replay(); | 1155 | { |
1156 | unsigned long flags; | ||
1157 | |||
1158 | local_irq_save(flags); | ||
1159 | __smtc_ipi_replay(); | ||
1160 | local_irq_restore(flags); | ||
1161 | } | ||
1121 | #endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */ | 1162 | #endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */ |
1122 | } | 1163 | } |
1123 | 1164 | ||