Merge branch 'acpi-general'
* acpi-general: (38 commits) ACPI / thermal: _TMP and _CRT/_HOT/_PSV/_ACx dependency fix ACPI: drop unnecessary local variable from acpi_system_write_wakeup_device() ACPI: Fix logging when no pci_irq is allocated ACPI: Update Dock hotplug error messages ACPI: Update Container hotplug error messages ACPI: Update Memory hotplug error messages ACPI: Update CPU hotplug error messages ACPI: Add acpi_handle_<level>() interfaces ACPI: remove use of __devexit ACPI / PM: Add Sony Vaio VPCEB1S1E to nonvs blacklist. ACPI / battery: Correct battery capacity values on Thinkpads Revert "ACPI / x86: Add quirk for "CheckPoint P-20-00" to not use bridge _CRS_ info" ACPI: create _SUN sysfs file ACPI / memhotplug: bind the memory device when the driver is being loaded ACPI / memhotplug: don't allow to eject the memory device if it is being used ACPI / memhotplug: free memory device if acpi_memory_enable_device() failed ACPI / memhotplug: fix memory leak when memory device is unbound from acpi_memhotplug ACPI / memhotplug: deal with eject request in hotplug queue ACPI / memory-hotplug: add memory offline code to acpi_memory_device_remove() ACPI / memory-hotplug: call acpi_bus_trim() to remove memory device ... Conflicts: include/linux/acpi.h (two additions at the end of the same file)
This commit is contained in:
Коммит
d4c091f13d
|
@ -0,0 +1,14 @@
|
||||||
|
Whatt: /sys/devices/.../sun
|
||||||
|
Date: October 2012
|
||||||
|
Contact: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
|
||||||
|
Description:
|
||||||
|
The file contains a Slot-unique ID which provided by the _SUN
|
||||||
|
method in the ACPI namespace. The value is written in Advanced
|
||||||
|
Configuration and Power Interface Specification as follows:
|
||||||
|
|
||||||
|
"The _SUN value is required to be unique among the slots of
|
||||||
|
the same type. It is also recommended that this number match
|
||||||
|
the slot number printed on the physical slot whenever possible."
|
||||||
|
|
||||||
|
So reading the sysfs file, we can identify a physical position
|
||||||
|
of the slot in the system.
|
|
@ -101,6 +101,8 @@ static int __init acpi_sleep_setup(char *str)
|
||||||
#endif
|
#endif
|
||||||
if (strncmp(str, "nonvs", 5) == 0)
|
if (strncmp(str, "nonvs", 5) == 0)
|
||||||
acpi_nvs_nosave();
|
acpi_nvs_nosave();
|
||||||
|
if (strncmp(str, "nonvs_s3", 8) == 0)
|
||||||
|
acpi_nvs_nosave_s3();
|
||||||
if (strncmp(str, "old_ordering", 12) == 0)
|
if (strncmp(str, "old_ordering", 12) == 0)
|
||||||
acpi_old_suspend_ordering();
|
acpi_old_suspend_ordering();
|
||||||
str = strchr(str, ',');
|
str = strchr(str, ',');
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/memory_hotplug.h>
|
#include <linux/memory_hotplug.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <acpi/acpi_drivers.h>
|
#include <acpi/acpi_drivers.h>
|
||||||
|
|
||||||
#define ACPI_MEMORY_DEVICE_CLASS "memory"
|
#define ACPI_MEMORY_DEVICE_CLASS "memory"
|
||||||
|
@ -78,6 +79,7 @@ struct acpi_memory_info {
|
||||||
unsigned short caching; /* memory cache attribute */
|
unsigned short caching; /* memory cache attribute */
|
||||||
unsigned short write_protect; /* memory read/write attribute */
|
unsigned short write_protect; /* memory read/write attribute */
|
||||||
unsigned int enabled:1;
|
unsigned int enabled:1;
|
||||||
|
unsigned int failed:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_memory_device {
|
struct acpi_memory_device {
|
||||||
|
@ -86,8 +88,6 @@ struct acpi_memory_device {
|
||||||
struct list_head res_list;
|
struct list_head res_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int acpi_hotmem_initialized;
|
|
||||||
|
|
||||||
static acpi_status
|
static acpi_status
|
||||||
acpi_memory_get_resource(struct acpi_resource *resource, void *context)
|
acpi_memory_get_resource(struct acpi_resource *resource, void *context)
|
||||||
{
|
{
|
||||||
|
@ -125,12 +125,20 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
acpi_memory_free_device_resources(struct acpi_memory_device *mem_device)
|
||||||
|
{
|
||||||
|
struct acpi_memory_info *info, *n;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(info, n, &mem_device->res_list, list)
|
||||||
|
kfree(info);
|
||||||
|
INIT_LIST_HEAD(&mem_device->res_list);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
|
acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
|
||||||
{
|
{
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
struct acpi_memory_info *info, *n;
|
|
||||||
|
|
||||||
|
|
||||||
if (!list_empty(&mem_device->res_list))
|
if (!list_empty(&mem_device->res_list))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -138,9 +146,7 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
|
||||||
status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
|
status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
|
||||||
acpi_memory_get_resource, mem_device);
|
acpi_memory_get_resource, mem_device);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
list_for_each_entry_safe(info, n, &mem_device->res_list, list)
|
acpi_memory_free_device_resources(mem_device);
|
||||||
kfree(info);
|
|
||||||
INIT_LIST_HEAD(&mem_device->res_list);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +176,7 @@ acpi_memory_get_device(acpi_handle handle,
|
||||||
/* Get the parent device */
|
/* Get the parent device */
|
||||||
result = acpi_bus_get_device(phandle, &pdevice);
|
result = acpi_bus_get_device(phandle, &pdevice);
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_WARNING PREFIX "Cannot get acpi bus device");
|
acpi_handle_warn(phandle, "Cannot get acpi bus device\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,14 +186,14 @@ acpi_memory_get_device(acpi_handle handle,
|
||||||
*/
|
*/
|
||||||
result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
|
result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_WARNING PREFIX "Cannot add acpi bus");
|
acpi_handle_warn(handle, "Cannot add acpi bus\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
*mem_device = acpi_driver_data(device);
|
*mem_device = acpi_driver_data(device);
|
||||||
if (!(*mem_device)) {
|
if (!(*mem_device)) {
|
||||||
printk(KERN_ERR "\n driver data not found");
|
dev_err(&device->dev, "driver data not found\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +230,8 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
||||||
/* Get the range from the _CRS */
|
/* Get the range from the _CRS */
|
||||||
result = acpi_memory_get_device_resources(mem_device);
|
result = acpi_memory_get_device_resources(mem_device);
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_ERR PREFIX "get_device_resources failed\n");
|
dev_err(&mem_device->device->dev,
|
||||||
|
"get_device_resources failed\n");
|
||||||
mem_device->state = MEMORY_INVALID_STATE;
|
mem_device->state = MEMORY_INVALID_STATE;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -251,13 +258,27 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
||||||
node = memory_add_physaddr_to_nid(info->start_addr);
|
node = memory_add_physaddr_to_nid(info->start_addr);
|
||||||
|
|
||||||
result = add_memory(node, info->start_addr, info->length);
|
result = add_memory(node, info->start_addr, info->length);
|
||||||
if (result)
|
|
||||||
|
/*
|
||||||
|
* If the memory block has been used by the kernel, add_memory()
|
||||||
|
* returns -EEXIST. If add_memory() returns the other error, it
|
||||||
|
* means that this memory block is not used by the kernel.
|
||||||
|
*/
|
||||||
|
if (result && result != -EEXIST) {
|
||||||
|
info->failed = 1;
|
||||||
continue;
|
continue;
|
||||||
info->enabled = 1;
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
info->enabled = 1;
|
||||||
|
/*
|
||||||
|
* Add num_enable even if add_memory() returns -EEXIST, so the
|
||||||
|
* device is bound to this driver.
|
||||||
|
*/
|
||||||
num_enabled++;
|
num_enabled++;
|
||||||
}
|
}
|
||||||
if (!num_enabled) {
|
if (!num_enabled) {
|
||||||
printk(KERN_ERR PREFIX "add_memory failed\n");
|
dev_err(&mem_device->device->dev, "add_memory failed\n");
|
||||||
mem_device->state = MEMORY_INVALID_STATE;
|
mem_device->state = MEMORY_INVALID_STATE;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -272,68 +293,31 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
|
static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
|
||||||
{
|
{
|
||||||
acpi_status status;
|
int result = 0;
|
||||||
struct acpi_object_list arg_list;
|
|
||||||
union acpi_object arg;
|
|
||||||
unsigned long long current_status;
|
|
||||||
|
|
||||||
|
|
||||||
/* Issue the _EJ0 command */
|
|
||||||
arg_list.count = 1;
|
|
||||||
arg_list.pointer = &arg;
|
|
||||||
arg.type = ACPI_TYPE_INTEGER;
|
|
||||||
arg.integer.value = 1;
|
|
||||||
status = acpi_evaluate_object(mem_device->device->handle,
|
|
||||||
"_EJ0", &arg_list, NULL);
|
|
||||||
/* Return on _EJ0 failure */
|
|
||||||
if (ACPI_FAILURE(status)) {
|
|
||||||
ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Evalute _STA to check if the device is disabled */
|
|
||||||
status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
|
|
||||||
NULL, ¤t_status);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/* Check for device status. Device should be disabled */
|
|
||||||
if (current_status & ACPI_STA_DEVICE_ENABLED)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
struct acpi_memory_info *info, *n;
|
struct acpi_memory_info *info, *n;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ask the VM to offline this memory range.
|
|
||||||
* Note: Assume that this function returns zero on success
|
|
||||||
*/
|
|
||||||
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
|
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
|
||||||
if (info->enabled) {
|
if (info->failed)
|
||||||
result = remove_memory(info->start_addr, info->length);
|
/* The kernel does not use this memory block */
|
||||||
if (result)
|
continue;
|
||||||
return result;
|
|
||||||
}
|
if (!info->enabled)
|
||||||
|
/*
|
||||||
|
* The kernel uses this memory block, but it may be not
|
||||||
|
* managed by us.
|
||||||
|
*/
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
result = remove_memory(info->start_addr, info->length);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
list_del(&info->list);
|
||||||
kfree(info);
|
kfree(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Power-off and eject the device */
|
|
||||||
result = acpi_memory_powerdown_device(mem_device);
|
|
||||||
if (result) {
|
|
||||||
/* Set the status of the device to invalid */
|
|
||||||
mem_device->state = MEMORY_INVALID_STATE;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_device->state = MEMORY_POWER_OFF_STATE;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,6 +325,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||||
{
|
{
|
||||||
struct acpi_memory_device *mem_device;
|
struct acpi_memory_device *mem_device;
|
||||||
struct acpi_device *device;
|
struct acpi_device *device;
|
||||||
|
struct acpi_eject_event *ej_event = NULL;
|
||||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
@ -353,7 +338,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||||
"\nReceived DEVICE CHECK notification for device\n"));
|
"\nReceived DEVICE CHECK notification for device\n"));
|
||||||
if (acpi_memory_get_device(handle, &mem_device)) {
|
if (acpi_memory_get_device(handle, &mem_device)) {
|
||||||
printk(KERN_ERR PREFIX "Cannot find driver data\n");
|
acpi_handle_err(handle, "Cannot find driver data\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +346,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (acpi_memory_enable_device(mem_device)) {
|
if (acpi_memory_enable_device(mem_device)) {
|
||||||
printk(KERN_ERR PREFIX "Cannot enable memory device\n");
|
acpi_handle_err(handle,"Cannot enable memory device\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,40 +358,28 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||||
"\nReceived EJECT REQUEST notification for device\n"));
|
"\nReceived EJECT REQUEST notification for device\n"));
|
||||||
|
|
||||||
if (acpi_bus_get_device(handle, &device)) {
|
if (acpi_bus_get_device(handle, &device)) {
|
||||||
printk(KERN_ERR PREFIX "Device doesn't exist\n");
|
acpi_handle_err(handle, "Device doesn't exist\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mem_device = acpi_driver_data(device);
|
mem_device = acpi_driver_data(device);
|
||||||
if (!mem_device) {
|
if (!mem_device) {
|
||||||
printk(KERN_ERR PREFIX "Driver Data is NULL\n");
|
acpi_handle_err(handle, "Driver Data is NULL\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
|
||||||
* Currently disabling memory device from kernel mode
|
if (!ej_event) {
|
||||||
* TBD: Can also be disabled from user mode scripts
|
pr_err(PREFIX "No memory, dropping EJECT\n");
|
||||||
* TBD: Can also be disabled by Callback registration
|
|
||||||
* with generic sysfs driver
|
|
||||||
*/
|
|
||||||
if (acpi_memory_disable_device(mem_device)) {
|
|
||||||
printk(KERN_ERR PREFIX "Disable memory device\n");
|
|
||||||
/*
|
|
||||||
* If _EJ0 was called but failed, _OST is not
|
|
||||||
* necessary.
|
|
||||||
*/
|
|
||||||
if (mem_device->state == MEMORY_INVALID_STATE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ej_event->handle = handle;
|
||||||
* TBD: Invoke acpi_bus_remove to cleanup data structures
|
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||||
*/
|
acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
|
||||||
|
(void *)ej_event);
|
||||||
|
|
||||||
/* _EJ0 succeeded; _OST is not necessary */
|
/* eject is performed asynchronously */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||||
"Unsupported event [0x%x]\n", event));
|
"Unsupported event [0x%x]\n", event));
|
||||||
|
@ -420,6 +393,15 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
|
||||||
|
{
|
||||||
|
if (!mem_device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
acpi_memory_free_device_resources(mem_device);
|
||||||
|
kfree(mem_device);
|
||||||
|
}
|
||||||
|
|
||||||
static int acpi_memory_device_add(struct acpi_device *device)
|
static int acpi_memory_device_add(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
@ -449,23 +431,16 @@ static int acpi_memory_device_add(struct acpi_device *device)
|
||||||
/* Set the device state */
|
/* Set the device state */
|
||||||
mem_device->state = MEMORY_POWER_ON_STATE;
|
mem_device->state = MEMORY_POWER_ON_STATE;
|
||||||
|
|
||||||
printk(KERN_DEBUG "%s \n", acpi_device_name(device));
|
pr_debug("%s\n", acpi_device_name(device));
|
||||||
|
|
||||||
/*
|
|
||||||
* Early boot code has recognized memory area by EFI/E820.
|
|
||||||
* If DSDT shows these memory devices on boot, hotplug is not necessary
|
|
||||||
* for them. So, it just returns until completion of this driver's
|
|
||||||
* start up.
|
|
||||||
*/
|
|
||||||
if (!acpi_hotmem_initialized)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!acpi_memory_check_device(mem_device)) {
|
if (!acpi_memory_check_device(mem_device)) {
|
||||||
/* call add_memory func */
|
/* call add_memory func */
|
||||||
result = acpi_memory_enable_device(mem_device);
|
result = acpi_memory_enable_device(mem_device);
|
||||||
if (result)
|
if (result) {
|
||||||
printk(KERN_ERR PREFIX
|
dev_err(&device->dev,
|
||||||
"Error in acpi_memory_enable_device\n");
|
"Error in acpi_memory_enable_device\n");
|
||||||
|
acpi_memory_device_free(mem_device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -473,13 +448,18 @@ static int acpi_memory_device_add(struct acpi_device *device)
|
||||||
static int acpi_memory_device_remove(struct acpi_device *device, int type)
|
static int acpi_memory_device_remove(struct acpi_device *device, int type)
|
||||||
{
|
{
|
||||||
struct acpi_memory_device *mem_device = NULL;
|
struct acpi_memory_device *mem_device = NULL;
|
||||||
|
int result;
|
||||||
|
|
||||||
if (!device || !acpi_driver_data(device))
|
if (!device || !acpi_driver_data(device))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mem_device = acpi_driver_data(device);
|
mem_device = acpi_driver_data(device);
|
||||||
kfree(mem_device);
|
|
||||||
|
result = acpi_memory_remove_memory(mem_device);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
acpi_memory_device_free(mem_device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -568,7 +548,6 @@ static int __init acpi_memory_device_init(void)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_hotmem_initialized = 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -286,7 +286,7 @@ static ssize_t acpi_pad_rrtime_store(struct device *dev,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
unsigned long num;
|
unsigned long num;
|
||||||
if (strict_strtoul(buf, 0, &num))
|
if (kstrtoul(buf, 0, &num))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (num < 1 || num >= 100)
|
if (num < 1 || num >= 100)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -309,7 +309,7 @@ static ssize_t acpi_pad_idlepct_store(struct device *dev,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
unsigned long num;
|
unsigned long num;
|
||||||
if (strict_strtoul(buf, 0, &num))
|
if (kstrtoul(buf, 0, &num))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (num < 1 || num >= 100)
|
if (num < 1 || num >= 100)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -332,7 +332,7 @@ static ssize_t acpi_pad_idlecpus_store(struct device *dev,
|
||||||
struct device_attribute *attr, const char *buf, size_t count)
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
unsigned long num;
|
unsigned long num;
|
||||||
if (strict_strtoul(buf, 0, &num))
|
if (kstrtoul(buf, 0, &num))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
mutex_lock(&isolated_cpus_lock);
|
mutex_lock(&isolated_cpus_lock);
|
||||||
acpi_pad_idle_cpus(num);
|
acpi_pad_idle_cpus(num);
|
||||||
|
@ -457,7 +457,7 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
|
||||||
dev_name(&device->dev), event, 0);
|
dev_name(&device->dev), event, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING "Unsupported event [0x%x]\n", event);
|
pr_warn("Unsupported event [0x%x]\n", event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -994,7 +994,7 @@ err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devexit ghes_remove(struct platform_device *ghes_dev)
|
static int ghes_remove(struct platform_device *ghes_dev)
|
||||||
{
|
{
|
||||||
struct ghes *ghes;
|
struct ghes *ghes;
|
||||||
struct acpi_hest_generic *generic;
|
struct acpi_hest_generic *generic;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
|
@ -95,6 +96,18 @@ enum {
|
||||||
ACPI_BATTERY_ALARM_PRESENT,
|
ACPI_BATTERY_ALARM_PRESENT,
|
||||||
ACPI_BATTERY_XINFO_PRESENT,
|
ACPI_BATTERY_XINFO_PRESENT,
|
||||||
ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
|
ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
|
||||||
|
/* On Lenovo Thinkpad models from 2010 and 2011, the power unit
|
||||||
|
switches between mWh and mAh depending on whether the system
|
||||||
|
is running on battery or not. When mAh is the unit, most
|
||||||
|
reported values are incorrect and need to be adjusted by
|
||||||
|
10000/design_voltage. Verified on x201, t410, t410s, and x220.
|
||||||
|
Pre-2010 and 2012 models appear to always report in mWh and
|
||||||
|
are thus unaffected (tested with t42, t61, t500, x200, x300,
|
||||||
|
and x230). Also, in mid-2012 Lenovo issued a BIOS update for
|
||||||
|
the 2011 models that fixes the issue (tested on x220 with a
|
||||||
|
post-1.29 BIOS), but as of Nov. 2012, no such update is
|
||||||
|
available for the 2010 models. */
|
||||||
|
ACPI_BATTERY_QUIRK_THINKPAD_MAH,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_battery {
|
struct acpi_battery {
|
||||||
|
@ -438,6 +451,21 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
|
||||||
kfree(buffer.pointer);
|
kfree(buffer.pointer);
|
||||||
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
|
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
|
||||||
battery->full_charge_capacity = battery->design_capacity;
|
battery->full_charge_capacity = battery->design_capacity;
|
||||||
|
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
|
||||||
|
battery->power_unit && battery->design_voltage) {
|
||||||
|
battery->design_capacity = battery->design_capacity *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
battery->full_charge_capacity = battery->full_charge_capacity *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
battery->design_capacity_warning =
|
||||||
|
battery->design_capacity_warning *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
/* Curiously, design_capacity_low, unlike the rest of them,
|
||||||
|
is correct. */
|
||||||
|
/* capacity_granularity_* equal 1 on the systems tested, so
|
||||||
|
it's impossible to tell if they would need an adjustment
|
||||||
|
or not if their values were higher. */
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,6 +514,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
|
||||||
&& battery->capacity_now >= 0 && battery->capacity_now <= 100)
|
&& battery->capacity_now >= 0 && battery->capacity_now <= 100)
|
||||||
battery->capacity_now = (battery->capacity_now *
|
battery->capacity_now = (battery->capacity_now *
|
||||||
battery->full_charge_capacity) / 100;
|
battery->full_charge_capacity) / 100;
|
||||||
|
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
|
||||||
|
battery->power_unit && battery->design_voltage) {
|
||||||
|
battery->capacity_now = battery->capacity_now *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,6 +628,24 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
|
||||||
mutex_unlock(&battery->sysfs_lock);
|
mutex_unlock(&battery->sysfs_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void find_battery(const struct dmi_header *dm, void *private)
|
||||||
|
{
|
||||||
|
struct acpi_battery *battery = (struct acpi_battery *)private;
|
||||||
|
/* Note: the hardcoded offsets below have been extracted from
|
||||||
|
the source code of dmidecode. */
|
||||||
|
if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) {
|
||||||
|
const u8 *dmi_data = (const u8 *)(dm + 1);
|
||||||
|
int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6));
|
||||||
|
if (dm->length >= 18)
|
||||||
|
dmi_capacity *= dmi_data[17];
|
||||||
|
if (battery->design_capacity * battery->design_voltage / 1000
|
||||||
|
!= dmi_capacity &&
|
||||||
|
battery->design_capacity * 10 == dmi_capacity)
|
||||||
|
set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
|
||||||
|
&battery->flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to the ACPI spec, some kinds of primary batteries can
|
* According to the ACPI spec, some kinds of primary batteries can
|
||||||
* report percentage battery remaining capacity directly to OS.
|
* report percentage battery remaining capacity directly to OS.
|
||||||
|
@ -620,6 +671,32 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
|
||||||
battery->capacity_now = (battery->capacity_now *
|
battery->capacity_now = (battery->capacity_now *
|
||||||
battery->full_charge_capacity) / 100;
|
battery->full_charge_capacity) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
|
||||||
|
return ;
|
||||||
|
|
||||||
|
if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
|
||||||
|
const char *s;
|
||||||
|
s = dmi_get_system_info(DMI_PRODUCT_VERSION);
|
||||||
|
if (s && !strnicmp(s, "ThinkPad", 8)) {
|
||||||
|
dmi_walk(find_battery, battery);
|
||||||
|
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
|
||||||
|
&battery->flags) &&
|
||||||
|
battery->design_voltage) {
|
||||||
|
battery->design_capacity =
|
||||||
|
battery->design_capacity *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
battery->full_charge_capacity =
|
||||||
|
battery->full_charge_capacity *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
battery->design_capacity_warning =
|
||||||
|
battery->design_capacity_warning *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
battery->capacity_now = battery->capacity_now *
|
||||||
|
10000 / battery->design_voltage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acpi_battery_update(struct acpi_battery *battery)
|
static int acpi_battery_update(struct acpi_battery *battery)
|
||||||
|
|
|
@ -92,17 +92,24 @@ static int is_device_present(acpi_handle handle)
|
||||||
return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
|
return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_container_device(const char *hid)
|
||||||
|
{
|
||||||
|
const struct acpi_device_id *container_id;
|
||||||
|
|
||||||
|
for (container_id = container_device_ids;
|
||||||
|
container_id->id[0]; container_id++) {
|
||||||
|
if (!strcmp((char *)container_id->id, hid))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
static int acpi_container_add(struct acpi_device *device)
|
static int acpi_container_add(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
struct acpi_container *container;
|
struct acpi_container *container;
|
||||||
|
|
||||||
|
|
||||||
if (!device) {
|
|
||||||
printk(KERN_ERR PREFIX "device is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
|
container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
|
||||||
if (!container)
|
if (!container)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -164,7 +171,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
|
||||||
case ACPI_NOTIFY_BUS_CHECK:
|
case ACPI_NOTIFY_BUS_CHECK:
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||||
printk(KERN_WARNING "Container driver received %s event\n",
|
pr_debug("Container driver received %s event\n",
|
||||||
(type == ACPI_NOTIFY_BUS_CHECK) ?
|
(type == ACPI_NOTIFY_BUS_CHECK) ?
|
||||||
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
|
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
|
||||||
|
|
||||||
|
@ -185,7 +192,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
|
||||||
|
|
||||||
result = container_device_add(&device, handle);
|
result = container_device_add(&device, handle);
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_WARNING "Failed to add container\n");
|
acpi_handle_warn(handle, "Failed to add container\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,10 +239,8 @@ container_walk_namespace_cb(acpi_handle handle,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
|
if (!is_container_device(hid))
|
||||||
strcmp(hid, "PNP0A06")) {
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
|
||||||
|
|
||||||
switch (*action) {
|
switch (*action) {
|
||||||
case INSTALL_NOTIFY_HANDLER:
|
case INSTALL_NOTIFY_HANDLER:
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <acpi/acpi_bus.h>
|
#include <acpi/acpi_bus.h>
|
||||||
#include <acpi/acpi_drivers.h>
|
#include <acpi/acpi_drivers.h>
|
||||||
|
|
||||||
|
@ -460,12 +461,8 @@ static void handle_dock(struct dock_station *ds, int dock)
|
||||||
struct acpi_object_list arg_list;
|
struct acpi_object_list arg_list;
|
||||||
union acpi_object arg;
|
union acpi_object arg;
|
||||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
||||||
|
|
||||||
acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
|
acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
|
||||||
|
|
||||||
printk(KERN_INFO PREFIX "%s - %s\n",
|
|
||||||
(char *)name_buffer.pointer, dock ? "docking" : "undocking");
|
|
||||||
|
|
||||||
/* _DCK method has one argument */
|
/* _DCK method has one argument */
|
||||||
arg_list.count = 1;
|
arg_list.count = 1;
|
||||||
|
@ -474,11 +471,10 @@ static void handle_dock(struct dock_station *ds, int dock)
|
||||||
arg.integer.value = dock;
|
arg.integer.value = dock;
|
||||||
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
||||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
||||||
ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute"
|
acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
|
||||||
" _DCK\n", (char *)name_buffer.pointer));
|
status);
|
||||||
|
|
||||||
kfree(buffer.pointer);
|
kfree(buffer.pointer);
|
||||||
kfree(name_buffer.pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dock(struct dock_station *ds)
|
static inline void dock(struct dock_station *ds)
|
||||||
|
@ -525,9 +521,11 @@ static void dock_lock(struct dock_station *ds, int lock)
|
||||||
status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
|
status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
|
||||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||||
if (lock)
|
if (lock)
|
||||||
printk(KERN_WARNING PREFIX "Locking device failed\n");
|
acpi_handle_warn(ds->handle,
|
||||||
|
"Locking device failed (0x%x)\n", status);
|
||||||
else
|
else
|
||||||
printk(KERN_WARNING PREFIX "Unlocking device failed\n");
|
acpi_handle_warn(ds->handle,
|
||||||
|
"Unlocking device failed (0x%x)\n", status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +665,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||||
dock_lock(ds, 0);
|
dock_lock(ds, 0);
|
||||||
eject_dock(ds);
|
eject_dock(ds);
|
||||||
if (dock_present(ds)) {
|
if (dock_present(ds)) {
|
||||||
printk(KERN_ERR PREFIX "Unable to undock!\n");
|
acpi_handle_err(ds->handle, "Unable to undock!\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
complete_undock(ds);
|
complete_undock(ds);
|
||||||
|
@ -715,7 +713,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||||
begin_dock(ds);
|
begin_dock(ds);
|
||||||
dock(ds);
|
dock(ds);
|
||||||
if (!dock_present(ds)) {
|
if (!dock_present(ds)) {
|
||||||
printk(KERN_ERR PREFIX "Unable to dock!\n");
|
acpi_handle_err(handle, "Unable to dock!\n");
|
||||||
complete_dock(ds);
|
complete_dock(ds);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -743,7 +741,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||||
dock_event(ds, event, UNDOCK_EVENT);
|
dock_event(ds, event, UNDOCK_EVENT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
|
acpi_handle_err(handle, "Unknown dock event %d\n", event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,7 +985,7 @@ err_rmgroup:
|
||||||
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
|
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
|
||||||
err_unregister:
|
err_unregister:
|
||||||
platform_device_unregister(dd);
|
platform_device_unregister(dd);
|
||||||
printk(KERN_ERR "%s encountered error %d\n", __func__, ret);
|
acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1016,51 +1014,39 @@ static int dock_remove(struct dock_station *ds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find_dock - look for a dock station
|
* find_dock_and_bay - look for dock stations and bays
|
||||||
* @handle: acpi handle of a device
|
* @handle: acpi handle of a device
|
||||||
* @lvl: unused
|
* @lvl: unused
|
||||||
* @context: counter of dock stations found
|
* @context: unused
|
||||||
* @rv: unused
|
* @rv: unused
|
||||||
*
|
*
|
||||||
* This is called by acpi_walk_namespace to look for dock stations.
|
* This is called by acpi_walk_namespace to look for dock stations and bays.
|
||||||
*/
|
*/
|
||||||
static __init acpi_status
|
static __init acpi_status
|
||||||
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
|
find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||||
{
|
{
|
||||||
if (is_dock(handle))
|
if (is_dock(handle) || is_ejectable_bay(handle))
|
||||||
dock_add(handle);
|
dock_add(handle);
|
||||||
|
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __init acpi_status
|
|
||||||
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|
||||||
{
|
|
||||||
/* If bay is a dock, it's already handled */
|
|
||||||
if (is_ejectable_bay(handle) && !is_dock(handle))
|
|
||||||
dock_add(handle);
|
|
||||||
return AE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init dock_init(void)
|
static int __init dock_init(void)
|
||||||
{
|
{
|
||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* look for a dock station */
|
/* look for dock stations and bays */
|
||||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||||
ACPI_UINT32_MAX, find_dock, NULL, NULL, NULL);
|
ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);
|
||||||
|
|
||||||
/* look for bay */
|
|
||||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
|
||||||
ACPI_UINT32_MAX, find_bay, NULL, NULL, NULL);
|
|
||||||
if (!dock_station_count) {
|
if (!dock_station_count) {
|
||||||
printk(KERN_INFO PREFIX "No dock devices found.\n");
|
pr_info(PREFIX "No dock devices found.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
register_acpi_bus_notifier(&dock_acpi_notifier);
|
register_acpi_bus_notifier(&dock_acpi_notifier);
|
||||||
printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
|
pr_info(PREFIX "%s: %d docks/bays found\n",
|
||||||
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,10 +158,10 @@ static int ec_transaction_done(struct acpi_ec *ec)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
spin_lock_irqsave(&ec->curr_lock, flags);
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
if (!ec->curr || ec->curr->done)
|
if (!ec->curr || ec->curr->done)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
spin_unlock_irqrestore(&ec->curr_lock, flags);
|
spin_unlock_irqrestore(&ec->lock, flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,32 +175,38 @@ static void start_transaction(struct acpi_ec *ec)
|
||||||
static void advance_transaction(struct acpi_ec *ec, u8 status)
|
static void advance_transaction(struct acpi_ec *ec, u8 status)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
spin_lock_irqsave(&ec->curr_lock, flags);
|
struct transaction *t = ec->curr;
|
||||||
if (!ec->curr)
|
|
||||||
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
|
if (!t)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
if (ec->curr->wlen > ec->curr->wi) {
|
if (t->wlen > t->wi) {
|
||||||
if ((status & ACPI_EC_FLAG_IBF) == 0)
|
if ((status & ACPI_EC_FLAG_IBF) == 0)
|
||||||
acpi_ec_write_data(ec,
|
acpi_ec_write_data(ec,
|
||||||
ec->curr->wdata[ec->curr->wi++]);
|
t->wdata[t->wi++]);
|
||||||
else
|
else
|
||||||
goto err;
|
goto err;
|
||||||
} else if (ec->curr->rlen > ec->curr->ri) {
|
} else if (t->rlen > t->ri) {
|
||||||
if ((status & ACPI_EC_FLAG_OBF) == 1) {
|
if ((status & ACPI_EC_FLAG_OBF) == 1) {
|
||||||
ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec);
|
t->rdata[t->ri++] = acpi_ec_read_data(ec);
|
||||||
if (ec->curr->rlen == ec->curr->ri)
|
if (t->rlen == t->ri)
|
||||||
ec->curr->done = true;
|
t->done = true;
|
||||||
} else
|
} else
|
||||||
goto err;
|
goto err;
|
||||||
} else if (ec->curr->wlen == ec->curr->wi &&
|
} else if (t->wlen == t->wi &&
|
||||||
(status & ACPI_EC_FLAG_IBF) == 0)
|
(status & ACPI_EC_FLAG_IBF) == 0)
|
||||||
ec->curr->done = true;
|
t->done = true;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
err:
|
err:
|
||||||
/* false interrupt, state didn't change */
|
/*
|
||||||
if (in_interrupt())
|
* If SCI bit is set, then don't think it's a false IRQ
|
||||||
++ec->curr->irq_count;
|
* otherwise will take a not handled IRQ as a false one.
|
||||||
|
*/
|
||||||
|
if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI))
|
||||||
|
++t->irq_count;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock_irqrestore(&ec->curr_lock, flags);
|
spin_unlock_irqrestore(&ec->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acpi_ec_sync_query(struct acpi_ec *ec);
|
static int acpi_ec_sync_query(struct acpi_ec *ec);
|
||||||
|
@ -238,9 +244,9 @@ static int ec_poll(struct acpi_ec *ec)
|
||||||
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
|
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
|
||||||
break;
|
break;
|
||||||
pr_debug(PREFIX "controller reset, restart transaction\n");
|
pr_debug(PREFIX "controller reset, restart transaction\n");
|
||||||
spin_lock_irqsave(&ec->curr_lock, flags);
|
spin_lock_irqsave(&ec->lock, flags);
|
||||||
start_transaction(ec);
|
start_transaction(ec);
|
||||||
spin_unlock_irqrestore(&ec->curr_lock, flags);
|
spin_unlock_irqrestore(&ec->lock, flags);
|
||||||
}
|
}
|
||||||
return -ETIME;
|
return -ETIME;
|
||||||
}
|
}
|
||||||
|
@ -253,17 +259,17 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
|
||||||
if (EC_FLAGS_MSI)
|
if (EC_FLAGS_MSI)
|
||||||
udelay(ACPI_EC_MSI_UDELAY);
|
udelay(ACPI_EC_MSI_UDELAY);
|
||||||
/* start transaction */
|
/* start transaction */
|
||||||
spin_lock_irqsave(&ec->curr_lock, tmp);
|
spin_lock_irqsave(&ec->lock, tmp);
|
||||||
/* following two actions should be kept atomic */
|
/* following two actions should be kept atomic */
|
||||||
ec->curr = t;
|
ec->curr = t;
|
||||||
start_transaction(ec);
|
start_transaction(ec);
|
||||||
if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
|
if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
|
||||||
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
||||||
spin_unlock_irqrestore(&ec->curr_lock, tmp);
|
spin_unlock_irqrestore(&ec->lock, tmp);
|
||||||
ret = ec_poll(ec);
|
ret = ec_poll(ec);
|
||||||
spin_lock_irqsave(&ec->curr_lock, tmp);
|
spin_lock_irqsave(&ec->lock, tmp);
|
||||||
ec->curr = NULL;
|
ec->curr = NULL;
|
||||||
spin_unlock_irqrestore(&ec->curr_lock, tmp);
|
spin_unlock_irqrestore(&ec->lock, tmp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +298,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (t->rdata)
|
if (t->rdata)
|
||||||
memset(t->rdata, 0, t->rlen);
|
memset(t->rdata, 0, t->rlen);
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
|
if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
@ -310,7 +316,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
||||||
status = -ETIME;
|
status = -ETIME;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
pr_debug(PREFIX "transaction start\n");
|
pr_debug(PREFIX "transaction start (cmd=0x%02x, addr=0x%02x)\n",
|
||||||
|
t->command, t->wdata ? t->wdata[0] : 0);
|
||||||
/* disable GPE during transaction if storm is detected */
|
/* disable GPE during transaction if storm is detected */
|
||||||
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
|
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
|
||||||
/* It has to be disabled, so that it doesn't trigger. */
|
/* It has to be disabled, so that it doesn't trigger. */
|
||||||
|
@ -326,8 +333,9 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
|
||||||
/* It is safe to enable the GPE outside of the transaction. */
|
/* It is safe to enable the GPE outside of the transaction. */
|
||||||
acpi_enable_gpe(NULL, ec->gpe);
|
acpi_enable_gpe(NULL, ec->gpe);
|
||||||
} else if (t->irq_count > ec_storm_threshold) {
|
} else if (t->irq_count > ec_storm_threshold) {
|
||||||
pr_info(PREFIX "GPE storm detected, "
|
pr_info(PREFIX "GPE storm detected(%d GPEs), "
|
||||||
"transactions will use polling mode\n");
|
"transactions will use polling mode\n",
|
||||||
|
t->irq_count);
|
||||||
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
|
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
|
||||||
}
|
}
|
||||||
pr_debug(PREFIX "transaction end\n");
|
pr_debug(PREFIX "transaction end\n");
|
||||||
|
@ -335,7 +343,7 @@ end:
|
||||||
if (ec->global_lock)
|
if (ec->global_lock)
|
||||||
acpi_release_global_lock(glk);
|
acpi_release_global_lock(glk);
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +411,7 @@ int ec_burst_disable(void)
|
||||||
|
|
||||||
EXPORT_SYMBOL(ec_burst_disable);
|
EXPORT_SYMBOL(ec_burst_disable);
|
||||||
|
|
||||||
int ec_read(u8 addr, u8 * val)
|
int ec_read(u8 addr, u8 *val)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u8 temp_data;
|
u8 temp_data;
|
||||||
|
@ -468,10 +476,10 @@ void acpi_ec_block_transactions(void)
|
||||||
if (!ec)
|
if (!ec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
/* Prevent transactions from being carried out */
|
/* Prevent transactions from being carried out */
|
||||||
set_bit(EC_FLAGS_BLOCKED, &ec->flags);
|
set_bit(EC_FLAGS_BLOCKED, &ec->flags);
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_ec_unblock_transactions(void)
|
void acpi_ec_unblock_transactions(void)
|
||||||
|
@ -481,10 +489,10 @@ void acpi_ec_unblock_transactions(void)
|
||||||
if (!ec)
|
if (!ec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
/* Allow transactions to be carried out again */
|
/* Allow transactions to be carried out again */
|
||||||
clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
|
clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_ec_unblock_transactions_early(void)
|
void acpi_ec_unblock_transactions_early(void)
|
||||||
|
@ -536,9 +544,9 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
|
||||||
handler->handle = handle;
|
handler->handle = handle;
|
||||||
handler->func = func;
|
handler->func = func;
|
||||||
handler->data = data;
|
handler->data = data;
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
list_add(&handler->node, &ec->list);
|
list_add(&handler->node, &ec->list);
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,14 +555,14 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
|
||||||
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
|
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
|
||||||
{
|
{
|
||||||
struct acpi_ec_query_handler *handler, *tmp;
|
struct acpi_ec_query_handler *handler, *tmp;
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
|
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
|
||||||
if (query_bit == handler->query_bit) {
|
if (query_bit == handler->query_bit) {
|
||||||
list_del(&handler->node);
|
list_del(&handler->node);
|
||||||
kfree(handler);
|
kfree(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
|
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
|
||||||
|
@ -601,9 +609,9 @@ static void acpi_ec_gpe_query(void *ec_cxt)
|
||||||
struct acpi_ec *ec = ec_cxt;
|
struct acpi_ec *ec = ec_cxt;
|
||||||
if (!ec)
|
if (!ec)
|
||||||
return;
|
return;
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
acpi_ec_sync_query(ec);
|
acpi_ec_sync_query(ec);
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ec_check_sci(struct acpi_ec *ec, u8 state)
|
static int ec_check_sci(struct acpi_ec *ec, u8 state)
|
||||||
|
@ -622,10 +630,11 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
|
||||||
u32 gpe_number, void *data)
|
u32 gpe_number, void *data)
|
||||||
{
|
{
|
||||||
struct acpi_ec *ec = data;
|
struct acpi_ec *ec = data;
|
||||||
|
u8 status = acpi_ec_read_status(ec);
|
||||||
|
|
||||||
pr_debug(PREFIX "~~~> interrupt\n");
|
pr_debug(PREFIX "~~~> interrupt, status:0x%02x\n", status);
|
||||||
|
|
||||||
advance_transaction(ec, acpi_ec_read_status(ec));
|
advance_transaction(ec, status);
|
||||||
if (ec_transaction_done(ec) &&
|
if (ec_transaction_done(ec) &&
|
||||||
(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
|
(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
|
||||||
wake_up(&ec->wait);
|
wake_up(&ec->wait);
|
||||||
|
@ -691,10 +700,10 @@ static struct acpi_ec *make_acpi_ec(void)
|
||||||
if (!ec)
|
if (!ec)
|
||||||
return NULL;
|
return NULL;
|
||||||
ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
|
ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
|
||||||
mutex_init(&ec->lock);
|
mutex_init(&ec->mutex);
|
||||||
init_waitqueue_head(&ec->wait);
|
init_waitqueue_head(&ec->wait);
|
||||||
INIT_LIST_HEAD(&ec->list);
|
INIT_LIST_HEAD(&ec->list);
|
||||||
spin_lock_init(&ec->curr_lock);
|
spin_lock_init(&ec->lock);
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,12 +862,12 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
|
||||||
|
|
||||||
ec = acpi_driver_data(device);
|
ec = acpi_driver_data(device);
|
||||||
ec_remove_handlers(ec);
|
ec_remove_handlers(ec);
|
||||||
mutex_lock(&ec->lock);
|
mutex_lock(&ec->mutex);
|
||||||
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
|
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
|
||||||
list_del(&handler->node);
|
list_del(&handler->node);
|
||||||
kfree(handler);
|
kfree(handler);
|
||||||
}
|
}
|
||||||
mutex_unlock(&ec->lock);
|
mutex_unlock(&ec->mutex);
|
||||||
release_region(ec->data_addr, 1);
|
release_region(ec->data_addr, 1);
|
||||||
release_region(ec->command_addr, 1);
|
release_region(ec->command_addr, 1);
|
||||||
device->driver_data = NULL;
|
device->driver_data = NULL;
|
||||||
|
|
|
@ -70,7 +70,7 @@ static int __devinit acpi_hed_add(struct acpi_device *device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devexit acpi_hed_remove(struct acpi_device *device, int type)
|
static int acpi_hed_remove(struct acpi_device *device, int type)
|
||||||
{
|
{
|
||||||
hed_handle = NULL;
|
hed_handle = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -58,11 +58,11 @@ struct acpi_ec {
|
||||||
unsigned long data_addr;
|
unsigned long data_addr;
|
||||||
unsigned long global_lock;
|
unsigned long global_lock;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct mutex lock;
|
struct mutex mutex;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct transaction *curr;
|
struct transaction *curr;
|
||||||
spinlock_t curr_lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct acpi_ec *first_ec;
|
extern struct acpi_ec *first_ec;
|
||||||
|
|
|
@ -932,7 +932,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||||
* having a static work_struct.
|
* having a static work_struct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
|
dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
|
||||||
if (!dpc)
|
if (!dpc)
|
||||||
return AE_NO_MEMORY;
|
return AE_NO_MEMORY;
|
||||||
|
|
||||||
|
@ -944,17 +944,22 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||||
* because the hotplug code may call driver .remove() functions,
|
* because the hotplug code may call driver .remove() functions,
|
||||||
* which invoke flush_scheduled_work/acpi_os_wait_events_complete
|
* which invoke flush_scheduled_work/acpi_os_wait_events_complete
|
||||||
* to flush these workqueues.
|
* to flush these workqueues.
|
||||||
|
*
|
||||||
|
* To prevent lockdep from complaining unnecessarily, make sure that
|
||||||
|
* there is a different static lockdep key for each workqueue by using
|
||||||
|
* INIT_WORK() for each of them separately.
|
||||||
*/
|
*/
|
||||||
queue = hp ? kacpi_hotplug_wq :
|
if (hp) {
|
||||||
(type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
|
queue = kacpi_hotplug_wq;
|
||||||
dpc->wait = hp ? 1 : 0;
|
dpc->wait = 1;
|
||||||
|
|
||||||
if (queue == kacpi_hotplug_wq)
|
|
||||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||||
else if (queue == kacpi_notify_wq)
|
} else if (type == OSL_NOTIFY_HANDLER) {
|
||||||
|
queue = kacpi_notify_wq;
|
||||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||||
else
|
} else {
|
||||||
|
queue = kacpid_wq;
|
||||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On some machines, a software-initiated SMI causes corruption unless
|
* On some machines, a software-initiated SMI causes corruption unless
|
||||||
|
@ -986,6 +991,7 @@ acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
|
||||||
{
|
{
|
||||||
return __acpi_os_execute(0, function, context, 1);
|
return __acpi_os_execute(0, function, context, 1);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(acpi_os_hotplug_execute);
|
||||||
|
|
||||||
void acpi_os_wait_events_complete(void)
|
void acpi_os_wait_events_complete(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -459,19 +459,19 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
||||||
*/
|
*/
|
||||||
if (gsi < 0) {
|
if (gsi < 0) {
|
||||||
u32 dev_gsi;
|
u32 dev_gsi;
|
||||||
dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin));
|
|
||||||
/* Interrupt Line values above 0xF are forbidden */
|
/* Interrupt Line values above 0xF are forbidden */
|
||||||
if (dev->irq > 0 && (dev->irq <= 0xF) &&
|
if (dev->irq > 0 && (dev->irq <= 0xF) &&
|
||||||
(acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
|
(acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
|
||||||
printk(" - using ISA IRQ %d\n", dev->irq);
|
dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
|
||||||
|
pin_name(pin), dev->irq);
|
||||||
acpi_register_gsi(&dev->dev, dev_gsi,
|
acpi_register_gsi(&dev->dev, dev_gsi,
|
||||||
ACPI_LEVEL_SENSITIVE,
|
ACPI_LEVEL_SENSITIVE,
|
||||||
ACPI_ACTIVE_LOW);
|
ACPI_ACTIVE_LOW);
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
printk("\n");
|
dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
|
||||||
return 0;
|
pin_name(pin));
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
|
rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
|
||||||
|
|
|
@ -473,7 +473,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
no_power_resource:
|
no_power_resource:
|
||||||
printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!");
|
printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
|
EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
|
||||||
|
|
|
@ -362,16 +362,13 @@ acpi_system_write_wakeup_device(struct file *file,
|
||||||
struct list_head *node, *next;
|
struct list_head *node, *next;
|
||||||
char strbuf[5];
|
char strbuf[5];
|
||||||
char str[5] = "";
|
char str[5] = "";
|
||||||
unsigned int len = count;
|
|
||||||
|
|
||||||
if (len > 4)
|
if (count > 4)
|
||||||
len = 4;
|
count = 4;
|
||||||
if (len < 0)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (copy_from_user(strbuf, buffer, len))
|
if (copy_from_user(strbuf, buffer, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
strbuf[len] = '\0';
|
strbuf[count] = '\0';
|
||||||
sscanf(strbuf, "%s", str);
|
sscanf(strbuf, "%s", str);
|
||||||
|
|
||||||
mutex_lock(&acpi_device_lock);
|
mutex_lock(&acpi_device_lock);
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/cpuidle.h>
|
#include <linux/cpuidle.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
|
@ -282,7 +283,9 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||||
/* Declared with "Processor" statement; match ProcessorID */
|
/* Declared with "Processor" statement; match ProcessorID */
|
||||||
status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
|
status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
printk(KERN_ERR PREFIX "Evaluating processor object\n");
|
dev_err(&device->dev,
|
||||||
|
"Failed to evaluate processor object (0x%x)\n",
|
||||||
|
status);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,8 +304,9 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||||
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
|
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
|
||||||
NULL, &value);
|
NULL, &value);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
printk(KERN_ERR PREFIX
|
dev_err(&device->dev,
|
||||||
"Evaluating processor _UID [%#x]\n", status);
|
"Failed to evaluate processor _UID (0x%x)\n",
|
||||||
|
status);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
device_declaration = 1;
|
device_declaration = 1;
|
||||||
|
@ -345,7 +349,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||||
if (!object.processor.pblk_address)
|
if (!object.processor.pblk_address)
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
|
||||||
else if (object.processor.pblk_length != 6)
|
else if (object.processor.pblk_length != 6)
|
||||||
printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n",
|
dev_err(&device->dev, "Invalid PBLK length [%d]\n",
|
||||||
object.processor.pblk_length);
|
object.processor.pblk_length);
|
||||||
else {
|
else {
|
||||||
pr->throttling.address = object.processor.pblk_address;
|
pr->throttling.address = object.processor.pblk_address;
|
||||||
|
@ -430,8 +434,8 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
|
||||||
* Initialize missing things
|
* Initialize missing things
|
||||||
*/
|
*/
|
||||||
if (pr->flags.need_hotplug_init) {
|
if (pr->flags.need_hotplug_init) {
|
||||||
printk(KERN_INFO "Will online and init hotplugged "
|
pr_info("Will online and init hotplugged CPU: %d\n",
|
||||||
"CPU: %d\n", pr->id);
|
pr->id);
|
||||||
WARN(acpi_processor_start(pr), "Failed to start CPU:"
|
WARN(acpi_processor_start(pr), "Failed to start CPU:"
|
||||||
" %d\n", pr->id);
|
" %d\n", pr->id);
|
||||||
pr->flags.need_hotplug_init = 0;
|
pr->flags.need_hotplug_init = 0;
|
||||||
|
@ -492,14 +496,16 @@ static __ref int acpi_processor_start(struct acpi_processor *pr)
|
||||||
&pr->cdev->device.kobj,
|
&pr->cdev->device.kobj,
|
||||||
"thermal_cooling");
|
"thermal_cooling");
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
dev_err(&device->dev,
|
||||||
|
"Failed to create sysfs link 'thermal_cooling'\n");
|
||||||
goto err_thermal_unregister;
|
goto err_thermal_unregister;
|
||||||
}
|
}
|
||||||
result = sysfs_create_link(&pr->cdev->device.kobj,
|
result = sysfs_create_link(&pr->cdev->device.kobj,
|
||||||
&device->dev.kobj,
|
&device->dev.kobj,
|
||||||
"device");
|
"device");
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
dev_err(&pr->cdev->device,
|
||||||
|
"Failed to create sysfs link 'device'\n");
|
||||||
goto err_remove_sysfs_thermal;
|
goto err_remove_sysfs_thermal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,8 +567,9 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
|
||||||
*/
|
*/
|
||||||
if (per_cpu(processor_device_array, pr->id) != NULL &&
|
if (per_cpu(processor_device_array, pr->id) != NULL &&
|
||||||
per_cpu(processor_device_array, pr->id) != device) {
|
per_cpu(processor_device_array, pr->id) != device) {
|
||||||
printk(KERN_WARNING "BIOS reported wrong ACPI id "
|
dev_warn(&device->dev,
|
||||||
"for the processor\n");
|
"BIOS reported wrong ACPI id %d for the processor\n",
|
||||||
|
pr->id);
|
||||||
result = -ENODEV;
|
result = -ENODEV;
|
||||||
goto err_free_cpumask;
|
goto err_free_cpumask;
|
||||||
}
|
}
|
||||||
|
@ -695,8 +702,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
|
||||||
static void acpi_processor_hotplug_notify(acpi_handle handle,
|
static void acpi_processor_hotplug_notify(acpi_handle handle,
|
||||||
u32 event, void *data)
|
u32 event, void *data)
|
||||||
{
|
{
|
||||||
struct acpi_processor *pr;
|
|
||||||
struct acpi_device *device = NULL;
|
struct acpi_device *device = NULL;
|
||||||
|
struct acpi_eject_event *ej_event = NULL;
|
||||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -716,7 +723,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
|
||||||
|
|
||||||
result = acpi_processor_device_add(handle, &device);
|
result = acpi_processor_device_add(handle, &device);
|
||||||
if (result) {
|
if (result) {
|
||||||
printk(KERN_ERR PREFIX "Unable to add the device\n");
|
acpi_handle_err(handle, "Unable to add the device\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,20 +735,29 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
|
||||||
"received ACPI_NOTIFY_EJECT_REQUEST\n"));
|
"received ACPI_NOTIFY_EJECT_REQUEST\n"));
|
||||||
|
|
||||||
if (acpi_bus_get_device(handle, &device)) {
|
if (acpi_bus_get_device(handle, &device)) {
|
||||||
printk(KERN_ERR PREFIX
|
acpi_handle_err(handle,
|
||||||
"Device don't exist, dropping EJECT\n");
|
"Device don't exist, dropping EJECT\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pr = acpi_driver_data(device);
|
if (!acpi_driver_data(device)) {
|
||||||
if (!pr) {
|
acpi_handle_err(handle,
|
||||||
printk(KERN_ERR PREFIX
|
"Driver data is NULL, dropping EJECT\n");
|
||||||
"Driver data is NULL, dropping EJECT\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* REVISIT: update when eject is supported */
|
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
|
||||||
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
|
if (!ej_event) {
|
||||||
break;
|
acpi_handle_err(handle, "No memory, dropping EJECT\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ej_event->handle = handle;
|
||||||
|
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||||
|
acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
|
||||||
|
(void *)ej_event);
|
||||||
|
|
||||||
|
/* eject is performed asynchronously */
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||||
|
@ -841,7 +857,7 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
|
||||||
* and do it when the CPU gets online the first time
|
* and do it when the CPU gets online the first time
|
||||||
* TBD: Cleanup above functions and try to do this more elegant.
|
* TBD: Cleanup above functions and try to do this more elegant.
|
||||||
*/
|
*/
|
||||||
printk(KERN_INFO "CPU %d got hotplugged\n", pr->id);
|
pr_info("CPU %d got hotplugged\n", pr->id);
|
||||||
pr->flags.need_hotplug_init = 1;
|
pr->flags.need_hotplug_init = 1;
|
||||||
|
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
|
@ -852,8 +868,22 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr)
|
||||||
if (cpu_online(pr->id))
|
if (cpu_online(pr->id))
|
||||||
cpu_down(pr->id);
|
cpu_down(pr->id);
|
||||||
|
|
||||||
|
get_online_cpus();
|
||||||
|
/*
|
||||||
|
* The cpu might become online again at this point. So we check whether
|
||||||
|
* the cpu has been onlined or not. If the cpu became online, it means
|
||||||
|
* that someone wants to use the cpu. So acpi_processor_handle_eject()
|
||||||
|
* returns -EAGAIN.
|
||||||
|
*/
|
||||||
|
if (unlikely(cpu_online(pr->id))) {
|
||||||
|
put_online_cpus();
|
||||||
|
pr_warn("Failed to remove CPU %d, because other task "
|
||||||
|
"brought the CPU back online\n", pr->id);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
arch_unregister_cpu(pr->id);
|
arch_unregister_cpu(pr->id);
|
||||||
acpi_unmap_lsapic(pr->id);
|
acpi_unmap_lsapic(pr->id);
|
||||||
|
put_online_cpus();
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -108,6 +108,7 @@ void acpi_bus_hot_remove_device(void *context)
|
||||||
struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
|
struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
|
||||||
struct acpi_device *device;
|
struct acpi_device *device;
|
||||||
acpi_handle handle = ej_event->handle;
|
acpi_handle handle = ej_event->handle;
|
||||||
|
acpi_handle temp;
|
||||||
struct acpi_object_list arg_list;
|
struct acpi_object_list arg_list;
|
||||||
union acpi_object arg;
|
union acpi_object arg;
|
||||||
acpi_status status = AE_OK;
|
acpi_status status = AE_OK;
|
||||||
|
@ -128,13 +129,16 @@ void acpi_bus_hot_remove_device(void *context)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* device has been freed */
|
||||||
|
device = NULL;
|
||||||
|
|
||||||
/* power off device */
|
/* power off device */
|
||||||
status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
|
status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
|
||||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
||||||
printk(KERN_WARNING PREFIX
|
printk(KERN_WARNING PREFIX
|
||||||
"Power-off device failed\n");
|
"Power-off device failed\n");
|
||||||
|
|
||||||
if (device->flags.lockable) {
|
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
|
||||||
arg_list.count = 1;
|
arg_list.count = 1;
|
||||||
arg_list.pointer = &arg;
|
arg_list.pointer = &arg;
|
||||||
arg.type = ACPI_TYPE_INTEGER;
|
arg.type = ACPI_TYPE_INTEGER;
|
||||||
|
@ -168,6 +172,7 @@ err_out:
|
||||||
kfree(context);
|
kfree(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
acpi_eject_store(struct device *d, struct device_attribute *attr,
|
acpi_eject_store(struct device *d, struct device_attribute *attr,
|
||||||
|
@ -227,6 +232,25 @@ acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *bu
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
|
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
|
||||||
|
|
||||||
|
static ssize_t acpi_device_uid_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
|
||||||
|
|
||||||
|
static ssize_t acpi_device_adr_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "0x%08x\n",
|
||||||
|
(unsigned int)(acpi_dev->pnp.bus_address));
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
|
acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
|
||||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||||
|
@ -270,11 +294,21 @@ static ssize_t description_show(struct device *dev,
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(description, 0444, description_show, NULL);
|
static DEVICE_ATTR(description, 0444, description_show, NULL);
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf) {
|
||||||
|
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%lu\n", acpi_dev->pnp.sun);
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
|
||||||
|
|
||||||
static int acpi_device_setup_files(struct acpi_device *dev)
|
static int acpi_device_setup_files(struct acpi_device *dev)
|
||||||
{
|
{
|
||||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
acpi_handle temp;
|
acpi_handle temp;
|
||||||
|
unsigned long long sun;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -311,6 +345,21 @@ static int acpi_device_setup_files(struct acpi_device *dev)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->flags.bus_address)
|
||||||
|
result = device_create_file(&dev->dev, &dev_attr_adr);
|
||||||
|
if (dev->pnp.unique_id)
|
||||||
|
result = device_create_file(&dev->dev, &dev_attr_uid);
|
||||||
|
|
||||||
|
status = acpi_evaluate_integer(dev->handle, "_SUN", NULL, &sun);
|
||||||
|
if (ACPI_SUCCESS(status)) {
|
||||||
|
dev->pnp.sun = (unsigned long)sun;
|
||||||
|
result = device_create_file(&dev->dev, &dev_attr_sun);
|
||||||
|
if (result)
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
dev->pnp.sun = (unsigned long)-1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If device has _EJ0, 'eject' file is created that is used to trigger
|
* If device has _EJ0, 'eject' file is created that is used to trigger
|
||||||
* hot-removal function from userland.
|
* hot-removal function from userland.
|
||||||
|
@ -342,6 +391,14 @@ static void acpi_device_remove_files(struct acpi_device *dev)
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
device_remove_file(&dev->dev, &dev_attr_eject);
|
device_remove_file(&dev->dev, &dev_attr_eject);
|
||||||
|
|
||||||
|
status = acpi_get_handle(dev->handle, "_SUN", &temp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
device_remove_file(&dev->dev, &dev_attr_sun);
|
||||||
|
|
||||||
|
if (dev->pnp.unique_id)
|
||||||
|
device_remove_file(&dev->dev, &dev_attr_uid);
|
||||||
|
if (dev->flags.bus_address)
|
||||||
|
device_remove_file(&dev->dev, &dev_attr_adr);
|
||||||
device_remove_file(&dev->dev, &dev_attr_modalias);
|
device_remove_file(&dev->dev, &dev_attr_modalias);
|
||||||
device_remove_file(&dev->dev, &dev_attr_hid);
|
device_remove_file(&dev->dev, &dev_attr_hid);
|
||||||
if (dev->handle)
|
if (dev->handle)
|
||||||
|
@ -418,6 +475,7 @@ static void acpi_device_release(struct device *dev)
|
||||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||||
|
|
||||||
acpi_free_ids(acpi_dev);
|
acpi_free_ids(acpi_dev);
|
||||||
|
kfree(acpi_dev->pnp.unique_id);
|
||||||
kfree(acpi_dev);
|
kfree(acpi_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,11 +1119,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
|
||||||
device->flags.ejectable = 1;
|
device->flags.ejectable = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Presence of _LCK indicates 'lockable' */
|
|
||||||
status = acpi_get_handle(device->handle, "_LCK", &temp);
|
|
||||||
if (ACPI_SUCCESS(status))
|
|
||||||
device->flags.lockable = 1;
|
|
||||||
|
|
||||||
/* Power resources cannot be power manageable. */
|
/* Power resources cannot be power manageable. */
|
||||||
if (device->device_type == ACPI_BUS_TYPE_POWER)
|
if (device->device_type == ACPI_BUS_TYPE_POWER)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1260,6 +1313,9 @@ static void acpi_device_set_id(struct acpi_device *device)
|
||||||
device->pnp.bus_address = info->address;
|
device->pnp.bus_address = info->address;
|
||||||
device->flags.bus_address = 1;
|
device->flags.bus_address = 1;
|
||||||
}
|
}
|
||||||
|
if (info->valid & ACPI_VALID_UID)
|
||||||
|
device->pnp.unique_id = kstrdup(info->unique_id.string,
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
kfree(info);
|
kfree(info);
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,21 @@ void __init acpi_nvs_nosave(void)
|
||||||
nvs_nosave = true;
|
nvs_nosave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ACPI specification wants us to save NVS memory regions during hibernation
|
||||||
|
* but says nothing about saving NVS during S3. Not all versions of Windows
|
||||||
|
* save NVS on S3 suspend either, and it is clear that not all systems need
|
||||||
|
* NVS to be saved at S3 time. To improve suspend/resume time, allow the
|
||||||
|
* user to disable saving NVS on S3 if their system does not require it, but
|
||||||
|
* continue to save/restore NVS for S4 as specified.
|
||||||
|
*/
|
||||||
|
static bool nvs_nosave_s3;
|
||||||
|
|
||||||
|
void __init acpi_nvs_nosave_s3(void)
|
||||||
|
{
|
||||||
|
nvs_nosave_s3 = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
|
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
|
||||||
* user to request that behavior by using the 'acpi_old_suspend_ordering'
|
* user to request that behavior by using the 'acpi_old_suspend_ordering'
|
||||||
|
@ -248,7 +263,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
|
||||||
u32 acpi_state = acpi_suspend_states[pm_state];
|
u32 acpi_state = acpi_suspend_states[pm_state];
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
error = nvs_nosave ? 0 : suspend_nvs_alloc();
|
error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -524,6 +539,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.callback = init_nvs_nosave,
|
.callback = init_nvs_nosave,
|
||||||
|
.ident = "Sony Vaio VPCEB1S1E",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = init_nvs_nosave,
|
||||||
.ident = "Sony Vaio VGN-FW520F",
|
.ident = "Sony Vaio VGN-FW520F",
|
||||||
.matches = {
|
.matches = {
|
||||||
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||||
|
|
|
@ -984,6 +984,38 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On some platforms, the AML code has dependency about
|
||||||
|
* the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx.
|
||||||
|
* 1. On HP Pavilion G4-1016tx, _TMP must be invoked after
|
||||||
|
* /_CRT/_HOT/_PSV/_ACx, or else system will be power off.
|
||||||
|
* 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0
|
||||||
|
* if _TMP has never been evaluated.
|
||||||
|
*
|
||||||
|
* As this dependency is totally transparent to OS, evaluate
|
||||||
|
* all of them once, in the order of _CRT/_HOT/_PSV/_ACx,
|
||||||
|
* _TMP, before they are actually used.
|
||||||
|
*/
|
||||||
|
static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
|
||||||
|
{
|
||||||
|
acpi_handle handle = tz->device->handle;
|
||||||
|
unsigned long long value;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
acpi_evaluate_integer(handle, "_CRT", NULL, &value);
|
||||||
|
acpi_evaluate_integer(handle, "_HOT", NULL, &value);
|
||||||
|
acpi_evaluate_integer(handle, "_PSV", NULL, &value);
|
||||||
|
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
|
||||||
|
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
status = acpi_evaluate_integer(handle, name, NULL, &value);
|
||||||
|
if (status == AE_NOT_FOUND)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acpi_evaluate_integer(handle, "_TMP", NULL, &value);
|
||||||
|
}
|
||||||
|
|
||||||
static int acpi_thermal_get_info(struct acpi_thermal *tz)
|
static int acpi_thermal_get_info(struct acpi_thermal *tz)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
@ -992,6 +1024,8 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
|
||||||
if (!tz)
|
if (!tz)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
acpi_thermal_aml_dependency_fix(tz);
|
||||||
|
|
||||||
/* Get trip points [_CRT, _PSV, etc.] (required) */
|
/* Get trip points [_CRT, _PSV, etc.] (required) */
|
||||||
result = acpi_thermal_get_trip_points(tz);
|
result = acpi_thermal_get_trip_points(tz);
|
||||||
if (result)
|
if (result)
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/hardirq.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <acpi/acpi_bus.h>
|
#include <acpi/acpi_bus.h>
|
||||||
#include <acpi/acpi_drivers.h>
|
#include <acpi/acpi_drivers.h>
|
||||||
|
|
||||||
|
@ -457,3 +459,39 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
|
EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_handle_printk: Print message with ACPI prefix and object path
|
||||||
|
*
|
||||||
|
* This function is called through acpi_handle_<level> macros and prints
|
||||||
|
* a message with ACPI prefix and object path. This function acquires
|
||||||
|
* the global namespace mutex to obtain an object path. In interrupt
|
||||||
|
* context, it shows the object path as <n/a>.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
struct va_format vaf;
|
||||||
|
va_list args;
|
||||||
|
struct acpi_buffer buffer = {
|
||||||
|
.length = ACPI_ALLOCATE_BUFFER,
|
||||||
|
.pointer = NULL
|
||||||
|
};
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vaf.fmt = fmt;
|
||||||
|
vaf.va = &args;
|
||||||
|
|
||||||
|
if (in_interrupt() ||
|
||||||
|
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
|
||||||
|
path = "<n/a>";
|
||||||
|
else
|
||||||
|
path = buffer.pointer;
|
||||||
|
|
||||||
|
printk("%sACPI: %s: %pV", level, path, &vaf);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
kfree(buffer.pointer);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(acpi_handle_printk);
|
||||||
|
|
|
@ -144,12 +144,11 @@ struct acpi_device_flags {
|
||||||
u32 bus_address:1;
|
u32 bus_address:1;
|
||||||
u32 removable:1;
|
u32 removable:1;
|
||||||
u32 ejectable:1;
|
u32 ejectable:1;
|
||||||
u32 lockable:1;
|
|
||||||
u32 suprise_removal_ok:1;
|
u32 suprise_removal_ok:1;
|
||||||
u32 power_manageable:1;
|
u32 power_manageable:1;
|
||||||
u32 performance_manageable:1;
|
u32 performance_manageable:1;
|
||||||
u32 eject_pending:1;
|
u32 eject_pending:1;
|
||||||
u32 reserved:23;
|
u32 reserved:24;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* File System */
|
/* File System */
|
||||||
|
@ -180,6 +179,7 @@ struct acpi_device_pnp {
|
||||||
acpi_device_name device_name; /* Driver-determined */
|
acpi_device_name device_name; /* Driver-determined */
|
||||||
acpi_device_class device_class; /* " */
|
acpi_device_class device_class; /* " */
|
||||||
union acpi_object *str_obj; /* unicode string for _STR method */
|
union acpi_object *str_obj; /* unicode string for _STR method */
|
||||||
|
unsigned long sun; /* _SUN */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define acpi_device_bid(d) ((d)->pnp.bus_id)
|
#define acpi_device_bid(d) ((d)->pnp.bus_id)
|
||||||
|
|
|
@ -279,10 +279,14 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
|
||||||
|
|
||||||
int acpi_resources_are_enforced(void);
|
int acpi_resources_are_enforced(void);
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_HIBERNATION
|
||||||
void __init acpi_no_s4_hw_signature(void);
|
void __init acpi_no_s4_hw_signature(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
void __init acpi_old_suspend_ordering(void);
|
void __init acpi_old_suspend_ordering(void);
|
||||||
void __init acpi_nvs_nosave(void);
|
void __init acpi_nvs_nosave(void);
|
||||||
|
void __init acpi_nvs_nosave_s3(void);
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
struct acpi_osc_context {
|
struct acpi_osc_context {
|
||||||
|
@ -516,4 +520,47 @@ static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
|
||||||
static inline void acpi_dev_pm_detach(struct device *dev, bool power_off) {}
|
static inline void acpi_dev_pm_detach(struct device *dev, bool power_off) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
__printf(3, 4)
|
||||||
|
void acpi_handle_printk(const char *level, acpi_handle handle,
|
||||||
|
const char *fmt, ...);
|
||||||
|
#else /* !CONFIG_ACPI */
|
||||||
|
static inline __printf(3, 4) void
|
||||||
|
acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {}
|
||||||
|
#endif /* !CONFIG_ACPI */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* acpi_handle_<level>: Print message with ACPI prefix and object path
|
||||||
|
*
|
||||||
|
* These interfaces acquire the global namespace mutex to obtain an object
|
||||||
|
* path. In interrupt context, it shows the object path as <n/a>.
|
||||||
|
*/
|
||||||
|
#define acpi_handle_emerg(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_EMERG, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#define acpi_handle_alert(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_ALERT, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#define acpi_handle_crit(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_CRIT, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#define acpi_handle_err(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_ERR, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#define acpi_handle_warn(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_WARNING, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#define acpi_handle_notice(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_NOTICE, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#define acpi_handle_info(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_INFO, handle, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/* REVISIT: Support CONFIG_DYNAMIC_DEBUG when necessary */
|
||||||
|
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
|
||||||
|
#define acpi_handle_debug(handle, fmt, ...) \
|
||||||
|
acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define acpi_handle_debug(handle, fmt, ...) \
|
||||||
|
({ \
|
||||||
|
if (0) \
|
||||||
|
acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__); \
|
||||||
|
0; \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /*_LINUX_ACPI_H*/
|
#endif /*_LINUX_ACPI_H*/
|
||||||
|
|
|
@ -348,11 +348,13 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
|
||||||
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
|
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
|
||||||
struct task_struct *idle;
|
struct task_struct *idle;
|
||||||
|
|
||||||
if (cpu_online(cpu) || !cpu_present(cpu))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
cpu_hotplug_begin();
|
cpu_hotplug_begin();
|
||||||
|
|
||||||
|
if (cpu_online(cpu) || !cpu_present(cpu)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
idle = idle_thread_get(cpu);
|
idle = idle_thread_get(cpu);
|
||||||
if (IS_ERR(idle)) {
|
if (IS_ERR(idle)) {
|
||||||
ret = PTR_ERR(idle);
|
ret = PTR_ERR(idle);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче