summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/acpi_perf.c
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2005-02-13 18:49:48 +0000
committernjl <njl@FreeBSD.org>2005-02-13 18:49:48 +0000
commitdb1d2335dc7a9b2d42bf4e84fe48b7eb13d1b5ca (patch)
tree1b9c80a4269b3ad8984bac6e8f81b0584a66b691 /sys/dev/acpica/acpi_perf.c
parentb08240453920c3b01dccdfdcaf4ead51c8751139 (diff)
downloadFreeBSD-src-db1d2335dc7a9b2d42bf4e84fe48b7eb13d1b5ca.zip
FreeBSD-src-db1d2335dc7a9b2d42bf4e84fe48b7eb13d1b5ca.tar.gz
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.
Diffstat (limited to 'sys/dev/acpica/acpi_perf.c')
-rw-r--r--sys/dev/acpica/acpi_perf.c51
1 files changed, 39 insertions, 12 deletions
diff --git a/sys/dev/acpica/acpi_perf.c b/sys/dev/acpica/acpi_perf.c
index bc4eb78..a8414d0 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);
OpenPOWER on IntegriCloud