1 /* 2 * Copyright (c) 2005 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Generic cputimer - access to a reliable, free-running counter. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/systm.h> 41 #include <sys/thread.h> 42 #include <sys/globaldata.h> 43 #include <sys/serialize.h> 44 #include <sys/systimer.h> 45 #include <sys/sysctl.h> 46 #include <sys/thread2.h> 47 48 static sysclock_t dummy_cputimer_count(void); 49 50 static struct cputimer dummy_cputimer = { 51 SLIST_ENTRY_INITIALIZER, 52 "dummy", 53 CPUTIMER_PRI_DUMMY, 54 CPUTIMER_DUMMY, 55 dummy_cputimer_count, 56 cputimer_default_fromhz, 57 cputimer_default_fromus, 58 cputimer_default_construct, 59 cputimer_default_destruct, 60 1000000, 61 (1000000LL << 32) / 1000000, 62 (1000000000LL << 32) / 1000000, 63 0 64 }; 65 66 struct cputimer *sys_cputimer = &dummy_cputimer; 67 SLIST_HEAD(, cputimer) cputimerhead = SLIST_HEAD_INITIALIZER(&cputimerhead); 68 69 static int cputimer_intr_ps_reqs; 70 static struct lwkt_serialize cputimer_intr_ps_slize = 71 LWKT_SERIALIZE_INITIALIZER; 72 73 /* 74 * Generic cputimer API 75 */ 76 void 77 cputimer_select(struct cputimer *timer, int pri) 78 { 79 sysclock_t oldclock; 80 81 /* 82 * Calculate helper fields 83 */ 84 cputimer_set_frequency(timer, timer->freq); 85 86 /* 87 * Install a new cputimer if its priority allows it. If timer is 88 * passed as NULL we deinstall the current timer and revert to our 89 * dummy. 90 */ 91 if (pri == 0) 92 pri = timer->pri; 93 if (timer == NULL || pri >= sys_cputimer->pri) { 94 oldclock = sys_cputimer->count(); 95 sys_cputimer->destruct(sys_cputimer); 96 sys_cputimer = &dummy_cputimer; 97 if (timer) { 98 sys_cputimer = timer; 99 timer->construct(timer, oldclock); 100 cputimer_intr_config(timer); 101 } 102 } 103 } 104 105 /* 106 * Register a timer. If the timer has already been registered, do nothing. 107 */ 108 void 109 cputimer_register(struct cputimer *timer) 110 { 111 struct cputimer *scan; 112 113 /* 114 * Initialize dummy_cputimer if the slist is empty, it does not get 115 * registered the normal way. 116 */ 117 if (SLIST_EMPTY(&cputimerhead)) 118 SLIST_FIRST(&cputimerhead) = &dummy_cputimer; 119 SLIST_FOREACH(scan, &cputimerhead, next) { 120 if (scan == timer) 121 return; 122 } 123 SLIST_INSERT_HEAD(&cputimerhead, timer, next); 124 } 125 126 /* 127 * Deregister a timer. If the timer has already been deregistered, do nothing. 128 */ 129 void 130 cputimer_deregister(struct cputimer *timer) 131 { 132 struct cputimer *scan; 133 struct cputimer *best; 134 135 /* 136 * Locate and remove the timer. If the timer is our currently active 137 * timer, revert to the dummy timer. 138 */ 139 SLIST_FOREACH(scan, &cputimerhead, next) { 140 if (timer == scan) { 141 if (timer == sys_cputimer) 142 cputimer_select(&dummy_cputimer, 0x7FFFFFFF); 143 SLIST_REMOVE(&cputimerhead, timer, cputimer, next); 144 break; 145 } 146 } 147 148 /* 149 * If sys_cputimer reverted to the dummy, select the best one 150 */ 151 if (sys_cputimer == &dummy_cputimer) { 152 best = NULL; 153 SLIST_FOREACH(scan, &cputimerhead, next) { 154 if (best == NULL || scan->pri > best->pri) 155 best = scan; 156 } 157 if (best) 158 cputimer_select(best, 0x7FFFFFFF); 159 } 160 } 161 162 /* 163 * Calculate usec / tick and nsec / tick, scaled by (1 << 32). 164 * 165 * so e.g. a 3 mhz timer would be 3 usec / tick x (1 << 32), 166 * or 3000 nsec / tick x (1 << 32) 167 */ 168 void 169 cputimer_set_frequency(struct cputimer *timer, sysclock_t freq) 170 { 171 timer->freq = freq; 172 timer->freq64_usec = (1000000LL << 32) / freq; 173 timer->freq64_nsec = (1000000000LL << 32) / freq; 174 if (timer == sys_cputimer) 175 cputimer_intr_config(timer); 176 } 177 178 sysclock_t 179 cputimer_default_fromhz(int freq) 180 { 181 return(sys_cputimer->freq / freq + 1); 182 } 183 184 sysclock_t 185 cputimer_default_fromus(int us) 186 { 187 return((int64_t)sys_cputimer->freq * us / 1000000); 188 } 189 190 /* 191 * Dummy counter implementation 192 */ 193 static 194 sysclock_t 195 dummy_cputimer_count(void) 196 { 197 return(++dummy_cputimer.base); 198 } 199 200 void 201 cputimer_default_construct(struct cputimer *cputimer, sysclock_t oldclock) 202 { 203 cputimer->base = oldclock; 204 } 205 206 void 207 cputimer_default_destruct(struct cputimer *cputimer) 208 { 209 } 210 211 /************************************************************************ 212 * SYSCTL SUPPORT * 213 ************************************************************************ 214 * 215 * Note: the ability to change the systimer is not currently enabled 216 * because it will mess up systimer calculations. You have to live 217 * with what is configured at boot. 218 */ 219 static int 220 sysctl_cputimer_reglist(SYSCTL_HANDLER_ARGS) 221 { 222 struct cputimer *scan; 223 int error = 0; 224 int loop = 0; 225 226 /* 227 * Build a list of available timers 228 */ 229 SLIST_FOREACH(scan, &cputimerhead, next) { 230 if (error == 0 && loop) 231 error = SYSCTL_OUT(req, " ", 1); 232 if (error == 0) 233 error = SYSCTL_OUT(req, scan->name, strlen(scan->name)); 234 ++loop; 235 } 236 return (error); 237 } 238 239 static int 240 sysctl_cputimer_name(SYSCTL_HANDLER_ARGS) 241 { 242 int error; 243 244 error = SYSCTL_OUT(req, sys_cputimer->name, strlen(sys_cputimer->name)); 245 return (error); 246 } 247 248 static int 249 sysctl_cputimer_clock(SYSCTL_HANDLER_ARGS) 250 { 251 sysclock_t clock; 252 int error; 253 254 clock = sys_cputimer->count(); 255 error = SYSCTL_OUT(req, &clock, sizeof(clock)); 256 return (error); 257 } 258 259 static int 260 sysctl_cputimer_freq(SYSCTL_HANDLER_ARGS) 261 { 262 int error; 263 264 error = SYSCTL_OUT(req, &sys_cputimer->freq, sizeof(sys_cputimer->freq)); 265 return (error); 266 } 267 268 SYSCTL_DECL(_kern_cputimer); 269 SYSCTL_NODE(_kern, OID_AUTO, cputimer, CTLFLAG_RW, NULL, "cputimer"); 270 271 SYSCTL_PROC(_kern_cputimer, OID_AUTO, select, CTLTYPE_STRING|CTLFLAG_RD, 272 NULL, 0, sysctl_cputimer_reglist, "A", ""); 273 SYSCTL_PROC(_kern_cputimer, OID_AUTO, name, CTLTYPE_STRING|CTLFLAG_RD, 274 NULL, 0, sysctl_cputimer_name, "A", ""); 275 SYSCTL_PROC(_kern_cputimer, OID_AUTO, clock, CTLTYPE_UINT|CTLFLAG_RD, 276 NULL, 0, sysctl_cputimer_clock, "IU", ""); 277 SYSCTL_PROC(_kern_cputimer, OID_AUTO, freq, CTLTYPE_INT|CTLFLAG_RD, 278 NULL, 0, sysctl_cputimer_freq, "I", ""); 279 280 static struct cputimer_intr *sys_cputimer_intr; 281 static uint32_t cputimer_intr_caps; 282 SLIST_HEAD(, cputimer_intr) cputimer_intr_head = 283 SLIST_HEAD_INITIALIZER(&cputimer_intr_head); 284 285 void 286 cputimer_intr_register(struct cputimer_intr *cti) 287 { 288 struct cputimer_intr *scan; 289 290 SLIST_FOREACH(scan, &cputimer_intr_head, next) { 291 if (scan == cti) 292 return; 293 } 294 cti->config(cti, sys_cputimer); 295 SLIST_INSERT_HEAD(&cputimer_intr_head, cti, next); 296 } 297 298 void 299 cputimer_intr_deregister(struct cputimer_intr *cti) 300 { 301 KKASSERT(cti != sys_cputimer_intr); 302 SLIST_REMOVE(&cputimer_intr_head, cti, cputimer_intr, next); 303 } 304 305 int 306 cputimer_intr_select(struct cputimer_intr *cti, int prio) 307 { 308 KKASSERT(cti != NULL); 309 310 if (prio == 0) 311 prio = cti->prio; 312 313 if (sys_cputimer_intr == NULL) { 314 KKASSERT(cputimer_intr_caps == 0); 315 sys_cputimer_intr = cti; 316 return 0; 317 } 318 319 if ((cti->caps & cputimer_intr_caps) == cputimer_intr_caps) { 320 if (prio > sys_cputimer_intr->prio) { 321 sys_cputimer_intr = cti; 322 return 0; 323 } else { 324 return EBUSY; 325 } 326 } else { 327 return EOPNOTSUPP; 328 } 329 } 330 331 void 332 cputimer_intr_default_enable(struct cputimer_intr *cti __unused) 333 { 334 } 335 336 void 337 cputimer_intr_default_restart(struct cputimer_intr *cti) 338 { 339 cti->reload(cti, 0); 340 } 341 342 void 343 cputimer_intr_default_config(struct cputimer_intr *cti __unused, 344 const struct cputimer *timer __unused) 345 { 346 } 347 348 void 349 cputimer_intr_default_pmfixup(struct cputimer_intr *cti __unused) 350 { 351 } 352 353 void 354 cputimer_intr_default_initclock(struct cputimer_intr *cti __unused, 355 boolean_t selected __unused) 356 { 357 } 358 359 void 360 cputimer_intr_enable(void) 361 { 362 struct cputimer_intr *cti; 363 364 SLIST_FOREACH(cti, &cputimer_intr_head, next) 365 cti->enable(cti); 366 } 367 368 void 369 cputimer_intr_config(const struct cputimer *timer) 370 { 371 struct cputimer_intr *cti; 372 373 SLIST_FOREACH(cti, &cputimer_intr_head, next) 374 cti->config(cti, timer); 375 } 376 377 void 378 cputimer_intr_pmfixup(void) 379 { 380 struct cputimer_intr *cti; 381 382 SLIST_FOREACH(cti, &cputimer_intr_head, next) 383 cti->pmfixup(cti); 384 } 385 386 void 387 cputimer_intr_reload(sysclock_t reload) 388 { 389 struct cputimer_intr *cti = sys_cputimer_intr; 390 391 cti->reload(cti, reload); 392 } 393 394 void 395 cputimer_intr_restart(void) 396 { 397 struct cputimer_intr *cti = sys_cputimer_intr; 398 399 cti->restart(cti); 400 } 401 402 int 403 cputimer_intr_select_caps(uint32_t caps) 404 { 405 struct cputimer_intr *cti, *maybe; 406 int error; 407 408 maybe = NULL; 409 SLIST_FOREACH(cti, &cputimer_intr_head, next) { 410 if ((cti->caps & caps) == caps) { 411 if (maybe == NULL) 412 maybe = cti; 413 else if (cti->prio > maybe->prio) 414 maybe = cti; 415 } 416 } 417 if (maybe == NULL) 418 return ENOENT; 419 420 if (sys_cputimer_intr == maybe) 421 return 0; 422 423 cputimer_intr_caps = caps; 424 error = cputimer_intr_select(maybe, CPUTIMER_INTR_PRIO_MAX); 425 KKASSERT(!error); 426 427 return ERESTART; 428 } 429 430 static void 431 cputimer_intr_initclocks(void) 432 { 433 struct cputimer_intr *cti, *ncti; 434 435 /* 436 * An interrupt cputimer may deregister itself, 437 * so use SLIST_FOREACH_MUTABLE here. 438 */ 439 SLIST_FOREACH_MUTABLE(cti, &cputimer_intr_head, next, ncti) { 440 boolean_t selected = FALSE; 441 442 if (cti == sys_cputimer_intr) 443 selected = TRUE; 444 cti->initclock(cti, selected); 445 } 446 } 447 /* NOTE: Must be SECOND to allow platform initialization to go first */ 448 SYSINIT(cputimer_intr, SI_BOOT2_CLOCKREG, SI_ORDER_SECOND, 449 cputimer_intr_initclocks, NULL); 450 451 static int 452 sysctl_cputimer_intr_reglist(SYSCTL_HANDLER_ARGS) 453 { 454 struct cputimer_intr *scan; 455 int error = 0; 456 int loop = 0; 457 458 /* 459 * Build a list of available interrupt cputimers 460 */ 461 SLIST_FOREACH(scan, &cputimer_intr_head, next) { 462 if (error == 0 && loop) 463 error = SYSCTL_OUT(req, " ", 1); 464 if (error == 0) 465 error = SYSCTL_OUT(req, scan->name, strlen(scan->name)); 466 ++loop; 467 } 468 return (error); 469 } 470 471 static int 472 sysctl_cputimer_intr_freq(SYSCTL_HANDLER_ARGS) 473 { 474 int error; 475 476 error = SYSCTL_OUT(req, &sys_cputimer_intr->freq, 477 sizeof(sys_cputimer_intr->freq)); 478 return (error); 479 } 480 481 static int 482 sysctl_cputimer_intr_select(SYSCTL_HANDLER_ARGS) 483 { 484 struct cputimer_intr *cti; 485 char name[32]; 486 int error; 487 488 ksnprintf(name, sizeof(name), "%s", sys_cputimer_intr->name); 489 error = sysctl_handle_string(oidp, name, sizeof(name), req); 490 if (error != 0 || req->newptr == NULL) 491 return error; 492 493 SLIST_FOREACH(cti, &cputimer_intr_head, next) { 494 if (strcmp(cti->name, name) == 0) 495 break; 496 } 497 if (cti == NULL) 498 return ENOENT; 499 if (cti == sys_cputimer_intr) 500 return 0; 501 502 error = cputimer_intr_select(cti, CPUTIMER_INTR_PRIO_MAX); 503 if (!error) 504 cputimer_intr_restart(); 505 return error; 506 } 507 508 SYSCTL_NODE(_kern_cputimer, OID_AUTO, intr, CTLFLAG_RW, NULL, 509 "interrupt cputimer"); 510 511 SYSCTL_PROC(_kern_cputimer_intr, OID_AUTO, reglist, CTLTYPE_STRING|CTLFLAG_RD, 512 NULL, 0, sysctl_cputimer_intr_reglist, "A", ""); 513 SYSCTL_PROC(_kern_cputimer_intr, OID_AUTO, freq, CTLTYPE_INT|CTLFLAG_RD, 514 NULL, 0, sysctl_cputimer_intr_freq, "I", ""); 515 SYSCTL_PROC(_kern_cputimer_intr, OID_AUTO, select, CTLTYPE_STRING|CTLFLAG_RW, 516 NULL, 0, sysctl_cputimer_intr_select, "A", ""); 517 518 int 519 cputimer_intr_powersave_addreq(void) 520 { 521 int error = 0; 522 523 lwkt_serialize_enter(&cputimer_intr_ps_slize); 524 525 ++cputimer_intr_ps_reqs; 526 if (cputimer_intr_ps_reqs == 1) { 527 /* 528 * Upon the first power saving request, switch to an one shot 529 * timer, which would not stop in the any power saving state. 530 */ 531 error = cputimer_intr_select_caps(CPUTIMER_INTR_CAP_PS); 532 if (error == ERESTART) { 533 error = 0; 534 if (bootverbose) 535 kprintf("cputimer: first power save request, restart\n"); 536 cputimer_intr_restart(); 537 } else if (error) { 538 kprintf("no suitable intr cputimer found\n"); 539 --cputimer_intr_ps_reqs; 540 } else if (bootverbose) { 541 kprintf("cputimer: first power save request\n"); 542 } 543 } 544 545 lwkt_serialize_exit(&cputimer_intr_ps_slize); 546 547 return error; 548 } 549 550 void 551 cputimer_intr_powersave_remreq(void) 552 { 553 lwkt_serialize_enter(&cputimer_intr_ps_slize); 554 555 KASSERT(cputimer_intr_ps_reqs > 0, 556 ("invalid # of powersave reqs %d", cputimer_intr_ps_reqs)); 557 --cputimer_intr_ps_reqs; 558 if (cputimer_intr_ps_reqs == 0) { 559 int error; 560 561 /* No one needs power saving, use a better one shot timer. */ 562 error = cputimer_intr_select_caps(CPUTIMER_INTR_CAP_NONE); 563 KKASSERT(!error || error == ERESTART); 564 if (error == ERESTART) { 565 if (bootverbose) 566 kprintf("cputimer: no powser save request, restart\n"); 567 cputimer_intr_restart(); 568 } else if (bootverbose) { 569 kprintf("cputimer: no power save request\n"); 570 } 571 } 572 573 lwkt_serialize_exit(&cputimer_intr_ps_slize); 574 } 575