aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt8
-rw-r--r--drivers/acpi/bus.c14
-rw-r--r--drivers/acpi/power.c42
-rw-r--r--include/acpi/acpi_drivers.h1
4 files changed, 53 insertions, 12 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 44d1bd142ed..99cf83fd694 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -251,6 +251,14 @@ and is between 256 and 4096 characters. It is defined in the file
Warning: Many of these options can produce a lot of
output and make your system unusable. Be very careful.
+ acpi.power_nocheck= [HW,ACPI]
+ Format: 1/0 enable/disable the check of power state.
+ On some bogus BIOS the _PSC object/_STA object of
+ power resource can't return the correct device power
+ state. In such case it is unneccessary to check its
+ power state again in power transition.
+ 1 : disable the power state check
+
acpi_pm_good [X86-32,X86-64]
Override the pmtimer bug detection: force the kernel
to assume that this machine's pmtimer latches its value
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index ccae305ee55..91bdeb3b081 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -223,7 +223,19 @@ int acpi_bus_set_power(acpi_handle handle, int state)
/*
* Get device's current power state
*/
- acpi_bus_get_power(device->handle, &device->power.state);
+ if (!acpi_power_nocheck) {
+ /*
+ * Maybe the incorrect power state is returned on the bogus
+ * bios, which is different with the real power state.
+ * For example: the bios returns D0 state and the real power
+ * state is D3. OS expects to set the device to D0 state. In
+ * such case if OS uses the power state returned by the BIOS,
+ * the device can't be transisted to the correct power state.
+ * So if the acpi_power_nocheck is set, it is unnecessary to
+ * get the power state by calling acpi_bus_get_power.
+ */
+ acpi_bus_get_power(device->handle, &device->power.state);
+ }
if ((state == device->power.state) && !device->flags.force_power_state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index e7bab75075a..7ff7349c0c5 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -54,6 +54,14 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+int acpi_power_nocheck;
+module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
+
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
@@ -228,12 +236,18 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource->device->handle, &state);
- if (result)
- return result;
- if (state != ACPI_POWER_RESOURCE_STATE_ON)
- return -ENOEXEC;
-
+ if (!acpi_power_nocheck) {
+ /*
+ * If acpi_power_nocheck is set, it is unnecessary to check
+ * the power state after power transition.
+ */
+ result = acpi_power_get_state(resource->device->handle,
+ &state);
+ if (result)
+ return result;
+ if (state != ACPI_POWER_RESOURCE_STATE_ON)
+ return -ENOEXEC;
+ }
/* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D0;
@@ -279,11 +293,17 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(handle, &state);
- if (result)
- return result;
- if (state != ACPI_POWER_RESOURCE_STATE_OFF)
- return -ENOEXEC;
+ if (!acpi_power_nocheck) {
+ /*
+ * If acpi_power_nocheck is set, it is unnecessary to check
+ * the power state after power transition.
+ */
+ result = acpi_power_get_state(handle, &state);
+ if (result)
+ return result;
+ if (state != ACPI_POWER_RESOURCE_STATE_OFF)
+ return -ENOEXEC;
+ }
/* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D3;
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index e5f38e5ce86..efbaa271ee1 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -93,6 +93,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state);
int acpi_disable_wakeup_device_power(struct acpi_device *dev);
int acpi_power_get_inferred_state(struct acpi_device *device);
int acpi_power_transition(struct acpi_device *device, int state);
+extern int acpi_power_nocheck;
#endif
/* --------------------------------------------------------------------------