aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/time.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-11-21 11:39:44 -0500
committerRalf Baechle <ralf@linux-mips.org>2007-11-26 12:26:14 -0500
commit5aa85c9fc49a6ce44dc10a42e2011bbde9dc445a (patch)
tree14b8d1a014349568be39753f879c152e1e3f2b41 /arch/mips/kernel/time.c
parent0f67e90e1caea4a0a14d2c60102547bce29f7f08 (diff)
[MIPS] Handle R4000/R4400 mfc0 from count register.
The R4000 and R4400 have an errata where if the cp0 count register is read in the exact moment when it matches the compare register no interrupt will be generated. This bug may be triggered if the cp0 count register is being used as clocksource and the compare interrupt as clockevent. So a simple workaround is to avoid using the compare for both facilities on the affected CPUs. This is different from the workaround suggested in the old errata documents; at some opportunity probably the official version should be implemented and tested. Another thing to find out is which processor versions exactly are affected. I only have errata documents upto R4400 V3.0 available so for the moment the code treats all R4000 and R4400 as broken. This is potencially a problem for some machines that have no other decent clocksource available; this workaround will cause them to fall back to another clocksource, worst case the "jiffies" source.
Diffstat (limited to 'arch/mips/kernel/time.c')
-rw-r--r--arch/mips/kernel/time.c87
1 files changed, 33 insertions, 54 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 3284b9b4ecac..d7d52efff51f 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -91,48 +91,6 @@ static struct clocksource clocksource_mips = {
91 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 91 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
92}; 92};
93 93
94static unsigned int __init calibrate_hpt(void)
95{
96 cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
97
98 const int loops = HZ / 10;
99 int log_2_loops = 0;
100 int i;
101
102 /*
103 * We want to calibrate for 0.1s, but to avoid a 64-bit
104 * division we round the number of loops up to the nearest
105 * power of 2.
106 */
107 while (loops > 1 << log_2_loops)
108 log_2_loops++;
109 i = 1 << log_2_loops;
110
111 /*
112 * Wait for a rising edge of the timer interrupt.
113 */
114 while (mips_timer_state());
115 while (!mips_timer_state());
116
117 /*
118 * Now see how many high precision timer ticks happen
119 * during the calculated number of periods between timer
120 * interrupts.
121 */
122 hpt_start = clocksource_mips.read();
123 do {
124 while (mips_timer_state());
125 while (!mips_timer_state());
126 } while (--i);
127 hpt_end = clocksource_mips.read();
128
129 hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
130 hz = HZ;
131 frequency = hpt_count * hz;
132
133 return frequency >> log_2_loops;
134}
135
136void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock) 94void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
137{ 95{
138 u64 temp; 96 u64 temp;
@@ -194,21 +152,42 @@ void __init plat_timer_setup(void)
194 BUG(); 152 BUG();
195} 153}
196 154
155static __init int cpu_has_mfc0_count_bug(void)
156{
157 switch (current_cpu_type()) {
158 case CPU_R4000PC:
159 case CPU_R4000SC:
160 case CPU_R4000MC:
161 /*
162 * V3.0 is documented as suffering from the mfc0 from count bug.
163 * Afaik this is the last version of the R4000. Later versions
164 * were marketed as R4400.
165 */
166 return 1;
167
168 case CPU_R4400PC:
169 case CPU_R4400SC:
170 case CPU_R4400MC:
171 /*
172 * The published errata for the R4400 upto 3.0 say the CPU
173 * has the mfc0 from count bug.
174 */
175 if ((current_cpu_data.processor_id & 0xff) <= 0x30)
176 return 1;
177
178 /*
179 * I don't have erratas for newer R4400 so be paranoid.
180 */
181 return 1;
182 }
183
184 return 0;
185}
186
197void __init time_init(void) 187void __init time_init(void)
198{ 188{
199 plat_time_init(); 189 plat_time_init();
200 190
201 if (cpu_has_counter && (mips_hpt_frequency || mips_timer_state)) { 191 if (mips_clockevent_init() || !cpu_has_mfc0_count_bug())
202 /* We know counter frequency. Or we can get it. */
203 if (!mips_hpt_frequency)
204 mips_hpt_frequency = calibrate_hpt();
205
206 /* Report the high precision timer rate for a reference. */
207 printk("Using %u.%03u MHz high precision timer.\n",
208 ((mips_hpt_frequency + 500) / 1000) / 1000,
209 ((mips_hpt_frequency + 500) / 1000) % 1000);
210 init_mips_clocksource(); 192 init_mips_clocksource();
211 }
212
213 mips_clockevent_init();
214} 193}