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 | ||
