Commit 4f1a1eb530071c39fb239fd26c912a64284b1408
Committed by
Ralf Baechle
1 parent
e63fb7a9da
Exists in
master
and in
6 other branches
MIPS: Kernel hangs occasionally during boot.
The Kernel hangs occasionally during boot after "Calibrating delay loop..". This is caused by the c0_compare_int_usable() routine in cevt-r4k.c returning false which causes the system to disable the timer and hang later. The false return happens because the routine is using a series of four calls to irq_disable_hazard() as a delay while it waits for the timer changes to propagate to the cp0 cause register. On newer MIPS cores, like the 74K, the series of irq_disable_hazard() calls turn into ehb instructions and can take as little as a few clock ticks for all 4 instructions. This is not enough of a delay, so the routine thinks the timer is not working. This fix uses up to a max number of cycle counter ticks for the delay and uses back_to_back_c0_hazard() instead of irq_disable_hazard() to handle the hazard condition between cp0 writes and cp0 reads. Signed-off-by: Al Cooper <alcooperx@gmail.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2911/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Showing 1 changed file with 19 additions and 19 deletions Side-by-side Diff
arch/mips/kernel/cevt-r4k.c
... | ... | @@ -103,20 +103,11 @@ |
103 | 103 | |
104 | 104 | /* |
105 | 105 | * Compare interrupt can be routed and latched outside the core, |
106 | - * so a single execution hazard barrier may not be enough to give | |
107 | - * it time to clear as seen in the Cause register. 4 time the | |
108 | - * pipeline depth seems reasonably conservative, and empirically | |
109 | - * works better in configurations with high CPU/bus clock ratios. | |
106 | + * so wait up to worst case number of cycle counter ticks for timer interrupt | |
107 | + * changes to propagate to the cause register. | |
110 | 108 | */ |
109 | +#define COMPARE_INT_SEEN_TICKS 50 | |
111 | 110 | |
112 | -#define compare_change_hazard() \ | |
113 | - do { \ | |
114 | - irq_disable_hazard(); \ | |
115 | - irq_disable_hazard(); \ | |
116 | - irq_disable_hazard(); \ | |
117 | - irq_disable_hazard(); \ | |
118 | - } while (0) | |
119 | - | |
120 | 111 | int c0_compare_int_usable(void) |
121 | 112 | { |
122 | 113 | unsigned int delta; |
... | ... | @@ -126,8 +117,12 @@ |
126 | 117 | * IP7 already pending? Try to clear it by acking the timer. |
127 | 118 | */ |
128 | 119 | if (c0_compare_int_pending()) { |
129 | - write_c0_compare(read_c0_count()); | |
130 | - compare_change_hazard(); | |
120 | + cnt = read_c0_count(); | |
121 | + write_c0_compare(cnt); | |
122 | + back_to_back_c0_hazard(); | |
123 | + while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) | |
124 | + if (!c0_compare_int_pending()) | |
125 | + break; | |
131 | 126 | if (c0_compare_int_pending()) |
132 | 127 | return 0; |
133 | 128 | } |
... | ... | @@ -136,7 +131,7 @@ |
136 | 131 | cnt = read_c0_count(); |
137 | 132 | cnt += delta; |
138 | 133 | write_c0_compare(cnt); |
139 | - compare_change_hazard(); | |
134 | + back_to_back_c0_hazard(); | |
140 | 135 | if ((int)(read_c0_count() - cnt) < 0) |
141 | 136 | break; |
142 | 137 | /* increase delta if the timer was already expired */ |
143 | 138 | |
... | ... | @@ -145,12 +140,17 @@ |
145 | 140 | while ((int)(read_c0_count() - cnt) <= 0) |
146 | 141 | ; /* Wait for expiry */ |
147 | 142 | |
148 | - compare_change_hazard(); | |
143 | + while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) | |
144 | + if (c0_compare_int_pending()) | |
145 | + break; | |
149 | 146 | if (!c0_compare_int_pending()) |
150 | 147 | return 0; |
151 | - | |
152 | - write_c0_compare(read_c0_count()); | |
153 | - compare_change_hazard(); | |
148 | + cnt = read_c0_count(); | |
149 | + write_c0_compare(cnt); | |
150 | + back_to_back_c0_hazard(); | |
151 | + while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) | |
152 | + if (!c0_compare_int_pending()) | |
153 | + break; | |
154 | 154 | if (c0_compare_int_pending()) |
155 | 155 | return 0; |
156 | 156 |