| 630 | } |
| 631 | |
| 632 | static int |
| 633 | cf_levels_method(device_t dev, struct cf_level *levels, int *count) |
| 634 | { |
| 635 | struct cf_setting_array *set_arr; |
| 636 | struct cf_setting_lst rel_sets; |
| 637 | struct cpufreq_softc *sc; |
| 638 | struct cf_level *lev; |
| 639 | struct pcpu *pc; |
| 640 | int error, i; |
| 641 | uint64_t rate; |
| 642 | |
| 643 | if (levels == NULL || count == NULL) |
| 644 | return (EINVAL); |
| 645 | |
| 646 | TAILQ_INIT(&rel_sets); |
| 647 | sc = device_get_softc(dev); |
| 648 | |
| 649 | CF_MTX_LOCK(&sc->lock); |
| 650 | error = cpufreq_add_levels(sc->dev, &rel_sets); |
| 651 | if (error) |
| 652 | goto out; |
| 653 | |
| 654 | /* |
| 655 | * If there are no absolute levels, create a fake one at 100%. We |
| 656 | * then cache the clockrate for later use as our base frequency. |
| 657 | */ |
| 658 | if (TAILQ_EMPTY(&sc->all_levels)) { |
| 659 | struct cf_setting set; |
| 660 | |
| 661 | CF_DEBUG("No absolute levels returned by driver\n"); |
| 662 | |
| 663 | if (sc->max_mhz == CPUFREQ_VAL_UNKNOWN) { |
| 664 | sc->max_mhz = cpu_get_nominal_mhz(dev); |
| 665 | /* |
| 666 | * If the CPU can't report a rate for 100%, hope |
| 667 | * the CPU is running at its nominal rate right now, |
| 668 | * and use that instead. |
| 669 | */ |
| 670 | if (sc->max_mhz <= 0) { |
| 671 | pc = cpu_get_pcpu(dev); |
| 672 | cpu_est_clockrate(pc->pc_cpuid, &rate); |
| 673 | sc->max_mhz = rate / 1000000; |
| 674 | } |
| 675 | } |
| 676 | memset(&set, CPUFREQ_VAL_UNKNOWN, sizeof(set)); |
| 677 | set.freq = sc->max_mhz; |
| 678 | set.dev = NULL; |
| 679 | error = cpufreq_insert_abs(sc, &set, 1); |
| 680 | if (error) |
| 681 | goto out; |
| 682 | } |
| 683 | |
| 684 | /* Create a combined list of absolute + relative levels. */ |
| 685 | TAILQ_FOREACH(set_arr, &rel_sets, link) |
| 686 | cpufreq_expand_set(sc, set_arr); |
| 687 | |
| 688 | /* If the caller doesn't have enough space, return the actual count. */ |
| 689 | if (sc->all_count > *count) { |
nothing calls this directly
no test coverage detected