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}