Skip to content

Commit daed128

Browse files
Maciej W. Rozyckiralfbaechle
Maciej W. Rozycki
authored andcommitted
MIPS: DECstation HRT initialization rearrangement
Not all I/O ASIC versions have the free-running counter implemented, an early revision used in the 5000/1xx models aka 3MIN and 4MIN did not have it. Therefore we cannot unconditionally use it as a clock source. Fortunately if not implemented its register slot has a fixed value so it is enough if we check for the value at the end of the calibration period being the same as at the beginning. This also means we need to look for another high-precision clock source on the systems affected. The 5000/1xx can have an R4000SC processor installed where the CP0 Count register can be used as a clock source. Unfortunately all the R4k DECstations suffer from the missed timer interrupt on CP0 Count reads erratum, so we cannot use the CP0 timer as a clock source and a clock event both at a time. However we never need an R4k clock event device because all DECstations have a DS1287A RTC chip whose periodic interrupt can be used as a clock source. This gives us the following four configuration possibilities for I/O ASIC DECstations: 1. No I/O ASIC counter and no CP0 timer, e.g. R3k 5000/1xx (3MIN). 2. No I/O ASIC counter but the CP0 timer, i.e. R4k 5000/150 (4MIN). 3. The I/O ASIC counter but no CP0 timer, e.g. R3k 5000/240 (3MAX+). 4. The I/O ASIC counter and the CP0 timer, e.g. R4k 5000/260 (4MAX+). For #1 and #2 this change stops the I/O ASIC free-running counter from being installed as a clock source of a 0Hz frequency. For #2 it also arranges for the CP0 timer to be used as a clock source rather than a clock event device, because having an accurate wall clock is more important than a high-precision interval timer. For #3 there is no change. For #4 the change makes the I/O ASIC free-running counter installed as a clock source so that the CP0 timer can be used as a clock event device. Unfortunately the use of the CP0 timer as a clock event device relies on a succesful completion of c0_compare_interrupt. That never happens, because while waiting for a CP0 Compare interrupt to happen the function spins in a loop reading the CP0 Count register. This makes the CP0 Count erratum trigger reliably causing the interrupt waited for to be lost in all cases. As a result #4 resorts to using the CP0 timer as a clock source as well, just as #2. However we want to keep this separate arrangement in case (hope) c0_compare_interrupt is eventually rewritten such that it avoids the erratum. Signed-off-by: Maciej W. Rozycki <[email protected]> Cc: [email protected] Patchwork: https://patchwork.linux-mips.org/patch/5825/ Signed-off-by: Ralf Baechle <[email protected]>
1 parent 5a7d8a2 commit daed128

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

arch/mips/dec/time.c

+19-3
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,16 @@ int rtc_mips_set_mmss(unsigned long nowtime)
125125

126126
void __init plat_time_init(void)
127127
{
128+
int ioasic_clock = 0;
128129
u32 start, end;
129130
int i = HZ / 8;
130131

131132
/* Set up the rate of periodic DS1287 interrupts. */
132133
ds1287_set_base_clock(HZ);
133134

135+
/* On some I/O ASIC systems we have the I/O ASIC's counter. */
136+
if (IOASIC)
137+
ioasic_clock = dec_ioasic_clocksource_init() == 0;
134138
if (cpu_has_counter) {
135139
ds1287_timer_state();
136140
while (!ds1287_timer_state())
@@ -147,9 +151,21 @@ void __init plat_time_init(void)
147151
mips_hpt_frequency = (end - start) * 8;
148152
printk(KERN_INFO "MIPS counter frequency %dHz\n",
149153
mips_hpt_frequency);
150-
} else if (IOASIC)
151-
/* For pre-R4k systems we use the I/O ASIC's counter. */
152-
dec_ioasic_clocksource_init();
154+
155+
/*
156+
* All R4k DECstations suffer from the CP0 Count erratum,
157+
* so we can't use the timer as a clock source, and a clock
158+
* event both at a time. An accurate wall clock is more
159+
* important than a high-precision interval timer so only
160+
* use the timer as a clock source, and not a clock event
161+
* if there's no I/O ASIC counter available to serve as a
162+
* clock source.
163+
*/
164+
if (!ioasic_clock) {
165+
init_r4k_clocksource();
166+
mips_hpt_frequency = 0;
167+
}
168+
}
153169

154170
ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]);
155171
}

arch/mips/include/asm/dec/ioasic.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ static inline u32 ioasic_read(unsigned int reg)
3333

3434
extern void init_ioasic_irqs(int base);
3535

36-
extern void dec_ioasic_clocksource_init(void);
36+
extern int dec_ioasic_clocksource_init(void);
3737

3838
#endif /* __ASM_DEC_IOASIC_H */

arch/mips/kernel/csrc-ioasic.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static struct clocksource clocksource_dec = {
3737
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
3838
};
3939

40-
void __init dec_ioasic_clocksource_init(void)
40+
int __init dec_ioasic_clocksource_init(void)
4141
{
4242
unsigned int freq;
4343
u32 start, end;
@@ -56,8 +56,14 @@ void __init dec_ioasic_clocksource_init(void)
5656
end = dec_ioasic_hpt_read(&clocksource_dec);
5757

5858
freq = (end - start) * 8;
59+
60+
/* An early revision of the I/O ASIC didn't have the counter. */
61+
if (!freq)
62+
return -ENXIO;
63+
5964
printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
6065

6166
clocksource_dec.rating = 200 + freq / 10000000;
6267
clocksource_register_hz(&clocksource_dec, freq);
68+
return 0;
6369
}

0 commit comments

Comments
 (0)