* Expand a group of relative settings, creating derived levels from them. */
| 782 | * Expand a group of relative settings, creating derived levels from them. |
| 783 | */ |
| 784 | static int |
| 785 | cpufreq_expand_set(struct cpufreq_softc *sc, struct cf_setting_array *set_arr) |
| 786 | { |
| 787 | struct cf_level *fill, *search; |
| 788 | struct cf_setting *set; |
| 789 | int i; |
| 790 | |
| 791 | CF_MTX_ASSERT(&sc->lock); |
| 792 | |
| 793 | /* |
| 794 | * Walk the set of all existing levels in reverse. This is so we |
| 795 | * create derived states from the lowest absolute settings first |
| 796 | * and discard duplicates created from higher absolute settings. |
| 797 | * For instance, a level of 50 Mhz derived from 100 Mhz + 50% is |
| 798 | * preferable to 200 Mhz + 25% because absolute settings are more |
| 799 | * efficient since they often change the voltage as well. |
| 800 | */ |
| 801 | TAILQ_FOREACH_REVERSE(search, &sc->all_levels, cf_level_lst, link) { |
| 802 | /* Add each setting to the level, duplicating if necessary. */ |
| 803 | for (i = 0; i < set_arr->count; i++) { |
| 804 | set = &set_arr->sets[i]; |
| 805 | |
| 806 | /* |
| 807 | * If this setting is less than 100%, split the level |
| 808 | * into two and add this setting to the new level. |
| 809 | */ |
| 810 | fill = search; |
| 811 | if (set->freq < 10000) { |
| 812 | fill = cpufreq_dup_set(sc, search, set); |
| 813 | |
| 814 | /* |
| 815 | * The new level was a duplicate of an existing |
| 816 | * level or its absolute setting is too high |
| 817 | * so we freed it. For example, we discard a |
| 818 | * derived level of 1000 MHz/25% if a level |
| 819 | * of 500 MHz/100% already exists. |
| 820 | */ |
| 821 | if (fill == NULL) |
| 822 | break; |
| 823 | } |
| 824 | |
| 825 | /* Add this setting to the existing or new level. */ |
| 826 | KASSERT(fill->rel_count < MAX_SETTINGS, |
| 827 | ("cpufreq: too many relative drivers (%d)", |
| 828 | MAX_SETTINGS)); |
| 829 | fill->rel_set[fill->rel_count] = *set; |
| 830 | fill->rel_count++; |
| 831 | CF_DEBUG( |
| 832 | "expand set added rel setting %d%% to %d level\n", |
| 833 | set->freq / 100, fill->total_set.freq); |
| 834 | } |
| 835 | } |
| 836 | |
| 837 | return (0); |
| 838 | } |
| 839 | |
| 840 | static struct cf_level * |
| 841 | cpufreq_dup_set(struct cpufreq_softc *sc, struct cf_level *dup, |
no test coverage detected