summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2010-10-19 19:53:06 +0000
committerjkim <jkim@FreeBSD.org>2010-10-19 19:53:06 +0000
commit637883fc4e1ec3b88c5c13b8b1a273f70e123b37 (patch)
treedecfa76ab503f13e062c818d0664f8da8c58b908 /sys/dev/acpica
parenta11f2eb6e8461181df320a07e802a8eb4a5394b5 (diff)
downloadFreeBSD-src-637883fc4e1ec3b88c5c13b8b1a273f70e123b37.zip
FreeBSD-src-637883fc4e1ec3b88c5c13b8b1a273f70e123b37.tar.gz
Remove PCI_SET_POWERSTATE method from acpi.c and eradicate all PCI-specific
knowledges from the file. All PCI devices enumerated in ACPI tree must use correct one from acpi_pci.c any way. Reduce duplicate codes as we did for pci.c in r213905. Do not return ESRCH from PCIB_POWER_FOR_SLEEP method. When the method is not found, just return zero without modifying the given default value as it is completely optional. As a side effect, the return state must not be NULL. Note there is actually no functional change by removing ESRCH because acpi_pcib_power_for_sleep() always returns zero. Adjust debugging messages and add new ones under bootverbose to help debugging device power state related issues. Reviewed by: jhb, imp (earlier versions)
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r--sys/dev/acpica/acpi.c153
-rw-r--r--sys/dev/acpica/acpi_if.m3
-rw-r--r--sys/dev/acpica/acpi_pci.c8
3 files changed, 68 insertions, 96 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index f9b981b..c19748b 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -66,10 +66,6 @@ __FBSDID("$FreeBSD$");
#include <dev/acpica/acpivar.h>
#include <dev/acpica/acpiio.h>
-#include "pci_if.h"
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pci_private.h>
-
#include <vm/vm_param.h>
MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
@@ -133,8 +129,7 @@ static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
void *context, void **retval);
static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
int max_depth, acpi_scan_cb_t user_fn, void *arg);
-static int acpi_set_powerstate_method(device_t bus, device_t child,
- int state);
+static int acpi_set_powerstate(device_t child, int state);
static int acpi_isa_pnp_probe(device_t bus, device_t child,
struct isa_pnp_id *ids);
static void acpi_probe_children(device_t bus);
@@ -205,9 +200,6 @@ static device_method_t acpi_methods[] = {
DEVMETHOD(acpi_pwr_for_sleep, acpi_device_pwr_for_sleep),
DEVMETHOD(acpi_scan_children, acpi_device_scan_children),
- /* PCI emulation */
- DEVMETHOD(pci_set_powerstate, acpi_set_powerstate_method),
-
/* ISA emulation */
DEVMETHOD(isa_pnp_probe, acpi_isa_pnp_probe),
@@ -668,45 +660,46 @@ acpi_attach(device_t dev)
return_VALUE (error);
}
+static void
+acpi_set_power_children(device_t dev, int state)
+{
+ device_t child, parent;
+ device_t *devlist;
+ struct pci_devinfo *dinfo;
+ int dstate, i, numdevs;
+
+ if (!acpi_do_powerstate)
+ return;
+
+ if (device_get_children(dev, &devlist, &numdevs) != 0)
+ return;
+
+ /*
+ * Retrieve and set D-state for the sleep state if _SxD is present.
+ * Skip children who aren't attached since they are handled separately.
+ */
+ parent = device_get_parent(dev);
+ for (i = 0; i < numdevs; i++) {
+ child = devlist[i];
+ dinfo = device_get_ivars(child);
+ dstate = state;
+ if (device_is_attached(child) &&
+ acpi_device_pwr_for_sleep(parent, dev, &dstate) == 0)
+ acpi_set_powerstate(child, dstate);
+ }
+ free(devlist, M_TEMP);
+}
+
static int
acpi_suspend(device_t dev)
{
- device_t child, *devlist;
- int error, i, numdevs, pstate;
+ int error;
GIANT_REQUIRED;
- /* First give child devices a chance to suspend. */
error = bus_generic_suspend(dev);
- if (error)
- return (error);
-
- /*
- * Now, set them into the appropriate power state, usually D3. If the
- * device has an _SxD method for the next sleep state, use that power
- * state instead.
- */
- error = device_get_children(dev, &devlist, &numdevs);
- if (error)
- return (error);
- for (i = 0; i < numdevs; i++) {
- /* If the device is not attached, we've powered it down elsewhere. */
- child = devlist[i];
- if (!device_is_attached(child))
- continue;
-
- /*
- * Default to D3 for all sleep states. The _SxD method is optional
- * so set the powerstate even if it's absent.
- */
- pstate = PCI_POWERSTATE_D3;
- error = acpi_device_pwr_for_sleep(device_get_parent(child),
- child, &pstate);
- if ((error == 0 || error == ESRCH) && acpi_do_powerstate)
- pci_set_powerstate(child, pstate);
- }
- free(devlist, M_TEMP);
- error = 0;
+ if (error == 0)
+ acpi_set_power_children(dev, ACPI_STATE_D3);
return (error);
}
@@ -714,28 +707,10 @@ acpi_suspend(device_t dev)
static int
acpi_resume(device_t dev)
{
- ACPI_HANDLE handle;
- int i, numdevs, error;
- device_t child, *devlist;
GIANT_REQUIRED;
- /*
- * Put all devices in D0 before resuming them. Call _S0D on each one
- * since some systems expect this.
- */
- error = device_get_children(dev, &devlist, &numdevs);
- if (error)
- return (error);
- for (i = 0; i < numdevs; i++) {
- child = devlist[i];
- handle = acpi_get_handle(child);
- if (handle)
- AcpiEvaluateObject(handle, "_S0D", NULL, NULL);
- if (device_is_attached(child) && acpi_do_powerstate)
- pci_set_powerstate(child, PCI_POWERSTATE_D0);
- }
- free(devlist, M_TEMP);
+ acpi_set_power_children(dev, ACPI_STATE_D0);
return (bus_generic_resume(dev));
}
@@ -811,7 +786,7 @@ static void
acpi_probe_nomatch(device_t bus, device_t child)
{
#ifdef ACPI_ENABLE_POWERDOWN_NODRIVER
- pci_set_powerstate(child, PCI_POWERSTATE_D3);
+ acpi_set_powerstate(child, ACPI_STATE_D3);
#endif
}
@@ -833,9 +808,9 @@ acpi_driver_added(device_t dev, driver_t *driver)
child = devlist[i];
if (device_get_state(child) == DS_NOTPRESENT) {
#ifdef ACPI_ENABLE_POWERDOWN_NODRIVER
- pci_set_powerstate(child, PCI_POWERSTATE_D0);
+ acpi_set_powerstate(child, ACPI_STATE_D0);
if (device_probe_and_attach(child) != 0)
- pci_set_powerstate(child, PCI_POWERSTATE_D3);
+ acpi_set_powerstate(child, ACPI_STATE_D3);
#else
device_probe_and_attach(child);
#endif
@@ -1401,9 +1376,7 @@ acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
ACPI_HANDLE handle;
ACPI_STATUS status;
char sxd[8];
- int error;
- sc = device_get_softc(bus);
handle = acpi_get_handle(dev);
/*
@@ -1412,7 +1385,7 @@ acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
* set to D3 and it appears that such legacy devices may
* need special handling in their drivers.
*/
- if (handle == NULL ||
+ if (dstate == NULL || handle == NULL ||
acpi_MatchHid(handle, "PNP0500") ||
acpi_MatchHid(handle, "PNP0501") ||
acpi_MatchHid(handle, "PNP0502") ||
@@ -1421,28 +1394,19 @@ acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
return (ENXIO);
/*
- * Override next state with the value from _SxD, if present. If no
- * dstate argument was provided, don't fetch the return value.
+ * Override next state with the value from _SxD, if present.
+ * Note illegal _S0D is evaluated because some systems expect this.
*/
+ sc = device_get_softc(bus);
snprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate);
- if (dstate)
- status = acpi_GetInteger(handle, sxd, dstate);
- else
- status = AcpiEvaluateObject(handle, sxd, NULL, NULL);
-
- switch (status) {
- case AE_OK:
- error = 0;
- break;
- case AE_NOT_FOUND:
- error = ESRCH;
- break;
- default:
- error = ENXIO;
- break;
+ status = acpi_GetInteger(handle, sxd, dstate);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ device_printf(dev, "failed to get %s on %s: %s\n", sxd,
+ acpi_name(handle), AcpiFormatException(status));
+ return (ENXIO);
}
- return (error);
+ return (0);
}
/* Callback arg for our implementation of walking the namespace. */
@@ -1524,13 +1488,14 @@ acpi_device_scan_children(device_t bus, device_t dev, int max_depth,
* device power states since it's close enough to ACPI.
*/
static int
-acpi_set_powerstate_method(device_t bus, device_t child, int state)
+acpi_set_powerstate(device_t child, int state)
{
ACPI_HANDLE h;
ACPI_STATUS status;
- int error;
- error = 0;
+ if (!acpi_do_powerstate)
+ return (0);
+
h = acpi_get_handle(child);
if (state < ACPI_STATE_D0 || state > ACPI_D_STATES_MAX)
return (EINVAL);
@@ -1539,12 +1504,16 @@ acpi_set_powerstate_method(device_t bus, device_t child, int state)
/* Ignore errors if the power methods aren't present. */
status = acpi_pwr_switch_consumer(h, state);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND
- && status != AE_BAD_PARAMETER)
- device_printf(bus, "failed to set ACPI power state D%d on %s: %s\n",
- state, acpi_name(h), AcpiFormatException(status));
+ if (ACPI_SUCCESS(status)) {
+ if (bootverbose)
+ device_printf(child, "set ACPI power state D%d on %s\n",
+ state, acpi_name(h));
+ } else if (status != AE_NOT_FOUND)
+ device_printf(child,
+ "failed to set ACPI power state D%d on %s: %s\n", state,
+ acpi_name(h), AcpiFormatException(status));
- return (error);
+ return (0);
}
static int
diff --git a/sys/dev/acpica/acpi_if.m b/sys/dev/acpica/acpi_if.m
index 36fad85..f0a68e3 100644
--- a/sys/dev/acpica/acpi_if.m
+++ b/sys/dev/acpica/acpi_if.m
@@ -123,8 +123,7 @@ METHOD ACPI_STATUS evaluate_object {
#
# int *dstate: if successful, contains the highest valid sleep state
#
-# Returns: 0 on success, ESRCH if device has no special state, or
-# some other error value.
+# Returns: 0 on success or some other error value.
#
METHOD int pwr_for_sleep {
device_t bus;
diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c
index cb213ef..bf7cf2e 100644
--- a/sys/dev/acpica/acpi_pci.c
+++ b/sys/dev/acpica/acpi_pci.c
@@ -186,9 +186,13 @@ acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
}
h = acpi_get_handle(child);
status = acpi_pwr_switch_consumer(h, state);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+ if (ACPI_SUCCESS(status)) {
+ if (bootverbose)
+ device_printf(dev, "set ACPI power state D%d on %s\n",
+ state, acpi_name(h));
+ } else if (status != AE_NOT_FOUND)
device_printf(dev,
- "Failed to set ACPI power state D%d on %s: %s\n",
+ "failed to set ACPI power state D%d on %s: %s\n",
state, acpi_name(h), AcpiFormatException(status));
if (old_state > state && pci_do_power_resume)
error = pci_set_powerstate_method(dev, child, state);
OpenPOWER on IntegriCloud