diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 44d1bd142edf83fdf7c83ee509c44c0b6b20a136..99cf83fd69478aab1e675688cab2463d8815edc8 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 ccae305ee55dcb554c441d908c20b43d509b3709..91bdeb3b081e7d5f7f2dde1309e6a597175fd9c1 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 e7bab75075a90dce99ad98e085f264f96d56cc68..7ff7349c0c52b92d02e230a4322b3b85f4baa516 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 e5f38e5ce86fc5a4e28ec624e529ee1db59c16c0..efbaa271ee11517b66f0d764df3a297f115dc72b 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 /* --------------------------------------------------------------------------