diff options
Diffstat (limited to 'arch/mips/mips-boards/generic/time.c')
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 557bf961f36a..de5798e1e015 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c | |||
@@ -92,10 +92,9 @@ extern int (*perf_irq)(struct pt_regs *regs); | |||
92 | irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 92 | irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
93 | { | 93 | { |
94 | int cpu = smp_processor_id(); | 94 | int cpu = smp_processor_id(); |
95 | int r2 = cpu_has_mips_r2; | ||
96 | 95 | ||
97 | #ifdef CONFIG_MIPS_MT_SMTC | 96 | #ifdef CONFIG_MIPS_MT_SMTC |
98 | /* | 97 | /* |
99 | * In an SMTC system, one Count/Compare set exists per VPE. | 98 | * In an SMTC system, one Count/Compare set exists per VPE. |
100 | * Which TC within a VPE gets the interrupt is essentially | 99 | * Which TC within a VPE gets the interrupt is essentially |
101 | * random - we only know that it shouldn't be one with | 100 | * random - we only know that it shouldn't be one with |
@@ -108,29 +107,46 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
108 | * the general MIPS timer_interrupt routine. | 107 | * the general MIPS timer_interrupt routine. |
109 | */ | 108 | */ |
110 | 109 | ||
110 | int vpflags; | ||
111 | |||
111 | /* | 112 | /* |
112 | * DVPE is necessary so long as cross-VPE interrupts | 113 | * We could be here due to timer interrupt, |
113 | * are done via read-modify-write of Cause register. | 114 | * perf counter overflow, or both. |
114 | */ | 115 | */ |
115 | int vpflags = dvpe(); | 116 | if (read_c0_cause() & (1 << 26)) |
116 | write_c0_compare (read_c0_count() - 1); | 117 | perf_irq(regs); |
117 | clear_c0_cause(CPUCTR_IMASKBIT); | ||
118 | evpe(vpflags); | ||
119 | |||
120 | if (cpu_data[cpu].vpe_id == 0) { | ||
121 | timer_interrupt(irq, dev_id, regs); | ||
122 | scroll_display_message(); | ||
123 | } else | ||
124 | write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); | ||
125 | smtc_timer_broadcast(cpu_data[cpu].vpe_id); | ||
126 | 118 | ||
127 | if (cpu != 0) | 119 | if (read_c0_cause() & (1 << 30)) { |
120 | /* If timer interrupt, make it de-assert */ | ||
121 | write_c0_compare (read_c0_count() - 1); | ||
128 | /* | 122 | /* |
129 | * Other CPUs should do profiling and process accounting | 123 | * DVPE is necessary so long as cross-VPE interrupts |
124 | * are done via read-modify-write of Cause register. | ||
130 | */ | 125 | */ |
131 | local_timer_interrupt(irq, dev_id, regs); | 126 | vpflags = dvpe(); |
132 | 127 | clear_c0_cause(CPUCTR_IMASKBIT); | |
128 | evpe(vpflags); | ||
129 | /* | ||
130 | * There are things we only want to do once per tick | ||
131 | * in an "MP" system. One TC of each VPE will take | ||
132 | * the actual timer interrupt. The others will get | ||
133 | * timer broadcast IPIs. We use whoever it is that takes | ||
134 | * the tick on VPE 0 to run the full timer_interrupt(). | ||
135 | */ | ||
136 | if (cpu_data[cpu].vpe_id == 0) { | ||
137 | timer_interrupt(irq, NULL, regs); | ||
138 | smtc_timer_broadcast(cpu_data[cpu].vpe_id); | ||
139 | scroll_display_message(); | ||
140 | } else { | ||
141 | write_c0_compare(read_c0_count() + | ||
142 | (mips_hpt_frequency/HZ)); | ||
143 | local_timer_interrupt(irq, dev_id, regs); | ||
144 | smtc_timer_broadcast(cpu_data[cpu].vpe_id); | ||
145 | } | ||
146 | } | ||
133 | #else /* CONFIG_MIPS_MT_SMTC */ | 147 | #else /* CONFIG_MIPS_MT_SMTC */ |
148 | int r2 = cpu_has_mips_r2; | ||
149 | |||
134 | if (cpu == 0) { | 150 | if (cpu == 0) { |
135 | /* | 151 | /* |
136 | * CPU 0 handles the global timer interrupt job and process | 152 | * CPU 0 handles the global timer interrupt job and process |
@@ -161,9 +177,8 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
161 | */ | 177 | */ |
162 | local_timer_interrupt(irq, dev_id, regs); | 178 | local_timer_interrupt(irq, dev_id, regs); |
163 | } | 179 | } |
164 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
165 | |||
166 | out: | 180 | out: |
181 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
167 | return IRQ_HANDLED; | 182 | return IRQ_HANDLED; |
168 | } | 183 | } |
169 | 184 | ||