Commit f4cb707e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pm+acpi-3.17-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI and power management fixes from Rafael Wysocki:
 "These are regression fixes (ACPI hotplug, cpufreq, hibernation, ACPI
  LPSS driver), fixes for stuff that never worked correctly (ACPI GPIO
  support in some cases and a wrong sign of an error code in the ACPI
  core in one place), and one blacklist item for ACPI backlight
  handling.

  Specifics:

   - Revert of a recent hibernation core commit that introduced a NULL
     pointer dereference during resume for at least one user (Rafael J
     Wysocki).

   - Fix for the ACPI LPSS (Low-Power Subsystem) driver to disable
     asynchronous PM callback execution for LPSS devices during system
     suspend/resume (introduced in 3.16) which turns out to break
     ordering expectations on some systems.  From Fu Zhonghui.

   - cpufreq core fix related to the handling of sysfs nodes during
     system suspend/resume that has been broken for intel_pstate since
     3.15 from Lan Tianyu.

   - Restore the generation of "online" uevents for ACPI container
     devices that was removed in 3.14, but some user space utilities
     turn out to need them (Rafael J Wysocki).

   - The cpufreq core fails to release a lock in an error code path
     after changes made in 3.14.  Fix from Prarit Bhargava.

   - ACPICA and ACPI/GPIO fixes to make the handling of ACPI GPIO
     operation regions (which means AML using GPIOs) work correctly in
     all cases from Bob Moore and Srinivas Pandruvada.

   - Fix for a wrong sign of the ACPI core's create_modalias() return
     value in case of an error from Mika Westerberg.

   - ACPI backlight blacklist entry for ThinkPad X201s from Aaron Lu"

* tag 'pm+acpi-3.17-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  Revert "PM / Hibernate: Iterate over set bits instead of PFNs in swsusp_free()"
  gpio / ACPI: Use pin index and bit length
  ACPICA: Update to GPIO region handler interface.
  ACPI / platform / LPSS: disable async suspend/resume of LPSS devices
  cpufreq: release policy->rwsem on error
  cpufreq: fix cpufreq suspend/resume for intel_pstate
  ACPI / scan: Correct error return value of create_modalias()
  ACPI / video: disable native backlight for ThinkPad X201s
  ACPI / hotplug: Generate online uevents for ACPI containers
