kern_cpu.c (326867616fb55d6808aa927b9bb5ec22c46b869c) | kern_cpu.c (4577cf3744b98d0fa7cea80c75079c3cf5155471) |
---|---|
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004-2007 Nate Lawson (SDG) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 62 unchanged lines hidden (view full) --- 71 struct sx lock; 72 struct cf_level curr_level; 73 int curr_priority; 74 SLIST_HEAD(, cf_saved_freq) saved_freq; 75 struct cf_level_lst all_levels; 76 int all_count; 77 int max_mhz; 78 device_t dev; | 1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004-2007 Nate Lawson (SDG) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 62 unchanged lines hidden (view full) --- 71 struct sx lock; 72 struct cf_level curr_level; 73 int curr_priority; 74 SLIST_HEAD(, cf_saved_freq) saved_freq; 75 struct cf_level_lst all_levels; 76 int all_count; 77 int max_mhz; 78 device_t dev; |
79 device_t cf_drv_dev; |
|
79 struct sysctl_ctx_list sysctl_ctx; 80 struct task startup_task; 81 struct cf_level *levels_buf; 82}; 83 84struct cf_setting_array { 85 struct cf_setting sets[MAX_SETTINGS]; 86 int count; --- 50 unchanged lines hidden (view full) --- 137static int cf_verbose; 138static SYSCTL_NODE(_debug, OID_AUTO, cpufreq, CTLFLAG_RD, NULL, 139 "cpufreq debugging"); 140SYSCTL_INT(_debug_cpufreq, OID_AUTO, lowest, CTLFLAG_RWTUN, &cf_lowest_freq, 1, 141 "Don't provide levels below this frequency."); 142SYSCTL_INT(_debug_cpufreq, OID_AUTO, verbose, CTLFLAG_RWTUN, &cf_verbose, 1, 143 "Print verbose debugging messages"); 144 | 80 struct sysctl_ctx_list sysctl_ctx; 81 struct task startup_task; 82 struct cf_level *levels_buf; 83}; 84 85struct cf_setting_array { 86 struct cf_setting sets[MAX_SETTINGS]; 87 int count; --- 50 unchanged lines hidden (view full) --- 138static int cf_verbose; 139static SYSCTL_NODE(_debug, OID_AUTO, cpufreq, CTLFLAG_RD, NULL, 140 "cpufreq debugging"); 141SYSCTL_INT(_debug_cpufreq, OID_AUTO, lowest, CTLFLAG_RWTUN, &cf_lowest_freq, 1, 142 "Don't provide levels below this frequency."); 143SYSCTL_INT(_debug_cpufreq, OID_AUTO, verbose, CTLFLAG_RWTUN, &cf_verbose, 1, 144 "Print verbose debugging messages"); 145 |
146/* 147 * This is called as the result of a hardware specific frequency control driver 148 * calling cpufreq_register. It provides a general interface for system wide 149 * frequency controls and operates on a per cpu basis. 150 */ |
|
145static int 146cpufreq_attach(device_t dev) 147{ 148 struct cpufreq_softc *sc; 149 struct pcpu *pc; 150 device_t parent; 151 uint64_t rate; | 151static int 152cpufreq_attach(device_t dev) 153{ 154 struct cpufreq_softc *sc; 155 struct pcpu *pc; 156 device_t parent; 157 uint64_t rate; |
152 int numdevs; | |
153 154 CF_DEBUG("initializing %s\n", device_get_nameunit(dev)); 155 sc = device_get_softc(dev); 156 parent = device_get_parent(dev); 157 sc->dev = dev; 158 sysctl_ctx_init(&sc->sysctl_ctx); 159 TAILQ_INIT(&sc->all_levels); 160 CF_MTX_INIT(&sc->lock); 161 sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; 162 SLIST_INIT(&sc->saved_freq); 163 /* Try to get nominal CPU freq to use it as maximum later if needed */ 164 sc->max_mhz = cpu_get_nominal_mhz(dev); 165 /* If that fails, try to measure the current rate */ 166 if (sc->max_mhz <= 0) { | 158 159 CF_DEBUG("initializing %s\n", device_get_nameunit(dev)); 160 sc = device_get_softc(dev); 161 parent = device_get_parent(dev); 162 sc->dev = dev; 163 sysctl_ctx_init(&sc->sysctl_ctx); 164 TAILQ_INIT(&sc->all_levels); 165 CF_MTX_INIT(&sc->lock); 166 sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; 167 SLIST_INIT(&sc->saved_freq); 168 /* Try to get nominal CPU freq to use it as maximum later if needed */ 169 sc->max_mhz = cpu_get_nominal_mhz(dev); 170 /* If that fails, try to measure the current rate */ 171 if (sc->max_mhz <= 0) { |
172 CF_DEBUG("Unable to obtain nominal frequency.\n"); |
|
167 pc = cpu_get_pcpu(dev); 168 if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) 169 sc->max_mhz = rate / 1000000; 170 else 171 sc->max_mhz = CPUFREQ_VAL_UNKNOWN; 172 } 173 | 173 pc = cpu_get_pcpu(dev); 174 if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) 175 sc->max_mhz = rate / 1000000; 176 else 177 sc->max_mhz = CPUFREQ_VAL_UNKNOWN; 178 } 179 |
174 /* 175 * Only initialize one set of sysctls for all CPUs. In the future, 176 * if multiple CPUs can have different settings, we can move these 177 * sysctls to be under every CPU instead of just the first one. 178 */ 179 numdevs = devclass_get_count(cpufreq_dc); 180 if (numdevs > 1) 181 return (0); 182 | |
183 CF_DEBUG("initializing one-time data for %s\n", 184 device_get_nameunit(dev)); 185 sc->levels_buf = malloc(CF_MAX_LEVELS * sizeof(*sc->levels_buf), 186 M_DEVBUF, M_WAITOK); 187 SYSCTL_ADD_PROC(&sc->sysctl_ctx, 188 SYSCTL_CHILDREN(device_get_sysctl_tree(parent)), 189 OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 190 cpufreq_curr_sysctl, "I", "Current CPU frequency"); --- 20 unchanged lines hidden (view full) --- 211 cpufreq_settings_changed((device_t)ctx); 212} 213 214static int 215cpufreq_detach(device_t dev) 216{ 217 struct cpufreq_softc *sc; 218 struct cf_saved_freq *saved_freq; | 180 CF_DEBUG("initializing one-time data for %s\n", 181 device_get_nameunit(dev)); 182 sc->levels_buf = malloc(CF_MAX_LEVELS * sizeof(*sc->levels_buf), 183 M_DEVBUF, M_WAITOK); 184 SYSCTL_ADD_PROC(&sc->sysctl_ctx, 185 SYSCTL_CHILDREN(device_get_sysctl_tree(parent)), 186 OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 187 cpufreq_curr_sysctl, "I", "Current CPU frequency"); --- 20 unchanged lines hidden (view full) --- 208 cpufreq_settings_changed((device_t)ctx); 209} 210 211static int 212cpufreq_detach(device_t dev) 213{ 214 struct cpufreq_softc *sc; 215 struct cf_saved_freq *saved_freq; |
219 int numdevs; | |
220 221 CF_DEBUG("shutdown %s\n", device_get_nameunit(dev)); 222 sc = device_get_softc(dev); 223 sysctl_ctx_free(&sc->sysctl_ctx); 224 225 while ((saved_freq = SLIST_FIRST(&sc->saved_freq)) != NULL) { 226 SLIST_REMOVE_HEAD(&sc->saved_freq, link); 227 free(saved_freq, M_TEMP); 228 } 229 | 216 217 CF_DEBUG("shutdown %s\n", device_get_nameunit(dev)); 218 sc = device_get_softc(dev); 219 sysctl_ctx_free(&sc->sysctl_ctx); 220 221 while ((saved_freq = SLIST_FIRST(&sc->saved_freq)) != NULL) { 222 SLIST_REMOVE_HEAD(&sc->saved_freq, link); 223 free(saved_freq, M_TEMP); 224 } 225 |
230 /* Only clean up these resources when the last device is detaching. */ 231 numdevs = devclass_get_count(cpufreq_dc); 232 if (numdevs == 1) { 233 CF_DEBUG("final shutdown for %s\n", device_get_nameunit(dev)); 234 free(sc->levels_buf, M_DEVBUF); 235 } | 226 free(sc->levels_buf, M_DEVBUF); |
236 237 return (0); 238} 239 240static int 241cf_set_method(device_t dev, const struct cf_level *level, int priority) 242{ 243 struct cpufreq_softc *sc; --- 173 unchanged lines hidden (view full) --- 417 EVENTHANDLER_INVOKE(cpufreq_post_change, level, error); 418 if (error && set) 419 device_printf(set->dev, "set freq failed, err %d\n", error); 420 421 return (error); 422} 423 424static int | 227 228 return (0); 229} 230 231static int 232cf_set_method(device_t dev, const struct cf_level *level, int priority) 233{ 234 struct cpufreq_softc *sc; --- 173 unchanged lines hidden (view full) --- 408 EVENTHANDLER_INVOKE(cpufreq_post_change, level, error); 409 if (error && set) 410 device_printf(set->dev, "set freq failed, err %d\n", error); 411 412 return (error); 413} 414 415static int |
416cpufreq_get_frequency(device_t dev) 417{ 418 struct cf_setting set; 419 420 if (CPUFREQ_DRV_GET(dev, &set) != 0) 421 return (-1); 422 423 return (set.freq); 424} 425 426/* Returns the index into *levels with the match */ 427static int 428cpufreq_get_level(device_t dev, struct cf_level *levels, int count) 429{ 430 int i, freq; 431 432 if ((freq = cpufreq_get_frequency(dev)) < 0) 433 return (-1); 434 for (i = 0; i < count; i++) 435 if (freq == levels[i].total_set.freq) 436 return (i); 437 438 return (-1); 439} 440 441/* 442 * Used by the cpufreq core, this function will populate *level with the current 443 * frequency as either determined by a cached value sc->curr_level, or in the 444 * case the lower level driver has set the CPUFREQ_FLAG_UNCACHED flag, it will 445 * obtain the frequency from the driver itself. 446 */ 447static int |
|
425cf_get_method(device_t dev, struct cf_level *level) 426{ 427 struct cpufreq_softc *sc; 428 struct cf_level *levels; | 448cf_get_method(device_t dev, struct cf_level *level) 449{ 450 struct cpufreq_softc *sc; 451 struct cf_level *levels; |
429 struct cf_setting *curr_set, set; | 452 struct cf_setting *curr_set; |
430 struct pcpu *pc; | 453 struct pcpu *pc; |
431 device_t *devs; 432 int bdiff, count, diff, error, i, n, numdevs; | 454 int bdiff, count, diff, error, i, type; |
433 uint64_t rate; 434 435 sc = device_get_softc(dev); 436 error = 0; 437 levels = NULL; 438 | 455 uint64_t rate; 456 457 sc = device_get_softc(dev); 458 error = 0; 459 levels = NULL; 460 |
439 /* If we already know the current frequency, we're done. */ | 461 /* 462 * If we already know the current frequency, and the driver didn't ask 463 * for uncached usage, we're done. 464 */ |
440 CF_MTX_LOCK(&sc->lock); 441 curr_set = &sc->curr_level.total_set; | 465 CF_MTX_LOCK(&sc->lock); 466 curr_set = &sc->curr_level.total_set; |
442 if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) { | 467 error = CPUFREQ_DRV_TYPE(sc->cf_drv_dev, &type); 468 if (error == 0 && (type & CPUFREQ_FLAG_UNCACHED)) { 469 struct cf_setting set; 470 471 /* 472 * If the driver wants to always report back the real frequency, 473 * first try the driver and if that fails, fall back to 474 * estimating. 475 */ 476 if (CPUFREQ_DRV_GET(sc->cf_drv_dev, &set) != 0) 477 goto estimate; 478 sc->curr_level.total_set = set; 479 CF_DEBUG("get returning immediate freq %d\n", curr_set->freq); 480 goto out; 481 } else if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) { |
443 CF_DEBUG("get returning known freq %d\n", curr_set->freq); | 482 CF_DEBUG("get returning known freq %d\n", curr_set->freq); |
483 error = 0; |
|
444 goto out; 445 } 446 CF_MTX_UNLOCK(&sc->lock); 447 448 /* 449 * We need to figure out the current level. Loop through every 450 * driver, getting the current setting. Then, attempt to get a best 451 * match of settings against each level. --- 4 unchanged lines hidden (view full) --- 456 return (ENOMEM); 457 error = CPUFREQ_LEVELS(sc->dev, levels, &count); 458 if (error) { 459 if (error == E2BIG) 460 printf("cpufreq: need to increase CF_MAX_LEVELS\n"); 461 free(levels, M_TEMP); 462 return (error); 463 } | 484 goto out; 485 } 486 CF_MTX_UNLOCK(&sc->lock); 487 488 /* 489 * We need to figure out the current level. Loop through every 490 * driver, getting the current setting. Then, attempt to get a best 491 * match of settings against each level. --- 4 unchanged lines hidden (view full) --- 496 return (ENOMEM); 497 error = CPUFREQ_LEVELS(sc->dev, levels, &count); 498 if (error) { 499 if (error == E2BIG) 500 printf("cpufreq: need to increase CF_MAX_LEVELS\n"); 501 free(levels, M_TEMP); 502 return (error); 503 } |
464 error = device_get_children(device_get_parent(dev), &devs, &numdevs); 465 if (error) { 466 free(levels, M_TEMP); 467 return (error); 468 } | |
469 470 /* 471 * Reacquire the lock and search for the given level. 472 * 473 * XXX Note: this is not quite right since we really need to go 474 * through each level and compare both absolute and relative 475 * settings for each driver in the system before making a match. 476 * The estimation code below catches this case though. 477 */ 478 CF_MTX_LOCK(&sc->lock); | 504 505 /* 506 * Reacquire the lock and search for the given level. 507 * 508 * XXX Note: this is not quite right since we really need to go 509 * through each level and compare both absolute and relative 510 * settings for each driver in the system before making a match. 511 * The estimation code below catches this case though. 512 */ 513 CF_MTX_LOCK(&sc->lock); |
479 for (n = 0; n < numdevs && curr_set->freq == CPUFREQ_VAL_UNKNOWN; n++) { 480 if (!device_is_attached(devs[n])) 481 continue; 482 if (CPUFREQ_DRV_GET(devs[n], &set) != 0) 483 continue; 484 for (i = 0; i < count; i++) { 485 if (set.freq == levels[i].total_set.freq) { 486 sc->curr_level = levels[i]; 487 break; 488 } 489 } 490 } 491 free(devs, M_TEMP); | 514 i = cpufreq_get_level(sc->cf_drv_dev, levels, count); 515 if (i >= 0) 516 sc->curr_level = levels[i]; 517 else 518 CF_DEBUG("Couldn't find supported level for %s\n", 519 device_get_nameunit(sc->cf_drv_dev)); 520 |
492 if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) { 493 CF_DEBUG("get matched freq %d from drivers\n", curr_set->freq); 494 goto out; 495 } 496 | 521 if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) { 522 CF_DEBUG("get matched freq %d from drivers\n", curr_set->freq); 523 goto out; 524 } 525 |
526estimate: 527 CF_MTX_ASSERT(&sc->lock); 528 |
|
497 /* 498 * We couldn't find an exact match, so attempt to estimate and then 499 * match against a level. 500 */ 501 pc = cpu_get_pcpu(dev); 502 if (pc == NULL) { 503 error = ENXIO; 504 goto out; --- 15 unchanged lines hidden (view full) --- 520 *level = sc->curr_level; 521 522 CF_MTX_UNLOCK(&sc->lock); 523 if (levels) 524 free(levels, M_TEMP); 525 return (error); 526} 527 | 529 /* 530 * We couldn't find an exact match, so attempt to estimate and then 531 * match against a level. 532 */ 533 pc = cpu_get_pcpu(dev); 534 if (pc == NULL) { 535 error = ENXIO; 536 goto out; --- 15 unchanged lines hidden (view full) --- 552 *level = sc->curr_level; 553 554 CF_MTX_UNLOCK(&sc->lock); 555 if (levels) 556 free(levels, M_TEMP); 557 return (error); 558} 559 |
560/* 561 * Either directly obtain settings from the cpufreq driver, or build a list of 562 * relative settings to be integrated later against an absolute max. 563 */ |
|
528static int | 564static int |
565cpufreq_add_levels(device_t cf_dev, struct cf_setting_lst *rel_sets) 566{ 567 struct cf_setting_array *set_arr; 568 struct cf_setting *sets; 569 device_t dev; 570 struct cpufreq_softc *sc; 571 int type, set_count, error; 572 573 sc = device_get_softc(cf_dev); 574 dev = sc->cf_drv_dev; 575 576 /* Skip devices that aren't ready. */ 577 if (!device_is_attached(cf_dev)) 578 return (0); 579 580 /* 581 * Get settings, skipping drivers that offer no settings or 582 * provide settings for informational purposes only. 583 */ 584 error = CPUFREQ_DRV_TYPE(dev, &type); 585 if (error != 0 || (type & CPUFREQ_FLAG_INFO_ONLY)) { 586 if (error == 0) { 587 CF_DEBUG("skipping info-only driver %s\n", 588 device_get_nameunit(cf_dev)); 589 } 590 return (error); 591 } 592 593 sets = malloc(MAX_SETTINGS * sizeof(*sets), M_TEMP, M_NOWAIT); 594 if (sets == NULL) 595 return (ENOMEM); 596 597 set_count = MAX_SETTINGS; 598 error = CPUFREQ_DRV_SETTINGS(dev, sets, &set_count); 599 if (error != 0 || set_count == 0) 600 goto out; 601 602 /* Add the settings to our absolute/relative lists. */ 603 switch (type & CPUFREQ_TYPE_MASK) { 604 case CPUFREQ_TYPE_ABSOLUTE: 605 error = cpufreq_insert_abs(sc, sets, set_count); 606 break; 607 case CPUFREQ_TYPE_RELATIVE: 608 CF_DEBUG("adding %d relative settings\n", set_count); 609 set_arr = malloc(sizeof(*set_arr), M_TEMP, M_NOWAIT); 610 if (set_arr == NULL) { 611 error = ENOMEM; 612 goto out; 613 } 614 bcopy(sets, set_arr->sets, set_count * sizeof(*sets)); 615 set_arr->count = set_count; 616 TAILQ_INSERT_TAIL(rel_sets, set_arr, link); 617 break; 618 default: 619 error = EINVAL; 620 } 621 622out: 623 free(sets, M_TEMP); 624 return (error); 625} 626 627static int |
|
529cf_levels_method(device_t dev, struct cf_level *levels, int *count) 530{ 531 struct cf_setting_array *set_arr; 532 struct cf_setting_lst rel_sets; 533 struct cpufreq_softc *sc; 534 struct cf_level *lev; | 628cf_levels_method(device_t dev, struct cf_level *levels, int *count) 629{ 630 struct cf_setting_array *set_arr; 631 struct cf_setting_lst rel_sets; 632 struct cpufreq_softc *sc; 633 struct cf_level *lev; |
535 struct cf_setting *sets; | |
536 struct pcpu *pc; | 634 struct pcpu *pc; |
537 device_t *devs; 538 int error, i, numdevs, set_count, type; | 635 int error, i; |
539 uint64_t rate; 540 541 if (levels == NULL || count == NULL) 542 return (EINVAL); 543 544 TAILQ_INIT(&rel_sets); 545 sc = device_get_softc(dev); | 636 uint64_t rate; 637 638 if (levels == NULL || count == NULL) 639 return (EINVAL); 640 641 TAILQ_INIT(&rel_sets); 642 sc = device_get_softc(dev); |
546 error = device_get_children(device_get_parent(dev), &devs, &numdevs); 547 if (error) 548 return (error); 549 sets = malloc(MAX_SETTINGS * sizeof(*sets), M_TEMP, M_NOWAIT); 550 if (sets == NULL) { 551 free(devs, M_TEMP); 552 return (ENOMEM); 553 } | |
554 | 643 |
555 /* Get settings from all cpufreq drivers. */ | |
556 CF_MTX_LOCK(&sc->lock); | 644 CF_MTX_LOCK(&sc->lock); |
557 for (i = 0; i < numdevs; i++) { 558 /* Skip devices that aren't ready. */ 559 if (!device_is_attached(devs[i])) 560 continue; | 645 error = cpufreq_add_levels(sc->dev, &rel_sets); 646 if (error) 647 goto out; |
561 | 648 |
562 /* 563 * Get settings, skipping drivers that offer no settings or 564 * provide settings for informational purposes only. 565 */ 566 error = CPUFREQ_DRV_TYPE(devs[i], &type); 567 if (error || (type & CPUFREQ_FLAG_INFO_ONLY)) { 568 if (error == 0) { 569 CF_DEBUG("skipping info-only driver %s\n", 570 device_get_nameunit(devs[i])); 571 } 572 continue; 573 } 574 set_count = MAX_SETTINGS; 575 error = CPUFREQ_DRV_SETTINGS(devs[i], sets, &set_count); 576 if (error || set_count == 0) 577 continue; 578 579 /* Add the settings to our absolute/relative lists. */ 580 switch (type & CPUFREQ_TYPE_MASK) { 581 case CPUFREQ_TYPE_ABSOLUTE: 582 error = cpufreq_insert_abs(sc, sets, set_count); 583 break; 584 case CPUFREQ_TYPE_RELATIVE: 585 CF_DEBUG("adding %d relative settings\n", set_count); 586 set_arr = malloc(sizeof(*set_arr), M_TEMP, M_NOWAIT); 587 if (set_arr == NULL) { 588 error = ENOMEM; 589 goto out; 590 } 591 bcopy(sets, set_arr->sets, set_count * sizeof(*sets)); 592 set_arr->count = set_count; 593 TAILQ_INSERT_TAIL(&rel_sets, set_arr, link); 594 break; 595 default: 596 error = EINVAL; 597 } 598 if (error) 599 goto out; 600 } 601 | |
602 /* 603 * If there are no absolute levels, create a fake one at 100%. We 604 * then cache the clockrate for later use as our base frequency. 605 */ 606 if (TAILQ_EMPTY(&sc->all_levels)) { | 649 /* 650 * If there are no absolute levels, create a fake one at 100%. We 651 * then cache the clockrate for later use as our base frequency. 652 */ 653 if (TAILQ_EMPTY(&sc->all_levels)) { |
654 struct cf_setting set; 655 656 CF_DEBUG("No absolute levels returned by driver\n"); 657 |
|
607 if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) { 608 sc->max_mhz = cpu_get_nominal_mhz(dev); 609 /* 610 * If the CPU can't report a rate for 100%, hope 611 * the CPU is running at its nominal rate right now, 612 * and use that instead. 613 */ 614 if (sc->max_mhz <= 0) { 615 pc = cpu_get_pcpu(dev); 616 cpu_est_clockrate(pc->pc_cpuid, &rate); 617 sc->max_mhz = rate / 1000000; 618 } 619 } | 658 if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) { 659 sc->max_mhz = cpu_get_nominal_mhz(dev); 660 /* 661 * If the CPU can't report a rate for 100%, hope 662 * the CPU is running at its nominal rate right now, 663 * and use that instead. 664 */ 665 if (sc->max_mhz <= 0) { 666 pc = cpu_get_pcpu(dev); 667 cpu_est_clockrate(pc->pc_cpuid, &rate); 668 sc->max_mhz = rate / 1000000; 669 } 670 } |
620 memset(&sets[0], CPUFREQ_VAL_UNKNOWN, sizeof(*sets)); 621 sets[0].freq = sc->max_mhz; 622 sets[0].dev = NULL; 623 error = cpufreq_insert_abs(sc, sets, 1); | 671 memset(&set, CPUFREQ_VAL_UNKNOWN, sizeof(set)); 672 set.freq = sc->max_mhz; 673 set.dev = NULL; 674 error = cpufreq_insert_abs(sc, &set, 1); |
624 if (error) 625 goto out; 626 } 627 628 /* Create a combined list of absolute + relative levels. */ 629 TAILQ_FOREACH(set_arr, &rel_sets, link) 630 cpufreq_expand_set(sc, set_arr); 631 --- 28 unchanged lines hidden (view full) --- 660 } 661 sc->all_count = 0; 662 663 CF_MTX_UNLOCK(&sc->lock); 664 while ((set_arr = TAILQ_FIRST(&rel_sets)) != NULL) { 665 TAILQ_REMOVE(&rel_sets, set_arr, link); 666 free(set_arr, M_TEMP); 667 } | 675 if (error) 676 goto out; 677 } 678 679 /* Create a combined list of absolute + relative levels. */ 680 TAILQ_FOREACH(set_arr, &rel_sets, link) 681 cpufreq_expand_set(sc, set_arr); 682 --- 28 unchanged lines hidden (view full) --- 711 } 712 sc->all_count = 0; 713 714 CF_MTX_UNLOCK(&sc->lock); 715 while ((set_arr = TAILQ_FIRST(&rel_sets)) != NULL) { 716 TAILQ_REMOVE(&rel_sets, set_arr, link); 717 free(set_arr, M_TEMP); 718 } |
668 free(devs, M_TEMP); 669 free(sets, M_TEMP); | |
670 return (error); 671} 672 673/* 674 * Create levels for an array of absolute settings and insert them in 675 * sorted order in the specified list. 676 */ 677static int --- 328 unchanged lines hidden (view full) --- 1006 error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 1007 1008out: 1009 free(sets, M_TEMP); 1010 sbuf_delete(&sb); 1011 return (error); 1012} 1013 | 719 return (error); 720} 721 722/* 723 * Create levels for an array of absolute settings and insert them in 724 * sorted order in the specified list. 725 */ 726static int --- 328 unchanged lines hidden (view full) --- 1055 error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 1056 1057out: 1058 free(sets, M_TEMP); 1059 sbuf_delete(&sb); 1060 return (error); 1061} 1062 |
1063static void 1064cpufreq_add_freq_driver_sysctl(device_t cf_dev) 1065{ 1066 struct cpufreq_softc *sc; 1067 1068 sc = device_get_softc(cf_dev); 1069 SYSCTL_ADD_CONST_STRING(&sc->sysctl_ctx, 1070 SYSCTL_CHILDREN(device_get_sysctl_tree(cf_dev)), OID_AUTO, 1071 "freq_driver", CTLFLAG_RD, device_get_nameunit(sc->cf_drv_dev), 1072 "cpufreq driver used by this cpu"); 1073} 1074 |
|
1014int 1015cpufreq_register(device_t dev) 1016{ 1017 struct cpufreq_softc *sc; 1018 device_t cf_dev, cpu_dev; | 1075int 1076cpufreq_register(device_t dev) 1077{ 1078 struct cpufreq_softc *sc; 1079 device_t cf_dev, cpu_dev; |
1080 int error; |
|
1019 1020 /* Add a sysctl to get each driver's settings separately. */ 1021 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1022 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1023 OID_AUTO, "freq_settings", CTLTYPE_STRING | CTLFLAG_RD, dev, 0, 1024 cpufreq_settings_sysctl, "A", "CPU frequency driver settings"); 1025 1026 /* 1027 * Add only one cpufreq device to each CPU. Currently, all CPUs 1028 * must offer the same levels and be switched at the same time. 1029 */ 1030 cpu_dev = device_get_parent(dev); 1031 if ((cf_dev = device_find_child(cpu_dev, "cpufreq", -1))) { 1032 sc = device_get_softc(cf_dev); 1033 sc->max_mhz = CPUFREQ_VAL_UNKNOWN; | 1081 1082 /* Add a sysctl to get each driver's settings separately. */ 1083 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1084 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1085 OID_AUTO, "freq_settings", CTLTYPE_STRING | CTLFLAG_RD, dev, 0, 1086 cpufreq_settings_sysctl, "A", "CPU frequency driver settings"); 1087 1088 /* 1089 * Add only one cpufreq device to each CPU. Currently, all CPUs 1090 * must offer the same levels and be switched at the same time. 1091 */ 1092 cpu_dev = device_get_parent(dev); 1093 if ((cf_dev = device_find_child(cpu_dev, "cpufreq", -1))) { 1094 sc = device_get_softc(cf_dev); 1095 sc->max_mhz = CPUFREQ_VAL_UNKNOWN; |
1096 MPASS(sc->cf_drv_dev != NULL); |
|
1034 return (0); 1035 } 1036 1037 /* Add the child device and possibly sysctls. */ 1038 cf_dev = BUS_ADD_CHILD(cpu_dev, 0, "cpufreq", -1); 1039 if (cf_dev == NULL) 1040 return (ENOMEM); 1041 device_quiet(cf_dev); 1042 | 1097 return (0); 1098 } 1099 1100 /* Add the child device and possibly sysctls. */ 1101 cf_dev = BUS_ADD_CHILD(cpu_dev, 0, "cpufreq", -1); 1102 if (cf_dev == NULL) 1103 return (ENOMEM); 1104 device_quiet(cf_dev); 1105 |
1043 return (device_probe_and_attach(cf_dev)); | 1106 error = device_probe_and_attach(cf_dev); 1107 if (error) 1108 return (error); 1109 1110 sc = device_get_softc(cf_dev); 1111 sc->cf_drv_dev = dev; 1112 cpufreq_add_freq_driver_sysctl(cf_dev); 1113 return (error); |
1044} 1045 1046int 1047cpufreq_unregister(device_t dev) 1048{ | 1114} 1115 1116int 1117cpufreq_unregister(device_t dev) 1118{ |
1049 device_t cf_dev, *devs; 1050 int cfcount, devcount, error, i, type; | 1119 device_t cf_dev; 1120 struct cpufreq_softc *sc; |
1051 1052 /* 1053 * If this is the last cpufreq child device, remove the control 1054 * device as well. We identify cpufreq children by calling a method 1055 * they support. 1056 */ | 1121 1122 /* 1123 * If this is the last cpufreq child device, remove the control 1124 * device as well. We identify cpufreq children by calling a method 1125 * they support. 1126 */ |
1057 error = device_get_children(device_get_parent(dev), &devs, &devcount); 1058 if (error) 1059 return (error); | |
1060 cf_dev = device_find_child(device_get_parent(dev), "cpufreq", -1); 1061 if (cf_dev == NULL) { 1062 device_printf(dev, 1063 "warning: cpufreq_unregister called with no cpufreq device active\n"); | 1127 cf_dev = device_find_child(device_get_parent(dev), "cpufreq", -1); 1128 if (cf_dev == NULL) { 1129 device_printf(dev, 1130 "warning: cpufreq_unregister called with no cpufreq device active\n"); |
1064 free(devs, M_TEMP); | |
1065 return (0); 1066 } | 1131 return (0); 1132 } |
1067 cfcount = 0; 1068 for (i = 0; i < devcount; i++) { 1069 if (!device_is_attached(devs[i])) 1070 continue; 1071 if (CPUFREQ_DRV_TYPE(devs[i], &type) == 0) 1072 cfcount++; 1073 } 1074 if (cfcount <= 1) 1075 device_delete_child(device_get_parent(cf_dev), cf_dev); 1076 free(devs, M_TEMP); | 1133 sc = device_get_softc(cf_dev); 1134 MPASS(sc->cf_drv_dev == dev); 1135 device_delete_child(device_get_parent(cf_dev), cf_dev); |
1077 1078 return (0); 1079} 1080 1081int 1082cpufreq_settings_changed(device_t dev) 1083{ 1084 1085 EVENTHANDLER_INVOKE(cpufreq_levels_changed, 1086 device_get_unit(device_get_parent(dev))); 1087 return (0); 1088} | 1136 1137 return (0); 1138} 1139 1140int 1141cpufreq_settings_changed(device_t dev) 1142{ 1143 1144 EVENTHANDLER_INVOKE(cpufreq_levels_changed, 1145 device_get_unit(device_get_parent(dev))); 1146 return (0); 1147} |