forked from Minki/linux
ACPI and power management fixes for 3.12-rc1
1) ACPI-based PCI hotplug (ACPIPHP) fixes related to spurious events After the recent ACPIPHP changes we've seen some interesting breakage on a system that triggers device check notifications during boot for non-existing devices. Although those notifications are really spurious, we should be able to deal with them nevertheless and that shouldn't introduce too much overhead. Four commits to make that work properly. 2) Memory hotplug and hibernation mutual exclusion rework This was maent to be a cleanup, but it happens to fix a classical ABBA deadlock between system suspend/hibernation and ACPI memory hotplug which is possible if they are started roughly at the same time. Three commits rework memory hotplug so that it doesn't acquire pm_mutex and make hibernation use device_hotplug_lock which prevents it from racing with memory hotplug. 3) ACPI Intel LPSS (Low-Power Subsystem) driver crash fix The ACPI LPSS driver crashes during boot on Apple Macbook Air with Haswell that has slightly unusual BIOS configuration in which one of the LPSS device's _CRS method doesn't return all of the information expected by the driver. Fix from Mika Westerberg, for stable. 4) ACPICA fix related to Store->ArgX operation AML interpreter fix for obscure breakage that causes AML to be executed incorrectly on some machines (observed in practice). From Bob Moore. 5) ACPI core fix for PCI ACPI device objects lookup There still are cases in which there is more than one ACPI device object matching a given PCI device and we don't choose the one that the BIOS expects us to choose, so this makes the lookup take more criteria into account in those cases. 6) Fix to prevent cpuidle from crashing in some rare cases If the result of cpuidle_get_driver() is NULL, which can happen on some systems, cpuidle_driver_ref() will crash trying to use that pointer and the Daniel Fu's fix prevents that from happening. 7) cpufreq fixes related to CPU hotplug Stephen Boyd reported a number of concurrency problems with cpufreq related to CPU hotplug which are addressed by a series of fixes from Srivatsa S Bhat and Viresh Kumar. 8) cpufreq fix for time conversion in time_in_state attribute Time conversion carried out by cpufreq when user space attempts to read /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state won't work correcty if cputime_t doesn't map directly to jiffies. Fix from Andreas Schwab. 9) Revert of a troublesome cpufreq commit Commit7c30ed5
(cpufreq: make sure frequency transitions are serialized) was intended to address some known concurrency problems in cpufreq related to the ordering of transitions, but unfortunately it introduced several problems of its own, so I decided to revert it now and address the original problems later in a more robust way. 10) Intel Haswell CPU models for intel_pstate from Nell Hardcastle. 11) cpufreq fixes related to system suspend/resume The recent cpufreq changes that made it preserve CPU sysfs attributes over suspend/resume cycles introduced a possible NULL pointer dereference that caused it to crash during the second attempt to suspend. Three commits from Srivatsa S Bhat fix that problem and a couple of related issues. 12) cpufreq locking fix cpufreq_policy_restore() should acquire the lock for reading, but it acquires it for writing. Fix from Lan Tianyu. / -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABCAAGBQJSMbdRAAoJEKhOf7ml8uNsiFkQAKSh1iBXuiUCxBApEGZgoQio 8lmnuyWdhNQWdjZTnh7ptjpDxdrWhxcoxvoaGABU++reDObjef1QnyrQtdO3r8dl oy0C/YGh5kq5SIffIDEwPIb/ipDe/47cgRMW8iBlnViDa1MJBqICuLyefcTRIrKp QGvv0owUM2o7TXpA10+qm8zXjv6m5mu1DTtxYI+2Eodhwi54neAqb+aKMspa2thy V9KFcVv3Td4rJrNvw6BhXNM81QbaYpRxaK3DRr1T6SM++EKvbqYFA1jgW24YvqTL nrCZlDMb6KRww5DCxA/ns9Kx5H+ZyicoRwdtAM3PBYA6MGqsLqPozC/8VKV1fSvZ sgUdbUSuLqKRAkOqM1bjKAhi9PdCGBvkQAg2AqbRK6IBl4HJC8xhdb5E6eZ/J42G GyNBpKef7wVJwYKXE2hSChZ5dYjqMizNHWxFHf8Xy1dveExbQ2nmSJmaWMy2A3kx YOXFkcTV5F6GOIZB8WCRruzUalff9xal4G+iVhGF+AZIOCm7bC+FDXfwIS82uVor ej2l+uQLLZCB499IRmM6942ZIAXshmtN7eRfGtKBc6jsbSCEdQDqf1Z7oRwqAD6h WkD/k/zz30CyM8y4snOkAXkZgqAQsZodtqfowE3e9OHd51tfcNiqdht+obwCx+eD MWXc2xATMAX6NcZTXSZS =U/Jw -----END PGP SIGNATURE----- Merge tag 'pm+acpi-fixes-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull ACPI and power management fixes from Rafael Wysocki: "All of these commits are fixes that have emerged recently and some of them fix bugs introduced during this merge window. Specifics: 1) ACPI-based PCI hotplug (ACPIPHP) fixes related to spurious events After the recent ACPIPHP changes we've seen some interesting breakage on a system that triggers device check notifications during boot for non-existing devices. Although those notifications are really spurious, we should be able to deal with them nevertheless and that shouldn't introduce too much overhead. Four commits to make that work properly. 2) Memory hotplug and hibernation mutual exclusion rework This was maent to be a cleanup, but it happens to fix a classical ABBA deadlock between system suspend/hibernation and ACPI memory hotplug which is possible if they are started roughly at the same time. Three commits rework memory hotplug so that it doesn't acquire pm_mutex and make hibernation use device_hotplug_lock which prevents it from racing with memory hotplug. 3) ACPI Intel LPSS (Low-Power Subsystem) driver crash fix The ACPI LPSS driver crashes during boot on Apple Macbook Air with Haswell that has slightly unusual BIOS configuration in which one of the LPSS device's _CRS method doesn't return all of the information expected by the driver. Fix from Mika Westerberg, for stable. 4) ACPICA fix related to Store->ArgX operation AML interpreter fix for obscure breakage that causes AML to be executed incorrectly on some machines (observed in practice). From Bob Moore. 5) ACPI core fix for PCI ACPI device objects lookup There still are cases in which there is more than one ACPI device object matching a given PCI device and we don't choose the one that the BIOS expects us to choose, so this makes the lookup take more criteria into account in those cases. 6) Fix to prevent cpuidle from crashing in some rare cases If the result of cpuidle_get_driver() is NULL, which can happen on some systems, cpuidle_driver_ref() will crash trying to use that pointer and the Daniel Fu's fix prevents that from happening. 7) cpufreq fixes related to CPU hotplug Stephen Boyd reported a number of concurrency problems with cpufreq related to CPU hotplug which are addressed by a series of fixes from Srivatsa S Bhat and Viresh Kumar. 8) cpufreq fix for time conversion in time_in_state attribute Time conversion carried out by cpufreq when user space attempts to read /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state won't work correcty if cputime_t doesn't map directly to jiffies. Fix from Andreas Schwab. 9) Revert of a troublesome cpufreq commit Commit7c30ed5
(cpufreq: make sure frequency transitions are serialized) was intended to address some known concurrency problems in cpufreq related to the ordering of transitions, but unfortunately it introduced several problems of its own, so I decided to revert it now and address the original problems later in a more robust way. 10) Intel Haswell CPU models for intel_pstate from Nell Hardcastle. 11) cpufreq fixes related to system suspend/resume The recent cpufreq changes that made it preserve CPU sysfs attributes over suspend/resume cycles introduced a possible NULL pointer dereference that caused it to crash during the second attempt to suspend. Three commits from Srivatsa S Bhat fix that problem and a couple of related issues. 12) cpufreq locking fix cpufreq_policy_restore() should acquire the lock for reading, but it acquires it for writing. Fix from Lan Tianyu" * tag 'pm+acpi-fixes-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (25 commits) cpufreq: Acquire the lock in cpufreq_policy_restore() for reading cpufreq: Prevent problems in update_policy_cpu() if last_cpu == new_cpu cpufreq: Restructure if/else block to avoid unintended behavior cpufreq: Fix crash in cpufreq-stats during suspend/resume intel_pstate: Add Haswell CPU models Revert "cpufreq: make sure frequency transitions are serialized" cpufreq: Use signed type for 'ret' variable, to store negative error values cpufreq: Remove temporary fix for race between CPU hotplug and sysfs-writes cpufreq: Synchronize the cpufreq store_*() routines with CPU hotplug cpufreq: Invoke __cpufreq_remove_dev_finish() after releasing cpu_hotplug.lock cpufreq: Split __cpufreq_remove_dev() into two parts cpufreq: Fix wrong time unit conversion cpufreq: serialize calls to __cpufreq_governor() cpufreq: don't allow governor limits to be changed when it is disabled ACPI / bind: Prefer device objects with _STA to those without it ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks ACPI / hotplug / PCI: Use _OST to notify firmware about notify status ACPI / hotplug / PCI: Avoid doing too much for spurious notifies ACPICA: Fix for a Store->ArgX when ArgX contains a reference to a field. ACPI / hotplug / PCI: Don't trim devices before scanning the namespace ...
This commit is contained in:
commit
02b9735c12
@ -257,12 +257,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
|
||||
pdata->mmio_size = resource_size(&rentry->res);
|
||||
pdata->mmio_base = ioremap(rentry->res.start,
|
||||
pdata->mmio_size);
|
||||
pdata->dev_desc = dev_desc;
|
||||
break;
|
||||
}
|
||||
|
||||
acpi_dev_free_resource_list(&resource_list);
|
||||
|
||||
pdata->dev_desc = dev_desc;
|
||||
|
||||
if (dev_desc->clk_required) {
|
||||
ret = register_device_clock(adev, pdata);
|
||||
if (ret) {
|
||||
|
@ -57,6 +57,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *val_desc,
|
||||
union acpi_operand_object *dest_desc,
|
||||
struct acpi_walk_state *walk_state);
|
||||
|
||||
static acpi_status
|
||||
acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,
|
||||
struct acpi_namespace_node *node,
|
||||
struct acpi_walk_state *walk_state);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_store
|
||||
@ -375,7 +380,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
|
||||
* When storing into an object the data is converted to the
|
||||
* target object type then stored in the object. This means
|
||||
* that the target object type (for an initialized target) will
|
||||
* not be changed by a store operation.
|
||||
* not be changed by a store operation. A copy_object can change
|
||||
* the target type, however.
|
||||
*
|
||||
* The implicit_conversion flag is set to NO/FALSE only when
|
||||
* storing to an arg_x -- as per the rules of the ACPI spec.
|
||||
*
|
||||
* Assumes parameters are already validated.
|
||||
*
|
||||
@ -399,7 +408,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||||
target_type = acpi_ns_get_type(node);
|
||||
target_desc = acpi_ns_get_attached_object(node);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
|
||||
source_desc,
|
||||
acpi_ut_get_object_type_name(source_desc), node,
|
||||
acpi_ut_get_type_name(target_type)));
|
||||
@ -413,45 +422,30 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* If no implicit conversion, drop into the default case below */
|
||||
|
||||
if ((!implicit_conversion) ||
|
||||
((walk_state->opcode == AML_COPY_OP) &&
|
||||
(target_type != ACPI_TYPE_LOCAL_REGION_FIELD) &&
|
||||
(target_type != ACPI_TYPE_LOCAL_BANK_FIELD) &&
|
||||
(target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) {
|
||||
/*
|
||||
* Force execution of default (no implicit conversion). Note:
|
||||
* copy_object does not perform an implicit conversion, as per the ACPI
|
||||
* spec -- except in case of region/bank/index fields -- because these
|
||||
* objects must retain their original type permanently.
|
||||
*/
|
||||
target_type = ACPI_TYPE_ANY;
|
||||
}
|
||||
|
||||
/* Do the actual store operation */
|
||||
|
||||
switch (target_type) {
|
||||
case ACPI_TYPE_BUFFER_FIELD:
|
||||
case ACPI_TYPE_LOCAL_REGION_FIELD:
|
||||
case ACPI_TYPE_LOCAL_BANK_FIELD:
|
||||
case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
||||
|
||||
/* For fields, copy the source data to the target field. */
|
||||
|
||||
status = acpi_ex_write_data_to_field(source_desc, target_desc,
|
||||
&walk_state->result_obj);
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_INTEGER:
|
||||
case ACPI_TYPE_STRING:
|
||||
case ACPI_TYPE_BUFFER:
|
||||
/*
|
||||
* These target types are all of type Integer/String/Buffer, and
|
||||
* therefore support implicit conversion before the store.
|
||||
*
|
||||
* Copy and/or convert the source object to a new target object
|
||||
* The simple data types all support implicit source operand
|
||||
* conversion before the store.
|
||||
*/
|
||||
|
||||
if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) {
|
||||
/*
|
||||
* However, copy_object and Stores to arg_x do not perform
|
||||
* an implicit conversion, as per the ACPI specification.
|
||||
* A direct store is performed instead.
|
||||
*/
|
||||
status = acpi_ex_store_direct_to_node(source_desc, node,
|
||||
walk_state);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Store with implicit source operand conversion support */
|
||||
|
||||
status =
|
||||
acpi_ex_store_object_to_object(source_desc, target_desc,
|
||||
&new_desc, walk_state);
|
||||
@ -465,13 +459,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||||
* the Name's type to that of the value being stored in it.
|
||||
* source_desc reference count is incremented by attach_object.
|
||||
*
|
||||
* Note: This may change the type of the node if an explicit store
|
||||
* has been performed such that the node/object type has been
|
||||
* changed.
|
||||
* Note: This may change the type of the node if an explicit
|
||||
* store has been performed such that the node/object type
|
||||
* has been changed.
|
||||
*/
|
||||
status =
|
||||
acpi_ns_attach_object(node, new_desc,
|
||||
new_desc->common.type);
|
||||
status = acpi_ns_attach_object(node, new_desc,
|
||||
new_desc->common.type);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Store %s into %s via Convert/Attach\n",
|
||||
@ -482,38 +475,83 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER_FIELD:
|
||||
case ACPI_TYPE_LOCAL_REGION_FIELD:
|
||||
case ACPI_TYPE_LOCAL_BANK_FIELD:
|
||||
case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
||||
/*
|
||||
* For all fields, always write the source data to the target
|
||||
* field. Any required implicit source operand conversion is
|
||||
* performed in the function below as necessary. Note, field
|
||||
* objects must retain their original type permanently.
|
||||
*/
|
||||
status = acpi_ex_write_data_to_field(source_desc, target_desc,
|
||||
&walk_state->result_obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Storing [%s] (%p) directly into node [%s] (%p)"
|
||||
" with no implicit conversion\n",
|
||||
acpi_ut_get_object_type_name(source_desc),
|
||||
source_desc,
|
||||
acpi_ut_get_object_type_name(target_desc),
|
||||
node));
|
||||
|
||||
/*
|
||||
* No conversions for all other types. Directly store a copy of
|
||||
* the source object. NOTE: This is a departure from the ACPI
|
||||
* spec, which states "If conversion is impossible, abort the
|
||||
* running control method".
|
||||
* the source object. This is the ACPI spec-defined behavior for
|
||||
* the copy_object operator.
|
||||
*
|
||||
* This code implements "If conversion is impossible, treat the
|
||||
* Store operation as a CopyObject".
|
||||
* NOTE: For the Store operator, this is a departure from the
|
||||
* ACPI spec, which states "If conversion is impossible, abort
|
||||
* the running control method". Instead, this code implements
|
||||
* "If conversion is impossible, treat the Store operation as
|
||||
* a CopyObject".
|
||||
*/
|
||||
status =
|
||||
acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
|
||||
walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status =
|
||||
acpi_ns_attach_object(node, new_desc,
|
||||
new_desc->common.type);
|
||||
acpi_ut_remove_reference(new_desc);
|
||||
status = acpi_ex_store_direct_to_node(source_desc, node,
|
||||
walk_state);
|
||||
break;
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ex_store_direct_to_node
|
||||
*
|
||||
* PARAMETERS: source_desc - Value to be stored
|
||||
* node - Named object to receive the value
|
||||
* walk_state - Current walk state
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: "Store" an object directly to a node. This involves a copy
|
||||
* and an attach.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,
|
||||
struct acpi_namespace_node *node,
|
||||
struct acpi_walk_state *walk_state)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_operand_object *new_desc;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_store_direct_to_node);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Storing [%s] (%p) directly into node [%s] (%p)"
|
||||
" with no implicit conversion\n",
|
||||
acpi_ut_get_object_type_name(source_desc),
|
||||
source_desc, acpi_ut_get_type_name(node->type),
|
||||
node));
|
||||
|
||||
/* Copy the source object to a new object */
|
||||
|
||||
status =
|
||||
acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Attach the new object to the node */
|
||||
|
||||
status = acpi_ns_attach_object(node, new_desc, new_desc->common.type);
|
||||
acpi_ut_remove_reference(new_desc);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define FIND_CHILD_MIN_SCORE 1
|
||||
#define FIND_CHILD_MAX_SCORE 2
|
||||
|
||||
static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
|
||||
void *not_used, void **ret_p)
|
||||
{
|
||||
@ -92,14 +95,17 @@ static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
|
||||
static int do_find_child_checks(acpi_handle handle, bool is_bridge)
|
||||
{
|
||||
bool sta_present = true;
|
||||
unsigned long long sta;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_bus_get_status_handle(handle, &sta);
|
||||
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
|
||||
return false;
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
if (status == AE_NOT_FOUND)
|
||||
sta_present = false;
|
||||
else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
|
||||
return -ENODEV;
|
||||
|
||||
if (is_bridge) {
|
||||
void *test = NULL;
|
||||
@ -107,16 +113,17 @@ static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
|
||||
/* Check if this object has at least one child device. */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
|
||||
acpi_dev_present, NULL, NULL, &test);
|
||||
return !!test;
|
||||
if (!test)
|
||||
return -ENODEV;
|
||||
}
|
||||
return true;
|
||||
return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
|
||||
}
|
||||
|
||||
struct find_child_context {
|
||||
u64 addr;
|
||||
bool is_bridge;
|
||||
acpi_handle ret;
|
||||
bool ret_checked;
|
||||
int ret_score;
|
||||
};
|
||||
|
||||
static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
|
||||
@ -125,6 +132,7 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
|
||||
struct find_child_context *context = data;
|
||||
unsigned long long addr;
|
||||
acpi_status status;
|
||||
int score;
|
||||
|
||||
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
|
||||
if (ACPI_FAILURE(status) || addr != context->addr)
|
||||
@ -144,15 +152,20 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
|
||||
* its handle if so. Second, check the same for the object that we've
|
||||
* just found.
|
||||
*/
|
||||
if (!context->ret_checked) {
|
||||
if (acpi_extra_checks_passed(context->ret, context->is_bridge))
|
||||
if (!context->ret_score) {
|
||||
score = do_find_child_checks(context->ret, context->is_bridge);
|
||||
if (score == FIND_CHILD_MAX_SCORE)
|
||||
return AE_CTRL_TERMINATE;
|
||||
else
|
||||
context->ret_checked = true;
|
||||
context->ret_score = score;
|
||||
}
|
||||
if (acpi_extra_checks_passed(handle, context->is_bridge)) {
|
||||
score = do_find_child_checks(handle, context->is_bridge);
|
||||
if (score == FIND_CHILD_MAX_SCORE) {
|
||||
context->ret = handle;
|
||||
return AE_CTRL_TERMINATE;
|
||||
} else if (score > context->ret_score) {
|
||||
context->ret = handle;
|
||||
context->ret_score = score;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
@ -204,8 +204,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lock_device_hotplug();
|
||||
|
||||
/*
|
||||
* Carry out two passes here and ignore errors in the first pass,
|
||||
* because if the devices in question are memory blocks and
|
||||
@ -236,9 +234,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
ACPI_UINT32_MAX,
|
||||
acpi_bus_online_companions, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
unlock_device_hotplug();
|
||||
|
||||
put_device(&device->dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -249,8 +244,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
|
||||
acpi_bus_trim(device);
|
||||
|
||||
unlock_device_hotplug();
|
||||
|
||||
/* Device node has been unregistered. */
|
||||
put_device(&device->dev);
|
||||
device = NULL;
|
||||
@ -289,6 +282,7 @@ static void acpi_bus_device_eject(void *context)
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
int error;
|
||||
|
||||
lock_device_hotplug();
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
acpi_bus_get_device(handle, &device);
|
||||
@ -312,6 +306,7 @@ static void acpi_bus_device_eject(void *context)
|
||||
|
||||
out:
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
unlock_device_hotplug();
|
||||
return;
|
||||
|
||||
err_out:
|
||||
@ -326,8 +321,8 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
int error;
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
lock_device_hotplug();
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
|
||||
acpi_bus_get_device(handle, &device);
|
||||
@ -353,9 +348,9 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
|
||||
|
||||
out:
|
||||
unlock_device_hotplug();
|
||||
acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
unlock_device_hotplug();
|
||||
}
|
||||
|
||||
static void acpi_scan_bus_check(void *context)
|
||||
@ -446,6 +441,7 @@ void acpi_bus_hot_remove_device(void *context)
|
||||
acpi_handle handle = device->handle;
|
||||
int error;
|
||||
|
||||
lock_device_hotplug();
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
error = acpi_scan_hot_remove(device);
|
||||
@ -455,6 +451,7 @@ void acpi_bus_hot_remove_device(void *context)
|
||||
NULL);
|
||||
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
unlock_device_hotplug();
|
||||
kfree(context);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
|
||||
|
@ -280,13 +280,6 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
switch (state) {
|
||||
|
||||
case CPUFREQ_PRECHANGE:
|
||||
if (WARN(policy->transition_ongoing ==
|
||||
cpumask_weight(policy->cpus),
|
||||
"In middle of another frequency transition\n"))
|
||||
return;
|
||||
|
||||
policy->transition_ongoing++;
|
||||
|
||||
/* detect if the driver reported a value as "old frequency"
|
||||
* which is not equal to what the cpufreq core thinks is
|
||||
* "old frequency".
|
||||
@ -306,12 +299,6 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
break;
|
||||
|
||||
case CPUFREQ_POSTCHANGE:
|
||||
if (WARN(!policy->transition_ongoing,
|
||||
"No frequency transition in progress\n"))
|
||||
return;
|
||||
|
||||
policy->transition_ongoing--;
|
||||
|
||||
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
|
||||
pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
|
||||
(unsigned long)freqs->cpu);
|
||||
@ -437,7 +424,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
static ssize_t store_##file_name \
|
||||
(struct cpufreq_policy *policy, const char *buf, size_t count) \
|
||||
{ \
|
||||
unsigned int ret; \
|
||||
int ret; \
|
||||
struct cpufreq_policy new_policy; \
|
||||
\
|
||||
ret = cpufreq_get_policy(&new_policy, policy->cpu); \
|
||||
@ -490,7 +477,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
|
||||
static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret;
|
||||
int ret;
|
||||
char str_governor[16];
|
||||
struct cpufreq_policy new_policy;
|
||||
|
||||
@ -694,8 +681,13 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
|
||||
struct freq_attr *fattr = to_attr(attr);
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
if (!cpu_online(policy->cpu))
|
||||
goto unlock;
|
||||
|
||||
if (!down_read_trylock(&cpufreq_rwsem))
|
||||
goto exit;
|
||||
goto unlock;
|
||||
|
||||
if (lock_policy_rwsem_write(policy->cpu) < 0)
|
||||
goto up_read;
|
||||
@ -709,7 +701,9 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
|
||||
|
||||
up_read:
|
||||
up_read(&cpufreq_rwsem);
|
||||
exit:
|
||||
unlock:
|
||||
put_online_cpus();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -912,11 +906,11 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
|
||||
struct cpufreq_policy *policy;
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
|
||||
policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
|
||||
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
return policy;
|
||||
}
|
||||
@ -953,6 +947,21 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
|
||||
kfree(policy);
|
||||
}
|
||||
|
||||
static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
{
|
||||
if (cpu == policy->cpu)
|
||||
return;
|
||||
|
||||
policy->last_cpu = policy->cpu;
|
||||
policy->cpu = cpu;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_TABLE
|
||||
cpufreq_frequency_table_update_policy_cpu(policy);
|
||||
#endif
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_UPDATE_POLICY_CPU, policy);
|
||||
}
|
||||
|
||||
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
{
|
||||
@ -1006,7 +1015,18 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
if (!policy)
|
||||
goto nomem_out;
|
||||
|
||||
policy->cpu = cpu;
|
||||
|
||||
/*
|
||||
* In the resume path, since we restore a saved policy, the assignment
|
||||
* to policy->cpu is like an update of the existing policy, rather than
|
||||
* the creation of a brand new one. So we need to perform this update
|
||||
* by invoking update_policy_cpu().
|
||||
*/
|
||||
if (frozen && cpu != policy->cpu)
|
||||
update_policy_cpu(policy, cpu);
|
||||
else
|
||||
policy->cpu = cpu;
|
||||
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
cpumask_copy(policy->cpus, cpumask_of(cpu));
|
||||
|
||||
@ -1098,18 +1118,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
||||
return __cpufreq_add_dev(dev, sif, false);
|
||||
}
|
||||
|
||||
static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
{
|
||||
policy->last_cpu = policy->cpu;
|
||||
policy->cpu = cpu;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_TABLE
|
||||
cpufreq_frequency_table_update_policy_cpu(policy);
|
||||
#endif
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_UPDATE_POLICY_CPU, policy);
|
||||
}
|
||||
|
||||
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
unsigned int old_cpu, bool frozen)
|
||||
{
|
||||
@ -1141,22 +1149,14 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
return cpu_dev->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* __cpufreq_remove_dev - remove a CPU device
|
||||
*
|
||||
* Removes the cpufreq interface for a CPU device.
|
||||
* Caller should already have policy_rwsem in write mode for this CPU.
|
||||
* This routine frees the rwsem before returning.
|
||||
*/
|
||||
static int __cpufreq_remove_dev(struct device *dev,
|
||||
struct subsys_interface *sif, bool frozen)
|
||||
static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
{
|
||||
unsigned int cpu = dev->id, cpus;
|
||||
int new_cpu, ret;
|
||||
unsigned long flags;
|
||||
struct cpufreq_policy *policy;
|
||||
struct kobject *kobj;
|
||||
struct completion *cmp;
|
||||
|
||||
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
|
||||
|
||||
@ -1196,8 +1196,9 @@ static int __cpufreq_remove_dev(struct device *dev,
|
||||
cpumask_clear_cpu(cpu, policy->cpus);
|
||||
unlock_policy_rwsem_write(cpu);
|
||||
|
||||
if (cpu != policy->cpu && !frozen) {
|
||||
sysfs_remove_link(&dev->kobj, "cpufreq");
|
||||
if (cpu != policy->cpu) {
|
||||
if (!frozen)
|
||||
sysfs_remove_link(&dev->kobj, "cpufreq");
|
||||
} else if (cpus > 1) {
|
||||
|
||||
new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen);
|
||||
@ -1213,6 +1214,33 @@ static int __cpufreq_remove_dev(struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
{
|
||||
unsigned int cpu = dev->id, cpus;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct cpufreq_policy *policy;
|
||||
struct kobject *kobj;
|
||||
struct completion *cmp;
|
||||
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
if (!policy) {
|
||||
pr_debug("%s: No cpu_data found\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lock_policy_rwsem_read(cpu);
|
||||
cpus = cpumask_weight(policy->cpus);
|
||||
unlock_policy_rwsem_read(cpu);
|
||||
|
||||
/* If cpu is last user of policy, free policy */
|
||||
if (cpus == 1) {
|
||||
if (cpufreq_driver->target) {
|
||||
@ -1272,6 +1300,27 @@ static int __cpufreq_remove_dev(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __cpufreq_remove_dev - remove a CPU device
|
||||
*
|
||||
* Removes the cpufreq interface for a CPU device.
|
||||
* Caller should already have policy_rwsem in write mode for this CPU.
|
||||
* This routine frees the rwsem before returning.
|
||||
*/
|
||||
static inline int __cpufreq_remove_dev(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __cpufreq_remove_dev_prepare(dev, sif, frozen);
|
||||
|
||||
if (!ret)
|
||||
ret = __cpufreq_remove_dev_finish(dev, sif, frozen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int cpu = dev->id;
|
||||
@ -1610,8 +1659,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
|
||||
if (cpufreq_disabled())
|
||||
return -ENODEV;
|
||||
if (policy->transition_ongoing)
|
||||
return -EBUSY;
|
||||
|
||||
/* Make sure that target_freq is within supported range */
|
||||
if (target_freq > policy->max)
|
||||
@ -1692,8 +1739,9 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
||||
policy->cpu, event);
|
||||
|
||||
mutex_lock(&cpufreq_governor_lock);
|
||||
if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
|
||||
(policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
|
||||
if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
|
||||
|| (!policy->governor_enabled
|
||||
&& (event == CPUFREQ_GOV_LIMITS || event == CPUFREQ_GOV_STOP))) {
|
||||
mutex_unlock(&cpufreq_governor_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -1994,7 +2042,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
|
||||
break;
|
||||
|
||||
case CPU_DOWN_PREPARE:
|
||||
__cpufreq_remove_dev(dev, NULL, frozen);
|
||||
__cpufreq_remove_dev_prepare(dev, NULL, frozen);
|
||||
break;
|
||||
|
||||
case CPU_POST_DEAD:
|
||||
__cpufreq_remove_dev_finish(dev, NULL, frozen);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_FAILED:
|
||||
|
@ -74,7 +74,7 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
||||
for (i = 0; i < stat->state_num; i++) {
|
||||
len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
|
||||
(unsigned long long)
|
||||
cputime64_to_clock_t(stat->time_in_state[i]));
|
||||
jiffies_64_to_clock_t(stat->time_in_state[i]));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
@ -522,6 +522,11 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
|
||||
ICPU(0x2a, default_policy),
|
||||
ICPU(0x2d, default_policy),
|
||||
ICPU(0x3a, default_policy),
|
||||
ICPU(0x3c, default_policy),
|
||||
ICPU(0x3e, default_policy),
|
||||
ICPU(0x3f, default_policy),
|
||||
ICPU(0x45, default_policy),
|
||||
ICPU(0x46, default_policy),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
|
||||
|
@ -331,7 +331,8 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
|
||||
spin_lock(&cpuidle_driver_lock);
|
||||
|
||||
drv = cpuidle_get_driver();
|
||||
drv->refcnt++;
|
||||
if (drv)
|
||||
drv->refcnt++;
|
||||
|
||||
spin_unlock(&cpuidle_driver_lock);
|
||||
return drv;
|
||||
|
@ -487,7 +487,6 @@ static void acpiphp_bus_add(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *adev = NULL;
|
||||
|
||||
acpiphp_bus_trim(handle);
|
||||
acpi_bus_scan(handle);
|
||||
acpi_bus_get_device(handle, &adev);
|
||||
if (adev)
|
||||
@ -529,6 +528,16 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
|
||||
{
|
||||
struct acpiphp_func *func;
|
||||
|
||||
list_for_each_entry(func, &slot->funcs, sibling)
|
||||
acpiphp_bus_add(func_to_handle(func));
|
||||
|
||||
return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* enable_slot - enable, configure a slot
|
||||
* @slot: slot to be enabled
|
||||
@ -543,12 +552,9 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
|
||||
struct acpiphp_func *func;
|
||||
int max, pass;
|
||||
LIST_HEAD(add_list);
|
||||
int nr_found;
|
||||
|
||||
list_for_each_entry(func, &slot->funcs, sibling)
|
||||
acpiphp_bus_add(func_to_handle(func));
|
||||
|
||||
pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
|
||||
|
||||
nr_found = acpiphp_rescan_slot(slot);
|
||||
max = acpiphp_max_busnr(bus);
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
@ -567,8 +573,11 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__pci_bus_assign_resources(bus, &add_list, NULL);
|
||||
/* Nothing more to do here if there are no new devices on this bus. */
|
||||
if (!nr_found && (slot->flags & SLOT_ENABLED))
|
||||
return;
|
||||
|
||||
acpiphp_sanitize_bus(bus);
|
||||
acpiphp_set_hpp_values(bus);
|
||||
acpiphp_set_acpi_region(slot);
|
||||
@ -837,11 +846,22 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
/* device check */
|
||||
dbg("%s: Device check notify on %s\n", __func__, objname);
|
||||
if (bridge)
|
||||
if (bridge) {
|
||||
acpiphp_check_bridge(bridge);
|
||||
else
|
||||
acpiphp_check_bridge(func->parent);
|
||||
} else {
|
||||
struct acpiphp_slot *slot = func->slot;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Check if anything has changed in the slot and rescan
|
||||
* from the parent if that's the case.
|
||||
*/
|
||||
mutex_lock(&slot->crit_sect);
|
||||
ret = acpiphp_rescan_slot(slot);
|
||||
mutex_unlock(&slot->crit_sect);
|
||||
if (ret)
|
||||
acpiphp_check_bridge(func->parent);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
@ -867,6 +887,8 @@ static void hotplug_event_work(struct work_struct *work)
|
||||
hotplug_event(hp_work->handle, hp_work->type, context);
|
||||
|
||||
acpi_scan_lock_release();
|
||||
acpi_evaluate_hotplug_ost(hp_work->handle, hp_work->type,
|
||||
ACPI_OST_SC_SUCCESS, NULL);
|
||||
kfree(hp_work); /* allocated in handle_hotplug_event() */
|
||||
put_bridge(context->func.parent);
|
||||
}
|
||||
@ -882,11 +904,15 @@ static void hotplug_event_work(struct work_struct *work)
|
||||
static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
struct acpiphp_context *context;
|
||||
u32 ost_code = ACPI_OST_SC_SUCCESS;
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
|
||||
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_DEVICE_WAKE:
|
||||
@ -895,20 +921,21 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
|
||||
acpi_handle_err(handle, "Device cannot be configured due "
|
||||
"to a frequency mismatch\n");
|
||||
return;
|
||||
goto out;
|
||||
|
||||
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
|
||||
acpi_handle_err(handle, "Device cannot be configured due "
|
||||
"to a bus mode mismatch\n");
|
||||
return;
|
||||
goto out;
|
||||
|
||||
case ACPI_NOTIFY_POWER_FAULT:
|
||||
acpi_handle_err(handle, "Device has suffered a power fault\n");
|
||||
return;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
|
||||
return;
|
||||
ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&acpiphp_context_lock);
|
||||
@ -917,8 +944,14 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
get_bridge(context->func.parent);
|
||||
acpiphp_put_context(context);
|
||||
alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
|
||||
mutex_unlock(&acpiphp_context_lock);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&acpiphp_context_lock);
|
||||
ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
|
||||
out:
|
||||
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -85,7 +85,6 @@ struct cpufreq_policy {
|
||||
struct list_head policy_list;
|
||||
struct kobject kobj;
|
||||
struct completion kobj_unregister;
|
||||
int transition_ongoing; /* Tracks transition status */
|
||||
};
|
||||
|
||||
/* Only for ACPI */
|
||||
|
@ -644,22 +644,23 @@ int hibernate(void)
|
||||
if (error)
|
||||
goto Exit;
|
||||
|
||||
/* Allocate memory management structures */
|
||||
error = create_basic_memory_bitmaps();
|
||||
if (error)
|
||||
goto Exit;
|
||||
|
||||
printk(KERN_INFO "PM: Syncing filesystems ... ");
|
||||
sys_sync();
|
||||
printk("done.\n");
|
||||
|
||||
error = freeze_processes();
|
||||
if (error)
|
||||
goto Free_bitmaps;
|
||||
goto Exit;
|
||||
|
||||
lock_device_hotplug();
|
||||
/* Allocate memory management structures */
|
||||
error = create_basic_memory_bitmaps();
|
||||
if (error)
|
||||
goto Thaw;
|
||||
|
||||
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
|
||||
if (error || freezer_test_done)
|
||||
goto Thaw;
|
||||
goto Free_bitmaps;
|
||||
|
||||
if (in_suspend) {
|
||||
unsigned int flags = 0;
|
||||
@ -682,14 +683,14 @@ int hibernate(void)
|
||||
pr_debug("PM: Image restored successfully.\n");
|
||||
}
|
||||
|
||||
Free_bitmaps:
|
||||
free_basic_memory_bitmaps();
|
||||
Thaw:
|
||||
unlock_device_hotplug();
|
||||
thaw_processes();
|
||||
|
||||
/* Don't bother checking whether freezer_test_done is true */
|
||||
freezer_test_done = false;
|
||||
|
||||
Free_bitmaps:
|
||||
free_basic_memory_bitmaps();
|
||||
Exit:
|
||||
pm_notifier_call_chain(PM_POST_HIBERNATION);
|
||||
pm_restore_console();
|
||||
@ -806,21 +807,20 @@ static int software_resume(void)
|
||||
pm_prepare_console();
|
||||
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
|
||||
if (error)
|
||||
goto close_finish;
|
||||
|
||||
error = create_basic_memory_bitmaps();
|
||||
if (error)
|
||||
goto close_finish;
|
||||
goto Close_Finish;
|
||||
|
||||
pr_debug("PM: Preparing processes for restore.\n");
|
||||
error = freeze_processes();
|
||||
if (error) {
|
||||
swsusp_close(FMODE_READ);
|
||||
goto Done;
|
||||
}
|
||||
if (error)
|
||||
goto Close_Finish;
|
||||
|
||||
pr_debug("PM: Loading hibernation image.\n");
|
||||
|
||||
lock_device_hotplug();
|
||||
error = create_basic_memory_bitmaps();
|
||||
if (error)
|
||||
goto Thaw;
|
||||
|
||||
error = swsusp_read(&flags);
|
||||
swsusp_close(FMODE_READ);
|
||||
if (!error)
|
||||
@ -828,9 +828,10 @@ static int software_resume(void)
|
||||
|
||||
printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
|
||||
swsusp_free();
|
||||
thaw_processes();
|
||||
Done:
|
||||
free_basic_memory_bitmaps();
|
||||
Thaw:
|
||||
unlock_device_hotplug();
|
||||
thaw_processes();
|
||||
Finish:
|
||||
pm_notifier_call_chain(PM_POST_RESTORE);
|
||||
pm_restore_console();
|
||||
@ -840,7 +841,7 @@ static int software_resume(void)
|
||||
mutex_unlock(&pm_mutex);
|
||||
pr_debug("PM: Hibernation image not present or could not be loaded.\n");
|
||||
return error;
|
||||
close_finish:
|
||||
Close_Finish:
|
||||
swsusp_close(FMODE_READ);
|
||||
goto Finish;
|
||||
}
|
||||
|
@ -60,11 +60,6 @@ static int snapshot_open(struct inode *inode, struct file *filp)
|
||||
error = -ENOSYS;
|
||||
goto Unlock;
|
||||
}
|
||||
if(create_basic_memory_bitmaps()) {
|
||||
atomic_inc(&snapshot_device_available);
|
||||
error = -ENOMEM;
|
||||
goto Unlock;
|
||||
}
|
||||
nonseekable_open(inode, filp);
|
||||
data = &snapshot_state;
|
||||
filp->private_data = data;
|
||||
@ -90,10 +85,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
|
||||
if (error)
|
||||
pm_notifier_call_chain(PM_POST_RESTORE);
|
||||
}
|
||||
if (error) {
|
||||
free_basic_memory_bitmaps();
|
||||
if (error)
|
||||
atomic_inc(&snapshot_device_available);
|
||||
}
|
||||
|
||||
data->frozen = 0;
|
||||
data->ready = 0;
|
||||
data->platform_support = 0;
|
||||
@ -111,11 +105,11 @@ static int snapshot_release(struct inode *inode, struct file *filp)
|
||||
lock_system_sleep();
|
||||
|
||||
swsusp_free();
|
||||
free_basic_memory_bitmaps();
|
||||
data = filp->private_data;
|
||||
free_all_swap_pages(data->swap);
|
||||
if (data->frozen) {
|
||||
pm_restore_gfp_mask();
|
||||
free_basic_memory_bitmaps();
|
||||
thaw_processes();
|
||||
}
|
||||
pm_notifier_call_chain(data->mode == O_RDONLY ?
|
||||
@ -207,6 +201,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||
if (!mutex_trylock(&pm_mutex))
|
||||
return -EBUSY;
|
||||
|
||||
lock_device_hotplug();
|
||||
data = filp->private_data;
|
||||
|
||||
switch (cmd) {
|
||||
@ -220,14 +215,22 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||
printk("done.\n");
|
||||
|
||||
error = freeze_processes();
|
||||
if (!error)
|
||||
if (error)
|
||||
break;
|
||||
|
||||
error = create_basic_memory_bitmaps();
|
||||
if (error)
|
||||
thaw_processes();
|
||||
else
|
||||
data->frozen = 1;
|
||||
|
||||
break;
|
||||
|
||||
case SNAPSHOT_UNFREEZE:
|
||||
if (!data->frozen || data->ready)
|
||||
break;
|
||||
pm_restore_gfp_mask();
|
||||
free_basic_memory_bitmaps();
|
||||
thaw_processes();
|
||||
data->frozen = 0;
|
||||
break;
|
||||
@ -371,6 +374,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
|
||||
|
||||
}
|
||||
|
||||
unlock_device_hotplug();
|
||||
mutex_unlock(&pm_mutex);
|
||||
|
||||
return error;
|
||||
|
@ -52,14 +52,10 @@ DEFINE_MUTEX(mem_hotplug_mutex);
|
||||
void lock_memory_hotplug(void)
|
||||
{
|
||||
mutex_lock(&mem_hotplug_mutex);
|
||||
|
||||
/* for exclusive hibernation if CONFIG_HIBERNATION=y */
|
||||
lock_system_sleep();
|
||||
}
|
||||
|
||||
void unlock_memory_hotplug(void)
|
||||
{
|
||||
unlock_system_sleep();
|
||||
mutex_unlock(&mem_hotplug_mutex);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user