diff --git a/sys/dev/acpica/acpi_perf.c b/sys/dev/acpica/acpi_perf.c index bc4eb787f782..a8414d04c531 100644 --- a/sys/dev/acpica/acpi_perf.c +++ b/sys/dev/acpica/acpi_perf.c @@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$"); /* * Support for ACPI processor performance states (Px) according to - * section x of the ACPI specification. + * section 8.3.3 of the ACPI 2.0c specification. */ struct acpi_px { @@ -78,6 +78,7 @@ struct acpi_perf_softc { uint32_t px_max_avail; /* Lowest index state available. */ int px_curr_state; /* Active state index. */ int px_rid; + int info_only; /* Can we set new states? */ }; #define PX_GET_REG(reg) \ @@ -160,8 +161,8 @@ acpi_perf_probe(device_t dev) /* * Check the performance state registers. If they are of type - * functional fixed hardware, we don't attach to allow a more - * specific hardware driver to manage this CPU. + * "functional fixed hardware", we attach quietly since we will + * only be providing information on settings to other drivers. */ error = ENXIO; handle = acpi_get_handle(dev); @@ -170,13 +171,19 @@ acpi_perf_probe(device_t dev) if (ACPI_FAILURE(AcpiEvaluateObject(handle, "_PCT", NULL, &buf))) return (error); pkg = (ACPI_OBJECT *)buf.Pointer; - - rid = 0; - if (ACPI_PKG_VALID(pkg, 2) && - acpi_PkgGas(dev, pkg, 0, &type, &rid, &res) == 0) { - bus_release_resource(dev, type, rid, res); - device_set_desc(dev, "ACPI CPU Frequency Control"); - error = -10; + if (ACPI_PKG_VALID(pkg, 2)) { + rid = 0; + error = acpi_PkgGas(dev, pkg, 0, &type, &rid, &res); + switch (error) { + case 0: + bus_release_resource(dev, type, rid, res); + device_set_desc(dev, "ACPI CPU Frequency Control"); + break; + case EOPNOTSUPP: + device_quiet(dev); + error = 0; + break; + } } AcpiOsFree(buf.Pointer); @@ -274,7 +281,14 @@ acpi_perf_evaluate(device_t dev) error = acpi_PkgGas(sc->dev, pkg, 0, &sc->perf_ctrl_type, &sc->px_rid, &sc->perf_ctrl); if (error) { - if (error != EOPNOTSUPP) + /* + * If the register is of type FFixedHW, we can only return + * info, we can't get or set new settings. + */ + if (error == EOPNOTSUPP) { + sc->info_only = TRUE; + error = 0; + } else device_printf(dev, "failed in PERF_CTL attach\n"); goto out; } @@ -283,7 +297,10 @@ acpi_perf_evaluate(device_t dev) error = acpi_PkgGas(sc->dev, pkg, 1, &sc->perf_sts_type, &sc->px_rid, &sc->perf_status); if (error) { - if (error != EOPNOTSUPP) + if (error == EOPNOTSUPP) { + sc->info_only = TRUE; + error = 0; + } else device_printf(dev, "failed in PERF_STATUS attach\n"); goto out; } @@ -392,6 +409,8 @@ acpi_px_settings(device_t dev, struct cf_setting *sets, int *count, int *type) acpi_px_to_set(dev, &sc->px_states[x], &sets[y]); *count = sc->px_count - sc->px_max_avail; *type = CPUFREQ_TYPE_ABSOLUTE; + if (sc->info_only) + *type |= CPUFREQ_FLAG_INFO_ONLY; return (0); } @@ -406,6 +425,10 @@ acpi_px_set(device_t dev, const struct cf_setting *set) return (EINVAL); sc = device_get_softc(dev); + /* If we can't set new states, return immediately. */ + if (sc->info_only) + return (ENXIO); + /* Look up appropriate state, based on frequency. */ for (i = sc->px_max_avail; i < sc->px_count; i++) { if (CPUFREQ_CMP(set->freq, sc->px_states[i].core_freq)) @@ -447,6 +470,10 @@ acpi_px_get(device_t dev, struct cf_setting *set) return (EINVAL); sc = device_get_softc(dev); + /* If we can't get new states, return immediately. */ + if (sc->info_only) + return (ENXIO); + /* If we've set the rate before, use the cached value. */ if (sc->px_curr_state != CPUFREQ_VAL_UNKNOWN) { acpi_px_to_set(dev, &sc->px_states[sc->px_curr_state], set); diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c index c058ead38d4b..ff1d006d9d2d 100644 --- a/sys/kern/kern_cpu.c +++ b/sys/kern/kern_cpu.c @@ -348,13 +348,20 @@ cf_levels_method(device_t dev, struct cf_level *levels, int *count) /* Get settings from all cpufreq drivers. */ for (i = 0; i < numdevs; i++) { + /* Skip devices that aren't ready. */ if (!device_is_attached(devs[i])) continue; + + /* + * Get settings, skipping drivers that offer no settings or + * provide settings for informational purposes only. + */ set_count = MAX_SETTINGS; error = CPUFREQ_DRV_SETTINGS(devs[i], sets, &set_count, &type); - if (error || set_count == 0) + if (error || set_count == 0 || (type & CPUFREQ_FLAG_INFO_ONLY)) continue; + /* Add the settings to our absolute/relative lists. */ switch (type & CPUFREQ_TYPE_MASK) { case CPUFREQ_TYPE_ABSOLUTE: error = cpufreq_insert_abs(sc, sets, set_count);