Lines Matching +full:switching +full:- +full:freq

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2004-2007 Nate Lawson (SDG)
168 sc->dev = dev;
169 sysctl_ctx_init(&sc->sysctl_ctx);
170 TAILQ_INIT(&sc->all_levels);
171 CF_MTX_INIT(&sc->lock);
172 sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
173 SLIST_INIT(&sc->saved_freq);
174 /* Try to get nominal CPU freq to use it as maximum later if needed */
175 sc->max_mhz = cpu_get_nominal_mhz(dev);
177 if (sc->max_mhz <= 0) {
180 if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0)
181 sc->max_mhz = rate / 1000000;
183 sc->max_mhz = CPUFREQ_VAL_UNKNOWN;
186 CF_DEBUG("initializing one-time data for %s\n",
188 sc->levels_buf = malloc(CF_MAX_LEVELS * sizeof(*sc->levels_buf),
190 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
192 OID_AUTO, "freq", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
194 SYSCTL_ADD_PROC(&sc->sysctl_ctx,
201 * Queue a one-shot broadcast that levels have changed.
204 TASK_INIT(&sc->startup_task, 0, cpufreq_startup_task, dev);
205 taskqueue_enqueue(taskqueue_thread, &sc->startup_task);
226 sysctl_ctx_free(&sc->sysctl_ctx);
228 while ((saved_freq = SLIST_FIRST(&sc->saved_freq)) != NULL) {
229 SLIST_REMOVE_HEAD(&sc->saved_freq, link);
233 free(sc->levels_buf, M_DEVBUF);
253 /* We are going to change levels so notify the pre-change handler. */
260 CF_MTX_LOCK(&sc->lock);
270 * switching the main CPU. XXXTODO: Need to think more about how to
285 if (priority < sc->curr_priority) {
287 sc->curr_priority);
297 saved_freq = SLIST_FIRST(&sc->saved_freq);
303 level = &saved_freq->level;
304 priority = saved_freq->priority;
305 CF_DEBUG("restoring saved level, freq %d prio %d\n",
306 level->total_set.freq, priority);
310 if (level->total_set.freq < cf_lowest_freq) {
311 CF_DEBUG("rejecting freq %d, less than %d limit\n",
312 level->total_set.freq, cf_lowest_freq);
318 if (sc->curr_level.total_set.freq == level->total_set.freq) {
319 CF_DEBUG("skipping freq %d, same as current level %d\n",
320 level->total_set.freq, sc->curr_level.total_set.freq);
325 set = &level->abs_set;
326 if (set->dev) {
327 if (!device_is_attached(set->dev)) {
332 /* Bind to the target CPU before switching. */
333 pc = cpu_get_pcpu(set->dev);
341 pri = curthread->td_priority;
343 sched_bind(curthread, pc->pc_cpuid);
345 CF_DEBUG("setting abs freq %d on %s (cpu %d)\n", set->freq,
346 device_get_nameunit(set->dev), PCPU_GET(cpuid));
347 error = CPUFREQ_DRV_SET(set->dev, set);
358 for (i = 0; i < level->rel_count; i++) {
359 set = &level->rel_set[i];
360 if (!device_is_attached(set->dev)) {
365 /* Bind to the target CPU before switching. */
366 pc = cpu_get_pcpu(set->dev);
368 pri = curthread->td_priority;
370 sched_bind(curthread, pc->pc_cpuid);
372 CF_DEBUG("setting rel freq %d on %s (cpu %d)\n", set->freq,
373 device_get_nameunit(set->dev), PCPU_GET(cpuid));
374 error = CPUFREQ_DRV_SET(set->dev, set);
390 if (sc->curr_level.total_set.freq != CPUFREQ_VAL_UNKNOWN &&
391 priority > sc->curr_priority) {
392 CF_DEBUG("saving level, freq %d prio %d\n",
393 sc->curr_level.total_set.freq, sc->curr_priority);
399 curr_freq->level = sc->curr_level;
400 curr_freq->priority = sc->curr_priority;
401 SLIST_INSERT_HEAD(&sc->saved_freq, curr_freq, link);
403 sc->curr_level = *level;
404 sc->curr_priority = priority;
409 sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN;
410 SLIST_REMOVE_HEAD(&sc->saved_freq, link);
415 CF_MTX_UNLOCK(&sc->lock);
418 * We changed levels (or attempted to) so notify the post-change
423 device_printf(set->dev, "set freq failed, err %d\n", error);
434 return (-1);
436 return (set.freq);
443 int i, freq;
445 if ((freq = cpufreq_get_frequency(dev)) < 0)
446 return (-1);
448 if (freq == levels[i].total_set.freq)
451 return (-1);
456 * frequency as either determined by a cached value sc->curr_level, or in the
478 CF_MTX_LOCK(&sc->lock);
479 curr_set = &sc->curr_level.total_set;
480 error = CPUFREQ_DRV_TYPE(sc->cf_drv_dev, &type);
489 if (CPUFREQ_DRV_GET(sc->cf_drv_dev, &set) == 0) {
490 sc->curr_level.total_set = set;
491 CF_DEBUG("get returning immediate freq %d\n",
492 curr_set->freq);
495 } else if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) {
496 CF_DEBUG("get returning known freq %d\n", curr_set->freq);
500 CF_MTX_UNLOCK(&sc->lock);
511 error = CPUFREQ_LEVELS(sc->dev, levels, &count);
527 CF_MTX_LOCK(&sc->lock);
528 i = cpufreq_get_level(sc->cf_drv_dev, levels, count);
530 sc->curr_level = levels[i];
533 device_get_nameunit(sc->cf_drv_dev));
535 if (curr_set->freq != CPUFREQ_VAL_UNKNOWN) {
536 CF_DEBUG("get matched freq %d from drivers\n", curr_set->freq);
549 cpu_est_clockrate(pc->pc_cpuid, &rate);
553 diff = abs(levels[i].total_set.freq - rate);
556 sc->curr_level = levels[i];
559 CF_DEBUG("get estimated freq %d\n", curr_set->freq);
563 *level = sc->curr_level;
565 CF_MTX_UNLOCK(&sc->lock);
585 dev = sc->cf_drv_dev;
598 CF_DEBUG("skipping info-only driver %s\n",
625 bcopy(sets, set_arr->sets, set_count * sizeof(*sets));
626 set_arr->count = set_count;
655 CF_MTX_LOCK(&sc->lock);
656 error = cpufreq_add_levels(sc->dev, &rel_sets);
664 if (TAILQ_EMPTY(&sc->all_levels)) {
669 if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) {
670 sc->max_mhz = cpu_get_nominal_mhz(dev);
676 if (sc->max_mhz <= 0) {
678 cpu_est_clockrate(pc->pc_cpuid, &rate);
679 sc->max_mhz = rate / 1000000;
683 set.freq = sc->max_mhz;
695 if (sc->all_count > *count) {
696 *count = sc->all_count;
703 TAILQ_FOREACH(lev, &sc->all_levels, link) {
705 if (lev->total_set.freq < cf_lowest_freq) {
706 sc->all_count--;
713 *count = sc->all_count;
718 while ((lev = TAILQ_FIRST(&sc->all_levels)) != NULL) {
719 TAILQ_REMOVE(&sc->all_levels, lev, link);
722 sc->all_count = 0;
724 CF_MTX_UNLOCK(&sc->lock);
744 CF_MTX_ASSERT(&sc->lock);
746 list = &sc->all_levels;
751 level->abs_set = sets[i];
752 level->total_set = sets[i];
753 level->total_set.dev = NULL;
754 sc->all_count++;
759 sets[i].freq);
765 if (sets[i].freq <= search->total_set.freq) {
767 sets[i].freq, search->total_set.freq);
775 if (sets[i].freq >= search->total_set.freq) {
777 sets[i].freq, search->total_set.freq);
797 CF_MTX_ASSERT(&sc->lock);
807 TAILQ_FOREACH_REVERSE(search, &sc->all_levels, cf_level_lst, link) {
809 for (i = 0; i < set_arr->count; i++) {
810 set = &set_arr->sets[i];
817 if (set->freq < 10000) {
832 KASSERT(fill->rel_count < MAX_SETTINGS,
835 fill->rel_set[fill->rel_count] = *set;
836 fill->rel_count++;
839 set->freq / 100, fill->total_set.freq);
855 CF_MTX_ASSERT(&sc->lock);
866 fill_set = &fill->total_set;
867 fill_set->freq =
868 ((uint64_t)fill_set->freq * set->freq) / 10000;
869 if (fill_set->power != CPUFREQ_VAL_UNKNOWN) {
870 fill_set->power = ((uint64_t)fill_set->power * set->freq)
873 if (set->lat != CPUFREQ_VAL_UNKNOWN) {
874 if (fill_set->lat != CPUFREQ_VAL_UNKNOWN)
875 fill_set->lat += set->lat;
877 fill_set->lat = set->lat;
879 CF_DEBUG("dup set considering derived setting %d\n", fill_set->freq);
887 for (i = fill->rel_count; i != 0; i--) {
888 if (fill->rel_set[i - 1].dev != set->dev)
891 device_get_nameunit(set->dev));
892 fill->rel_count--;
905 list = &sc->all_levels;
908 itr_set = &itr->total_set;
909 if (CPUFREQ_CMP(fill_set->freq, itr_set->freq)) {
911 fill_set->freq);
914 } else if (fill_set->freq < itr_set->freq) {
915 if (fill->abs_set.freq <= itr->abs_set.freq) {
918 fill_set->freq, itr_set->freq);
920 sc->all_count++;
923 fill_set->freq);
933 fill_set->freq);
946 int best, count, diff, bdiff, devcount, error, freq, i, n;
950 sc = oidp->oid_arg1;
951 levels = sc->levels_buf;
953 error = CPUFREQ_GET(sc->dev, &levels[0]);
956 freq = levels[0].total_set.freq;
957 error = sysctl_handle_int(oidp, &freq, 0, req);
958 if (error != 0 || req->newptr == NULL)
981 diff = abs(levels[i].total_set.freq - freq);
1005 sc = oidp->oid_arg1;
1010 levels = sc->levels_buf;
1015 error = CPUFREQ_LEVELS(sc->dev, levels, &count);
1024 sbuf_printf(&sb, "%d/%d ", set->freq, set->power);
1045 dev = oidp->oid_arg1;
1060 sbuf_printf(&sb, "%d/%d ", sets[i].freq, sets[i].power);
1079 SYSCTL_ADD_CONST_STRING(&sc->sysctl_ctx,
1081 "freq_driver", CTLFLAG_RD, device_get_nameunit(sc->cf_drv_dev),
1104 if ((cf_dev = device_find_child(cpu_dev, "cpufreq", -1))) {
1106 sc->max_mhz = CPUFREQ_VAL_UNKNOWN;
1107 MPASS(sc->cf_drv_dev != NULL);
1122 sc->cf_drv_dev = dev;
1138 cf_dev = device_find_child(device_get_parent(dev), "cpufreq", -1);
1145 MPASS(sc->cf_drv_dev == dev);