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:
Rafael J. Wysocki 2012-11-29 21:43:06 +01:00
commit d4c091f13d
23 changed files with 567 additions and 262 deletions

View File

@ -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.

View File

@ -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, ',');

View File

@ -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, &current_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;
} }

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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)

View File

@ -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:

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)
{ {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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"),

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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*/

View File

@ -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);