1/*- 2 * Copyright (c) 2006-2007 Bruce M. Simpson. 3 * Copyright (c) 2003-2004 Juli Mallett. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* 29 * Simple driver for the 32-bit interval counter built in to all 30 * MIPS32 CPUs. 31 */ 32 33#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2006-2007 Bruce M. Simpson. 3 * Copyright (c) 2003-2004 Juli Mallett. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* 29 * Simple driver for the 32-bit interval counter built in to all 30 * MIPS32 CPUs. 31 */ 32 33#include <sys/cdefs.h>
|
69 70struct clock_softc { 71 int intr_rid; 72 struct resource *intr_res; 73 void *intr_handler; 74 struct timecounter tc; 75 struct eventtimer et; 76}; 77static struct clock_softc *softc; 78 79/* 80 * Device methods 81 */ 82static int clock_probe(device_t); 83static void clock_identify(driver_t *, device_t); 84static int clock_attach(device_t); 85static unsigned counter_get_timecount(struct timecounter *tc); 86 87void 88mips_timer_early_init(uint64_t clock_hz) 89{ 90 /* Initialize clock early so that we can use DELAY sooner */ 91 counter_freq = clock_hz; 92 cycles_per_usec = (clock_hz / (1000 * 1000)); 93} 94 95void 96platform_initclocks(void) 97{ 98 99 if (platform_timecounter != NULL) 100 tc_init(platform_timecounter); 101} 102 103static uint64_t 104tick_ticker(void) 105{ 106 uint64_t ret; 107 uint32_t ticktock; 108 uint32_t t_lower_last, t_upper; 109 110 /* 111 * Disable preemption because we are working with cpu specific data. 112 */ 113 critical_enter(); 114 115 /* 116 * Note that even though preemption is disabled, interrupts are 117 * still enabled. In particular there is a race with clock_intr() 118 * reading the values of 'counter_upper' and 'counter_lower_last'. 119 * 120 * XXX this depends on clock_intr() being executed periodically 121 * so that 'counter_upper' and 'counter_lower_last' are not stale. 122 */ 123 do { 124 t_upper = DPCPU_GET(counter_upper); 125 t_lower_last = DPCPU_GET(counter_lower_last); 126 } while (t_upper != DPCPU_GET(counter_upper)); 127 128 ticktock = mips_rd_count(); 129 130 critical_exit(); 131 132 /* COUNT register wrapped around */ 133 if (ticktock < t_lower_last) 134 t_upper++; 135 136 ret = ((uint64_t)t_upper << 32) | ticktock; 137 return (ret); 138} 139 140void 141mips_timer_init_params(uint64_t platform_counter_freq, int double_count) 142{ 143 144 /* 145 * XXX: Do not use printf here: uart code 8250 may use DELAY so this 146 * function should be called before cninit. 147 */ 148 counter_freq = platform_counter_freq; 149 /* 150 * XXX: Some MIPS32 cores update the Count register only every two 151 * pipeline cycles. 152 * We know this because of status registers in CP0, make it automatic. 153 */ 154 if (double_count != 0) 155 counter_freq /= 2; 156 157 cycles_per_usec = counter_freq / (1 * 1000 * 1000); 158 set_cputicker(tick_ticker, counter_freq, 1); 159} 160 161static int 162sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) 163{ 164 int error; 165 uint64_t freq; 166 167 if (softc == NULL) 168 return (EOPNOTSUPP); 169 freq = counter_freq; 170 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 171 if (error == 0 && req->newptr != NULL) { 172 counter_freq = freq; 173 softc->et.et_frequency = counter_freq; 174 softc->tc.tc_frequency = counter_freq; 175 } 176 return (error); 177} 178 179SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_QUAD | CTLFLAG_RW, 180 0, sizeof(u_int), sysctl_machdep_counter_freq, "IU", 181 "Timecounter frequency in Hz"); 182 183static unsigned 184counter_get_timecount(struct timecounter *tc) 185{ 186 187 return (mips_rd_count()); 188} 189 190/* 191 * Wait for about n microseconds (at least!). 192 */ 193void 194DELAY(int n) 195{ 196 uint32_t cur, last, delta, usecs; 197 198 /* 199 * This works by polling the timer and counting the number of 200 * microseconds that go by. 201 */ 202 last = mips_rd_count(); 203 delta = usecs = 0; 204 205 while (n > usecs) { 206 cur = mips_rd_count(); 207 208 /* Check to see if the timer has wrapped around. */ 209 if (cur < last) 210 delta += cur + (0xffffffff - last) + 1; 211 else 212 delta += cur - last; 213 214 last = cur; 215 216 if (delta >= cycles_per_usec) { 217 usecs += delta / cycles_per_usec; 218 delta %= cycles_per_usec; 219 } 220 } 221} 222 223static int 224clock_start(struct eventtimer *et, 225 struct bintime *first, struct bintime *period) 226{ 227 uint32_t fdiv, div, next; 228 229 if (period != NULL) { 230 div = (et->et_frequency * (period->frac >> 32)) >> 32; 231 if (period->sec != 0) 232 div += et->et_frequency * period->sec; 233 } else 234 div = 0; 235 if (first != NULL) { 236 fdiv = (et->et_frequency * (first->frac >> 32)) >> 32; 237 if (first->sec != 0) 238 fdiv += et->et_frequency * first->sec; 239 } else 240 fdiv = div; 241 DPCPU_SET(cycles_per_tick, div); 242 next = mips_rd_count() + fdiv; 243 DPCPU_SET(compare_ticks, next); 244 mips_wr_compare(next); 245 return (0); 246} 247 248static int 249clock_stop(struct eventtimer *et) 250{ 251 252 DPCPU_SET(cycles_per_tick, 0); 253 mips_wr_compare(0xffffffff); 254 return (0); 255} 256 257/* 258 * Device section of file below 259 */ 260static int 261clock_intr(void *arg) 262{ 263 struct clock_softc *sc = (struct clock_softc *)arg; 264 uint32_t cycles_per_tick; 265 uint32_t count, compare_last, compare_next, lost_ticks; 266 267 cycles_per_tick = DPCPU_GET(cycles_per_tick); 268 /* 269 * Set next clock edge. 270 */ 271 count = mips_rd_count(); 272 compare_last = DPCPU_GET(compare_ticks); 273 if (cycles_per_tick > 0) { 274 compare_next = count + cycles_per_tick; 275 DPCPU_SET(compare_ticks, compare_next); 276 mips_wr_compare(compare_next); 277 } else /* In one-shot mode timer should be stopped after the event. */ 278 mips_wr_compare(0xffffffff); 279 280 /* COUNT register wrapped around */ 281 if (count < DPCPU_GET(counter_lower_last)) { 282 DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); 283 } 284 DPCPU_SET(counter_lower_last, count); 285 286 if (cycles_per_tick > 0) { 287 288 /* 289 * Account for the "lost time" between when the timer interrupt 290 * fired and when 'clock_intr' actually started executing. 291 */ 292 lost_ticks = DPCPU_GET(lost_ticks); 293 lost_ticks += count - compare_last; 294 295 /* 296 * If the COUNT and COMPARE registers are no longer in sync 297 * then make up some reasonable value for the 'lost_ticks'. 298 * 299 * This could happen, for e.g., after we resume normal 300 * operations after exiting the debugger. 301 */ 302 if (lost_ticks > 2 * cycles_per_tick) 303 lost_ticks = cycles_per_tick; 304 305 while (lost_ticks >= cycles_per_tick) { 306 if (sc->et.et_active) 307 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 308 lost_ticks -= cycles_per_tick; 309 } 310 DPCPU_SET(lost_ticks, lost_ticks); 311 } 312 if (sc->et.et_active) 313 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 314 return (FILTER_HANDLED); 315} 316 317static int 318clock_probe(device_t dev) 319{ 320 321 if (device_get_unit(dev) != 0) 322 panic("can't attach more clocks"); 323 324 device_set_desc(dev, "Generic MIPS32 ticker"); 325 return (0); 326} 327 328static void 329clock_identify(driver_t * drv, device_t parent) 330{ 331 332 BUS_ADD_CHILD(parent, 0, "clock", 0); 333} 334 335static int 336clock_attach(device_t dev) 337{ 338 struct clock_softc *sc; 339 340 softc = sc = device_get_softc(dev); 341 cpu_establish_hardintr("compare", clock_intr, NULL, 342 sc, IRQ_TIMER, INTR_TYPE_CLK, &sc->intr_handler); 343 344 sc->tc.tc_get_timecount = counter_get_timecount; 345 sc->tc.tc_counter_mask = 0xffffffff; 346 sc->tc.tc_frequency = counter_freq; 347 sc->tc.tc_name = "MIPS32"; 348 sc->tc.tc_quality = 800; 349 sc->tc.tc_priv = sc; 350 tc_init(&sc->tc); 351 sc->et.et_name = "MIPS32"; 352 sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | 353 ET_FLAGS_PERCPU; 354 sc->et.et_quality = 800; 355 sc->et.et_frequency = counter_freq; 356 sc->et.et_min_period.sec = 0; 357 sc->et.et_min_period.frac = 0x00004000LLU << 32; /* To be safe. */ 358 sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency; 359 sc->et.et_max_period.frac = 360 ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; 361 sc->et.et_start = clock_start; 362 sc->et.et_stop = clock_stop; 363 sc->et.et_priv = sc; 364 et_register(&sc->et); 365 return (0); 366} 367 368static device_method_t clock_methods[] = { 369 /* Device interface */ 370 DEVMETHOD(device_probe, clock_probe), 371 DEVMETHOD(device_identify, clock_identify), 372 DEVMETHOD(device_attach, clock_attach), 373 DEVMETHOD(device_detach, bus_generic_detach), 374 DEVMETHOD(device_shutdown, bus_generic_shutdown), 375 376 {0, 0} 377}; 378 379static driver_t clock_driver = { 380 "clock", 381 clock_methods, 382 sizeof(struct clock_softc), 383}; 384 385static devclass_t clock_devclass; 386 387DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0);
| 69 70struct clock_softc { 71 int intr_rid; 72 struct resource *intr_res; 73 void *intr_handler; 74 struct timecounter tc; 75 struct eventtimer et; 76}; 77static struct clock_softc *softc; 78 79/* 80 * Device methods 81 */ 82static int clock_probe(device_t); 83static void clock_identify(driver_t *, device_t); 84static int clock_attach(device_t); 85static unsigned counter_get_timecount(struct timecounter *tc); 86 87void 88mips_timer_early_init(uint64_t clock_hz) 89{ 90 /* Initialize clock early so that we can use DELAY sooner */ 91 counter_freq = clock_hz; 92 cycles_per_usec = (clock_hz / (1000 * 1000)); 93} 94 95void 96platform_initclocks(void) 97{ 98 99 if (platform_timecounter != NULL) 100 tc_init(platform_timecounter); 101} 102 103static uint64_t 104tick_ticker(void) 105{ 106 uint64_t ret; 107 uint32_t ticktock; 108 uint32_t t_lower_last, t_upper; 109 110 /* 111 * Disable preemption because we are working with cpu specific data. 112 */ 113 critical_enter(); 114 115 /* 116 * Note that even though preemption is disabled, interrupts are 117 * still enabled. In particular there is a race with clock_intr() 118 * reading the values of 'counter_upper' and 'counter_lower_last'. 119 * 120 * XXX this depends on clock_intr() being executed periodically 121 * so that 'counter_upper' and 'counter_lower_last' are not stale. 122 */ 123 do { 124 t_upper = DPCPU_GET(counter_upper); 125 t_lower_last = DPCPU_GET(counter_lower_last); 126 } while (t_upper != DPCPU_GET(counter_upper)); 127 128 ticktock = mips_rd_count(); 129 130 critical_exit(); 131 132 /* COUNT register wrapped around */ 133 if (ticktock < t_lower_last) 134 t_upper++; 135 136 ret = ((uint64_t)t_upper << 32) | ticktock; 137 return (ret); 138} 139 140void 141mips_timer_init_params(uint64_t platform_counter_freq, int double_count) 142{ 143 144 /* 145 * XXX: Do not use printf here: uart code 8250 may use DELAY so this 146 * function should be called before cninit. 147 */ 148 counter_freq = platform_counter_freq; 149 /* 150 * XXX: Some MIPS32 cores update the Count register only every two 151 * pipeline cycles. 152 * We know this because of status registers in CP0, make it automatic. 153 */ 154 if (double_count != 0) 155 counter_freq /= 2; 156 157 cycles_per_usec = counter_freq / (1 * 1000 * 1000); 158 set_cputicker(tick_ticker, counter_freq, 1); 159} 160 161static int 162sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) 163{ 164 int error; 165 uint64_t freq; 166 167 if (softc == NULL) 168 return (EOPNOTSUPP); 169 freq = counter_freq; 170 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 171 if (error == 0 && req->newptr != NULL) { 172 counter_freq = freq; 173 softc->et.et_frequency = counter_freq; 174 softc->tc.tc_frequency = counter_freq; 175 } 176 return (error); 177} 178 179SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_QUAD | CTLFLAG_RW, 180 0, sizeof(u_int), sysctl_machdep_counter_freq, "IU", 181 "Timecounter frequency in Hz"); 182 183static unsigned 184counter_get_timecount(struct timecounter *tc) 185{ 186 187 return (mips_rd_count()); 188} 189 190/* 191 * Wait for about n microseconds (at least!). 192 */ 193void 194DELAY(int n) 195{ 196 uint32_t cur, last, delta, usecs; 197 198 /* 199 * This works by polling the timer and counting the number of 200 * microseconds that go by. 201 */ 202 last = mips_rd_count(); 203 delta = usecs = 0; 204 205 while (n > usecs) { 206 cur = mips_rd_count(); 207 208 /* Check to see if the timer has wrapped around. */ 209 if (cur < last) 210 delta += cur + (0xffffffff - last) + 1; 211 else 212 delta += cur - last; 213 214 last = cur; 215 216 if (delta >= cycles_per_usec) { 217 usecs += delta / cycles_per_usec; 218 delta %= cycles_per_usec; 219 } 220 } 221} 222 223static int 224clock_start(struct eventtimer *et, 225 struct bintime *first, struct bintime *period) 226{ 227 uint32_t fdiv, div, next; 228 229 if (period != NULL) { 230 div = (et->et_frequency * (period->frac >> 32)) >> 32; 231 if (period->sec != 0) 232 div += et->et_frequency * period->sec; 233 } else 234 div = 0; 235 if (first != NULL) { 236 fdiv = (et->et_frequency * (first->frac >> 32)) >> 32; 237 if (first->sec != 0) 238 fdiv += et->et_frequency * first->sec; 239 } else 240 fdiv = div; 241 DPCPU_SET(cycles_per_tick, div); 242 next = mips_rd_count() + fdiv; 243 DPCPU_SET(compare_ticks, next); 244 mips_wr_compare(next); 245 return (0); 246} 247 248static int 249clock_stop(struct eventtimer *et) 250{ 251 252 DPCPU_SET(cycles_per_tick, 0); 253 mips_wr_compare(0xffffffff); 254 return (0); 255} 256 257/* 258 * Device section of file below 259 */ 260static int 261clock_intr(void *arg) 262{ 263 struct clock_softc *sc = (struct clock_softc *)arg; 264 uint32_t cycles_per_tick; 265 uint32_t count, compare_last, compare_next, lost_ticks; 266 267 cycles_per_tick = DPCPU_GET(cycles_per_tick); 268 /* 269 * Set next clock edge. 270 */ 271 count = mips_rd_count(); 272 compare_last = DPCPU_GET(compare_ticks); 273 if (cycles_per_tick > 0) { 274 compare_next = count + cycles_per_tick; 275 DPCPU_SET(compare_ticks, compare_next); 276 mips_wr_compare(compare_next); 277 } else /* In one-shot mode timer should be stopped after the event. */ 278 mips_wr_compare(0xffffffff); 279 280 /* COUNT register wrapped around */ 281 if (count < DPCPU_GET(counter_lower_last)) { 282 DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); 283 } 284 DPCPU_SET(counter_lower_last, count); 285 286 if (cycles_per_tick > 0) { 287 288 /* 289 * Account for the "lost time" between when the timer interrupt 290 * fired and when 'clock_intr' actually started executing. 291 */ 292 lost_ticks = DPCPU_GET(lost_ticks); 293 lost_ticks += count - compare_last; 294 295 /* 296 * If the COUNT and COMPARE registers are no longer in sync 297 * then make up some reasonable value for the 'lost_ticks'. 298 * 299 * This could happen, for e.g., after we resume normal 300 * operations after exiting the debugger. 301 */ 302 if (lost_ticks > 2 * cycles_per_tick) 303 lost_ticks = cycles_per_tick; 304 305 while (lost_ticks >= cycles_per_tick) { 306 if (sc->et.et_active) 307 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 308 lost_ticks -= cycles_per_tick; 309 } 310 DPCPU_SET(lost_ticks, lost_ticks); 311 } 312 if (sc->et.et_active) 313 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 314 return (FILTER_HANDLED); 315} 316 317static int 318clock_probe(device_t dev) 319{ 320 321 if (device_get_unit(dev) != 0) 322 panic("can't attach more clocks"); 323 324 device_set_desc(dev, "Generic MIPS32 ticker"); 325 return (0); 326} 327 328static void 329clock_identify(driver_t * drv, device_t parent) 330{ 331 332 BUS_ADD_CHILD(parent, 0, "clock", 0); 333} 334 335static int 336clock_attach(device_t dev) 337{ 338 struct clock_softc *sc; 339 340 softc = sc = device_get_softc(dev); 341 cpu_establish_hardintr("compare", clock_intr, NULL, 342 sc, IRQ_TIMER, INTR_TYPE_CLK, &sc->intr_handler); 343 344 sc->tc.tc_get_timecount = counter_get_timecount; 345 sc->tc.tc_counter_mask = 0xffffffff; 346 sc->tc.tc_frequency = counter_freq; 347 sc->tc.tc_name = "MIPS32"; 348 sc->tc.tc_quality = 800; 349 sc->tc.tc_priv = sc; 350 tc_init(&sc->tc); 351 sc->et.et_name = "MIPS32"; 352 sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | 353 ET_FLAGS_PERCPU; 354 sc->et.et_quality = 800; 355 sc->et.et_frequency = counter_freq; 356 sc->et.et_min_period.sec = 0; 357 sc->et.et_min_period.frac = 0x00004000LLU << 32; /* To be safe. */ 358 sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency; 359 sc->et.et_max_period.frac = 360 ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; 361 sc->et.et_start = clock_start; 362 sc->et.et_stop = clock_stop; 363 sc->et.et_priv = sc; 364 et_register(&sc->et); 365 return (0); 366} 367 368static device_method_t clock_methods[] = { 369 /* Device interface */ 370 DEVMETHOD(device_probe, clock_probe), 371 DEVMETHOD(device_identify, clock_identify), 372 DEVMETHOD(device_attach, clock_attach), 373 DEVMETHOD(device_detach, bus_generic_detach), 374 DEVMETHOD(device_shutdown, bus_generic_shutdown), 375 376 {0, 0} 377}; 378 379static driver_t clock_driver = { 380 "clock", 381 clock_methods, 382 sizeof(struct clock_softc), 383}; 384 385static devclass_t clock_devclass; 386 387DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0);
|