Lines Matching +full:combined +full:- +full:power +full:- +full:req

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2004-2007 Nate Lawson (SDG)
168 sc->dev = dev; in cpufreq_attach()
169 sysctl_ctx_init(&sc->sysctl_ctx); in cpufreq_attach()
170 TAILQ_INIT(&sc->all_levels); in cpufreq_attach()
171 CF_MTX_INIT(&sc->lock); in cpufreq_attach()
172 sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; in cpufreq_attach()
173 SLIST_INIT(&sc->saved_freq); in cpufreq_attach()
175 sc->max_mhz = cpu_get_nominal_mhz(dev); in cpufreq_attach()
177 if (sc->max_mhz <= 0) { in cpufreq_attach()
180 if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) in cpufreq_attach()
181 sc->max_mhz = rate / 1000000; in cpufreq_attach()
183 sc->max_mhz = CPUFREQ_VAL_UNKNOWN; in cpufreq_attach()
186 CF_DEBUG("initializing one-time data for %s\n", in cpufreq_attach()
188 sc->levels_buf = malloc(CF_MAX_LEVELS * sizeof(*sc->levels_buf), in cpufreq_attach()
190 SYSCTL_ADD_PROC(&sc->sysctl_ctx, in cpufreq_attach()
194 SYSCTL_ADD_PROC(&sc->sysctl_ctx, in cpufreq_attach()
201 * Queue a one-shot broadcast that levels have changed. in cpufreq_attach()
204 TASK_INIT(&sc->startup_task, 0, cpufreq_startup_task, dev); in cpufreq_attach()
205 taskqueue_enqueue(taskqueue_thread, &sc->startup_task); in cpufreq_attach()
226 sysctl_ctx_free(&sc->sysctl_ctx); in cpufreq_detach()
228 while ((saved_freq = SLIST_FIRST(&sc->saved_freq)) != NULL) { in cpufreq_detach()
229 SLIST_REMOVE_HEAD(&sc->saved_freq, link); in cpufreq_detach()
233 free(sc->levels_buf, M_DEVBUF); in cpufreq_detach()
253 /* We are going to change levels so notify the pre-change handler. */ in cf_set_method()
260 CF_MTX_LOCK(&sc->lock); in cf_set_method()
285 if (priority < sc->curr_priority) { in cf_set_method()
287 sc->curr_priority); in cf_set_method()
297 saved_freq = SLIST_FIRST(&sc->saved_freq); in cf_set_method()
303 level = &saved_freq->level; in cf_set_method()
304 priority = saved_freq->priority; in cf_set_method()
306 level->total_set.freq, priority); in cf_set_method()
310 if (level->total_set.freq < cf_lowest_freq) { in cf_set_method()
312 level->total_set.freq, cf_lowest_freq); in cf_set_method()
318 if (sc->curr_level.total_set.freq == level->total_set.freq) { in cf_set_method()
320 level->total_set.freq, sc->curr_level.total_set.freq); in cf_set_method()
325 set = &level->abs_set; in cf_set_method()
326 if (set->dev) { in cf_set_method()
327 if (!device_is_attached(set->dev)) { in cf_set_method()
333 pc = cpu_get_pcpu(set->dev); in cf_set_method()
341 pri = curthread->td_priority; in cf_set_method()
343 sched_bind(curthread, pc->pc_cpuid); in cf_set_method()
345 CF_DEBUG("setting abs freq %d on %s (cpu %d)\n", set->freq, in cf_set_method()
346 device_get_nameunit(set->dev), PCPU_GET(cpuid)); in cf_set_method()
347 error = CPUFREQ_DRV_SET(set->dev, set); in cf_set_method()
358 for (i = 0; i < level->rel_count; i++) { in cf_set_method()
359 set = &level->rel_set[i]; in cf_set_method()
360 if (!device_is_attached(set->dev)) { in cf_set_method()
366 pc = cpu_get_pcpu(set->dev); in cf_set_method()
368 pri = curthread->td_priority; in cf_set_method()
370 sched_bind(curthread, pc->pc_cpuid); in cf_set_method()
372 CF_DEBUG("setting rel freq %d on %s (cpu %d)\n", set->freq, in cf_set_method()
373 device_get_nameunit(set->dev), PCPU_GET(cpuid)); in cf_set_method()
374 error = CPUFREQ_DRV_SET(set->dev, set); in cf_set_method()
390 if (sc->curr_level.total_set.freq != CPUFREQ_VAL_UNKNOWN && in cf_set_method()
391 priority > sc->curr_priority) { in cf_set_method()
393 sc->curr_level.total_set.freq, sc->curr_priority); in cf_set_method()
399 curr_freq->level = sc->curr_level; in cf_set_method()
400 curr_freq->priority = sc->curr_priority; in cf_set_method()
401 SLIST_INSERT_HEAD(&sc->saved_freq, curr_freq, link); in cf_set_method()
403 sc->curr_level = *level; in cf_set_method()
404 sc->curr_priority = priority; in cf_set_method()
409 sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; in cf_set_method()
410 SLIST_REMOVE_HEAD(&sc->saved_freq, link); in cf_set_method()
415 CF_MTX_UNLOCK(&sc->lock); in cf_set_method()
418 * We changed levels (or attempted to) so notify the post-change in cf_set_method()
423 device_printf(set->dev, "set freq failed, err %d\n", error); in cf_set_method()
434 return (-1); in cpufreq_get_frequency()
446 return (-1); in cpufreq_get_level()
451 return (-1); in cpufreq_get_level()
456 * frequency as either determined by a cached value sc->curr_level, or in the
478 CF_MTX_LOCK(&sc->lock); in cf_get_method()
479 curr_set = &sc->curr_level.total_set; in cf_get_method()
480 error = CPUFREQ_DRV_TYPE(sc->cf_drv_dev, &type); in cf_get_method()
489 if (CPUFREQ_DRV_GET(sc->cf_drv_dev, &set) == 0) { in cf_get_method()
490 sc->curr_level.total_set = set; in cf_get_method()
492 curr_set->freq); in cf_get_method()
495 } else if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) { in cf_get_method()
496 CF_DEBUG("get returning known freq %d\n", curr_set->freq); in cf_get_method()
500 CF_MTX_UNLOCK(&sc->lock); in cf_get_method()
511 error = CPUFREQ_LEVELS(sc->dev, levels, &count); in cf_get_method()
527 CF_MTX_LOCK(&sc->lock); in cf_get_method()
528 i = cpufreq_get_level(sc->cf_drv_dev, levels, count); in cf_get_method()
530 sc->curr_level = levels[i]; in cf_get_method()
533 device_get_nameunit(sc->cf_drv_dev)); in cf_get_method()
535 if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) { in cf_get_method()
536 CF_DEBUG("get matched freq %d from drivers\n", curr_set->freq); in cf_get_method()
549 cpu_est_clockrate(pc->pc_cpuid, &rate); in cf_get_method()
553 diff = abs(levels[i].total_set.freq - rate); in cf_get_method()
556 sc->curr_level = levels[i]; in cf_get_method()
559 CF_DEBUG("get estimated freq %d\n", curr_set->freq); in cf_get_method()
563 *level = sc->curr_level; in cf_get_method()
565 CF_MTX_UNLOCK(&sc->lock); in cf_get_method()
585 dev = sc->cf_drv_dev; in cpufreq_add_levels()
598 CF_DEBUG("skipping info-only driver %s\n", in cpufreq_add_levels()
625 bcopy(sets, set_arr->sets, set_count * sizeof(*sets)); in cpufreq_add_levels()
626 set_arr->count = set_count; in cpufreq_add_levels()
655 CF_MTX_LOCK(&sc->lock); in cf_levels_method()
656 error = cpufreq_add_levels(sc->dev, &rel_sets); in cf_levels_method()
664 if (TAILQ_EMPTY(&sc->all_levels)) { in cf_levels_method()
669 if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) { in cf_levels_method()
670 sc->max_mhz = cpu_get_nominal_mhz(dev); in cf_levels_method()
676 if (sc->max_mhz <= 0) { in cf_levels_method()
678 cpu_est_clockrate(pc->pc_cpuid, &rate); in cf_levels_method()
679 sc->max_mhz = rate / 1000000; in cf_levels_method()
683 set.freq = sc->max_mhz; in cf_levels_method()
690 /* Create a combined list of absolute + relative levels. */ in cf_levels_method()
695 if (sc->all_count > *count) { in cf_levels_method()
696 *count = sc->all_count; in cf_levels_method()
703 TAILQ_FOREACH(lev, &sc->all_levels, link) { in cf_levels_method()
705 if (lev->total_set.freq < cf_lowest_freq) { in cf_levels_method()
706 sc->all_count--; in cf_levels_method()
713 *count = sc->all_count; in cf_levels_method()
718 while ((lev = TAILQ_FIRST(&sc->all_levels)) != NULL) { in cf_levels_method()
719 TAILQ_REMOVE(&sc->all_levels, lev, link); in cf_levels_method()
722 sc->all_count = 0; in cf_levels_method()
724 CF_MTX_UNLOCK(&sc->lock); in cf_levels_method()
744 CF_MTX_ASSERT(&sc->lock); in cpufreq_insert_abs()
746 list = &sc->all_levels; in cpufreq_insert_abs()
751 level->abs_set = sets[i]; in cpufreq_insert_abs()
752 level->total_set = sets[i]; in cpufreq_insert_abs()
753 level->total_set.dev = NULL; in cpufreq_insert_abs()
754 sc->all_count++; in cpufreq_insert_abs()
765 if (sets[i].freq <= search->total_set.freq) { in cpufreq_insert_abs()
767 sets[i].freq, search->total_set.freq); in cpufreq_insert_abs()
775 if (sets[i].freq >= search->total_set.freq) { in cpufreq_insert_abs()
777 sets[i].freq, search->total_set.freq); in cpufreq_insert_abs()
797 CF_MTX_ASSERT(&sc->lock); in cpufreq_expand_set()
807 TAILQ_FOREACH_REVERSE(search, &sc->all_levels, cf_level_lst, link) { in cpufreq_expand_set()
809 for (i = 0; i < set_arr->count; i++) { in cpufreq_expand_set()
810 set = &set_arr->sets[i]; in cpufreq_expand_set()
817 if (set->freq < 10000) { in cpufreq_expand_set()
832 KASSERT(fill->rel_count < MAX_SETTINGS, in cpufreq_expand_set()
835 fill->rel_set[fill->rel_count] = *set; in cpufreq_expand_set()
836 fill->rel_count++; in cpufreq_expand_set()
839 set->freq / 100, fill->total_set.freq); in cpufreq_expand_set()
855 CF_MTX_ASSERT(&sc->lock); in cpufreq_dup_set()
859 * total frequency and power by the percentage specified in the in cpufreq_dup_set()
866 fill_set = &fill->total_set; in cpufreq_dup_set()
867 fill_set->freq = in cpufreq_dup_set()
868 ((uint64_t)fill_set->freq * set->freq) / 10000; in cpufreq_dup_set()
869 if (fill_set->power != CPUFREQ_VAL_UNKNOWN) { in cpufreq_dup_set()
870 fill_set->power = ((uint64_t)fill_set->power * set->freq) in cpufreq_dup_set()
873 if (set->lat != CPUFREQ_VAL_UNKNOWN) { in cpufreq_dup_set()
874 if (fill_set->lat != CPUFREQ_VAL_UNKNOWN) in cpufreq_dup_set()
875 fill_set->lat += set->lat; in cpufreq_dup_set()
877 fill_set->lat = set->lat; in cpufreq_dup_set()
879 CF_DEBUG("dup set considering derived setting %d\n", fill_set->freq); in cpufreq_dup_set()
887 for (i = fill->rel_count; i != 0; i--) { in cpufreq_dup_set()
888 if (fill->rel_set[i - 1].dev != set->dev) in cpufreq_dup_set()
891 device_get_nameunit(set->dev)); in cpufreq_dup_set()
892 fill->rel_count--; in cpufreq_dup_set()
899 * level is guaranteed use less power. For example (1), a level with in cpufreq_dup_set()
900 * one absolute setting of 800 Mhz uses less power than one composed in cpufreq_dup_set()
905 list = &sc->all_levels; in cpufreq_dup_set()
908 itr_set = &itr->total_set; in cpufreq_dup_set()
909 if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) { in cpufreq_dup_set()
911 fill_set->freq); in cpufreq_dup_set()
914 } else if (fill_set->freq < itr_set->freq) { in cpufreq_dup_set()
915 if (fill->abs_set.freq <= itr->abs_set.freq) { in cpufreq_dup_set()
918 fill_set->freq, itr_set->freq); in cpufreq_dup_set()
920 sc->all_count++; in cpufreq_dup_set()
923 fill_set->freq); in cpufreq_dup_set()
933 fill_set->freq); in cpufreq_dup_set()
950 sc = oidp->oid_arg1; in cpufreq_curr_sysctl()
951 levels = sc->levels_buf; in cpufreq_curr_sysctl()
953 error = CPUFREQ_GET(sc->dev, &levels[0]); in cpufreq_curr_sysctl()
957 error = sysctl_handle_int(oidp, &freq, 0, req); in cpufreq_curr_sysctl()
958 if (error != 0 || req->newptr == NULL) in cpufreq_curr_sysctl()
981 diff = abs(levels[i].total_set.freq - freq); in cpufreq_curr_sysctl()
1005 sc = oidp->oid_arg1; in cpufreq_levels_sysctl()
1010 levels = sc->levels_buf; in cpufreq_levels_sysctl()
1015 error = CPUFREQ_LEVELS(sc->dev, levels, &count); in cpufreq_levels_sysctl()
1024 sbuf_printf(&sb, "%d/%d ", set->freq, set->power); in cpufreq_levels_sysctl()
1030 error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); in cpufreq_levels_sysctl()
1045 dev = oidp->oid_arg1; in cpufreq_settings_sysctl()
1060 sbuf_printf(&sb, "%d/%d ", sets[i].freq, sets[i].power); in cpufreq_settings_sysctl()
1065 error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); in cpufreq_settings_sysctl()
1079 SYSCTL_ADD_CONST_STRING(&sc->sysctl_ctx, in cpufreq_add_freq_driver_sysctl()
1081 "freq_driver", CTLFLAG_RD, device_get_nameunit(sc->cf_drv_dev), in cpufreq_add_freq_driver_sysctl()
1106 sc->max_mhz = CPUFREQ_VAL_UNKNOWN; in cpufreq_register()
1107 MPASS(sc->cf_drv_dev != NULL); in cpufreq_register()
1122 sc->cf_drv_dev = dev; in cpufreq_register()
1146 MPASS(sc->cf_drv_dev == dev); in cpufreq_unregister()