| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: clock.c,v 1.14 2014/03/03 15:36:36 macallan Exp $ */ | | 1 | /* $NetBSD: clock.c,v 1.15 2014/03/18 14:34:31 macallan Exp $ */ |
2 | /* $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $ */ | | 2 | /* $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (C) 1995, 1996 Wolfgang Solfrank. | | 5 | * Copyright (C) 1995, 1996 Wolfgang Solfrank. |
6 | * Copyright (C) 1995, 1996 TooLs GmbH. | | 6 | * Copyright (C) 1995, 1996 TooLs GmbH. |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -23,66 +23,78 @@ | | | @@ -23,66 +23,78 @@ |
23 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR | | 23 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR |
24 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 24 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
26 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | | 26 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | | 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
28 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | | 28 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
29 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | | 29 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | | 30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
31 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | | 31 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
32 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 32 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.14 2014/03/03 15:36:36 macallan Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.15 2014/03/18 14:34:31 macallan Exp $"); |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | #include <sys/systm.h> | | 40 | #include <sys/systm.h> |
41 | #include <sys/device.h> | | 41 | #include <sys/device.h> |
42 | #include <sys/timetc.h> | | 42 | #include <sys/timetc.h> |
43 | | | 43 | |
44 | #include <uvm/uvm_extern.h> | | 44 | #include <uvm/uvm_extern.h> |
45 | | | 45 | |
46 | #include <powerpc/psl.h> | | 46 | #include <powerpc/psl.h> |
47 | #include <powerpc/spr.h> | | 47 | #include <powerpc/spr.h> |
48 | #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) | | 48 | #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE) |
49 | #include <powerpc/oea/spr.h> | | 49 | #include <powerpc/oea/spr.h> |
50 | #elif defined (PPC_BOOKE) | | 50 | #elif defined (PPC_BOOKE) |
51 | #include <powerpc/booke/spr.h> | | 51 | #include <powerpc/booke/spr.h> |
52 | #elif defined (PPC_IBM4XX) | | 52 | #elif defined (PPC_IBM4XX) |
53 | #include <powerpc/ibm4xx/spr.h> | | 53 | #include <powerpc/ibm4xx/spr.h> |
54 | #else | | 54 | #else |
55 | #error unknown powerpc variant | | 55 | #error unknown powerpc variant |
56 | #endif | | 56 | #endif |
57 | | | 57 | |
58 | void decr_intr(struct clockframe *); | | 58 | void decr_intr(struct clockframe *); |
59 | void init_powerpc_tc(void); | | 59 | void init_powerpc_tc(void); |
60 | static u_int get_powerpc_timecount(struct timecounter *); | | 60 | static u_int get_powerpc_timecount(struct timecounter *); |
| | | 61 | #ifdef PPC_OEA601 |
| | | 62 | static u_int get_601_timecount(struct timecounter *); |
| | | 63 | #endif |
61 | | | 64 | |
62 | uint32_t ticks_per_sec; | | 65 | uint32_t ticks_per_sec; |
63 | uint32_t ns_per_tick; | | 66 | uint32_t ns_per_tick; |
64 | uint32_t ticks_per_intr = 0; | | 67 | uint32_t ticks_per_intr = 0; |
65 | | | 68 | |
| | | 69 | #ifdef PPC_OEA601 |
| | | 70 | static struct timecounter powerpc_601_timecounter = { |
| | | 71 | get_601_timecount, /* get_timecount */ |
| | | 72 | 0, /* no poll_pps */ |
| | | 73 | 0x7fffffff, /* counter_mask */ |
| | | 74 | 0, /* frequency */ |
| | | 75 | "rtc", /* name */ |
| | | 76 | 100, /* quality */ |
| | | 77 | NULL, /* tc_priv */ |
| | | 78 | NULL /* tc_next */ |
| | | 79 | }; |
| | | 80 | #endif |
| | | 81 | |
66 | static struct timecounter powerpc_timecounter = { | | 82 | static struct timecounter powerpc_timecounter = { |
67 | get_powerpc_timecount, /* get_timecount */ | | 83 | get_powerpc_timecount, /* get_timecount */ |
68 | 0, /* no poll_pps */ | | 84 | 0, /* no poll_pps */ |
69 | 0x7fffffff, /* counter_mask */ | | 85 | 0x7fffffff, /* counter_mask */ |
70 | 0, /* frequency */ | | 86 | 0, /* frequency */ |
71 | #if PPC_OEA601 | | | |
72 | "rtc", /* name */ | | | |
73 | #else | | | |
74 | "mftb", /* name */ | | 87 | "mftb", /* name */ |
75 | #endif | | | |
76 | 100, /* quality */ | | 88 | 100, /* quality */ |
77 | NULL, /* tc_priv */ | | 89 | NULL, /* tc_priv */ |
78 | NULL /* tc_next */ | | 90 | NULL /* tc_next */ |
79 | }; | | 91 | }; |
80 | | | 92 | |
81 | /* | | 93 | /* |
82 | * Start the real-time and statistics clocks. Leave stathz 0 since there | | 94 | * Start the real-time and statistics clocks. Leave stathz 0 since there |
83 | * are no other timers available. | | 95 | * are no other timers available. |
84 | */ | | 96 | */ |
85 | void | | 97 | void |
86 | cpu_initclocks(void) | | 98 | cpu_initclocks(void) |
87 | { | | 99 | { |
88 | struct cpu_info * const ci = curcpu(); | | 100 | struct cpu_info * const ci = curcpu(); |
| @@ -112,27 +124,27 @@ cpu_initclocks(void) | | | @@ -112,27 +124,27 @@ cpu_initclocks(void) |
112 | * but that would be a drag. | | 124 | * but that would be a drag. |
113 | */ | | 125 | */ |
114 | void | | 126 | void |
115 | setstatclockrate(int arg) | | 127 | setstatclockrate(int arg) |
116 | { | | 128 | { |
117 | | | 129 | |
118 | /* Nothing we can do */ | | 130 | /* Nothing we can do */ |
119 | } | | 131 | } |
120 | | | 132 | |
121 | void | | 133 | void |
122 | decr_intr(struct clockframe *cfp) | | 134 | decr_intr(struct clockframe *cfp) |
123 | { | | 135 | { |
124 | struct cpu_info * const ci = curcpu(); | | 136 | struct cpu_info * const ci = curcpu(); |
125 | int msr; | | 137 | const register_t msr = mfmsr(); |
126 | int pri; | | 138 | int pri; |
127 | u_long tb; | | 139 | u_long tb; |
128 | long ticks; | | 140 | long ticks; |
129 | int nticks; | | 141 | int nticks; |
130 | | | 142 | |
131 | /* Check whether we are initialized */ | | 143 | /* Check whether we are initialized */ |
132 | if (!ticks_per_intr) | | 144 | if (!ticks_per_intr) |
133 | return; | | 145 | return; |
134 | | | 146 | |
135 | /* | | 147 | /* |
136 | * Based on the actual time delay since the last decrementer reload, | | 148 | * Based on the actual time delay since the last decrementer reload, |
137 | * we arrange for earlier interrupt next time. | | 149 | * we arrange for earlier interrupt next time. |
138 | */ | | 150 | */ |
| @@ -153,42 +165,41 @@ decr_intr(struct clockframe *cfp) | | | @@ -153,42 +165,41 @@ decr_intr(struct clockframe *cfp) |
153 | | | 165 | |
154 | /* | | 166 | /* |
155 | * lasttb is used during microtime. Set it to the virtual | | 167 | * lasttb is used during microtime. Set it to the virtual |
156 | * start of this tick interval. | | 168 | * start of this tick interval. |
157 | */ | | 169 | */ |
158 | #ifdef PPC_OEA601 | | 170 | #ifdef PPC_OEA601 |
159 | if ((mfpvr() >> 16) == MPC601) | | 171 | if ((mfpvr() >> 16) == MPC601) |
160 | tb = rtc_nanosecs(); | | 172 | tb = rtc_nanosecs(); |
161 | else | | 173 | else |
162 | #endif | | 174 | #endif |
163 | __asm volatile ("mftb %0" : "=r"(tb)); | | 175 | __asm volatile ("mftb %0" : "=r"(tb)); |
164 | | | 176 | |
165 | ci->ci_lasttb = tb + ticks - ticks_per_intr; | | 177 | ci->ci_lasttb = tb + ticks - ticks_per_intr; |
166 | | | 178 | ci->ci_idepth++; |
167 | /* | | 179 | mtmsr(msr | PSL_EE); |
168 | * Reenable interrupts | | | |
169 | */ | | | |
170 | __asm volatile ("mfmsr %0; ori %0, %0, %1; mtmsr %0" | | | |
171 | : "=r"(msr) : "K"(PSL_EE)); | | | |
172 | | | | |
173 | /* | | 180 | /* |
174 | * Do standard timer interrupt stuff. | | 181 | * Do standard timer interrupt stuff. |
175 | * Do softclock stuff only on the last iteration. | | 182 | * Do softclock stuff only on the last iteration. |
176 | */ | | 183 | */ |
177 | while (--nticks > 0) | | 184 | while (--nticks > 0) |
178 | hardclock(cfp); | | 185 | hardclock(cfp); |
179 | hardclock(cfp); | | 186 | hardclock(cfp); |
| | | 187 | mtmsr(msr); |
| | | 188 | ci->ci_idepth--; |
180 | } | | 189 | } |
| | | 190 | mtmsr(msr | PSL_EE); |
181 | splx(pri); | | 191 | splx(pri); |
| | | 192 | mtmsr(msr); |
182 | } | | 193 | } |
183 | | | 194 | |
184 | /* | | 195 | /* |
185 | * Wait for about n microseconds (at least!). | | 196 | * Wait for about n microseconds (at least!). |
186 | */ | | 197 | */ |
187 | void | | 198 | void |
188 | delay(unsigned int n) | | 199 | delay(unsigned int n) |
189 | { | | 200 | { |
190 | #ifdef _ARCH_PPC64 | | 201 | #ifdef _ARCH_PPC64 |
191 | uint64_t tb, scratch; | | 202 | uint64_t tb, scratch; |
192 | #else | | 203 | #else |
193 | uint64_t tb; | | 204 | uint64_t tb; |
194 | uint32_t tbh, tbl, scratch; | | 205 | uint32_t tbh, tbl, scratch; |
| @@ -231,31 +242,52 @@ delay(unsigned int n) | | | @@ -231,31 +242,52 @@ delay(unsigned int n) |
231 | : "cr0"); | | 242 | : "cr0"); |
232 | #endif | | 243 | #endif |
233 | } | | 244 | } |
234 | } | | 245 | } |
235 | | | 246 | |
236 | static u_int | | 247 | static u_int |
237 | get_powerpc_timecount(struct timecounter *tc) | | 248 | get_powerpc_timecount(struct timecounter *tc) |
238 | { | | 249 | { |
239 | u_long tb; | | 250 | u_long tb; |
240 | int msr, scratch; | | 251 | int msr, scratch; |
241 | | | 252 | |
242 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" | | 253 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" |
243 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); | | 254 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); |
| | | 255 | |
| | | 256 | tb = (u_int)(mftb() & 0x7fffffff); |
| | | 257 | mtmsr(msr); |
| | | 258 | |
| | | 259 | return tb; |
| | | 260 | } |
| | | 261 | |
244 | #ifdef PPC_OEA601 | | 262 | #ifdef PPC_OEA601 |
245 | if ((mfpvr() >> 16) == MPC601) | | 263 | static u_int |
246 | tb = rtc_nanosecs(); | | 264 | get_601_timecount(struct timecounter *tc) |
247 | else | | 265 | { |
248 | #endif | | 266 | u_long tb; |
249 | __asm volatile ("mftb %0" : "=r"(tb)); | | 267 | int msr, scratch; |
| | | 268 | |
| | | 269 | __asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" |
| | | 270 | : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE)); |
| | | 271 | |
| | | 272 | tb = rtc_nanosecs(); |
250 | mtmsr(msr); | | 273 | mtmsr(msr); |
251 | | | 274 | |
252 | return tb; | | 275 | return tb; |
253 | } | | 276 | } |
| | | 277 | #endif |
254 | | | 278 | |
255 | void | | 279 | void |
256 | init_powerpc_tc(void) | | 280 | init_powerpc_tc(void) |
257 | { | | 281 | { |
258 | /* from machdep initialization */ | | 282 | struct timecounter *tc; |
259 | powerpc_timecounter.tc_frequency = ticks_per_sec; | | 283 | |
260 | tc_init(&powerpc_timecounter); | | 284 | #ifdef PPC_OEA601 |
| | | 285 | if ((mfpvr() >> 16) == MPC601) { |
| | | 286 | tc = &powerpc_601_timecounter; |
| | | 287 | } else |
| | | 288 | #endif |
| | | 289 | tc = &powerpc_timecounter; |
| | | 290 | |
| | | 291 | tc->tc_frequency = ticks_per_sec; |
| | | 292 | tc_init(tc); |
261 | } | | 293 | } |