1 /* 2 * Copyright (c) 2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Sepherosa Ziehau <sepherosa@gmail.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 #include <sys/param.h> 36 #include <sys/conf.h> 37 #include <sys/kernel.h> 38 #include <sys/bus.h> 39 #include <sys/cpu_topology.h> 40 #include <sys/module.h> 41 #include <sys/queue.h> 42 #include <sys/serialize.h> 43 #include <sys/sysctl.h> 44 #include <sys/systm.h> 45 46 #include <net/netmsg2.h> 47 #include <net/netisr2.h> 48 49 #include <machine/specialreg.h> 50 #include <machine/cpufunc.h> 51 #include <machine/cputypes.h> 52 #include <machine/md_var.h> 53 54 struct clockmod_dom; 55 56 struct netmsg_clockmod { 57 struct netmsg_base base; 58 uint64_t ctl_value; 59 }; 60 61 struct clockmod_softc { 62 TAILQ_ENTRY(clockmod_softc) sc_link; 63 struct clockmod_dom *sc_dom; 64 int sc_cpuid; 65 }; 66 67 struct clockmod_dom { 68 TAILQ_ENTRY(clockmod_dom) dom_link; 69 TAILQ_HEAD(, clockmod_softc) dom_list; 70 struct sysctl_ctx_list dom_sysctl_ctx; 71 struct sysctl_oid *dom_sysctl_tree; 72 cpumask_t dom_cpumask; 73 char dom_name[16]; 74 int dom_select; 75 uint32_t dom_flags; 76 }; 77 78 #define CLOCKMOD_DOM_FLAG_ACTIVE 0x1 79 80 struct clockmod_dom_ctrl { 81 char ctl_name[8]; 82 uint64_t ctl_value; 83 }; 84 85 static int clockmod_dom_attach(struct clockmod_softc *); 86 static void clockmod_dom_detach(struct clockmod_softc *); 87 static struct clockmod_dom *clockmod_dom_find(cpumask_t); 88 static struct clockmod_dom *clockmod_dom_create(cpumask_t); 89 static void clockmod_dom_destroy(struct clockmod_dom *); 90 91 static int clockmod_dom_sysctl_select(SYSCTL_HANDLER_ARGS); 92 static int clockmod_dom_sysctl_members(SYSCTL_HANDLER_ARGS); 93 static int clockmod_dom_sysctl_available(SYSCTL_HANDLER_ARGS); 94 95 static void clockmod_identify(driver_t *, device_t); 96 static int clockmod_probe(device_t); 97 static int clockmod_attach(device_t); 98 static int clockmod_detach(device_t); 99 100 static void clockmod_select_handler(netmsg_t); 101 static int clockmod_select(const struct clockmod_softc *, 102 const struct clockmod_dom_ctrl *); 103 104 static boolean_t clockmod_errata_duty(int); 105 106 static struct lwkt_serialize clockmod_dom_slize = LWKT_SERIALIZE_INITIALIZER; 107 static int clockmod_dom_id; 108 static TAILQ_HEAD(, clockmod_dom) clockmod_dom_list = 109 TAILQ_HEAD_INITIALIZER(clockmod_dom_list); 110 static int clockmod_dom_nctrl; 111 static struct clockmod_dom_ctrl *clockmod_dom_controls; 112 113 static device_method_t clockmod_methods[] = { 114 /* Device interface */ 115 DEVMETHOD(device_identify, clockmod_identify), 116 DEVMETHOD(device_probe, clockmod_probe), 117 DEVMETHOD(device_attach, clockmod_attach), 118 DEVMETHOD(device_detach, clockmod_detach), 119 120 DEVMETHOD_END 121 }; 122 123 static driver_t clockmod_driver = { 124 "clockmod", 125 clockmod_methods, 126 sizeof(struct clockmod_softc), 127 }; 128 129 static devclass_t clockmod_devclass; 130 DRIVER_MODULE(clockmod, cpu, clockmod_driver, clockmod_devclass, NULL, NULL); 131 132 static void 133 clockmod_identify(driver_t *driver, device_t parent) 134 { 135 device_t child; 136 137 if (device_find_child(parent, "clockmod", -1) != NULL) 138 return; 139 140 if (cpu_vendor_id != CPU_VENDOR_INTEL) 141 return; 142 143 if ((cpu_feature & (CPUID_ACPI | CPUID_TM)) != (CPUID_ACPI | CPUID_TM)) 144 return; 145 146 child = device_add_child(parent, "clockmod", device_get_unit(parent)); 147 if (child == NULL) 148 device_printf(parent, "add clockmod failed\n"); 149 } 150 151 static int 152 clockmod_probe(device_t dev) 153 { 154 device_set_desc(dev, "CPU clock modulation"); 155 return 0; 156 } 157 158 static int 159 clockmod_attach(device_t dev) 160 { 161 struct clockmod_softc *sc = device_get_softc(dev); 162 int error; 163 164 sc->sc_cpuid = device_get_unit(dev); 165 166 error = clockmod_dom_attach(sc); 167 if (error) { 168 device_printf(dev, "domain attach failed\n"); 169 return error; 170 } 171 172 return 0; 173 } 174 175 static int 176 clockmod_detach(device_t dev) 177 { 178 clockmod_dom_detach(device_get_softc(dev)); 179 return 0; 180 } 181 182 static int 183 clockmod_dom_attach(struct clockmod_softc *sc) 184 { 185 struct clockmod_softc *sc1; 186 struct clockmod_dom *dom; 187 cpumask_t mask, found_mask; 188 int error = 0; 189 190 CPUMASK_ASSZERO(found_mask); 191 192 mask = get_cpumask_from_level(sc->sc_cpuid, CORE_LEVEL); 193 if (CPUMASK_TESTZERO(mask)) 194 CPUMASK_ASSBIT(mask, sc->sc_cpuid); 195 196 lwkt_serialize_enter(&clockmod_dom_slize); 197 198 dom = clockmod_dom_find(mask); 199 if (dom == NULL) { 200 dom = clockmod_dom_create(mask); 201 if (dom == NULL) { 202 error = ENOMEM; 203 goto back; 204 } 205 } 206 207 sc->sc_dom = dom; 208 TAILQ_INSERT_TAIL(&dom->dom_list, sc, sc_link); 209 210 TAILQ_FOREACH(sc1, &dom->dom_list, sc_link) 211 CPUMASK_ORBIT(found_mask, sc1->sc_cpuid); 212 213 if (CPUMASK_CMPMASKEQ(found_mask, dom->dom_cpumask)) { 214 /* All cpus in this domain is found */ 215 dom->dom_flags |= CLOCKMOD_DOM_FLAG_ACTIVE; 216 } 217 back: 218 lwkt_serialize_exit(&clockmod_dom_slize); 219 return error; 220 } 221 222 static void 223 clockmod_dom_detach(struct clockmod_softc *sc) 224 { 225 struct clockmod_dom *dom; 226 227 lwkt_serialize_enter(&clockmod_dom_slize); 228 229 dom = sc->sc_dom; 230 sc->sc_dom = NULL; 231 232 if (dom->dom_flags & CLOCKMOD_DOM_FLAG_ACTIVE) { 233 struct clockmod_softc *sc1; 234 235 /* Raise to 100% */ 236 TAILQ_FOREACH(sc1, &dom->dom_list, sc_link) 237 clockmod_select(sc1, &clockmod_dom_controls[0]); 238 } 239 240 /* One cpu is leaving; domain is no longer active */ 241 dom->dom_flags &= ~CLOCKMOD_DOM_FLAG_ACTIVE; 242 243 TAILQ_REMOVE(&dom->dom_list, sc, sc_link); 244 if (TAILQ_EMPTY(&dom->dom_list)) 245 clockmod_dom_destroy(dom); 246 247 lwkt_serialize_exit(&clockmod_dom_slize); 248 } 249 250 static struct clockmod_dom * 251 clockmod_dom_find(cpumask_t mask) 252 { 253 struct clockmod_dom *dom; 254 255 TAILQ_FOREACH(dom, &clockmod_dom_list, dom_link) { 256 if (CPUMASK_CMPMASKEQ(dom->dom_cpumask, mask)) 257 return dom; 258 } 259 return NULL; 260 } 261 262 static struct clockmod_dom * 263 clockmod_dom_create(cpumask_t mask) 264 { 265 struct clockmod_dom *dom; 266 int id; 267 268 id = clockmod_dom_id++; 269 dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO); 270 271 TAILQ_INIT(&dom->dom_list); 272 dom->dom_cpumask = mask; 273 ksnprintf(dom->dom_name, sizeof(dom->dom_name), "clockmod_dom%d", id); 274 275 sysctl_ctx_init(&dom->dom_sysctl_ctx); 276 dom->dom_sysctl_tree = SYSCTL_ADD_NODE(&dom->dom_sysctl_ctx, 277 SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO, dom->dom_name, 278 CTLFLAG_RD, 0, ""); 279 if (dom->dom_sysctl_tree == NULL) { 280 kprintf("%s: can't add sysctl node\n", dom->dom_name); 281 kfree(dom, M_DEVBUF); 282 return NULL; 283 } 284 285 SYSCTL_ADD_PROC(&dom->dom_sysctl_ctx, 286 SYSCTL_CHILDREN(dom->dom_sysctl_tree), 287 OID_AUTO, "members", CTLTYPE_STRING | CTLFLAG_RD, 288 dom, 0, clockmod_dom_sysctl_members, "A", "member cpus"); 289 290 SYSCTL_ADD_PROC(&dom->dom_sysctl_ctx, 291 SYSCTL_CHILDREN(dom->dom_sysctl_tree), 292 OID_AUTO, "available", CTLTYPE_STRING | CTLFLAG_RD, 293 dom, 0, clockmod_dom_sysctl_available, "A", 294 "available duty percent"); 295 296 SYSCTL_ADD_PROC(&dom->dom_sysctl_ctx, 297 SYSCTL_CHILDREN(dom->dom_sysctl_tree), 298 OID_AUTO, "select", CTLTYPE_STRING | CTLFLAG_RW, 299 dom, 0, clockmod_dom_sysctl_select, "A", "select duty"); 300 301 TAILQ_INSERT_TAIL(&clockmod_dom_list, dom, dom_link); 302 303 if (clockmod_dom_controls == NULL) { 304 int nctrl, step, i, shift, cnt; 305 306 #ifdef __x86_64__ 307 if (cpu_thermal_feature & CPUID_THERMAL_ECMD) 308 shift = 0; 309 else 310 #endif 311 shift = 1; 312 313 nctrl = 8 << (1 - shift); 314 step = 10000 / nctrl; 315 316 clockmod_dom_controls = 317 kmalloc(sizeof(struct clockmod_dom_ctrl) * nctrl, M_DEVBUF, 318 M_WAITOK | M_ZERO); 319 320 if (bootverbose) 321 kprintf("clock modulation:\n"); 322 323 cnt = 0; 324 for (i = 0; i < nctrl; ++i) { 325 struct clockmod_dom_ctrl *ctrl = 326 &clockmod_dom_controls[cnt]; 327 int duty; 328 329 duty = 10000 - (i * step); 330 if (clockmod_errata_duty(duty)) 331 continue; 332 ++cnt; 333 334 ksnprintf(ctrl->ctl_name, sizeof(ctrl->ctl_name), 335 "%d.%02d%%", duty / 100, duty % 100); 336 ctrl->ctl_value = (((nctrl - i) << shift) & 0xf); 337 if (i != 0) 338 ctrl->ctl_value |= 1 << 4; 339 340 if (bootverbose) { 341 kprintf(" 0x%04jx %s\n", 342 (uintmax_t)ctrl->ctl_value, 343 ctrl->ctl_name); 344 } 345 } 346 clockmod_dom_nctrl = cnt; 347 } 348 return dom; 349 } 350 351 static void 352 clockmod_dom_destroy(struct clockmod_dom *dom) 353 { 354 KASSERT(TAILQ_EMPTY(&dom->dom_list), 355 ("%s: still has member cpus", dom->dom_name)); 356 TAILQ_REMOVE(&clockmod_dom_list, dom, dom_link); 357 358 sysctl_ctx_free(&dom->dom_sysctl_ctx); 359 kfree(dom, M_DEVBUF); 360 361 if (TAILQ_EMPTY(&clockmod_dom_list)) { 362 clockmod_dom_nctrl = 0; 363 kfree(clockmod_dom_controls, M_DEVBUF); 364 clockmod_dom_controls = NULL; 365 } 366 } 367 368 static int 369 clockmod_dom_sysctl_members(SYSCTL_HANDLER_ARGS) 370 { 371 struct clockmod_dom *dom = arg1; 372 struct clockmod_softc *sc; 373 int loop, error; 374 375 lwkt_serialize_enter(&clockmod_dom_slize); 376 377 loop = error = 0; 378 TAILQ_FOREACH(sc, &dom->dom_list, sc_link) { 379 char buf[16]; 380 381 if (error == 0 && loop) 382 error = SYSCTL_OUT(req, " ", 1); 383 if (error == 0) { 384 ksnprintf(buf, sizeof(buf), "cpu%d", sc->sc_cpuid); 385 error = SYSCTL_OUT(req, buf, strlen(buf)); 386 } 387 ++loop; 388 } 389 390 lwkt_serialize_exit(&clockmod_dom_slize); 391 return error; 392 } 393 394 static int 395 clockmod_dom_sysctl_available(SYSCTL_HANDLER_ARGS) 396 { 397 struct clockmod_dom *dom = arg1; 398 int loop, error, i; 399 400 lwkt_serialize_enter(&clockmod_dom_slize); 401 402 if ((dom->dom_flags & CLOCKMOD_DOM_FLAG_ACTIVE) == 0) { 403 error = SYSCTL_OUT(req, " ", 1); 404 goto done; 405 } 406 407 loop = error = 0; 408 for (i = 0; i < clockmod_dom_nctrl; ++i) { 409 if (error == 0 && loop) 410 error = SYSCTL_OUT(req, " ", 1); 411 if (error == 0) { 412 error = SYSCTL_OUT(req, 413 clockmod_dom_controls[i].ctl_name, 414 strlen(clockmod_dom_controls[i].ctl_name)); 415 } 416 ++loop; 417 } 418 done: 419 lwkt_serialize_exit(&clockmod_dom_slize); 420 return error; 421 } 422 423 static int 424 clockmod_dom_sysctl_select(SYSCTL_HANDLER_ARGS) 425 { 426 struct clockmod_dom *dom = arg1; 427 struct clockmod_softc *sc; 428 const struct clockmod_dom_ctrl *ctrl = NULL; 429 char duty[16]; 430 int error, i; 431 432 lwkt_serialize_enter(&clockmod_dom_slize); 433 KKASSERT(dom->dom_select >= 0 && dom->dom_select < clockmod_dom_nctrl); 434 ksnprintf(duty, sizeof(duty), "%s", 435 clockmod_dom_controls[dom->dom_select].ctl_name); 436 lwkt_serialize_exit(&clockmod_dom_slize); 437 438 error = sysctl_handle_string(oidp, duty, sizeof(duty), req); 439 if (error != 0 || req->newptr == NULL) 440 return error; 441 442 lwkt_serialize_enter(&clockmod_dom_slize); 443 444 if ((dom->dom_flags & CLOCKMOD_DOM_FLAG_ACTIVE) == 0) { 445 error = EOPNOTSUPP; 446 goto back; 447 } 448 449 for (i = 0; i < clockmod_dom_nctrl; ++i) { 450 ctrl = &clockmod_dom_controls[i]; 451 if (strcmp(duty, ctrl->ctl_name) == 0) 452 break; 453 } 454 if (i == clockmod_dom_nctrl) { 455 error = EINVAL; 456 goto back; 457 } 458 dom->dom_select = i; 459 460 TAILQ_FOREACH(sc, &dom->dom_list, sc_link) 461 clockmod_select(sc, ctrl); 462 back: 463 lwkt_serialize_exit(&clockmod_dom_slize); 464 return error; 465 } 466 467 static void 468 clockmod_select_handler(netmsg_t msg) 469 { 470 struct netmsg_clockmod *cmsg = (struct netmsg_clockmod *)msg; 471 472 #if 0 473 if (bootverbose) { 474 kprintf("cpu%d: clockmod 0x%04jx\n", mycpuid, 475 (uintmax_t)cmsg->ctl_value); 476 } 477 #endif 478 479 wrmsr(MSR_THERM_CONTROL, cmsg->ctl_value); 480 lwkt_replymsg(&cmsg->base.lmsg, 0); 481 } 482 483 static int 484 clockmod_select(const struct clockmod_softc *sc, 485 const struct clockmod_dom_ctrl *ctrl) 486 { 487 struct netmsg_clockmod msg; 488 489 netmsg_init(&msg.base, NULL, &curthread->td_msgport, MSGF_PRIORITY, 490 clockmod_select_handler); 491 msg.ctl_value = ctrl->ctl_value; 492 return lwkt_domsg(netisr_cpuport(sc->sc_cpuid), &msg.base.lmsg, 0); 493 } 494 495 static boolean_t 496 clockmod_errata_duty(int duty) 497 { 498 uint32_t model, stepping; 499 500 /* 501 * This is obtained from the original p4tcc code. 502 * 503 * The original errata checking code in p4tcc is obviously wrong. 504 * However, I am no longer being able to find the errata mentioned 505 * in the code. The guess is that the errata only affects family 506 * 0x0f CPUs, since: 507 * - The errata applies to only to model 0x00, 0x01 and 0x02 in 508 * the original p4tcc code. 509 * - Software controlled clock modulation has been supported since 510 * 0f_00 and the model of the oldest family 0x06 CPUs supporting 511 * this feature is 0x09. 512 */ 513 if (CPUID_TO_FAMILY(cpu_id) != 0xf) 514 return FALSE; 515 516 model = CPUID_TO_MODEL(cpu_id); 517 stepping = cpu_id & 0xf; 518 519 if (model == 0x6) { 520 switch (stepping) { 521 case 0x2: 522 case 0x4: 523 case 0x5: 524 /* Hang w/ 12.50% and 25.00% */ 525 if (duty == 1250 || duty == 2500) 526 return TRUE; 527 break; 528 } 529 } else if (model == 0x2) { 530 switch (stepping) { 531 case 0x2: 532 case 0x4: 533 case 0x5: 534 case 0x7: 535 case 0x9: 536 /* Hang w/ 12.50% */ 537 if (duty == 1250) 538 return TRUE; 539 break; 540 } 541 } else if (model == 0x1) { 542 switch (stepping) { 543 case 0x2: 544 case 0x3: 545 /* Hang w/ 12.50% and 25.00% */ 546 if (duty == 1250 || duty == 2500) 547 return TRUE; 548 break; 549 } 550 } else if (model == 0x0) { 551 switch (stepping) { 552 case 0x7: 553 case 0xa: 554 /* Hang w/ 12.50% and 25.00% */ 555 if (duty == 1250 || duty == 2500) 556 return TRUE; 557 break; 558 } 559 } 560 return FALSE; 561 } 562