parents 12df9f37 381e63da
...@@ -419,7 +419,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev, ...@@ -419,7 +419,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
adev->driver_data = pdata; adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev); pdev = acpi_create_platform_device(adev);
if (!IS_ERR_OR_NULL(pdev)) { if (!IS_ERR_OR_NULL(pdev)) {
device_enable_async_suspend(&pdev->dev);
return 1; return 1;
} }
......
...@@ -254,6 +254,7 @@ struct acpi_create_field_info { ...@@ -254,6 +254,7 @@ struct acpi_create_field_info {
u32 field_bit_position; u32 field_bit_position;
u32 field_bit_length; u32 field_bit_length;
u16 resource_length; u16 resource_length;
u16 pin_number_index;
u8 field_flags; u8 field_flags;
u8 attribute; u8 attribute;
u8 field_type; u8 field_type;
......
...@@ -264,6 +264,7 @@ struct acpi_object_region_field { ...@@ -264,6 +264,7 @@ struct acpi_object_region_field {
ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length;
union acpi_operand_object *region_obj; /* Containing op_region object */ union acpi_operand_object *region_obj; /* Containing op_region object */
u8 *resource_buffer; /* resource_template for serial regions/fields */ u8 *resource_buffer; /* resource_template for serial regions/fields */
u16 pin_number_index; /* Index relative to previous Connection/Template */
}; };
struct acpi_object_bank_field { struct acpi_object_bank_field {
......
...@@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, ...@@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
*/ */
info->resource_buffer = NULL; info->resource_buffer = NULL;
info->connection_node = NULL; info->connection_node = NULL;
info->pin_number_index = 0;
/* /*
* A Connection() is either an actual resource descriptor (buffer) * A Connection() is either an actual resource descriptor (buffer)
...@@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, ...@@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
} }
info->field_bit_position += info->field_bit_length; info->field_bit_position += info->field_bit_length;
info->pin_number_index++; /* Index relative to previous Connection() */
break; break;
default: default:
......
...@@ -142,6 +142,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -142,6 +142,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
union acpi_operand_object *region_obj2; union acpi_operand_object *region_obj2;
void *region_context = NULL; void *region_context = NULL;
struct acpi_connection_info *context; struct acpi_connection_info *context;
acpi_physical_address address;
ACPI_FUNCTION_TRACE(ev_address_space_dispatch); ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
...@@ -231,25 +232,32 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -231,25 +232,32 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
/* We have everything we need, we can invoke the address space handler */ /* We have everything we need, we can invoke the address space handler */
handler = handler_desc->address_space.handler; handler = handler_desc->address_space.handler;
address = (region_obj->region.address + region_offset);
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.handler->address_space, handler,
ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
region_offset),
acpi_ut_get_region_name(region_obj->region.
space_id)));
/* /*
* Special handling for generic_serial_bus and general_purpose_io: * Special handling for generic_serial_bus and general_purpose_io:
* There are three extra parameters that must be passed to the * There are three extra parameters that must be passed to the
* handler via the context: * handler via the context:
* 1) Connection buffer, a resource template from Connection() op. * 1) Connection buffer, a resource template from Connection() op
* 2) Length of the above buffer. * 2) Length of the above buffer
* 3) Actual access length from the access_as() op. * 3) Actual access length from the access_as() op
*
* In addition, for general_purpose_io, the Address and bit_width fields
* are defined as follows:
* 1) Address is the pin number index of the field (bit offset from
* the previous Connection)
* 2) bit_width is the actual bit length of the field (number of pins)
*/ */
if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
(region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) && context && field_obj) {
/* Get the Connection (resource_template) buffer */
context->connection = field_obj->field.resource_buffer;
context->length = field_obj->field.resource_length;
context->access_length = field_obj->field.access_length;
}
if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
context && field_obj) { context && field_obj) {
/* Get the Connection (resource_template) buffer */ /* Get the Connection (resource_template) buffer */
...@@ -257,8 +265,17 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -257,8 +265,17 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
context->connection = field_obj->field.resource_buffer; context->connection = field_obj->field.resource_buffer;
context->length = field_obj->field.resource_length; context->length = field_obj->field.resource_length;
context->access_length = field_obj->field.access_length; context->access_length = field_obj->field.access_length;
address = field_obj->field.pin_number_index;
bit_width = field_obj->field.bit_length;
} }
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.handler->address_space, handler,
ACPI_FORMAT_NATIVE_UINT(address),
acpi_ut_get_region_name(region_obj->region.
space_id)));
if (!(handler_desc->address_space.handler_flags & if (!(handler_desc->address_space.handler_flags &
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
/* /*
...@@ -271,9 +288,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ...@@ -271,9 +288,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
/* Call the handler */ /* Call the handler */
status = handler(function, status = handler(function, address, bit_width, value, context,
(region_obj->region.address + region_offset),
bit_width, value, context,
region_obj2->extra.region_context); region_obj2->extra.region_context);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
......
...@@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, ...@@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
buffer = &buffer_desc->integer.value; buffer = &buffer_desc->integer.value;
} }
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_GPIO)) {
/*
* For GPIO (general_purpose_io), the Address will be the bit offset
* from the previous Connection() operator, making it effectively a
* pin number index. The bit_length is the length of the field, which
* is thus the number of pins.
*/
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"GPIO FieldRead [FROM]: Pin %u Bits %u\n",
obj_desc->field.pin_number_index,
obj_desc->field.bit_length));
/* Lock entire transaction if requested */
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Perform the write */
status = acpi_ex_access_region(obj_desc, 0,
(u64 *)buffer, ACPI_READ);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(buffer_desc);
} else {
*ret_buffer_desc = buffer_desc;
}
return_ACPI_STATUS(status);
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
obj_desc, obj_desc->common.type, buffer, obj_desc, obj_desc->common.type, buffer,
...@@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, ...@@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
*result_desc = buffer_desc; *result_desc = buffer_desc;
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_GPIO)) {
/*
* For GPIO (general_purpose_io), we will bypass the entire field
* mechanism and handoff the bit address and bit width directly to
* the handler. The Address will be the bit offset
* from the previous Connection() operator, making it effectively a
* pin number index. The bit_length is the length of the field, which
* is thus the number of pins.
*/
if (source_desc->common.type != ACPI_TYPE_INTEGER) {
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
acpi_ut_get_type_name(source_desc->common.
type),
source_desc->common.type,
(u32)source_desc->integer.value,
obj_desc->field.pin_number_index,
obj_desc->field.bit_length));
buffer = &source_desc->integer.value;
/* Lock entire transaction if requested */
acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Perform the write */
status = acpi_ex_access_region(obj_desc, 0,
(u64 *)buffer, ACPI_WRITE);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
return_ACPI_STATUS(status);
} }
/* Get a pointer to the data to be written */ /* Get a pointer to the data to be written */
......
...@@ -484,6 +484,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) ...@@ -484,6 +484,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
obj_desc->field.resource_length = info->resource_length; obj_desc->field.resource_length = info->resource_length;
} }
obj_desc->field.pin_number_index = info->pin_number_index;
/* Allow full data read from EC address space */ /* Allow full data read from EC address space */
if ((obj_desc->field.region_obj->region.space_id == if ((obj_desc->field.region_obj->region.space_id ==
......
...@@ -99,6 +99,13 @@ static void container_device_detach(struct acpi_device *adev) ...@@ -99,6 +99,13 @@ static void container_device_detach(struct acpi_device *adev)
device_unregister(dev); device_unregister(dev);
} }
static void container_device_online(struct acpi_device *adev)
{
struct device *dev = acpi_driver_data(adev);
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
}
static struct acpi_scan_handler container_handler = { static struct acpi_scan_handler container_handler = {
.ids = container_device_ids, .ids = container_device_ids,
.attach = container_device_attach, .attach = container_device_attach,
...@@ -106,6 +113,7 @@ static struct acpi_scan_handler container_handler = { ...@@ -106,6 +113,7 @@ static struct acpi_scan_handler container_handler = {
.hotplug = { .hotplug = {
.enabled = true, .enabled = true,
.demand_offline = true, .demand_offline = true,
.notify_online = container_device_online,
}, },
}; };
......
...@@ -130,7 +130,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, ...@@ -130,7 +130,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
list_for_each_entry(id, &acpi_dev->pnp.ids, list) { list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
count = snprintf(&modalias[len], size, "%s:", id->id); count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0) if (count < 0)
return EINVAL; return -EINVAL;
if (count >= size) if (count >= size)
return -ENOMEM; return -ENOMEM;
len += count; len += count;
...@@ -2189,6 +2189,9 @@ static void acpi_bus_attach(struct acpi_device *device) ...@@ -2189,6 +2189,9 @@ static void acpi_bus_attach(struct acpi_device *device)
ok: ok:
list_for_each_entry(child, &device->children, node) list_for_each_entry(child, &device->children, node)
acpi_bus_attach(child); acpi_bus_attach(child);
if (device->handler && device->handler->hotplug.notify_online)
device->handler->hotplug.notify_online(device);
} }
/** /**
......
...@@ -750,6 +750,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { ...@@ -750,6 +750,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
}, },
}, },
{
.callback = video_disable_native_backlight,
.ident = "ThinkPad X201s",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
},
},
/* The native backlight controls do not work on some older machines */ /* The native backlight controls do not work on some older machines */
{ {
......
...@@ -1289,6 +1289,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ...@@ -1289,6 +1289,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
per_cpu(cpufreq_cpu_data, j) = NULL; per_cpu(cpufreq_cpu_data, j) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
up_write(&policy->rwsem);
if (cpufreq_driver->exit) if (cpufreq_driver->exit)
cpufreq_driver->exit(policy); cpufreq_driver->exit(policy);
err_set_policy_cpu: err_set_policy_cpu:
...@@ -1656,6 +1658,8 @@ void cpufreq_suspend(void) ...@@ -1656,6 +1658,8 @@ void cpufreq_suspend(void)
if (!cpufreq_driver) if (!cpufreq_driver)
return; return;
cpufreq_suspended = true;
if (!has_target()) if (!has_target())
return; return;
...@@ -1670,8 +1674,6 @@ void cpufreq_suspend(void) ...@@ -1670,8 +1674,6 @@ void cpufreq_suspend(void)
pr_err("%s: Failed to suspend driver: %p\n", __func__, pr_err("%s: Failed to suspend driver: %p\n", __func__,
policy); policy);
} }
cpufreq_suspended = true;
} }
/** /**
...@@ -1687,13 +1689,13 @@ void cpufreq_resume(void) ...@@ -1687,13 +1689,13 @@ void cpufreq_resume(void)
if (!cpufreq_driver) if (!cpufreq_driver)
return; return;
cpufreq_suspended = false;
if (!has_target()) if (!has_target())
return; return;
pr_debug("%s: Resuming Governors\n", __func__); pr_debug("%s: Resuming Governors\n", __func__);
cpufreq_suspended = false;
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
pr_err("%s: Failed to resume driver: %p\n", __func__, pr_err("%s: Failed to resume driver: %p\n", __func__,
......
...@@ -377,8 +377,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, ...@@ -377,8 +377,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
struct gpio_chip *chip = achip->chip; struct gpio_chip *chip = achip->chip;
struct acpi_resource_gpio *agpio; struct acpi_resource_gpio *agpio;
struct acpi_resource *ares; struct acpi_resource *ares;
int pin_index = (int)address;
acpi_status status; acpi_status status;
bool pull_up; bool pull_up;
int length;
int i; int i;
status = acpi_buffer_to_resource(achip->conn_info.connection, status = acpi_buffer_to_resource(achip->conn_info.connection,
...@@ -400,7 +402,8 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, ...@@ -400,7 +402,8 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
} }
for (i = 0; i < agpio->pin_table_length; i++) { length = min(agpio->pin_table_length, (u16)(pin_index + bits));
for (i = pin_index; i < length; ++i) {
unsigned pin = agpio->pin_table[i]; unsigned pin = agpio->pin_table[i];
struct acpi_gpio_connection *conn; struct acpi_gpio_connection *conn;
struct gpio_desc *desc; struct gpio_desc *desc;
......
...@@ -118,6 +118,7 @@ struct acpi_device; ...@@ -118,6 +118,7 @@ struct acpi_device;
struct acpi_hotplug_profile { struct acpi_hotplug_profile {
struct kobject kobj; struct kobject kobj;
int (*scan_dependent)(struct acpi_device *adev); int (*scan_dependent)(struct acpi_device *adev);
void (*notify_online)(struct acpi_device *adev);
bool enabled:1; bool enabled:1;
bool demand_offline:1; bool demand_offline:1;
}; };
......
...@@ -725,14 +725,6 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) ...@@ -725,14 +725,6 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
clear_bit(bit, addr); clear_bit(bit, addr);
} }
static void memory_bm_clear_current(struct memory_bitmap *bm)
{
int bit;
bit = max(bm->cur.node_bit - 1, 0);
clear_bit(bit, bm->cur.node->data);
}
static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
{ {
void *addr; void *addr;
...@@ -1341,35 +1333,23 @@ static struct memory_bitmap copy_bm; ...@@ -1341,35 +1333,23 @@ static struct memory_bitmap copy_bm;
void swsusp_free(void) void swsusp_free(void)
{ {
unsigned long fb_pfn, fr_pfn; struct zone *zone;
unsigned long pfn, max_zone_pfn;
memory_bm_position_reset(forbidden_pages_map);
memory_bm_position_reset(free_pages_map);
loop:
fr_pfn = memory_bm_next_pfn(free_pages_map);
fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
/*
* Find the next bit set in both bitmaps. This is guaranteed to
* terminate when fb_pfn == fr_pfn == BM_END_OF_MAP.
*/
do {
if (fb_pfn < fr_pfn)
fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
if (fr_pfn < fb_pfn)
fr_pfn = memory_bm_next_pfn(free_pages_map);
} while (fb_pfn != fr_pfn);
if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) { for_each_populated_zone(zone) {
struct page *page = pfn_to_page(fr_pfn); max_zone_pfn = zone_end_pfn(zone);
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
memory_bm_clear_current(forbidden_pages_map); if (swsusp_page_is_forbidden(page) &&
memory_bm_clear_current(free_pages_map); swsusp_page_is_free(page)) {
swsusp_unset_page_forbidden(page);
swsusp_unset_page_free(page);
__free_page(page); __free_page(page);
goto loop;
} }
}
}
nr_copy_pages = 0; nr_copy_pages = 0;
nr_meta_pages = 0; nr_meta_pages = 0;
restore_pblist = NULL; restore_pblist = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment