Add support for the CPUFREQ_FLAG_INFO_ONLY flag. Devices that report this

are not added to the list(s) of available settings.  However, other drivers
can call the CPUFREQ_DRV_SETTINGS() method on those devices directly to
get info about available settings.

Update the acpi_perf(4) driver to use this flag in the presence of
"functional fixed hardware."  Thus, future drivers like Powernow can
query acpi_perf for platform info but perform frequency transitions
themselves.
This commit is contained in:
Nate Lawson 2005-02-13 18:49:48 +00:00
parent 36a1ac2c2e
commit e22cd41c01
2 changed files with 47 additions and 13 deletions

View File

@ -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);

View File

@ -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);