Index: sys/dev/acpica/acpi_thermal.c =================================================================== --- sys/dev/acpica/acpi_thermal.c +++ sys/dev/acpica/acpi_thermal.c @@ -1006,51 +1006,68 @@ static int acpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) { - device_t dev; - int error; + device_t *devs; + int devcount, error, n; if (!sc->tz_cooling_updated) return (0); - if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) + + if ((error = devclass_get_devices(devclass_find("cpufreq"), &devs, &devcount))) { + free(devs, M_TEMP); return (ENXIO); + } + ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); - error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); + for (n = 0; n < devcount; n++) { + if ((error = CPUFREQ_SET(devs[n], NULL, CPUFREQ_PRIO_KERN))) { + /* + * If you find yourself here: cf_set_method() in kern_cpu.c + * requires CPUFREQ_GET() be run before CPUFREQ_SET(), otherwise on + * a restore sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN, + * and then if it hasn't been updated the next save/restore will fail. + */ + device_printf(sc->tz_dev, "cpu%d: failed to restore cpufreq priority\n", n); + break; + } + } if (error == 0) sc->tz_cooling_updated = FALSE; + + free(devs, M_TEMP); return (error); } static int acpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) { - device_t dev; + device_t *devs; struct cf_level *levels; - int num_levels, error, freq, desired_freq, perf, i; + int num_levels, error, freq, desired_freq, perf, devcount, i, n; levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); if (levels == NULL) return (ENOMEM); /* - * Find the main device, cpufreq0. We don't yet support independent - * CPU frequency control on SMP. + * Find the main device, cpufreq0. We make plans based upon cpu0, and + * change all the cpu frequencies to the same level. */ - if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { - error = ENXIO; + if ((error = devclass_get_devices(devclass_find("cpufreq"), &devs, &devcount))) { + free(devs, M_TEMP); goto out; } - /* Get the current frequency. */ - error = CPUFREQ_GET(dev, &levels[0]); + /* Get the current frequency for cpu0. */ + error = CPUFREQ_GET(devs[0], &levels[0]); if (error) goto out; freq = levels[0].total_set.freq; - /* Get the current available frequency levels. */ + /* Get the current available frequency levels for cpu0. */ num_levels = CPUFREQ_MAX_LEVELS; - error = CPUFREQ_LEVELS(dev, levels, &num_levels); + error = CPUFREQ_LEVELS(devs[0], levels, &num_levels); if (error) { if (error == E2BIG) printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); @@ -1111,8 +1128,22 @@ TZ_KELVTOC(sc->tz_temperature), (freq > levels[i].total_set.freq) ? "de" : "in", freq, levels[i].total_set.freq); - error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); - if (error == 0 && !sc->tz_cooling_updated) { + + /* Change all the cpus to the chosen frequency. */ + for (n = 0; n < devcount; n++) { + /* CPUFREQ_SET() fails occasionally without this. */ + if ((error = CPUFREQ_GET(devs[n], &levels[0]))) + goto out; + + if ((error = CPUFREQ_LEVELS(devs[n], levels, &num_levels))) { + if (error == E2BIG) + printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); + goto out; + } + if ((error = CPUFREQ_SET(devs[n], &levels[i], CPUFREQ_PRIO_KERN))) + goto out; + } + if (!sc->tz_cooling_updated) { sc->tz_cooling_saved_freq = freq; sc->tz_cooling_updated = TRUE; } @@ -1121,6 +1152,7 @@ out: if (levels) free(levels, M_TEMP); + free(devs, M_TEMP); return (error); }