diff options
author | Paul Burton <paul.burton@imgtec.com> | 2013-06-15 11:34:40 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-06-21 12:07:03 -0400 |
commit | c5e1503fd0428ed3a2e5e48734f47c9f4dfe5a3d (patch) | |
tree | eee721bec54e7e879daf8736c78cdcd0b336dcb8 /arch/mips/kernel/watch.c | |
parent | c37441c127e000869a960a866fe2207626935e4f (diff) |
MIPS: Fix execution hazard during watchpoint register probe
Writing a value to a WatchLo* register creates an execution hazard, so
if its value is then read before that hazard is cleared then said value
may be invalid. The mips_probe_watch_registers function must therefore
clear the execution hazard between setting the match bits in a WatchLo*
register & reading the register back in order to check which are set.
This fixes intermittent incorrect watchpoint register probing on some
MIPS cores such as interAptiv & proAptiv.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Reviewed-by: James Hogan <james.hogan@imgtec.com>
Acked-by: Steven J. Hill <Steven.Hill@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/5474/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/watch.c')
-rw-r--r-- | arch/mips/kernel/watch.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/arch/mips/kernel/watch.c b/arch/mips/kernel/watch.c index 7726f6157d9e..cbdc4de85bb4 100644 --- a/arch/mips/kernel/watch.c +++ b/arch/mips/kernel/watch.c | |||
@@ -111,6 +111,7 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c) | |||
111 | * disable the register. | 111 | * disable the register. |
112 | */ | 112 | */ |
113 | write_c0_watchlo0(7); | 113 | write_c0_watchlo0(7); |
114 | back_to_back_c0_hazard(); | ||
114 | t = read_c0_watchlo0(); | 115 | t = read_c0_watchlo0(); |
115 | write_c0_watchlo0(0); | 116 | write_c0_watchlo0(0); |
116 | c->watch_reg_masks[0] = t & 7; | 117 | c->watch_reg_masks[0] = t & 7; |
@@ -121,12 +122,14 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c) | |||
121 | c->watch_reg_use_cnt = 1; | 122 | c->watch_reg_use_cnt = 1; |
122 | t = read_c0_watchhi0(); | 123 | t = read_c0_watchhi0(); |
123 | write_c0_watchhi0(t | 0xff8); | 124 | write_c0_watchhi0(t | 0xff8); |
125 | back_to_back_c0_hazard(); | ||
124 | t = read_c0_watchhi0(); | 126 | t = read_c0_watchhi0(); |
125 | c->watch_reg_masks[0] |= (t & 0xff8); | 127 | c->watch_reg_masks[0] |= (t & 0xff8); |
126 | if ((t & 0x80000000) == 0) | 128 | if ((t & 0x80000000) == 0) |
127 | return; | 129 | return; |
128 | 130 | ||
129 | write_c0_watchlo1(7); | 131 | write_c0_watchlo1(7); |
132 | back_to_back_c0_hazard(); | ||
130 | t = read_c0_watchlo1(); | 133 | t = read_c0_watchlo1(); |
131 | write_c0_watchlo1(0); | 134 | write_c0_watchlo1(0); |
132 | c->watch_reg_masks[1] = t & 7; | 135 | c->watch_reg_masks[1] = t & 7; |
@@ -135,12 +138,14 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c) | |||
135 | c->watch_reg_use_cnt = 2; | 138 | c->watch_reg_use_cnt = 2; |
136 | t = read_c0_watchhi1(); | 139 | t = read_c0_watchhi1(); |
137 | write_c0_watchhi1(t | 0xff8); | 140 | write_c0_watchhi1(t | 0xff8); |
141 | back_to_back_c0_hazard(); | ||
138 | t = read_c0_watchhi1(); | 142 | t = read_c0_watchhi1(); |
139 | c->watch_reg_masks[1] |= (t & 0xff8); | 143 | c->watch_reg_masks[1] |= (t & 0xff8); |
140 | if ((t & 0x80000000) == 0) | 144 | if ((t & 0x80000000) == 0) |
141 | return; | 145 | return; |
142 | 146 | ||
143 | write_c0_watchlo2(7); | 147 | write_c0_watchlo2(7); |
148 | back_to_back_c0_hazard(); | ||
144 | t = read_c0_watchlo2(); | 149 | t = read_c0_watchlo2(); |
145 | write_c0_watchlo2(0); | 150 | write_c0_watchlo2(0); |
146 | c->watch_reg_masks[2] = t & 7; | 151 | c->watch_reg_masks[2] = t & 7; |
@@ -149,12 +154,14 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c) | |||
149 | c->watch_reg_use_cnt = 3; | 154 | c->watch_reg_use_cnt = 3; |
150 | t = read_c0_watchhi2(); | 155 | t = read_c0_watchhi2(); |
151 | write_c0_watchhi2(t | 0xff8); | 156 | write_c0_watchhi2(t | 0xff8); |
157 | back_to_back_c0_hazard(); | ||
152 | t = read_c0_watchhi2(); | 158 | t = read_c0_watchhi2(); |
153 | c->watch_reg_masks[2] |= (t & 0xff8); | 159 | c->watch_reg_masks[2] |= (t & 0xff8); |
154 | if ((t & 0x80000000) == 0) | 160 | if ((t & 0x80000000) == 0) |
155 | return; | 161 | return; |
156 | 162 | ||
157 | write_c0_watchlo3(7); | 163 | write_c0_watchlo3(7); |
164 | back_to_back_c0_hazard(); | ||
158 | t = read_c0_watchlo3(); | 165 | t = read_c0_watchlo3(); |
159 | write_c0_watchlo3(0); | 166 | write_c0_watchlo3(0); |
160 | c->watch_reg_masks[3] = t & 7; | 167 | c->watch_reg_masks[3] = t & 7; |
@@ -163,6 +170,7 @@ __cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c) | |||
163 | c->watch_reg_use_cnt = 4; | 170 | c->watch_reg_use_cnt = 4; |
164 | t = read_c0_watchhi3(); | 171 | t = read_c0_watchhi3(); |
165 | write_c0_watchhi3(t | 0xff8); | 172 | write_c0_watchhi3(t | 0xff8); |
173 | back_to_back_c0_hazard(); | ||
166 | t = read_c0_watchhi3(); | 174 | t = read_c0_watchhi3(); |
167 | c->watch_reg_masks[3] |= (t & 0xff8); | 175 | c->watch_reg_masks[3] |= (t & 0xff8); |
168 | if ((t & 0x80000000) == 0) | 176 | if ((t & 0x80000000) == 0) |