| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: tsc.c,v 1.21 2008/11/25 15:40:30 ad Exp $ */ | | 1 | /* $NetBSD: tsc.c,v 1.22 2008/12/15 12:46:28 ad Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,51 +17,54 @@ | | | @@ -17,51 +17,54 @@ |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. | | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: tsc.c,v 1.21 2008/11/25 15:40:30 ad Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: tsc.c,v 1.22 2008/12/15 12:46:28 ad Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/systm.h> | | 33 | #include <sys/systm.h> |
34 | #include <sys/time.h> | | 34 | #include <sys/time.h> |
35 | #include <sys/timetc.h> | | 35 | #include <sys/timetc.h> |
36 | #include <sys/lwp.h> | | 36 | #include <sys/lwp.h> |
37 | #include <sys/atomic.h> | | 37 | #include <sys/atomic.h> |
38 | #include <sys/kernel.h> | | 38 | #include <sys/kernel.h> |
39 | #include <sys/cpu.h> | | 39 | #include <sys/cpu.h> |
40 | | | 40 | |
41 | #include <machine/cpu_counter.h> | | 41 | #include <machine/cpu_counter.h> |
42 | #include <machine/cpuvar.h> | | 42 | #include <machine/cpuvar.h> |
43 | #include <machine/cpufunc.h> | | 43 | #include <machine/cpufunc.h> |
44 | #include <machine/specialreg.h> | | 44 | #include <machine/specialreg.h> |
45 | #include <machine/cputypes.h> | | 45 | #include <machine/cputypes.h> |
46 | | | 46 | |
47 | #include "tsc.h" | | 47 | #include "tsc.h" |
48 | | | 48 | |
49 | u_int tsc_get_timecount(struct timecounter *); | | 49 | u_int tsc_get_timecount(struct timecounter *); |
50 | | | 50 | |
51 | uint64_t tsc_freq; | | 51 | uint64_t tsc_freq; |
52 | int64_t tsc_drift_max = 250; /* max cycles */ | | 52 | int64_t tsc_drift_max = 250; /* max cycles */ |
53 | int64_t tsc_drift_observed; | | 53 | int64_t tsc_drift_observed; |
54 | | | 54 | |
| | | 55 | static volatile int64_t tsc_sync_val; |
| | | 56 | static volatile struct cpu_info *tsc_sync_cpu; |
| | | 57 | |
55 | static struct timecounter tsc_timecounter = { | | 58 | static struct timecounter tsc_timecounter = { |
56 | .tc_get_timecount = tsc_get_timecount, | | 59 | .tc_get_timecount = tsc_get_timecount, |
57 | .tc_counter_mask = ~0U, | | 60 | .tc_counter_mask = ~0U, |
58 | .tc_name = "TSC", | | 61 | .tc_name = "TSC", |
59 | .tc_quality = 3000, | | 62 | .tc_quality = 3000, |
60 | }; | | 63 | }; |
61 | | | 64 | |
62 | void | | 65 | void |
63 | tsc_tc_init(void) | | 66 | tsc_tc_init(void) |
64 | { | | 67 | { |
65 | struct cpu_info *ci; | | 68 | struct cpu_info *ci; |
66 | uint32_t descs[4]; | | 69 | uint32_t descs[4]; |
67 | bool safe; | | 70 | bool safe; |
| @@ -158,69 +161,77 @@ tsc_sync_drift(int64_t drift) | | | @@ -158,69 +161,77 @@ tsc_sync_drift(int64_t drift) |
158 | if (drift > tsc_drift_observed) | | 161 | if (drift > tsc_drift_observed) |
159 | tsc_drift_observed = drift; | | 162 | tsc_drift_observed = drift; |
160 | } | | 163 | } |
161 | | | 164 | |
162 | /* | | 165 | /* |
163 | * Called during startup of APs, by the boot processor. Interrupts | | 166 | * Called during startup of APs, by the boot processor. Interrupts |
164 | * are disabled on entry. | | 167 | * are disabled on entry. |
165 | */ | | 168 | */ |
166 | void | | 169 | void |
167 | tsc_sync_bp(struct cpu_info *ci) | | 170 | tsc_sync_bp(struct cpu_info *ci) |
168 | { | | 171 | { |
169 | uint64_t tsc; | | 172 | uint64_t tsc; |
170 | | | 173 | |
171 | /* Clear remote result, pending later update. */ | | 174 | if (atomic_swap_ptr(&tsc_sync_cpu, ci) != NULL) { |
172 | ci->ci_data.cpu_cc_skew = 0x7fffffffffffffffLL; | | 175 | panic("tsc_sync_bp: 1"); |
| | | 176 | } |
173 | | | 177 | |
174 | /* Flag it and read our TSC. */ | | 178 | /* Flag it and read our TSC. */ |
175 | atomic_or_uint(&ci->ci_flags, CPUF_SYNCTSC); | | 179 | atomic_or_uint(&ci->ci_flags, CPUF_SYNCTSC); |
176 | tsc = rdmsr(MSR_TSC) >> 1; | | 180 | tsc = rdmsr(MSR_TSC) >> 1; |
177 | | | 181 | |
178 | /* Wait for remote to complete, and read ours again. */ | | 182 | /* Wait for remote to complete, and read ours again. */ |
179 | while ((ci->ci_flags & CPUF_SYNCTSC) != 0) { | | 183 | while ((ci->ci_flags & CPUF_SYNCTSC) != 0) { |
180 | __insn_barrier(); | | 184 | __insn_barrier(); |
181 | } | | 185 | } |
182 | tsc += (rdmsr(MSR_TSC) >> 1); | | 186 | tsc += (rdmsr(MSR_TSC) >> 1); |
183 | | | 187 | |
184 | /* Wait for the results to come in. */ | | 188 | /* Wait for the results to come in. */ |
185 | while (ci->ci_data.cpu_cc_skew == 0x7fffffffffffffffLL) { | | 189 | while (tsc_sync_cpu == ci) { |
186 | x86_pause(); | | 190 | x86_pause(); |
187 | } | | 191 | } |
| | | 192 | if (tsc_sync_cpu != NULL) { |
| | | 193 | panic("tsc_sync_bp: 2"); |
| | | 194 | } |
188 | | | 195 | |
189 | /* Compute final value to adjust for skew. */ | | 196 | /* Compute final value to adjust for skew. */ |
190 | ci->ci_data.cpu_cc_skew = tsc - ci->ci_data.cpu_cc_skew; | | 197 | ci->ci_data.cpu_cc_skew = tsc - tsc_sync_val; |
191 | } | | 198 | } |
192 | | | 199 | |
193 | /* | | 200 | /* |
194 | * Called during startup of AP, by the AP itself. Interrupts are | | 201 | * Called during startup of AP, by the AP itself. Interrupts are |
195 | * disabled on entry. | | 202 | * disabled on entry. |
196 | */ | | 203 | */ |
197 | void | | 204 | void |
198 | tsc_sync_ap(struct cpu_info *ci) | | 205 | tsc_sync_ap(struct cpu_info *ci) |
199 | { | | 206 | { |
200 | uint64_t tsc; | | 207 | uint64_t tsc; |
201 | | | 208 | |
202 | /* Wait for go-ahead from primary. */ | | 209 | /* Wait for go-ahead from primary. */ |
203 | while ((ci->ci_flags & CPUF_SYNCTSC) == 0) { | | 210 | while ((ci->ci_flags & CPUF_SYNCTSC) == 0) { |
204 | __insn_barrier(); | | 211 | __insn_barrier(); |
205 | } | | 212 | } |
206 | tsc = (rdmsr(MSR_TSC) >> 1); | | 213 | tsc = (rdmsr(MSR_TSC) >> 1); |
207 | | | 214 | |
208 | /* Instruct primary to read its counter. */ | | 215 | /* Instruct primary to read its counter. */ |
209 | atomic_and_uint(&ci->ci_flags, ~CPUF_SYNCTSC); | | 216 | atomic_and_uint(&ci->ci_flags, ~CPUF_SYNCTSC); |
210 | tsc += (rdmsr(MSR_TSC) >> 1); | | 217 | tsc += (rdmsr(MSR_TSC) >> 1); |
211 | | | 218 | |
212 | /* Post result. Ensure the whole value goes out atomically. */ | | 219 | /* Post result. Ensure the whole value goes out atomically. */ |
213 | (void)atomic_swap_64(&ci->ci_data.cpu_cc_skew, tsc); | | 220 | (void)atomic_swap_64(&tsc_sync_val, tsc); |
| | | 221 | |
| | | 222 | if (atomic_swap_ptr(&tsc_sync_cpu, NULL) != ci) { |
| | | 223 | panic("tsc_sync_ap"); |
| | | 224 | } |
214 | } | | 225 | } |
215 | | | 226 | |
216 | uint64_t | | 227 | uint64_t |
217 | cpu_frequency(struct cpu_info *ci) | | 228 | cpu_frequency(struct cpu_info *ci) |
218 | { | | 229 | { |
219 | | | 230 | |
220 | return ci->ci_data.cpu_cc_freq; | | 231 | return ci->ci_data.cpu_cc_freq; |
221 | } | | 232 | } |
222 | | | 233 | |
223 | int | | 234 | int |
224 | cpu_hascounter(void) | | 235 | cpu_hascounter(void) |
225 | { | | 236 | { |
226 | | | 237 | |