Index: libexec/rc/rc.conf =================================================================== --- libexec/rc/rc.conf +++ libexec/rc/rc.conf @@ -712,8 +712,12 @@ devfs_load_rulesets="YES" # Enable to always load the default rulesets performance_cx_lowest="NONE" # Online CPU idle state performance_cpu_freq="NONE" # Online CPU frequency +performance_tz0_active="NONE" # Online forced active cooling zone +performance_tz0_PSV="NONE" # Online passive cooling threshold economy_cx_lowest="Cmax" # Offline CPU idle state economy_cpu_freq="NONE" # Offline CPU frequency +economy_tz0_active="NONE" # Offline forced active cooling zone +economy_tz0_PSV="NONE" # Offline passive cooling threshold virecover_enable="YES" # Perform housekeeping for the vi(1) editor ugidfw_enable="NO" # Load mac_bsdextended(4) rules on boot bsdextended_script="/etc/rc.bsdextended" # Default mac_bsdextended(4) Index: libexec/rc/rc.d/power_profile =================================================================== --- libexec/rc/rc.d/power_profile +++ libexec/rc/rc.d/power_profile @@ -80,6 +80,14 @@ esac # Set the various sysctls based on the profile's values. +node="hw.acpi.thermal.tz0._PSV" +eval value=\$${profile}_tz0_PSV +sysctl_set + +node="hw.acpi.thermal.tz0.active" +eval value=\$${profile}_tz0_active +sysctl_set + node="hw.acpi.cpu.cx_lowest" highest_value="C1" lowest_value="Cmax" Index: sys/dev/acpica/acpi_thermal.c =================================================================== --- sys/dev/acpica/acpi_thermal.c +++ sys/dev/acpica/acpi_thermal.c @@ -605,7 +605,7 @@ /* XXX (de)activate any passive cooling that may be required. */ /* - * If the temperature is at _HOT or _CRT, increment our event count. + * If the temperature is at _CR3, _HOT or _CRT, increment our event count. * If it has occurred enough times, shutdown the system. This is * needed because some systems will report an invalid high temperature * for one poll cycle. It is suspected this is due to the embedded @@ -1023,51 +1023,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"); @@ -1128,8 +1145,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; } @@ -1138,6 +1169,7 @@ out: if (levels) free(levels, M_TEMP); + free(devs, M_TEMP); return (error); }