From d783156ea38431b20af0d4f910a6f9f9054d33b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:52:12 +0100 Subject: ACPI / scan: Define non-empty device removal handler If an ACPI namespace node is removed (usually, as a result of a table unload), and there is a data object attached to that node, acpi_ns_delete_node() executes the removal handler submitted to acpi_attach_data() for that object. That handler is currently empty for struct acpi_device objects, so it is necessary to detach those objects from the corresponding ACPI namespace nodes in advance every time a table unload may happen. That is cumbersome and inefficient and leads to some design constraints that turn out to be quite inconvenient (in particular, struct acpi_device objects cannot be registered for namespace nodes representing devices that are not reported as present or functional by _STA). For this reason, introduce a non-empty removal handler for ACPI device objects that will unregister them when their ACPI namespace nodes go away. This code modification alone should not change functionality except for the ordering of the ACPI hotplug workqueue which should not matter (without subsequent code changes). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/internal.h | 2 + drivers/acpi/osl.c | 6 ++- drivers/acpi/scan.c | 114 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 101 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a29739c0ba79..d8606498bf6f 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -73,6 +73,8 @@ void acpi_lpss_init(void); static inline void acpi_lpss_init(void) {} #endif +bool acpi_queue_hotplug_work(struct work_struct *work); + /* -------------------------------------------------------------------------- Device Node Initialization / Removal -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 54a20ff4b864..5b9a785e2155 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1215,6 +1215,10 @@ acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src) return AE_OK; } +bool acpi_queue_hotplug_work(struct work_struct *work) +{ + return queue_work(kacpi_hotplug_wq, work); +} acpi_status acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) @@ -1794,7 +1798,7 @@ acpi_status __init acpi_os_initialize1(void) { kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); - kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1); + kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); BUG_ON(!kacpid_wq); BUG_ON(!kacpi_notify_wq); BUG_ON(!kacpi_hotplug_wq); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fd39459926b1..ad2522015e5e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -14,6 +14,8 @@ #include +#include + #include "internal.h" #define _COMPONENT ACPI_BUS_COMPONENT @@ -27,6 +29,8 @@ extern struct acpi_device *acpi_root; #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) +#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) + /* * If set, devices will be hot-removed even if they cannot be put offline * gracefully (from the kernel's standpoint). @@ -907,9 +911,91 @@ struct bus_type acpi_bus_type = { .uevent = acpi_device_uevent, }; -static void acpi_bus_data_handler(acpi_handle handle, void *context) +static void acpi_device_del(struct acpi_device *device) +{ + mutex_lock(&acpi_device_lock); + if (device->parent) + list_del(&device->node); + + list_del(&device->wakeup_list); + mutex_unlock(&acpi_device_lock); + + acpi_power_add_remove_device(device, false); + acpi_device_remove_files(device); + if (device->remove) + device->remove(device); + + device_del(&device->dev); +} + +static LIST_HEAD(acpi_device_del_list); +static DEFINE_MUTEX(acpi_device_del_lock); + +static void acpi_device_del_work_fn(struct work_struct *work_not_used) +{ + for (;;) { + struct acpi_device *adev; + + mutex_lock(&acpi_device_del_lock); + + if (list_empty(&acpi_device_del_list)) { + mutex_unlock(&acpi_device_del_lock); + break; + } + adev = list_first_entry(&acpi_device_del_list, + struct acpi_device, del_list); + list_del(&adev->del_list); + + mutex_unlock(&acpi_device_del_lock); + + acpi_device_del(adev); + /* + * Drop references to all power resources that might have been + * used by the device. + */ + acpi_power_transition(adev, ACPI_STATE_D3_COLD); + put_device(&adev->dev); + } +} + +/** + * acpi_scan_drop_device - Drop an ACPI device object. + * @handle: Handle of an ACPI namespace node, not used. + * @context: Address of the ACPI device object to drop. + * + * This is invoked by acpi_ns_delete_node() during the removal of the ACPI + * namespace node the device object pointed to by @context is attached to. + * + * The unregistration is carried out asynchronously to avoid running + * acpi_device_del() under the ACPICA's namespace mutex and the list is used to + * ensure the correct ordering (the device objects must be unregistered in the + * same order in which the corresponding namespace nodes are deleted). + */ +static void acpi_scan_drop_device(acpi_handle handle, void *context) { - /* Intentionally empty. */ + static DECLARE_WORK(work, acpi_device_del_work_fn); + struct acpi_device *adev = context; + + mutex_lock(&acpi_device_del_lock); + + /* + * Use the ACPI hotplug workqueue which is ordered, so this work item + * won't run after any hotplug work items submitted subsequently. That + * prevents attempts to register device objects identical to those being + * deleted from happening concurrently (such attempts result from + * hotplug events handled via the ACPI hotplug workqueue). It also will + * run after all of the work items submitted previosuly, which helps + * those work items to ensure that they are not accessing stale device + * objects. + */ + if (list_empty(&acpi_device_del_list)) + acpi_queue_hotplug_work(&work); + + list_add_tail(&adev->del_list, &acpi_device_del_list); + /* Make acpi_ns_validate_handle() return NULL for this handle. */ + adev->handle = INVALID_ACPI_HANDLE; + + mutex_unlock(&acpi_device_del_lock); } int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) @@ -919,7 +1005,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) if (!device) return -EINVAL; - status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); + status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device); if (ACPI_FAILURE(status) || !*device) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", handle)); @@ -939,7 +1025,7 @@ int acpi_device_add(struct acpi_device *device, if (device->handle) { acpi_status status; - status = acpi_attach_data(device->handle, acpi_bus_data_handler, + status = acpi_attach_data(device->handle, acpi_scan_drop_device, device); if (ACPI_FAILURE(status)) { acpi_handle_err(device->handle, @@ -957,6 +1043,7 @@ int acpi_device_add(struct acpi_device *device, INIT_LIST_HEAD(&device->node); INIT_LIST_HEAD(&device->wakeup_list); INIT_LIST_HEAD(&device->physical_node_list); + INIT_LIST_HEAD(&device->del_list); mutex_init(&device->physical_node_lock); new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); @@ -1020,27 +1107,14 @@ int acpi_device_add(struct acpi_device *device, mutex_unlock(&acpi_device_lock); err_detach: - acpi_detach_data(device->handle, acpi_bus_data_handler); + acpi_detach_data(device->handle, acpi_scan_drop_device); return result; } static void acpi_device_unregister(struct acpi_device *device) { - mutex_lock(&acpi_device_lock); - if (device->parent) - list_del(&device->node); - - list_del(&device->wakeup_list); - mutex_unlock(&acpi_device_lock); - - acpi_detach_data(device->handle, acpi_bus_data_handler); - - acpi_power_add_remove_device(device, false); - acpi_device_remove_files(device); - if (device->remove) - device->remove(device); - - device_del(&device->dev); + acpi_detach_data(device->handle, acpi_scan_drop_device); + acpi_device_del(device); /* * Transition the device to D3cold to drop the reference counts of all * power resources the device depends on and turn off the ones that have -- cgit v1.2.3 From 202317a573b20d77a9abb7c16a3fd5b40cef3d9d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:54:37 +0100 Subject: ACPI / scan: Add acpi_device objects for all device nodes in the namespace Modify the ACPI namespace scanning code to register a struct acpi_device object for every namespace node representing a device, processor and so on, even if the device represented by that namespace node is reported to be not present and not functional by _STA. There are multiple reasons to do that. First of all, it avoids quite a lot of overhead when struct acpi_device objects are deleted every time acpi_bus_trim() is run and then added again by a subsequent acpi_bus_scan() for the same scope, although the namespace objects they correspond to stay in memory all the time (which always is the case on a vast majority of systems). Second, it will allow user space to see that there are namespace nodes representing devices that are not present at the moment and may be added to the system. It will also allow user space to evaluate _SUN for those nodes to check what physical slots the "missing" devices may be put into and it will make sense to add a sysfs attribute for _STA evaluation after this change (that will be useful for thermal management on some systems). Next, it will help to consolidate the ACPI hotplug handling among subsystems by making it possible to store hotplug-related information in struct acpi_device objects in a standard common way. Finally, it will help to avoid a race condition related to the deletion of ACPI namespace nodes. Namely, namespace nodes may be deleted as a result of a table unload triggered by _EJ0 or _DCK. If a hotplug notification for one of those nodes is triggered right before the deletion and it executes a hotplug callback via acpi_hotplug_execute(), the ACPI handle passed to that callback may be stale when the callback actually runs. One way to work around that is to always pass struct acpi_device pointers to hotplug callbacks after doing a get_device() on the objects in question which eliminates the use-after-free possibility (the ACPI handles in those objects are invalidated by acpi_scan_drop_device(), so they will trigger ACPICA errors on attempts to use them). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- Documentation/acpi/namespace.txt | 9 +--- drivers/acpi/device_pm.c | 22 ++++++-- drivers/acpi/dock.c | 9 ++-- drivers/acpi/internal.h | 3 ++ drivers/acpi/pci_root.c | 5 +- drivers/acpi/scan.c | 107 ++++++++++++++++++------------------- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/xen/xen-acpi-cpuhotplug.c | 8 +-- drivers/xen/xen-acpi-memhotplug.c | 7 +-- include/acpi/acpi_bus.h | 9 +++- 10 files changed, 97 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/Documentation/acpi/namespace.txt b/Documentation/acpi/namespace.txt index 260f6a3661fa..1860cb3865c6 100644 --- a/Documentation/acpi/namespace.txt +++ b/Documentation/acpi/namespace.txt @@ -235,10 +235,6 @@ Wysocki . named object's type in the second column). In that case the object's directory in sysfs will contain the 'path' attribute whose value is the full path to the node from the namespace root. - struct acpi_device objects are created for the ACPI namespace nodes - whose _STA control methods return PRESENT or FUNCTIONING. The power - resource nodes or nodes without _STA are assumed to be both PRESENT - and FUNCTIONING. F: The struct acpi_device object is created for a fixed hardware feature (as indicated by the fixed feature flag's name in the second @@ -340,7 +336,7 @@ Wysocki . | +-------------+-------+----------------+ | | | | +- - - - - - - +- - - - - - +- - - - - - - -+ - | +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: | + | +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: | | | +- - - - - - - +- - - - - - +- - - - - - - -+ | | | | +------------+------------+-----------------------+ @@ -390,6 +386,3 @@ Wysocki . attribute (as described earlier in this document). NOTE: N/A indicates the device object does not have the 'path' or the 'modalias' attribute. - NOTE: The PNP0C0D device listed above is highlighted (marked by "*") - to indicate it will be created only when its _STA methods return - PRESENT or FUNCTIONING. diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index b3480cf7db1a..d49f1e464703 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; + if (!acpi_device_is_present(device)) + return 0; result = acpi_device_get_power(device, &state); if (result) @@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device) return ret; } -int acpi_bus_update_power(acpi_handle handle, int *state_p) +int acpi_device_update_power(struct acpi_device *device, int *state_p) { - struct acpi_device *device; int state; int result; - result = acpi_bus_get_device(handle, &device); - if (result) + if (device->power.state == ACPI_STATE_UNKNOWN) { + result = acpi_bus_init_power(device); + if (!result && state_p) + *state_p = device->power.state; + return result; + } result = acpi_device_get_power(device, &state); if (result) @@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) return 0; } + +int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + return result ? result : acpi_device_update_power(device, state_p); +} EXPORT_SYMBOL_GPL(acpi_bus_update_power); bool acpi_bus_power_manageable(acpi_handle handle) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dcd73ccb514c..de032010da3c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -323,14 +323,11 @@ static int dock_present(struct dock_station *ds) */ static void dock_create_acpi_device(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; int ret; - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { ret = acpi_bus_scan(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index d8606498bf6f..809b8082c134 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -90,6 +90,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, acpi_handle handle); int acpi_unbind_one(struct device *dev); void acpi_bus_device_eject(void *data, u32 ost_src); +bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- Power Resource @@ -107,6 +108,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +int acpi_device_update_power(struct acpi_device *device, int *state_p); + int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 20360e480bd8..4076491c6ded 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -634,9 +634,10 @@ void __init acpi_pci_root_init(void) static void handle_root_bridge_insertion(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; - if (!acpi_bus_get_device(handle, &device)) { + acpi_bus_get_device(handle, &device); + if (acpi_device_enumerated(device)) { dev_printk(KERN_DEBUG, &device->dev, "acpi device already exists; ignoring notify\n"); return; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ad2522015e5e..bc52192785f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -259,7 +259,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_bus_trim(device); - /* Device node has been unregistered. */ put_device(&device->dev); device = NULL; @@ -328,7 +327,7 @@ void acpi_bus_device_eject(void *data, u32 ost_src) static void acpi_scan_bus_device_check(void *data, u32 ost_source) { acpi_handle handle = data; - struct acpi_device *device = NULL; + struct acpi_device *device; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error; @@ -336,8 +335,9 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) mutex_lock(&acpi_scan_lock); if (ost_source != ACPI_NOTIFY_BUS_CHECK) { + device = NULL; acpi_bus_get_device(handle, &device); - if (device) { + if (acpi_device_enumerated(device)) { dev_warn(&device->dev, "Attempt to re-insert\n"); goto out; } @@ -347,9 +347,10 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) acpi_handle_warn(handle, "Namespace scan failure\n"); goto out; } - error = acpi_bus_get_device(handle, &device); - if (error) { - acpi_handle_warn(handle, "Missing device node object\n"); + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { + acpi_handle_warn(handle, "Device not enumerated\n"); goto out; } ost_code = ACPI_OST_SC_SUCCESS; @@ -1111,20 +1112,6 @@ int acpi_device_add(struct acpi_device *device, return result; } -static void acpi_device_unregister(struct acpi_device *device) -{ - acpi_detach_data(device->handle, acpi_scan_drop_device); - acpi_device_del(device); - /* - * Transition the device to D3cold to drop the reference counts of all - * power resources the device depends on and turn off the ones that have - * no more references. - */ - acpi_device_set_power(device, ACPI_STATE_D3_COLD); - device->handle = NULL; - put_device(&device->dev); -} - /* -------------------------------------------------------------------------- Driver Management -------------------------------------------------------------------------- */ @@ -1703,6 +1690,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, acpi_set_pnp_ids(handle, &device->pnp, type); acpi_bus_get_flags(device); device->flags.match_driver = false; + device->flags.initialized = true; + device->flags.visited = false; device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); } @@ -1787,6 +1776,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } +bool acpi_device_is_present(struct acpi_device *adev) +{ + if (adev->status.present || adev->status.functional) + return true; + + adev->flags.initialized = false; + return false; +} + static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, char *idstr, const struct acpi_device_id **matchid) @@ -1880,18 +1878,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, acpi_scan_init_hotplug(handle, type); - if (!(sta & ACPI_STA_DEVICE_PRESENT) && - !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { - struct acpi_device_wakeup wakeup; - - if (acpi_has_method(handle, "_PRW")) { - acpi_bus_extract_wakeup_device_power_package(handle, - &wakeup); - acpi_power_resources_list_free(&wakeup.resources); - } - return AE_CTRL_DEPTH; - } - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; @@ -1930,32 +1916,50 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, void *not_used, void **ret_not_used) { struct acpi_device *device; - unsigned long long sta_not_used; + unsigned long long sta; int ret; /* * Ignore errors ignored by acpi_bus_check_add() to avoid terminating * namespace walks prematurely. */ - if (acpi_bus_type_and_status(handle, &ret, &sta_not_used)) + if (acpi_bus_type_and_status(handle, &ret, &sta)) return AE_OK; if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; + STRUCT_TO_INT(device->status) = sta; + /* Skip devices that are not present. */ + if (!acpi_device_is_present(device)) + goto err; + if (device->handler) return AE_OK; + if (!device->flags.initialized) { + acpi_bus_update_power(device, NULL); + device->flags.initialized = true; + } ret = acpi_scan_attach_handler(device); if (ret < 0) - return AE_CTRL_DEPTH; + goto err; device->flags.match_driver = true; if (ret > 0) - return AE_OK; + goto ok; ret = device_attach(&device->dev); - return ret >= 0 ? AE_OK : AE_CTRL_DEPTH; + if (ret < 0) + goto err; + + ok: + device->flags.visited = true; + return AE_OK; + + err: + device->flags.visited = false; + return AE_CTRL_DEPTH; } /** @@ -2007,21 +2011,17 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used, } else { device_release_driver(&device->dev); } + /* + * Most likely, the device is going away, so put it into D3cold + * before that. + */ + acpi_device_set_power(device, ACPI_STATE_D3_COLD); + device->flags.initialized = false; + device->flags.visited = false; } return AE_OK; } -static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device = NULL; - - if (!acpi_bus_get_device(handle, &device)) - acpi_device_unregister(device); - - return AE_OK; -} - /** * acpi_bus_trim - Remove ACPI device node and all of its descendants * @start: Root of the ACPI device nodes subtree to remove. @@ -2037,13 +2037,6 @@ void acpi_bus_trim(struct acpi_device *start) acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, acpi_bus_device_detach, NULL, NULL); acpi_bus_device_detach(start->handle, 0, NULL, NULL); - /* - * Execute acpi_bus_remove() as a post-order callback to remove device - * nodes in the given namespace scope. - */ - acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, - acpi_bus_remove, NULL, NULL); - acpi_bus_remove(start->handle, 0, NULL, NULL); } EXPORT_SYMBOL_GPL(acpi_bus_trim); @@ -2121,7 +2114,9 @@ int __init acpi_scan_init(void) result = acpi_bus_scan_fixed(); if (result) { - acpi_device_unregister(acpi_root); + acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); + acpi_device_del(acpi_root); + put_device(&acpi_root->dev); goto out; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 1cf605f67673..67be6bab7535 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -489,7 +489,7 @@ static void acpiphp_bus_add(acpi_handle handle) acpi_bus_scan(handle); acpi_bus_get_device(handle, &adev); - if (adev) + if (acpi_device_enumerated(adev)) acpi_device_set_power(adev, ACPI_STATE_D0); } diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c index 8dae6c13063a..73496c3d18ae 100644 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ b/drivers/xen/xen-acpi-cpuhotplug.c @@ -269,7 +269,8 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, if (!is_processor_present(handle)) break; - if (!acpi_bus_get_device(handle, &device)) + acpi_bus_get_device(handle, &device); + if (acpi_device_enumerated(device)) break; result = acpi_bus_scan(handle); @@ -277,8 +278,9 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, pr_err(PREFIX "Unable to add the device\n"); break; } - result = acpi_bus_get_device(handle, &device); - if (result) { + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { pr_err(PREFIX "Missing device object\n"); break; } diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index 9083f1e474f8..9b056f06691f 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -169,7 +169,7 @@ static int acpi_memory_get_device(acpi_handle handle, acpi_scan_lock_acquire(); acpi_bus_get_device(handle, &device); - if (device) + if (acpi_device_enumerated(device)) goto end; /* @@ -182,8 +182,9 @@ static int acpi_memory_get_device(acpi_handle handle, result = -EINVAL; goto out; } - result = acpi_bus_get_device(handle, &device); - if (result) { + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { pr_warn(PREFIX "Missing device object\n"); result = -EINVAL; goto out; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 9fe5f63155ed..e748dbfca9d5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -169,7 +169,9 @@ struct acpi_device_flags { u32 ejectable:1; u32 power_manageable:1; u32 match_driver:1; - u32 reserved:27; + u32 initialized:1; + u32 visited:1; + u32 reserved:25; }; /* File System */ @@ -386,6 +388,11 @@ int acpi_match_device_ids(struct acpi_device *device, int acpi_create_dir(struct acpi_device *); void acpi_remove_dir(struct acpi_device *); +static inline bool acpi_device_enumerated(struct acpi_device *adev) +{ + return adev && adev->flags.initialized && adev->flags.visited; +} + typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -- cgit v1.2.3 From 1ceaba05b4afb4bd7b4b4801f2718c13f59321eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:54:52 +0100 Subject: ACPI / hotplug: Do not fail bus and device checks for disabled hotplug If the scan handler for the given device has hotplug.enabled unset, it doesn't really make sense to fail bus check and device check notifications. First, bus check may not have anything to do with the device it is signaled for, but it may concern another device on the bus below this one. For this reason, bus check notifications should not be failed if hotplug is disabled for the target device. Second, device check notifications are signaled only after a device has already appeared (or disappeared), so failing it can only prevent scan handlers and drivers from attaching to that (already existing) device, which is not very useful. Consequently, if device hotplug is disabled through the device's scan handler, fail eject request notifications only. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index bc52192785f1..4fa416f94f52 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -363,43 +363,13 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) unlock_device_hotplug(); } -static void acpi_hotplug_unsupported(acpi_handle handle, u32 type) -{ - u32 ost_status; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - acpi_handle_debug(handle, - "ACPI_NOTIFY_BUS_CHECK event: unsupported\n"); - ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED; - break; - case ACPI_NOTIFY_DEVICE_CHECK: - acpi_handle_debug(handle, - "ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n"); - ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED; - break; - case ACPI_NOTIFY_EJECT_REQUEST: - acpi_handle_debug(handle, - "ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n"); - ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - break; - default: - /* non-hotplug event; possibly handled by other handler */ - return; - } - - acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL); -} - static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_scan_handler *handler = data; struct acpi_device *adev; acpi_status status; - if (!handler->hotplug.enabled) - return acpi_hotplug_unsupported(handle, type); - switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); @@ -409,6 +379,11 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); + if (!handler->hotplug.enabled) { + acpi_handle_err(handle, "Eject disabled\n"); + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + goto err_out; + } if (acpi_bus_get_device(handle, &adev)) goto err_out; @@ -428,8 +403,7 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) return; err_out: - acpi_evaluate_hotplug_ost(handle, type, - ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); + acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } static ssize_t real_power_state_show(struct device *dev, -- cgit v1.2.3 From c27b2c33b6215eeb3d5c290ac889ab6d543f6207 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:07 +0100 Subject: ACPI / hotplug: Introduce common hotplug function acpi_device_hotplug() Modify the common ACPI device hotplug code to always queue up the same function, acpi_device_hotplug(), using acpi_hotplug_execute() and make the PCI host bridge hotplug code use that function too for device hot removal. This allows some code duplication to be reduced and a race condition where the relevant ACPI handle may become invalid between the notification handler and the function queued up by it via acpi_hotplug_execute() to be avoided. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/internal.h | 2 +- drivers/acpi/pci_root.c | 4 +- drivers/acpi/scan.c | 141 ++++++++++++++++++++++-------------------------- 3 files changed, 68 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 809b8082c134..a0d42cf5b0c5 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -89,7 +89,7 @@ void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, acpi_handle handle); int acpi_unbind_one(struct device *dev); -void acpi_bus_device_eject(void *data, u32 ost_src); +void acpi_device_hotplug(void *data, u32 ost_src); bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4076491c6ded..ca05064f3ff7 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -683,11 +683,13 @@ static void hotplug_event_root(void *data, u32 type) if (!root) break; + acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&root->device->dev); acpi_scan_lock_release(); - acpi_bus_device_eject(root->device, ACPI_NOTIFY_EJECT_REQUEST); + acpi_device_hotplug(root->device, ACPI_NOTIFY_EJECT_REQUEST); return; default: acpi_handle_warn(handle, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4fa416f94f52..dd0ff9de9277 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -206,12 +206,8 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_status status; unsigned long long sta; - /* If there is no handle, the device node has been unregistered. */ - if (!handle) { - dev_dbg(&device->dev, "ACPI handle missing\n"); - put_device(&device->dev); - return -EINVAL; - } + if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); /* * Carry out two passes here and ignore errors in the first pass, @@ -230,7 +226,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) dev_warn(errdev, "Offline disabled.\n"); acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); - put_device(&device->dev); return -EPERM; } acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); @@ -249,7 +244,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); - put_device(&device->dev); return -EBUSY; } } @@ -259,9 +253,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_bus_trim(device); - put_device(&device->dev); - device = NULL; - acpi_evaluate_lck(handle, 0); /* * TBD: _EJD support. @@ -288,77 +279,74 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return 0; } -void acpi_bus_device_eject(void *data, u32 ost_src) +static int acpi_scan_device_check(struct acpi_device *adev) { - struct acpi_device *device = data; - acpi_handle handle = device->handle; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error; - lock_device_hotplug(); - mutex_lock(&acpi_scan_lock); - - if (ost_src == ACPI_NOTIFY_EJECT_REQUEST) - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); - - if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); - - error = acpi_scan_hot_remove(device); - if (error == -EPERM) { - goto err_support; - } else if (error) { - goto err_out; + /* + * This function is only called for device objects for which matching + * scan handlers exist. The only situation in which the scan handler is + * not attached to this device object yet is when the device has just + * appeared (either it wasn't present at all before or it was removed + * and then added again). + */ + if (adev->handler) { + dev_warn(&adev->dev, "Already enumerated\n"); + return -EBUSY; } - - out: - mutex_unlock(&acpi_scan_lock); - unlock_device_hotplug(); - return; - - err_support: - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - err_out: - acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL); - goto out; + error = acpi_bus_scan(adev->handle); + if (error) { + dev_warn(&adev->dev, "Namespace scan failure\n"); + return error; + } + if (adev->handler) { + if (adev->handler->hotplug.mode == AHM_CONTAINER) + kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); + } else { + dev_warn(&adev->dev, "Enumeration failure\n"); + return -ENODEV; + } + return 0; } -static void acpi_scan_bus_device_check(void *data, u32 ost_source) +void acpi_device_hotplug(void *data, u32 src) { - acpi_handle handle = data; - struct acpi_device *device; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + struct acpi_device *adev = data; int error; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); - if (ost_source != ACPI_NOTIFY_BUS_CHECK) { - device = NULL; - acpi_bus_get_device(handle, &device); - if (acpi_device_enumerated(device)) { - dev_warn(&device->dev, "Attempt to re-insert\n"); - goto out; - } - } - error = acpi_bus_scan(handle); - if (error) { - acpi_handle_warn(handle, "Namespace scan failure\n"); - goto out; - } - device = NULL; - acpi_bus_get_device(handle, &device); - if (!acpi_device_enumerated(device)) { - acpi_handle_warn(handle, "Device not enumerated\n"); + /* + * The device object's ACPI handle cannot become invalid as long as we + * are holding acpi_scan_lock, but it may have become invalid before + * that lock was acquired. + */ + if (adev->handle == INVALID_ACPI_HANDLE) goto out; + + switch (src) { + case ACPI_NOTIFY_BUS_CHECK: + error = acpi_bus_scan(adev->handle); + break; + case ACPI_NOTIFY_DEVICE_CHECK: + error = acpi_scan_device_check(adev); + break; + case ACPI_NOTIFY_EJECT_REQUEST: + case ACPI_OST_EC_OSPM_EJECT: + error = acpi_scan_hot_remove(adev); + break; + default: + error = -EINVAL; + break; } - ost_code = ACPI_OST_SC_SUCCESS; - if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); + if (!error) + ost_code = ACPI_OST_SC_SUCCESS; out: - acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL); + acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + put_device(&adev->dev); mutex_unlock(&acpi_scan_lock); unlock_device_hotplug(); } @@ -370,6 +358,9 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) struct acpi_device *adev; acpi_status status; + if (acpi_bus_get_device(handle, &adev)) + goto err_out; + switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); @@ -384,24 +375,20 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; goto err_out; } - if (acpi_bus_get_device(handle, &adev)) - goto err_out; - - get_device(&adev->dev); - status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type); - if (ACPI_SUCCESS(status)) - return; - - put_device(&adev->dev); - goto err_out; + acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); + break; default: /* non-hotplug event; possibly handled by other handler */ return; } - status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type); + get_device(&adev->dev); + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) return; + put_device(&adev->dev); + err_out: acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } @@ -454,7 +441,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&acpi_device->dev); - status = acpi_hotplug_execute(acpi_bus_device_eject, acpi_device, + status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, ACPI_OST_EC_OSPM_EJECT); if (ACPI_SUCCESS(status)) return count; -- cgit v1.2.3 From 3338db0057ed9f554050bd06863731c515d79672 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:20 +0100 Subject: ACPI / hotplug: Make ACPI PCI root hotplug use common hotplug code Rework the common ACPI device hotplug code so that it is suitable for PCI host bridge hotplug and switch the PCI host bridge scan handler to using the common hotplug code. This allows quite a few lines of code that are not necessary any more to be dropped from the PCI host bridge scan handler and removes arbitrary differences in behavior between PCI host bridge hotplug and ACPI-based hotplug of other components, like CPUs and memory. Also acpi_device_hotplug() can be static now. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/internal.h | 2 - drivers/acpi/pci_root.c | 125 +++++------------------------------------------- drivers/acpi/scan.c | 42 +++++++++------- include/acpi/acpi_bus.h | 2 +- 4 files changed, 37 insertions(+), 134 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a0d42cf5b0c5..f4aa467c407e 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -28,7 +28,6 @@ int init_acpi_device_notify(void); int acpi_scan_init(void); void acpi_pci_root_init(void); void acpi_pci_link_init(void); -void acpi_pci_root_hp_init(void); void acpi_processor_init(void); void acpi_platform_init(void); int acpi_sysfs_init(void); @@ -89,7 +88,6 @@ void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, acpi_handle handle); int acpi_unbind_one(struct device *dev); -void acpi_device_hotplug(void *data, u32 ost_src); bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ca05064f3ff7..2dd11e0bac24 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -51,6 +51,12 @@ static int acpi_pci_root_add(struct acpi_device *device, const struct acpi_device_id *not_used); static void acpi_pci_root_remove(struct acpi_device *device); +static int acpi_pci_root_scan_dependent(struct acpi_device *adev) +{ + acpiphp_check_host_bridge(adev->handle); + return 0; +} + #define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \ | OSC_PCI_ASPM_SUPPORT \ | OSC_PCI_CLOCK_PM_SUPPORT \ @@ -66,7 +72,8 @@ static struct acpi_scan_handler pci_root_handler = { .attach = acpi_pci_root_add, .detach = acpi_pci_root_remove, .hotplug = { - .ignore = true, + .enabled = true, + .scan_dependent = acpi_pci_root_scan_dependent, }, }; @@ -624,119 +631,9 @@ static void acpi_pci_root_remove(struct acpi_device *device) void __init acpi_pci_root_init(void) { acpi_hest_init(); - - if (!acpi_pci_disabled) { - pci_acpi_crs_quirks(); - acpi_scan_add_handler(&pci_root_handler); - } -} -/* Support root bridge hotplug */ - -static void handle_root_bridge_insertion(acpi_handle handle) -{ - struct acpi_device *device = NULL; - - acpi_bus_get_device(handle, &device); - if (acpi_device_enumerated(device)) { - dev_printk(KERN_DEBUG, &device->dev, - "acpi device already exists; ignoring notify\n"); - return; - } - - if (acpi_bus_scan(handle)) - acpi_handle_err(handle, "cannot add bridge to acpi list\n"); -} - -static void hotplug_event_root(void *data, u32 type) -{ - acpi_handle handle = data; - struct acpi_pci_root *root; - - acpi_scan_lock_acquire(); - - root = acpi_pci_find_root(handle); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus enumerate */ - acpi_handle_printk(KERN_DEBUG, handle, - "Bus check notify on %s\n", __func__); - if (root) - acpiphp_check_host_bridge(handle); - else - handle_root_bridge_insertion(handle); - - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check */ - acpi_handle_printk(KERN_DEBUG, handle, - "Device check notify on %s\n", __func__); - if (!root) - handle_root_bridge_insertion(handle); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - acpi_handle_printk(KERN_DEBUG, handle, - "Device eject notify on %s\n", __func__); - if (!root) - break; - - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); - get_device(&root->device->dev); - - acpi_scan_lock_release(); - - acpi_device_hotplug(root->device, ACPI_NOTIFY_EJECT_REQUEST); + if (acpi_pci_disabled) return; - default: - acpi_handle_warn(handle, - "notify_handler: unknown event type 0x%x\n", - type); - break; - } - - acpi_scan_lock_release(); -} - -static void handle_hotplug_event_root(acpi_handle handle, u32 type, - void *context) -{ - acpi_hotplug_execute(hotplug_event_root, handle, type); -} - -static acpi_status __init -find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - int *count = (int *)context; - - if (!acpi_is_root_bridge(handle)) - return AE_OK; - - (*count)++; - - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_root, NULL); - if (ACPI_FAILURE(status)) - acpi_handle_printk(KERN_DEBUG, handle, - "notify handler is not installed, exit status: %u\n", - (unsigned int)status); - else - acpi_handle_printk(KERN_DEBUG, handle, - "notify handler is installed\n"); - - return AE_OK; -} - -void __init acpi_pci_root_hp_init(void) -{ - int num = 0; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); - printk(KERN_DEBUG "Found %d acpi root devices\n", num); + pci_acpi_crs_quirks(); + acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root"); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index dd0ff9de9277..18865c86c463 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -283,17 +283,6 @@ static int acpi_scan_device_check(struct acpi_device *adev) { int error; - /* - * This function is only called for device objects for which matching - * scan handlers exist. The only situation in which the scan handler is - * not attached to this device object yet is when the device has just - * appeared (either it wasn't present at all before or it was removed - * and then added again). - */ - if (adev->handler) { - dev_warn(&adev->dev, "Already enumerated\n"); - return -EBUSY; - } error = acpi_bus_scan(adev->handle); if (error) { dev_warn(&adev->dev, "Namespace scan failure\n"); @@ -309,10 +298,11 @@ static int acpi_scan_device_check(struct acpi_device *adev) return 0; } -void acpi_device_hotplug(void *data, u32 src) +static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; + struct acpi_scan_handler *handler; int error; lock_device_hotplug(); @@ -326,12 +316,32 @@ void acpi_device_hotplug(void *data, u32 src) if (adev->handle == INVALID_ACPI_HANDLE) goto out; + handler = adev->handler; + switch (src) { case ACPI_NOTIFY_BUS_CHECK: - error = acpi_bus_scan(adev->handle); + if (handler) { + error = handler->hotplug.scan_dependent ? + handler->hotplug.scan_dependent(adev) : + acpi_bus_scan(adev->handle); + } else { + error = acpi_scan_device_check(adev); + } break; case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); + /* + * This code is only run for device objects for which matching + * scan handlers exist. The only situation in which the scan + * handler is not attached to this device object yet is when the + * device has just appeared (either it wasn't present at all + * before or it was removed and then added again). + */ + if (adev->handler) { + dev_warn(&adev->dev, "Already enumerated\n"); + error = -EBUSY; + } else { + error = acpi_scan_device_check(adev); + } break; case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: @@ -1805,7 +1815,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type) */ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler && !handler->hotplug.ignore) { + if (handler) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, acpi_hotplug_notify_cb, handler); break; @@ -2083,8 +2093,6 @@ int __init acpi_scan_init(void) acpi_update_all_gpes(); - acpi_pci_root_hp_init(); - out: mutex_unlock(&acpi_scan_lock); return result; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e748dbfca9d5..2359c69f1680 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -100,8 +100,8 @@ enum acpi_hotplug_mode { struct acpi_hotplug_profile { struct kobject kobj; bool enabled:1; - bool ignore:1; enum acpi_hotplug_mode mode; + int (*scan_dependent)(struct acpi_device *adev); }; static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile( -- cgit v1.2.3 From 46394fd017c0615982a3d29d45ced14bea9c526d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:32 +0100 Subject: ACPI / hotplug: Move container-specific code out of the core Move container-specific uevents from the core hotplug code to the container scan handler's .attach() and .detach() callbacks. This way the core will not have to special-case containers and the uevents will be guaranteed to happen every time a container is either scanned or trimmed as appropriate. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/container.c | 11 ++++++++--- drivers/acpi/scan.c | 8 +------- include/acpi/acpi_bus.h | 7 ------- 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index e23151667655..83d232c10f13 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -44,19 +44,24 @@ static const struct acpi_device_id container_device_ids[] = { {"", 0}, }; -static int container_device_attach(struct acpi_device *device, +static int container_device_attach(struct acpi_device *adev, const struct acpi_device_id *not_used) { - /* This is necessary for container hotplug to work. */ + kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); return 1; } +static void container_device_detach(struct acpi_device *adev) +{ + kobject_uevent(&adev->dev.kobj, KOBJ_OFFLINE); +} + static struct acpi_scan_handler container_handler = { .ids = container_device_ids, .attach = container_device_attach, + .detach = container_device_detach, .hotplug = { .enabled = true, - .mode = AHM_CONTAINER, }, }; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 18865c86c463..b1b8f4304597 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -206,9 +206,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_status status; unsigned long long sta; - if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); - /* * Carry out two passes here and ignore errors in the first pass, * because if the devices in question are memory blocks and @@ -288,10 +285,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) dev_warn(&adev->dev, "Namespace scan failure\n"); return error; } - if (adev->handler) { - if (adev->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); - } else { + if (!adev->handler) { dev_warn(&adev->dev, "Enumeration failure\n"); return -ENODEV; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 2359c69f1680..3e4150b6d71a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,16 +91,9 @@ struct acpi_device; * ----------------- */ -enum acpi_hotplug_mode { - AHM_GENERIC = 0, - AHM_CONTAINER, - AHM_COUNT -}; - struct acpi_hotplug_profile { struct kobject kobj; bool enabled:1; - enum acpi_hotplug_mode mode; int (*scan_dependent)(struct acpi_device *adev); }; -- cgit v1.2.3 From 443fc8202272190c4693209b772edba46cd7fe61 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:43 +0100 Subject: ACPI / hotplug: Rework generic code to handle suprise removals The generic ACPI hotplug code used for several types of device doesn't handle surprise removals, mostly because those devices currently cannot be removed by surprise in the majority of systems. However, surprise removals should be handled by that code as well as surprise additions of devices, so make it do that. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 85 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b1b8f4304597..06db2c036085 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -276,18 +276,72 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return 0; } +static int acpi_scan_device_not_present(struct acpi_device *adev) +{ + if (!acpi_device_enumerated(adev)) { + dev_warn(&adev->dev, "Still not present\n"); + return -EALREADY; + } + acpi_bus_trim(adev); + return 0; +} + static int acpi_scan_device_check(struct acpi_device *adev) { int error; + acpi_bus_get_status(adev); + if (adev->status.present || adev->status.functional) { + /* + * This function is only called for device objects for which + * matching scan handlers exist. The only situation in which + * the scan handler is not attached to this device object yet + * is when the device has just appeared (either it wasn't + * present at all before or it was removed and then added + * again). + */ + if (adev->handler) { + dev_warn(&adev->dev, "Already enumerated\n"); + return -EALREADY; + } + error = acpi_bus_scan(adev->handle); + if (error) { + dev_warn(&adev->dev, "Namespace scan failure\n"); + return error; + } + if (!adev->handler) { + dev_warn(&adev->dev, "Enumeration failure\n"); + error = -ENODEV; + } + } else { + error = acpi_scan_device_not_present(adev); + } + return error; +} + +static int acpi_scan_bus_check(struct acpi_device *adev) +{ + struct acpi_scan_handler *handler = adev->handler; + struct acpi_device *child; + int error; + + acpi_bus_get_status(adev); + if (!(adev->status.present || adev->status.functional)) { + acpi_scan_device_not_present(adev); + return 0; + } + if (handler && handler->hotplug.scan_dependent) + return handler->hotplug.scan_dependent(adev); + error = acpi_bus_scan(adev->handle); if (error) { dev_warn(&adev->dev, "Namespace scan failure\n"); return error; } - if (!adev->handler) { - dev_warn(&adev->dev, "Enumeration failure\n"); - return -ENODEV; + list_for_each_entry(child, &adev->children, node) { + error = acpi_scan_bus_check(child); + if (error) + return error; } return 0; } @@ -296,7 +350,6 @@ static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; - struct acpi_scan_handler *handler; int error; lock_device_hotplug(); @@ -310,32 +363,12 @@ static void acpi_device_hotplug(void *data, u32 src) if (adev->handle == INVALID_ACPI_HANDLE) goto out; - handler = adev->handler; - switch (src) { case ACPI_NOTIFY_BUS_CHECK: - if (handler) { - error = handler->hotplug.scan_dependent ? - handler->hotplug.scan_dependent(adev) : - acpi_bus_scan(adev->handle); - } else { - error = acpi_scan_device_check(adev); - } + error = acpi_scan_bus_check(adev); break; case ACPI_NOTIFY_DEVICE_CHECK: - /* - * This code is only run for device objects for which matching - * scan handlers exist. The only situation in which the scan - * handler is not attached to this device object yet is when the - * device has just appeared (either it wasn't present at all - * before or it was removed and then added again). - */ - if (adev->handler) { - dev_warn(&adev->dev, "Already enumerated\n"); - error = -EBUSY; - } else { - error = acpi_scan_device_check(adev); - } + error = acpi_scan_device_check(adev); break; case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: -- cgit v1.2.3 From f4b734c35e98c343cd99824153de09e48867b97e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:55 +0100 Subject: ACPI / hotplug: Drop unfinished global notification handling routines There are two global hotplug notification handling routines in bus.c, acpi_bus_check_device() and acpi_bus_check_scope(), that have never been finished and don't do anything useful, so drop them. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 64 ++---------------------------------------------------- 1 file changed, 2 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index bba9b72e25f8..8b09a75f6579 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -329,58 +329,6 @@ static void acpi_bus_osc_support(void) Notification Handling -------------------------------------------------------------------------- */ -static void acpi_bus_check_device(acpi_handle handle) -{ - struct acpi_device *device; - acpi_status status; - struct acpi_device_status old_status; - - if (acpi_bus_get_device(handle, &device)) - return; - if (!device) - return; - - old_status = device->status; - - /* - * Make sure this device's parent is present before we go about - * messing with the device. - */ - if (device->parent && !device->parent->status.present) { - device->status = device->parent->status; - return; - } - - status = acpi_bus_get_status(device); - if (ACPI_FAILURE(status)) - return; - - if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) - return; - - /* - * Device Insertion/Removal - */ - if ((device->status.present) && !(old_status.present)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n")); - /* TBD: Handle device insertion */ - } else if (!(device->status.present) && (old_status.present)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n")); - /* TBD: Handle device removal */ - } -} - -static void acpi_bus_check_scope(acpi_handle handle) -{ - /* Status Change? */ - acpi_bus_check_device(handle); - - /* - * TBD: Enumerate child devices within this device's scope and - * run acpi_bus_check_device()'s on them. - */ -} - /** * acpi_bus_notify * --------------- @@ -397,19 +345,11 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) switch (type) { case ACPI_NOTIFY_BUS_CHECK: - acpi_bus_check_scope(handle); - /* - * TBD: We'll need to outsource certain events to non-ACPI - * drivers via the device manager (device.c). - */ + /* TBD */ break; case ACPI_NOTIFY_DEVICE_CHECK: - acpi_bus_check_device(handle); - /* - * TBD: We'll need to outsource certain events to non-ACPI - * drivers via the device manager (device.c). - */ + /* TBD */ break; case ACPI_NOTIFY_DEVICE_WAKE: -- cgit v1.2.3 From 25db115b0bf72acfdf8a339fa8e37d8b895214d6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:56:06 +0100 Subject: ACPI: Introduce acpi_set_device_status() Introduce a static inline function for setting the status field of struct acpi_device on the basis of a supplied u32 number, acpi_set_device_status(), and use it instead of the horrible horrible STRUCT_TO_INT() macro wherever applicable. Having done that, drop STRUCT_TO_INT() (and pretend that it has never existed). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/bus.c | 11 +++-------- drivers/acpi/scan.c | 5 ++--- include/acpi/acpi_bus.h | 5 +++++ 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 8b09a75f6579..f509019ee2c7 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -52,9 +52,6 @@ struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); -#define STRUCT_TO_INT(s) (*((int*)&s)) - - #ifdef CONFIG_X86 static int set_copy_dsdt(const struct dmi_system_id *id) { @@ -115,18 +112,16 @@ int acpi_bus_get_status(struct acpi_device *device) if (ACPI_FAILURE(status)) return -ENODEV; - STRUCT_TO_INT(device->status) = (int) sta; + acpi_set_device_status(device, sta); if (device->status.functional && !device->status.present) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " "functional but not present;\n", - device->pnp.bus_id, - (u32) STRUCT_TO_INT(device->status))); + device->pnp.bus_id, (u32)sta)); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", - device->pnp.bus_id, - (u32) STRUCT_TO_INT(device->status))); + device->pnp.bus_id, (u32)sta)); return 0; } EXPORT_SYMBOL(acpi_bus_get_status); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 06db2c036085..cf773c918102 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -20,7 +20,6 @@ #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("scan"); -#define STRUCT_TO_INT(s) (*((int*)&s)) extern struct acpi_device *acpi_root; #define ACPI_BUS_CLASS "system_bus" @@ -1683,7 +1682,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); - STRUCT_TO_INT(device->status) = sta; + acpi_set_device_status(device, sta); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); acpi_bus_get_flags(device); @@ -1927,7 +1926,7 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; - STRUCT_TO_INT(device->status) = sta; + acpi_set_device_status(device, sta); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) goto err; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 3e4150b6d71a..95831e7b70be 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -320,6 +320,11 @@ static inline void *acpi_driver_data(struct acpi_device *d) #define to_acpi_device(d) container_of(d, struct acpi_device, dev) #define to_acpi_driver(d) container_of(d, struct acpi_driver, drv) +static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta) +{ + *((u32 *)&adev->status) = sta; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; -- cgit v1.2.3 From 2c22e6520ac87d8b12d4d9941e81d4119f2d903c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 25 Nov 2013 00:52:21 +0100 Subject: ACPI / scan: Use direct recurrence for device hierarchy walks Rework acpi_bus_trim() and acpi_bus_device_attach(), which is renamed as acpi_bus_attach(), to walk the list of each device object's children directly and call themselves recursively for each child instead of using acpi_walk_namespace(). This simplifies the code quite a bit and avoids the overhead of callbacks and the ACPICA's internal processing which are not really necessary for these two routines. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 120 ++++++++++++++++++++-------------------------------- 1 file changed, 45 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index cf773c918102..311904c720b1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1909,54 +1909,40 @@ static int acpi_scan_attach_handler(struct acpi_device *device) return ret; } -static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) +static void acpi_bus_attach(struct acpi_device *device) { - struct acpi_device *device; - unsigned long long sta; + struct acpi_device *child; int ret; - /* - * Ignore errors ignored by acpi_bus_check_add() to avoid terminating - * namespace walks prematurely. - */ - if (acpi_bus_type_and_status(handle, &ret, &sta)) - return AE_OK; - - if (acpi_bus_get_device(handle, &device)) - return AE_CTRL_DEPTH; - - acpi_set_device_status(device, sta); + acpi_bus_get_status(device); /* Skip devices that are not present. */ - if (!acpi_device_is_present(device)) - goto err; - + if (!acpi_device_is_present(device)) { + device->flags.visited = false; + return; + } if (device->handler) - return AE_OK; + goto ok; if (!device->flags.initialized) { acpi_bus_update_power(device, NULL); device->flags.initialized = true; } + device->flags.visited = false; ret = acpi_scan_attach_handler(device); if (ret < 0) - goto err; + return; device->flags.match_driver = true; - if (ret > 0) - goto ok; - - ret = device_attach(&device->dev); - if (ret < 0) - goto err; - - ok: + if (!ret) { + ret = device_attach(&device->dev); + if (ret < 0) + return; + } device->flags.visited = true; - return AE_OK; - err: - device->flags.visited = false; - return AE_CTRL_DEPTH; + ok: + list_for_each_entry(child, &device->children, node) + acpi_bus_attach(child); } /** @@ -1976,64 +1962,48 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, int acpi_bus_scan(acpi_handle handle) { void *device = NULL; - int error = 0; if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device))) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_check_add, NULL, NULL, &device); - if (!device) - error = -ENODEV; - else if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL))) - acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_device_attach, NULL, NULL, NULL); - - return error; -} -EXPORT_SYMBOL(acpi_bus_scan); - -static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device = NULL; - - if (!acpi_bus_get_device(handle, &device)) { - struct acpi_scan_handler *dev_handler = device->handler; - - if (dev_handler) { - if (dev_handler->detach) - dev_handler->detach(device); - - device->handler = NULL; - } else { - device_release_driver(&device->dev); - } - /* - * Most likely, the device is going away, so put it into D3cold - * before that. - */ - acpi_device_set_power(device, ACPI_STATE_D3_COLD); - device->flags.initialized = false; - device->flags.visited = false; + if (device) { + acpi_bus_attach(device); + return 0; } - return AE_OK; + return -ENODEV; } +EXPORT_SYMBOL(acpi_bus_scan); /** - * acpi_bus_trim - Remove ACPI device node and all of its descendants - * @start: Root of the ACPI device nodes subtree to remove. + * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. + * @adev: Root of the ACPI namespace scope to walk. * * Must be called under acpi_scan_lock. */ -void acpi_bus_trim(struct acpi_device *start) +void acpi_bus_trim(struct acpi_device *adev) { + struct acpi_scan_handler *handler = adev->handler; + struct acpi_device *child; + + list_for_each_entry_reverse(child, &adev->children, node) + acpi_bus_trim(child); + + if (handler) { + if (handler->detach) + handler->detach(adev); + + adev->handler = NULL; + } else { + device_release_driver(&adev->dev); + } /* - * Execute acpi_bus_device_detach() as a post-order callback to detach - * all ACPI drivers from the device nodes being removed. + * Most likely, the device is going away, so put it into D3cold before + * that. */ - acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, - acpi_bus_device_detach, NULL, NULL); - acpi_bus_device_detach(start->handle, 0, NULL, NULL); + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); + adev->flags.initialized = false; + adev->flags.visited = false; } EXPORT_SYMBOL_GPL(acpi_bus_trim); -- cgit v1.2.3 From 2209b0c964c7c402b07d0df6fcfbecf8ff53db30 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 25 Nov 2013 18:01:18 -0800 Subject: cpufreq: cpufreq-cpu0: clk_round_rate() can return a zero upon error Treat both negative and zero return values from clk_round_rate() as errors. This is needed since subsequent patches will convert clk_round_rate()'s return value to be an unsigned type, rather than a signed type, since some clock sources can generate rates higher than (2^31)-1 Hz. Eventually, when calling clk_round_rate(), only a return value of zero will be considered a error. All other values will be considered valid rates. The comparison against values less than 0 is kept to preserve the correct behavior in the meantime. Signed-off-by: Paul Walmsley Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-cpu0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index d4585ce2346c..0faf756f6197 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -44,7 +44,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) int ret; freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); - if (freq_Hz < 0) + if (freq_Hz <= 0) freq_Hz = freq_table[index].frequency * 1000; freq_exact = freq_Hz; -- cgit v1.2.3 From 189c9b8d925691cc58823ffdc3bf75dc8630ccdf Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 25 Nov 2013 18:04:34 -0800 Subject: cpufreq: SPEAr: clk_round_rate() can return a zero upon error Treat both negative and zero return values from clk_round_rate() as errors. This is needed since subsequent patches will convert clk_round_rate()'s return value to be an unsigned type, rather than a signed type, since some clock sources can generate rates higher than (2^31)-1 Hz. Eventually, when calling clk_round_rate(), only a return value of zero will be considered a error. All other values will be considered valid rates. The comparison against values less than 0 is kept to preserve the correct behavior in the meantime. Signed-off-by: Paul Walmsley Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/spear-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index d02ccd19c9c4..45ea4c094542 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -138,7 +138,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, } newfreq = clk_round_rate(srcclk, newfreq * mult); - if (newfreq < 0) { + if (newfreq <= 0) { pr_err("clk_round_rate failed for cpu src clock\n"); return newfreq; } -- cgit v1.2.3 From 8b48463f89429af408ff695244dc627e1acff4f7 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 3 Dec 2013 08:49:16 +0800 Subject: ACPI: Clean up inclusions of ACPI header files Replace direct inclusions of , and , which are incorrect, with inclusions and remove some inclusions of those files that aren't necessary. First of all, , and should not be included directly from any files that are built for CONFIG_ACPI unset, because that generally leads to build warnings about undefined symbols in !CONFIG_ACPI builds. For CONFIG_ACPI set, includes those files and for CONFIG_ACPI unset it provides stub ACPI symbols to be used in that case. Second, there are ordering dependencies between those files that always have to be met. Namely, it is required that be included prior to so that the acpi_pci_root declarations the latter depends on are always there. And which provides basic ACPICA type declarations should always be included prior to any other ACPI headers in CONFIG_ACPI builds. That also is taken care of including as appropriate. Signed-off-by: Lv Zheng Cc: Greg Kroah-Hartman Cc: Matthew Garrett Cc: Tony Luck Cc: "H. Peter Anvin" Acked-by: Bjorn Helgaas (drivers/pci stuff) Acked-by: Konrad Rzeszutek Wilk (Xen stuff) Signed-off-by: Rafael J. Wysocki --- arch/ia64/hp/common/aml_nfw.c | 3 +-- arch/x86/kernel/apic/apic_flat_64.c | 4 +--- arch/x86/kernel/apic/io_apic.c | 3 --- arch/x86/pci/mmconfig_32.c | 1 - arch/x86/platform/olpc/olpc-xo15-sci.c | 3 +-- drivers/acpi/ac.c | 3 +-- drivers/acpi/acpi_extlog.c | 1 - drivers/acpi/acpi_pad.c | 3 +-- drivers/acpi/apei/einj.c | 1 - drivers/acpi/battery.c | 3 +-- drivers/acpi/blacklist.c | 1 - drivers/acpi/bus.c | 2 -- drivers/acpi/button.c | 3 +-- drivers/acpi/custom_method.c | 2 +- drivers/acpi/debugfs.c | 2 +- drivers/acpi/dock.c | 2 -- drivers/acpi/ec.c | 5 ++--- drivers/acpi/event.c | 2 +- drivers/acpi/fan.c | 3 +-- drivers/acpi/hed.c | 2 -- drivers/acpi/numa.c | 1 - drivers/acpi/osl.c | 3 --- drivers/acpi/pci_irq.c | 2 -- drivers/acpi/pci_link.c | 4 +--- drivers/acpi/pci_root.c | 4 +--- drivers/acpi/power.c | 3 +-- drivers/acpi/proc.c | 4 +--- drivers/acpi/processor_core.c | 3 +-- drivers/acpi/processor_idle.c | 4 +--- drivers/acpi/processor_perflib.c | 7 ++----- drivers/acpi/processor_thermal.c | 7 ++----- drivers/acpi/processor_throttling.c | 7 ++----- drivers/acpi/sbshc.c | 3 +-- drivers/acpi/scan.c | 2 -- drivers/acpi/sleep.c | 4 ---- drivers/acpi/sysfs.c | 2 +- drivers/acpi/thermal.c | 5 ++--- drivers/acpi/utils.c | 2 -- drivers/acpi/video.c | 5 ++--- drivers/acpi/wakeup.c | 1 - drivers/ata/libata-acpi.c | 2 -- drivers/ata/pata_acpi.c | 5 ++--- drivers/char/hpet.c | 7 ++----- drivers/char/tpm/tpm_acpi.c | 2 +- drivers/char/tpm/tpm_ppi.c | 1 - drivers/gpu/drm/i915/intel_acpi.c | 2 -- drivers/gpu/drm/nouveau/nouveau_acpi.c | 7 +------ drivers/gpu/drm/radeon/radeon_acpi.c | 6 +----- drivers/hv/vmbus_drv.c | 2 -- drivers/hwmon/acpi_power_meter.c | 3 +-- drivers/hwmon/asus_atk0110.c | 7 +------ drivers/ide/ide-acpi.c | 1 - drivers/input/misc/atlas_btns.c | 2 +- drivers/iommu/amd_iommu_init.c | 1 - drivers/iommu/intel_irq_remapping.c | 4 ++-- drivers/pci/hotplug/acpiphp_ibm.c | 3 +-- drivers/pci/hotplug/pciehp.h | 2 -- drivers/pci/ioapic.c | 1 - drivers/pci/pci-acpi.c | 3 --- drivers/pci/pci-label.c | 1 - drivers/platform/x86/acer-wmi.c | 2 -- drivers/platform/x86/asus-laptop.c | 3 +-- drivers/platform/x86/asus-wmi.c | 3 +-- drivers/platform/x86/classmate-laptop.c | 3 +-- drivers/platform/x86/dell-wmi-aio.c | 1 - drivers/platform/x86/dell-wmi.c | 1 - drivers/platform/x86/eeepc-laptop.c | 3 +-- drivers/platform/x86/eeepc-wmi.c | 2 +- drivers/platform/x86/hp_accel.c | 2 +- drivers/platform/x86/ideapad-laptop.c | 3 +-- drivers/platform/x86/intel-rst.c | 2 +- drivers/platform/x86/intel-smartconnect.c | 2 +- drivers/platform/x86/intel_menlow.c | 4 +--- drivers/platform/x86/intel_oaktrail.c | 3 --- drivers/platform/x86/mxm-wmi.c | 3 +-- drivers/platform/x86/panasonic-laptop.c | 4 +--- drivers/platform/x86/pvpanic.c | 3 +-- drivers/platform/x86/samsung-q10.c | 2 +- drivers/platform/x86/sony-laptop.c | 4 +--- drivers/platform/x86/tc1100-wmi.c | 4 +--- drivers/platform/x86/thinkpad_acpi.c | 14 ++++---------- drivers/platform/x86/toshiba_acpi.c | 4 +--- drivers/platform/x86/toshiba_bluetooth.c | 4 +--- drivers/platform/x86/wmi.c | 2 -- drivers/platform/x86/xo15-ebook.c | 3 +-- drivers/pnp/pnpacpi/core.c | 1 - drivers/pnp/pnpacpi/pnpacpi.h | 1 - drivers/sfi/sfi_acpi.c | 2 +- drivers/staging/quickstart/quickstart.c | 2 +- drivers/usb/core/usb-acpi.c | 1 - drivers/xen/xen-acpi-cpuhotplug.c | 3 --- drivers/xen/xen-acpi-memhotplug.c | 1 - drivers/xen/xen-acpi-pad.c | 5 ++--- drivers/xen/xen-acpi-processor.c | 4 +--- include/acpi/acpi_bus.h | 2 -- include/acpi/acpi_drivers.h | 3 --- include/linux/acpi_io.h | 2 +- include/linux/ide.h | 8 ++------ include/linux/iscsi_ibft.h | 2 +- include/linux/pci_hotplug.h | 3 +-- include/linux/sfi_acpi.h | 2 +- include/linux/tboot.h | 2 +- tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | 5 +---- 103 files changed, 80 insertions(+), 234 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c index 916ffe770bcf..84715fcbba08 100644 --- a/arch/ia64/hp/common/aml_nfw.c +++ b/arch/ia64/hp/common/aml_nfw.c @@ -23,8 +23,7 @@ */ #include -#include -#include +#include #include MODULE_AUTHOR("Bjorn Helgaas "); diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 00c77cf78e9e..ccbf857d1d55 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -21,9 +21,7 @@ #include #include -#ifdef CONFIG_ACPI -#include -#endif +#include static struct apic apic_physflat; static struct apic apic_flat; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e63a5bd2a78f..4d67a7531d45 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -37,9 +37,6 @@ #include #include /* time_after() */ #include -#ifdef CONFIG_ACPI -#include -#endif #include #include #include diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index 5c90975cdf0f..43984bc1665a 100644 --- a/arch/x86/pci/mmconfig_32.c +++ b/arch/x86/pci/mmconfig_32.c @@ -14,7 +14,6 @@ #include #include #include -#include /* Assume systems with more busses have correct MCFG */ #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c index 649a12befba9..08e350e757dc 100644 --- a/arch/x86/platform/olpc/olpc-xo15-sci.c +++ b/arch/x86/platform/olpc/olpc-xo15-sci.c @@ -15,8 +15,7 @@ #include #include -#include -#include +#include #include #define DRV_NAME "olpc-xo15-sci" diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 8711e3797165..8095943e6e11 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index a6869e110ce5..2635a01c5b3e 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index fc6008fbce35..65610c0e7243 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -28,8 +28,7 @@ #include #include #include -#include -#include +#include #include #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fb57d03e698b..ca0c6d7ec0d4 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "apei-internal.h" diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fbf1aceda8b8..e90ef8b96f26 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -36,8 +36,7 @@ #include #include -#include -#include +#include #include #define PREFIX "ACPI: " diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 078c4f7fe2dd..05ee8f61bfb5 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include "internal.h" diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index bba9b72e25f8..cfea1c58f034 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -37,8 +37,6 @@ #include #endif #include -#include -#include #include #include #include diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c971929d75c2..9e3a6cb99f90 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -31,8 +31,7 @@ #include #include #include -#include -#include +#include #include #define PREFIX "ACPI: " diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index 12b62f2cdb3f..c68e72414a67 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "internal.h" diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index b55d6a20dc0e..6b1919f6bd82 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debugfs"); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dcd73ccb514c..9ab9e783a894 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ba5b56db9d27..ff40120e930e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -39,10 +39,9 @@ #include #include #include -#include -#include -#include +#include #include +#include #include "internal.h" diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index cae3b387b867..ef2d730734dc 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index ba3da88cee45..1fb62900f32a 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -29,8 +29,7 @@ #include #include #include -#include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 13b1d39d7cdf..aafe3ca829c2 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include static struct acpi_device_id acpi_hed_ids[] = { diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index a2343a1d9e0b..9e6816ef280a 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -29,7 +29,6 @@ #include #include #include -#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 54a20ff4b864..244be2affea7 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -49,9 +49,6 @@ #include #include -#include -#include -#include #include "internal.h" #define _COMPONENT ACPI_OS_SERVICES diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 41c5e1b799ef..52d45ea2bc4f 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 2652a614deeb..ea6b8d16dcc8 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -39,9 +39,7 @@ #include #include #include - -#include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0703bff5e60e..cd20f3486cfa 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -35,9 +35,7 @@ #include #include #include -#include -#include -#include +#include /* for acpi_hest_init() */ #include "internal.h" diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index c2ad391d8041..ad7da686e6e6 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -42,8 +42,7 @@ #include #include #include -#include -#include +#include #include "sleep.h" #include "internal.h" diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 6a5b152ad4d0..db061bfd95a8 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -3,11 +3,9 @@ #include #include #include +#include #include -#include -#include - #include "sleep.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b3171f30b319..34e7b3c6a08d 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -10,8 +10,7 @@ #include #include #include - -#include +#include #include #include "internal.h" diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 644516d9bde6..d2d44e0190a3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -35,6 +35,7 @@ #include #include #include +#include /* * Include the apic definitions for x86 to have the APIC timer related defines @@ -46,9 +47,6 @@ #include #endif -#include -#include - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 60a7c28fc167..ff90054f04fd 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -31,15 +31,12 @@ #include #include #include - +#include +#include #ifdef CONFIG_X86 #include #endif -#include -#include -#include - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index d1d2e7fb5b30..f95e7584d6e6 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -30,12 +30,9 @@ #include #include #include - -#include - -#include +#include #include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index e7dd2c1fee79..28baa05b8018 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -32,14 +32,11 @@ #include #include #include - +#include +#include #include #include -#include -#include -#include - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index b78bc605837e..26e5b5060523 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -8,8 +8,7 @@ * the Free Software Foundation version 2. */ -#include -#include +#include #include #include #include diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 15daa21fcd05..56421a921a2b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -12,8 +12,6 @@ #include #include -#include - #include "internal.h" #define _COMPONENT ACPI_BUS_COMPONENT diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 14df30580e15..ea9cc373ffd8 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -18,12 +18,8 @@ #include #include #include - #include -#include -#include - #include "internal.h" #include "sleep.h" diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index db5293650f62..ba07d9a927ab 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "internal.h" diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 0d9f46b5ae6d..1fd21ad69c98 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -41,10 +41,9 @@ #include #include #include -#include #include -#include -#include +#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 6d408bfbbb1d..1336b9151479 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,8 +30,6 @@ #include #include #include -#include -#include #include "internal.h" diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 995e91bcb97b..b727d105046d 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -37,12 +37,11 @@ #include #include #include -#include #include -#include -#include #include +#include #include +#include #include "internal.h" diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index 7bfbe40bc43b..1638401ab282 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 4372cfa883c9..8e22d9762328 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -20,8 +20,6 @@ #include #include "libata.h" -#include - unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT; module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644); MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)"); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 73212c9c6d5b..62c9ac80c6e9 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -12,11 +12,10 @@ #include #include #include -#include -#include - +#include #include #include +#include #define DRV_NAME "pata_acpi" #define DRV_VERSION "0.2.3" diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5d9c31dfc905..d5d4cd82b9f7 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -34,15 +34,12 @@ #include #include #include - +#include +#include #include #include #include -#include -#include -#include - /* * The High Precision Event Timer driver. * This driver is closely modelled after the rtc.c driver. diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 64420b3396a2..b9a57fa4b710 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "tpm.h" #include "tpm_eventlog.h" diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 8e562dc65601..dd60ef336f8d 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -1,5 +1,4 @@ #include -#include #include "tpm.h" static const u8 tpm_ppi_uuid[] = { diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index dfff0907f70e..5325b25ccbb4 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -6,8 +6,6 @@ #include #include #include -#include - #include #include "i915_drv.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 95c740454049..1f0b6d238cfa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -1,15 +1,10 @@ #include #include #include -#include -#include -#include -#include #include - #include - #include +#include #include "nouveau_drm.h" #include "nouveau_acpi.h" diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 98a9074b306b..77e9d07c55b6 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -25,18 +25,14 @@ #include #include #include -#include -#include +#include #include - #include #include #include "radeon.h" #include "radeon_acpi.h" #include "atom.h" -#include - #define ACPI_AC_CLASS "ac_adapter" extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 48aad4faea06..077bb1bdac34 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -39,7 +38,6 @@ #include #include "hyperv_vmbus.h" - static struct acpi_device *hv_acpi_dev; static struct tasklet_struct msg_dpc; diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 6a34f7f48eb9..579bdf93be43 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -30,8 +30,7 @@ #include #include #include -#include -#include +#include #define ACPI_POWER_METER_NAME "power_meter" ACPI_MODULE_NAME(ACPI_POWER_METER_NAME); diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 1d7ff46812c3..ae208f612198 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -16,12 +16,7 @@ #include #include #include - -#include -#include -#include -#include - +#include #define ATK_HID "ATK0110" diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index d9e1f7ccfe6f..333d4053e727 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 5d4402365a52..d781b5e52065 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include #define ACPI_ATLAS_NAME "Atlas ACPI" #define ACPI_ATLAS_CLASS "Atlas" diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 8f798be6e398..28b4bea7c109 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index bab10b1002fb..0cb7528b30a1 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -6,11 +6,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include #include #include #include diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index ecfac7e72d91..8dcccffd6e21 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -31,12 +31,11 @@ #include #include #include -#include #include #include -#include #include #include +#include #include "acpiphp.h" #include "../pci.h" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 21e865ded1dc..24e147cae667 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -163,8 +163,6 @@ static inline const char *slot_name(struct slot *slot) } #ifdef CONFIG_ACPI -#include -#include #include void __init pciehp_acpi_slot_detection_init(void); diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 50ce68098298..2122b2bf006f 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -20,7 +20,6 @@ #include #include #include -#include struct ioapic { acpi_handle handle; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 577074efbe62..43e317991326 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include - #include #include #include diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index d51f45aa669e..dbafcc8ef673 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "pci.h" #define DEVICE_LABEL_DSM 0x07 diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c9076bdaf2c1..c91f69b39db4 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -41,8 +41,6 @@ #include #include #include - -#include #include MODULE_AUTHOR("Carlos Corbacho"); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0e9c169b42f8..430b5c3c46b4 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -53,8 +53,7 @@ #include #include #include -#include -#include +#include #define ASUS_LAPTOP_VERSION "0.42" diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 19c313b056c3..df7ecb9ecd9d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -45,8 +45,7 @@ #include #include #include -#include -#include +#include #include #include "asus-wmi.h" diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 6dfa8d3b4eec..70d355a9ae2c 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -21,14 +21,13 @@ #include #include #include -#include +#include #include #include #include MODULE_LICENSE("GPL"); - struct cmpc_accel { int sensitivity; int g_select; diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c index bcf8cc6b5537..dbc97a33bbc8 100644 --- a/drivers/platform/x86/dell-wmi-aio.c +++ b/drivers/platform/x86/dell-wmi-aio.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index fa9a2171cc13..bdf483babb43 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index aefcc32e5634..cabd56700cae 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -28,8 +28,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index af67e6e56ebb..6112933f6278 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "asus-wmi.h" diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index a8e43cf70fac..aff4d0670edf 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "../../misc/lis3lv02d/lis3lv02d.h" #define DRIVER_NAME "hp_accel" diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 6788acc22ab9..70b57295d0a0 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/platform/x86/intel-rst.c b/drivers/platform/x86/intel-rst.c index a2083a9e5662..d45bca34bf1b 100644 --- a/drivers/platform/x86/intel-rst.c +++ b/drivers/platform/x86/intel-rst.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel-smartconnect.c b/drivers/platform/x86/intel-smartconnect.c index 1838400dc036..04cf5dffdfd9 100644 --- a/drivers/platform/x86/intel-smartconnect.c +++ b/drivers/platform/x86/intel-smartconnect.c @@ -19,7 +19,7 @@ #include #include -#include +#include MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index 11244f8703c4..e8b46d2c468c 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c @@ -36,10 +36,8 @@ #include #include #include - #include -#include -#include +#include MODULE_AUTHOR("Thomas Sujith"); MODULE_AUTHOR("Zhang Rui"); diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index f6f18cde0f11..4bc960416785 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -50,9 +50,6 @@ #include #include #include -#include -#include - #define DRIVER_NAME "intel_oaktrail" #define DRIVER_VERSION "0.4ac1" diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c index 0aea63b3729a..3c59c0a3ee0f 100644 --- a/drivers/platform/x86/mxm-wmi.c +++ b/drivers/platform/x86/mxm-wmi.c @@ -20,8 +20,7 @@ #include #include #include -#include -#include +#include MODULE_AUTHOR("Dave Airlie"); MODULE_DESCRIPTION("MXM WMI Driver"); diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 10d12b221601..137d602395e8 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -125,12 +125,10 @@ #include #include #include -#include -#include +#include #include #include - #ifndef ACPI_HOTKEY_COMPONENT #define ACPI_HOTKEY_COMPONENT 0x10000000 #endif diff --git a/drivers/platform/x86/pvpanic.c b/drivers/platform/x86/pvpanic.c index 47ae0c47d4b5..c9f6e511daa6 100644 --- a/drivers/platform/x86/pvpanic.c +++ b/drivers/platform/x86/pvpanic.c @@ -24,8 +24,7 @@ #include #include #include -#include -#include +#include MODULE_AUTHOR("Hu Tao "); MODULE_DESCRIPTION("pvpanic device driver"); diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c index cae7098e9b0d..5413f62d2e61 100644 --- a/drivers/platform/x86/samsung-q10.c +++ b/drivers/platform/x86/samsung-q10.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #define SAMSUNGQ10_BL_MAX_INTENSITY 7 diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 47caab0ea7a1..1d00039de72a 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -61,9 +61,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -71,6 +68,7 @@ #include #include #endif +#include #define dprintk(fmt, ...) \ do { \ diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index 9b93fdb61ed7..6a6ea28a7e51 100644 --- a/drivers/platform/x86/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c @@ -32,9 +32,7 @@ #include #include #include -#include -#include -#include +#include #include #define GUID "C364AC71-36DB-495A-8494-B439D472A505" diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 05e046aa5e31..9d7e34b0109c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -61,7 +61,6 @@ #include #include #include - #include #include #include @@ -74,21 +73,16 @@ #include #include #include -#include - #include #include #include - +#include +#include +#include #include #include #include - -#include - -#include - -#include +#include /* ThinkPad CMOS commands */ #define TP_CMOS_VOLUME_DOWN 0 diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0cfadb65f7c6..b5f17eb7ad2e 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -54,11 +54,9 @@ #include #include #include - +#include #include -#include - MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index 74dd01ae343b..2cb1ea62b4a7 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -23,14 +23,12 @@ #include #include #include -#include -#include +#include MODULE_AUTHOR("Jes Sorensen "); MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); MODULE_LICENSE("GPL"); - static int toshiba_bt_rfkill_add(struct acpi_device *device); static int toshiba_bt_rfkill_remove(struct acpi_device *device); static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 62e8c221d01e..ba13adea08b0 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include ACPI_MODULE_NAME("wmi"); MODULE_AUTHOR("Carlos Corbacho"); diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c index 4b1377bd5944..49cbccec6e2d 100644 --- a/drivers/platform/x86/xo15-ebook.c +++ b/drivers/platform/x86/xo15-ebook.c @@ -18,8 +18,7 @@ #include #include #include -#include -#include +#include #define MODULE_NAME "xo15-ebook" diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 14655a0f0431..e869ba698ac0 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "../base.h" #include "pnpacpi.h" diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h index 3e60225b0227..051ef9699777 100644 --- a/drivers/pnp/pnpacpi/pnpacpi.h +++ b/drivers/pnp/pnpacpi/pnpacpi.h @@ -1,7 +1,6 @@ #ifndef ACPI_PNP_H #define ACPI_PNP_H -#include #include #include diff --git a/drivers/sfi/sfi_acpi.c b/drivers/sfi/sfi_acpi.c index f5b4ca581541..5e753d799f61 100644 --- a/drivers/sfi/sfi_acpi.c +++ b/drivers/sfi/sfi_acpi.c @@ -60,7 +60,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include +#include /* FIXME: inclusion should be removed */ #include #include "sfi_core.h" diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c index 9f6ebdb23740..a85c3d68c462 100644 --- a/drivers/staging/quickstart/quickstart.c +++ b/drivers/staging/quickstart/quickstart.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 4e243c37f17f..11c656976cb5 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "usb.h" diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c index 8dae6c13063a..cd5bb0a507a2 100644 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ b/drivers/xen/xen-acpi-cpuhotplug.c @@ -24,10 +24,7 @@ #include #include #include -#include -#include #include - #include #include #include diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index 9083f1e474f8..f2872a1bb096 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c index 59708fdd068b..40c4bc06b5fa 100644 --- a/drivers/xen/xen-acpi-pad.c +++ b/drivers/xen/xen-acpi-pad.c @@ -18,11 +18,10 @@ #include #include -#include -#include -#include +#include #include #include +#include #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 13bc6c31c060..7231859119f1 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -28,10 +28,8 @@ #include #include #include -#include -#include +#include #include - #include #include #include diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7b2de026a4f3..510119a63fb2 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -28,8 +28,6 @@ #include -#include - /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 1cedfcb1bd88..b124fdb26046 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -26,9 +26,6 @@ #ifndef __ACPI_DRIVERS_H__ #define __ACPI_DRIVERS_H__ -#include -#include - #define ACPI_MAX_STRING 80 /* diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h index b0ffa219993e..2a5a1391ce72 100644 --- a/include/linux/acpi_io.h +++ b/include/linux/acpi_io.h @@ -2,7 +2,7 @@ #define _ACPI_IO_H_ #include -#include +#include /* FIXME: inclusion should be removed */ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) diff --git a/include/linux/ide.h b/include/linux/ide.h index 46a14229a162..93b5ca754b5b 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -18,14 +18,10 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_IDEACPI -#include -#endif -#include -#include - /* for request_sense */ #include +#include +#include #if defined(CONFIG_CRIS) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) # define SUPPORT_VLB_SYNC 0 diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h index 8ba7e5b9d62c..82f9673c2527 100644 --- a/include/linux/iscsi_ibft.h +++ b/include/linux/iscsi_ibft.h @@ -21,7 +21,7 @@ #ifndef ISCSI_IBFT_H #define ISCSI_IBFT_H -#include +#include /* FIXME: inclusion should be removed */ /* * Logical location of iSCSI Boot Format Table. diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index a2e2f1d17e16..5f2e559af6b0 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -175,8 +175,7 @@ struct hotplug_params { }; #ifdef CONFIG_ACPI -#include -#include +#include int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); diff --git a/include/linux/sfi_acpi.h b/include/linux/sfi_acpi.h index 631af63af42d..2cfcb7944a49 100644 --- a/include/linux/sfi_acpi.h +++ b/include/linux/sfi_acpi.h @@ -60,7 +60,7 @@ #define _LINUX_SFI_ACPI_H #ifdef CONFIG_SFI -#include /* struct acpi_table_header */ +#include /* FIXME: inclusion should be removed */ extern int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id, diff --git a/include/linux/tboot.h b/include/linux/tboot.h index c75128bed5fa..9a54b331f938 100644 --- a/include/linux/tboot.h +++ b/include/linux/tboot.h @@ -34,7 +34,7 @@ enum { }; #ifdef CONFIG_INTEL_TXT -#include +#include /* used to communicate between tboot and the launched kernel */ #define TB_KEY_SIZE 64 /* 512 bits */ diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index 66cace601e57..0f10b81e3322 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c @@ -25,12 +25,9 @@ #include #include #include - +#include #include -#include -#include - static int pm_tmr_ioport = 0; /*helper function to safely read acpi pm timesource*/ -- cgit v1.2.3 From d9fef0c4d2e08c3888add77f1dc54fb12afb3928 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:57:58 +0100 Subject: ACPI / bind: Simplify child device lookups Now that we create a struct acpi_device object for every ACPI namespace node representing a device, it is not necessary to use acpi_walk_namespace() for child device lookup in acpi_find_child() any more. Instead, we can simply walk the list of children of the given struct acpi_device object and return the matching one (or the one which is the best match if there are more of them). The checks done during the matching loop can be simplified too so that the secondary namespace walks in find_child_checks() are not necessary any more. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu --- drivers/acpi/glue.c | 137 +++++++++++++++++++----------------------------- include/acpi/acpi_bus.h | 3 ++ 2 files changed, 58 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a22a295edb69..ea77512ad70c 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -82,107 +82,80 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) #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) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) { - *ret_p = handle; - return AE_CTRL_TERMINATE; - } - return AE_OK; -} - -static int do_find_child_checks(acpi_handle handle, bool is_bridge) +static int find_child_checks(struct acpi_device *adev, bool check_children) { bool sta_present = true; unsigned long long sta; acpi_status status; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->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; + if (check_children && list_empty(&adev->children)) + return -ENODEV; - /* Check if this object has at least one child device. */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - acpi_dev_present, NULL, NULL, &test); - if (!test) - return -ENODEV; - } return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } -struct find_child_context { - u64 addr; - bool is_bridge; - acpi_handle ret; - int ret_score; -}; - -static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, - void *data, void **not_used) +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children) { - 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) - return AE_OK; - - if (!context->ret) { - /* This is the first matching object. Save its handle. */ - context->ret = handle; - return AE_OK; - } - /* - * There is more than one matching object with the same _ADR value. - * That really is unexpected, so we are kind of beyond the scope of the - * spec here. We have to choose which one to return, though. - * - * First, check if the previously found object is good enough and return - * its handle if so. Second, check the same for the object that we've - * just found. - */ - 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_score = score; - } - 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; + struct acpi_device *adev, *ret = NULL; + int ret_score = 0; + + list_for_each_entry(adev, &parent->children, node) { + unsigned long long addr; + acpi_status status; + int score; + + status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, + NULL, &addr); + if (ACPI_FAILURE(status) || addr != address) + continue; + + if (!ret) { + /* This is the first matching object. Save it. */ + ret = adev; + continue; + } + /* + * There is more than one matching device object with the same + * _ADR value. That really is unexpected, so we are kind of + * beyond the scope of the spec here. We have to choose which + * one to return, though. + * + * First, check if the previously found object is good enough + * and return it if so. Second, do the same for the object that + * we've just found. + */ + if (!ret_score) { + ret_score = find_child_checks(ret, check_children); + if (ret_score == FIND_CHILD_MAX_SCORE) + return ret; + } + score = find_child_checks(adev, check_children); + if (score == FIND_CHILD_MAX_SCORE) { + return adev; + } else if (score > ret_score) { + ret = adev; + ret_score = score; + } } - return AE_OK; + return ret; } -acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) +acpi_handle acpi_find_child(acpi_handle handle, u64 addr, bool is_bridge) { - if (parent) { - struct find_child_context context = { - .addr = addr, - .is_bridge = is_bridge, - }; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child, - NULL, &context, NULL); - return context.ret; - } - return NULL; + struct acpi_device *adev; + + if (!handle || acpi_bus_get_device(handle, &adev)) + return NULL; + + adev = acpi_find_child_device(adev, addr, is_bridge); + return adev ? adev->handle : NULL; } EXPORT_SYMBOL_GPL(acpi_find_child); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index b241b733052e..6d82c5c14c0f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -431,6 +431,9 @@ struct acpi_pci_root { }; /* helper */ + +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children); acpi_handle acpi_find_child(acpi_handle, u64, bool); static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { -- cgit v1.2.3 From 5ce79d201358d36f13d13b01d8614bd8e646036c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:58:08 +0100 Subject: PCI / ACPI: Use acpi_find_child_device() for child devices lookup It is much more efficient to use acpi_find_child_device() for child devices lookup in acpi_pci_find_device() and pass ACPI_COMPANION(dev->parent) to it directly instead of obtaining ACPI_HANDLE() of ACPI_COMPANION(dev->parent) and passing it to acpi_find_child() which has to run acpi_bus_get_device() to obtain ACPI_COMPANION(dev->parent) from that again. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu --- drivers/acpi/glue.c | 3 +++ drivers/pci/pci-acpi.c | 16 ++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index ea77512ad70c..9d200d5029ca 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -106,6 +106,9 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, struct acpi_device *adev, *ret = NULL; int ret_score = 0; + if (!parent) + return NULL; + list_for_each_entry(adev, &parent->children, node) { unsigned long long addr; acpi_status status; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 43e317991326..adbf34003995 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -306,7 +306,8 @@ void acpi_pci_remove_bus(struct pci_bus *bus) static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) { struct pci_dev *pci_dev = to_pci_dev(dev); - bool is_bridge; + struct acpi_device *adev; + bool check_children; u64 addr; /* @@ -314,14 +315,17 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) * is set only after acpi_pci_find_device() has been called for the * given device. */ - is_bridge = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE + check_children = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - *handle = acpi_find_child(ACPI_HANDLE(dev->parent), addr, is_bridge); - if (!*handle) - return -ENODEV; - return 0; + adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, + check_children); + if (adev) { + *handle = adev->handle; + return 0; + } + return -ENODEV; } static void pci_acpi_setup(struct device *dev) -- cgit v1.2.3 From 11dcc75dba5bf8b69c4612de10e366c4e04cb123 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:58:18 +0100 Subject: ACPI / bind: Redefine acpi_get_child() Since acpi_get_child() is the only user of acpi_find_child() now, drop the static inline definition of the former and redefine the latter as new acpi_get_child(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu Tested-by: Aaron Lu # for ATA binding --- drivers/acpi/glue.c | 6 +++--- include/acpi/acpi_bus.h | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 9d200d5029ca..12b2acbaa116 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -150,17 +150,17 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, return ret; } -acpi_handle acpi_find_child(acpi_handle handle, u64 addr, bool is_bridge) +acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { struct acpi_device *adev; if (!handle || acpi_bus_get_device(handle, &adev)) return NULL; - adev = acpi_find_child_device(adev, addr, is_bridge); + adev = acpi_find_child_device(adev, addr, false); return adev ? adev->handle : NULL; } -EXPORT_SYMBOL_GPL(acpi_find_child); +EXPORT_SYMBOL_GPL(acpi_get_child); static void acpi_physnode_link_name(char *buf, unsigned int node_id) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6d82c5c14c0f..a1a48f27933a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -434,11 +434,7 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); -acpi_handle acpi_find_child(acpi_handle, u64, bool); -static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr) -{ - return acpi_find_child(handle, addr, false); -} +acpi_handle acpi_get_child(acpi_handle handle, u64 addr); void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -- cgit v1.2.3 From 9c5ad36d987a1b06f6b0b9dc7bc61a45d277455d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:58:28 +0100 Subject: ACPI / bind: Redefine acpi_preset_companion() Modify acpi_preset_companion() to take a struct acpi_device pointer instead of an ACPI handle as its second argument and redefine it as a static inline wrapper around ACPI_COMPANION_SET() passing the return value of acpi_find_child_device() directly as the second argument to it. Update its users to pass struct acpi_device pointers instead of ACPI handles to it. This allows some unnecessary acpi_bus_get_device() calls to be avoided. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu Tested-by: Aaron Lu # for ATA binding --- drivers/acpi/glue.c | 10 +--------- drivers/ata/libata-acpi.c | 26 +++++++++++++------------- drivers/mmc/core/sdio_bus.c | 2 +- include/acpi/acpi_bus.h | 1 - include/linux/acpi.h | 6 ++++++ 5 files changed, 21 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 12b2acbaa116..c0d18b2145c1 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -149,6 +149,7 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, } return ret; } +EXPORT_SYMBOL_GPL(acpi_find_child_device); acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { @@ -298,15 +299,6 @@ int acpi_unbind_one(struct device *dev) } EXPORT_SYMBOL_GPL(acpi_unbind_one); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr) -{ - struct acpi_device *adev; - - if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev)) - ACPI_COMPANION_SET(dev, adev); -} -EXPORT_SYMBOL_GPL(acpi_preset_companion); - static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 8e22d9762328..9e69a5308693 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -178,12 +178,12 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { /* bind acpi handle to pata port */ void ata_acpi_bind_port(struct ata_port *ap) { - acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); + struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); - if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle) + if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) return; - acpi_preset_companion(&ap->tdev, host_handle, ap->port_no); + acpi_preset_companion(&ap->tdev, host_companion, ap->port_no); if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; @@ -196,17 +196,17 @@ void ata_acpi_bind_port(struct ata_port *ap) void ata_acpi_bind_dev(struct ata_device *dev) { struct ata_port *ap = dev->link->ap; - acpi_handle port_handle = ACPI_HANDLE(&ap->tdev); - acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); - acpi_handle parent_handle; + struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); + struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); + struct acpi_device *parent; u64 adr; /* - * For both sata/pata devices, host handle is required. - * For pata device, port handle is also required. + * For both sata/pata devices, host companion device is required. + * For pata device, port companion device is also required. */ - if (libata_noacpi || !host_handle || - (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle)) + if (libata_noacpi || !host_companion || + (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion)) return; if (ap->flags & ATA_FLAG_ACPI_SATA) { @@ -214,13 +214,13 @@ void ata_acpi_bind_dev(struct ata_device *dev) adr = SATA_ADR(ap->port_no, NO_PORT_MULT); else adr = SATA_ADR(ap->port_no, dev->link->pmp); - parent_handle = host_handle; + parent = host_companion; } else { adr = dev->devno; - parent_handle = port_handle; + parent = port_companion; } - acpi_preset_companion(&dev->tdev, parent_handle, adr); + acpi_preset_companion(&dev->tdev, parent, adr); register_hotplug_dock_device(ata_dev_acpi_handle(dev), &ata_acpi_dev_dock_ops, dev, NULL, NULL); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 157b570ba343..92d1ba8e8153 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -308,7 +308,7 @@ static void sdio_acpi_set_handle(struct sdio_func *func) struct mmc_host *host = func->card->host; u64 addr = (host->slotno << 16) | func->num; - acpi_preset_companion(&func->dev, ACPI_HANDLE(host->parent), addr); + acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); } #else static inline void sdio_acpi_set_handle(struct sdio_func *func) {} diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a1a48f27933a..918eaab892e1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -435,7 +435,6 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); acpi_handle acpi_get_child(acpi_handle handle, u64 addr); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d9099b15b472..115c610324d1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -53,6 +53,12 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) #define ACPI_COMPANION_SET(dev, adev) ACPI_COMPANION(dev) = (adev) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) +static inline void acpi_preset_companion(struct device *dev, + struct acpi_device *parent, u64 addr) +{ + ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, NULL)); +} + static inline const char *acpi_dev_name(struct acpi_device *adev) { return dev_name(&adev->dev); -- cgit v1.2.3 From e3f02c5228c4b600abf6ca243301176f25553bd5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Nov 2013 16:27:34 +0100 Subject: ACPI / bind: Rework struct acpi_bus_type Replace the .find_device function pointer in struct acpi_bus_type with a new one, .find_companion, that is supposed to point to a function returning struct acpi_device pointer (instead of an int) and takes one argument (instead of two). This way the role of this callback is more clear and the implementation of it can be more straightforward. Update all of the users of struct acpi_bus_type (PCI, PNP/ACPI and USB) to reflect the structure change. Signed-off-by: Rafael J. Wysocki Tested-by: Lan Tianyu # for USB/ACPI --- drivers/acpi/glue.c | 12 +++++++----- drivers/pci/pci-acpi.c | 12 +++--------- drivers/pnp/pnpacpi/core.c | 21 ++++++++------------- drivers/usb/core/usb-acpi.c | 40 ++++++++++++++++++++-------------------- include/acpi/acpi_bus.h | 2 +- 5 files changed, 39 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index c0d18b2145c1..7608d66f289b 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -37,7 +37,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type) { if (acpi_disabled) return -ENODEV; - if (type && type->match && type->find_device) { + if (type && type->match && type->find_companion) { down_write(&bus_type_sem); list_add_tail(&type->list, &bus_type_list); up_write(&bus_type_sem); @@ -302,17 +302,19 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one); static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); - acpi_handle handle; int ret; ret = acpi_bind_one(dev, NULL); if (ret && type) { - ret = type->find_device(dev, &handle); - if (ret) { + struct acpi_device *adev; + + adev = type->find_companion(dev); + if (!adev) { DBG("Unable to get handle for %s\n", dev_name(dev)); + ret = -ENODEV; goto out; } - ret = acpi_bind_one(dev, handle); + ret = acpi_bind_one(dev, adev->handle); if (ret) goto out; } diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index adbf34003995..ce31eb0cdca7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -303,10 +303,9 @@ void acpi_pci_remove_bus(struct pci_bus *bus) } /* ACPI bus type */ -static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) +static struct acpi_device *acpi_pci_find_companion(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct acpi_device *adev; bool check_children; u64 addr; @@ -319,13 +318,8 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, + return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, check_children); - if (adev) { - *handle = adev->handle; - return 0; - } - return -ENODEV; } static void pci_acpi_setup(struct device *dev) @@ -365,7 +359,7 @@ static bool pci_acpi_bus_match(struct device *dev) static struct acpi_bus_type acpi_pci_bus = { .name = "PCI", .match = pci_acpi_bus_match, - .find_device = acpi_pci_find_device, + .find_companion = acpi_pci_find_companion, .setup = pci_acpi_setup, .cleanup = pci_acpi_cleanup, }; diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index e869ba698ac0..156d14e2587e 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -328,20 +328,15 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp) && compare_pnp_id(pnp->id, acpi_device_hid(acpi)); } -static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle) +static struct acpi_device * __init acpi_pnp_find_companion(struct device *dev) { - struct device *adev; - struct acpi_device *acpi; - - adev = bus_find_device(&acpi_bus_type, NULL, - to_pnp_dev(dev), acpi_pnp_match); - if (!adev) - return -ENODEV; + dev = bus_find_device(&acpi_bus_type, NULL, to_pnp_dev(dev), + acpi_pnp_match); + if (!dev) + return NULL; - acpi = to_acpi_device(adev); - *handle = acpi->handle; - put_device(adev); - return 0; + put_device(dev); + return to_acpi_device(dev); } /* complete initialization of a PNPACPI device includes having @@ -355,7 +350,7 @@ static bool acpi_pnp_bus_match(struct device *dev) static struct acpi_bus_type __initdata acpi_pnp_bus = { .name = "PNP", .match = acpi_pnp_bus_match, - .find_device = acpi_pnp_find_device, + .find_companion = acpi_pnp_find_companion, }; int pnpacpi_disabled __initdata; diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 11c656976cb5..f0155a39aaa3 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -126,7 +126,7 @@ out: return ret; } -static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) +static struct acpi_device *usb_acpi_find_companion(struct device *dev) { struct usb_device *udev; acpi_handle *parent_handle; @@ -168,16 +168,15 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) break; } - return -ENODEV; + return NULL; } /* root hub's parent is the usb hcd. */ - parent_handle = ACPI_HANDLE(dev->parent); - *handle = acpi_get_child(parent_handle, udev->portnum); - if (!*handle) - return -ENODEV; - return 0; + return acpi_find_child_device(ACPI_COMPANION(dev->parent), + udev->portnum, false); } else if (is_usb_port(dev)) { + struct acpi_device *adev = NULL; + sscanf(dev_name(dev), "port%d", &port_num); /* Get the struct usb_device point of port's hub */ udev = to_usb_device(dev->parent->parent); @@ -193,26 +192,27 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) raw_port_num = usb_hcd_find_raw_port_number(hcd, port_num); - *handle = acpi_get_child(ACPI_HANDLE(&udev->dev), - raw_port_num); - if (!*handle) - return -ENODEV; + adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), + raw_port_num, false); + if (!adev) + return NULL; } else { parent_handle = usb_get_hub_port_acpi_handle(udev->parent, udev->portnum); if (!parent_handle) - return -ENODEV; + return NULL; - *handle = acpi_get_child(parent_handle, port_num); - if (!*handle) - return -ENODEV; + acpi_bus_get_device(parent_handle, &adev); + adev = acpi_find_child_device(adev, port_num, false); + if (!adev) + return NULL; } - usb_acpi_check_port_connect_type(udev, *handle, port_num); - } else - return -ENODEV; + usb_acpi_check_port_connect_type(udev, adev->handle, port_num); + return adev; + } - return 0; + return NULL; } static bool usb_acpi_bus_match(struct device *dev) @@ -223,7 +223,7 @@ static bool usb_acpi_bus_match(struct device *dev) static struct acpi_bus_type usb_acpi_bus = { .name = "USB", .match = usb_acpi_bus_match, - .find_device = usb_acpi_find_device, + .find_companion = usb_acpi_find_companion, }; int usb_acpi_register(void) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 918eaab892e1..a50898e67a68 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -412,7 +412,7 @@ struct acpi_bus_type { struct list_head list; const char *name; bool (*match)(struct device *dev); - int (*find_device) (struct device *, acpi_handle *); + struct acpi_device * (*find_companion)(struct device *); void (*setup)(struct device *); void (*cleanup)(struct device *); }; -- cgit v1.2.3 From 24dee1fc99fd6d38fc859d7f6dda1dab21493bef Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Nov 2013 16:27:43 +0100 Subject: ACPI / bind: Pass struct acpi_device pointer to acpi_bind_one() There is no reason to pass an ACPI handle to acpi_bind_one() instead of a struct acpi_device pointer to the target device object, so modify that function to take a struct acpi_device pointer as its second argument and update all code depending on it accordingly. Signed-off-by: Rafael J. Wysocki Tested-by: Lan Tianyu # for USB/ACPI --- drivers/acpi/acpi_memhotplug.c | 15 +++++++-------- drivers/acpi/acpi_processor.c | 2 +- drivers/acpi/glue.c | 9 +++------ drivers/acpi/internal.h | 2 +- 4 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 551dad712ffe..9aeacdfca410 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -180,14 +180,14 @@ static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info) static int acpi_bind_memblk(struct memory_block *mem, void *arg) { - return acpi_bind_one(&mem->dev, (acpi_handle)arg); + return acpi_bind_one(&mem->dev, arg); } static int acpi_bind_memory_blocks(struct acpi_memory_info *info, - acpi_handle handle) + struct acpi_device *adev) { return walk_memory_range(acpi_meminfo_start_pfn(info), - acpi_meminfo_end_pfn(info), (void *)handle, + acpi_meminfo_end_pfn(info), adev, acpi_bind_memblk); } @@ -197,8 +197,7 @@ static int acpi_unbind_memblk(struct memory_block *mem, void *arg) return 0; } -static void acpi_unbind_memory_blocks(struct acpi_memory_info *info, - acpi_handle handle) +static void acpi_unbind_memory_blocks(struct acpi_memory_info *info) { walk_memory_range(acpi_meminfo_start_pfn(info), acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk); @@ -242,9 +241,9 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) if (result && result != -EEXIST) continue; - result = acpi_bind_memory_blocks(info, handle); + result = acpi_bind_memory_blocks(info, mem_device->device); if (result) { - acpi_unbind_memory_blocks(info, handle); + acpi_unbind_memory_blocks(info); return -ENODEV; } @@ -285,7 +284,7 @@ static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device) if (nid == NUMA_NO_NODE) nid = memory_add_physaddr_to_nid(info->start_addr); - acpi_unbind_memory_blocks(info, handle); + acpi_unbind_memory_blocks(info); remove_memory(nid, info->start_addr, info->length); list_del(&info->list); kfree(info); diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 3c1d6b0c09a4..d58a2aba0930 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -395,7 +395,7 @@ static int acpi_processor_add(struct acpi_device *device, goto err; } - result = acpi_bind_one(dev, pr->handle); + result = acpi_bind_one(dev, device); if (result) goto err; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7608d66f289b..896351b9d483 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -172,9 +172,8 @@ static void acpi_physnode_link_name(char *buf, unsigned int node_id) strcpy(buf, PHYSICAL_NODE_STRING); } -int acpi_bind_one(struct device *dev, acpi_handle handle) +int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) { - struct acpi_device *acpi_dev = NULL; struct acpi_device_physical_node *physical_node, *pn; char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; struct list_head *physnode_list; @@ -182,14 +181,12 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) int retval = -EINVAL; if (ACPI_COMPANION(dev)) { - if (handle) { + if (acpi_dev) { dev_warn(dev, "ACPI companion already set\n"); return -EINVAL; } else { acpi_dev = ACPI_COMPANION(dev); } - } else { - acpi_bus_get_device(handle, &acpi_dev); } if (!acpi_dev) return -EINVAL; @@ -314,7 +311,7 @@ static int acpi_platform_notify(struct device *dev) ret = -ENODEV; goto out; } - ret = acpi_bind_one(dev, adev->handle); + ret = acpi_bind_one(dev, adev); if (ret) goto out; } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index f4aa467c407e..b125fdb0b30c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -86,7 +86,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, int type, unsigned long long sta); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); -int acpi_bind_one(struct device *dev, acpi_handle handle); +int acpi_bind_one(struct device *dev, struct acpi_device *adev); int acpi_unbind_one(struct device *dev); bool acpi_device_is_present(struct acpi_device *adev); -- cgit v1.2.3 From bfecc2b3e34c6751343bacd317c4dfd1d695142c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Nov 2013 16:27:53 +0100 Subject: ACPI / bind: Move acpi_get_child() to drivers/ide/ide-acpi.c Since drivers/ide/ide-acpi.c is the only remaining user of acpi_get_child(), move that function into that file as a static routine. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/glue.c | 12 ------------ drivers/ide/ide-acpi.c | 11 +++++++++++ include/acpi/acpi_bus.h | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 896351b9d483..0c789224d40d 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -151,18 +151,6 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, } EXPORT_SYMBOL_GPL(acpi_find_child_device); -acpi_handle acpi_get_child(acpi_handle handle, u64 addr) -{ - struct acpi_device *adev; - - if (!handle || acpi_bus_get_device(handle, &adev)) - return NULL; - - adev = acpi_find_child_device(adev, addr, false); - return adev ? adev->handle : NULL; -} -EXPORT_SYMBOL_GPL(acpi_get_child); - static void acpi_physnode_link_name(char *buf, unsigned int node_id) { if (node_id > 0) diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 333d4053e727..b6940992a6ff 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -97,6 +97,17 @@ bool ide_port_acpi(ide_hwif_t *hwif) return ide_noacpi == 0 && hwif->acpidata; } +static acpi_handle acpi_get_child(acpi_handle handle, u64 addr) +{ + struct acpi_device *adev; + + if (!handle || acpi_bus_get_device(handle, &adev)) + return NULL; + + adev = acpi_find_child_device(adev, addr, false); + return adev ? adev->handle : NULL; +} + /** * ide_get_dev_handle - finds acpi_handle and PCI device.function * @dev: device to locate diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a50898e67a68..7135fe3d6daa 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -434,7 +434,6 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); -acpi_handle acpi_get_child(acpi_handle handle, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -- cgit v1.2.3 From fe5e49cb5ac57f984a44287cf123fbbc712d7bec Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:51:46 +0800 Subject: ACPI: Clean up incorrect inclusion of an ACPICA header Since drivers/acpi/nvs.c includes and is only compiled for CONFIG_ACPI set, it doesn't need to include directly, which is formally incorrect. Remove the inclusion from that file. Signed-off-by: Lv Zheng [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/nvs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 266bc58ce0ce..386a9fe497b4 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -13,7 +13,6 @@ #include #include #include -#include /* ACPI NVS regions, APEI may use it */ -- cgit v1.2.3 From c099eacbcaec4475936fbf73e499507728ce47e1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:51:59 +0800 Subject: SFI / ACPI: Fix warnings reported during builds with W=1 The following warnings can be seen in W=1 builds, because the original sfi_acpi.[ch] header inclusions are incorrect: include/linux/sfi_acpi.h:72:2: error: implicit declaration of function 'acpi_table_parse' [-Werror=implicit-function-declaration] drivers/sfi/sfi_acpi.c:154:5: warning: no previous prototype for 'sfi_acpi_table_parse' [-Wmissing-prototypes] Fix linux/sfi_acpi.h and modify drivers/sfi/sfi_acpi.c accordingly. Reported-by: Andy Shevchenko Signed-off-by: Lv Zheng [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- arch/x86/pci/mmconfig-shared.c | 1 - drivers/sfi/sfi_acpi.c | 4 +--- include/linux/sfi_acpi.h | 3 +++ 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 082e88129712..248642f4bab7 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/sfi/sfi_acpi.c b/drivers/sfi/sfi_acpi.c index 5e753d799f61..d277b36eb389 100644 --- a/drivers/sfi/sfi_acpi.c +++ b/drivers/sfi/sfi_acpi.c @@ -60,9 +60,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include /* FIXME: inclusion should be removed */ - -#include +#include #include "sfi_core.h" /* diff --git a/include/linux/sfi_acpi.h b/include/linux/sfi_acpi.h index 2cfcb7944a49..4723bbfa1c26 100644 --- a/include/linux/sfi_acpi.h +++ b/include/linux/sfi_acpi.h @@ -59,6 +59,9 @@ #ifndef _LINUX_SFI_ACPI_H #define _LINUX_SFI_ACPI_H +#include +#include + #ifdef CONFIG_SFI #include /* FIXME: inclusion should be removed */ -- cgit v1.2.3 From 27d50c82714f6477ac690034b37d202f76eb4f70 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:52:05 +0800 Subject: ACPI / i915: Fix incorrect inclusions via To avoid build problems and breaking dependencies between ACPI header files, should not be included directly by code outside of the ACPI core subsystem. However, that is possible if is included, because that file contains a direct inclusion of . For this reason, remove the direct inclusion from , move that file from include/linux/ to include/acpi/ and make include it for CONFIG_ACPI set along with the other ACPI header files. Accordingly, Remove the inclusions of from everywhere. Of course, that causes the contents of the new file to be available for CONFIG_ACPI set only, so intel_opregion.o that depends on it should also depend on CONFIG_ACPI (and it really should not be compiled for CONFIG_ACPI unset anyway). References: https://01.org/linuxgraphics/sites/default/files/documentation/acpi_igd_opregion_spec.pdf Cc: Matthew Garrett Signed-off-by: Lv Zheng Acked-by: Daniel Vetter [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/apei-base.c | 1 - drivers/acpi/apei/apei-internal.h | 1 - drivers/acpi/apei/ghes.c | 1 - drivers/acpi/nvs.c | 1 - drivers/acpi/osl.c | 1 - drivers/gpu/drm/gma500/opregion.c | 1 - drivers/gpu/drm/i915/Makefile | 3 +-- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/intel_opregion.c | 1 - include/acpi/acpi_io.h | 17 +++++++++++++++++ include/linux/acpi.h | 1 + include/linux/acpi_io.h | 18 ------------------ 12 files changed, 21 insertions(+), 28 deletions(-) create mode 100644 include/acpi/acpi_io.h delete mode 100644 include/linux/acpi_io.h (limited to 'drivers') diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 6d2c49b86b7f..0760b75f79cc 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 21ba34a73883..e5bcd919d4e6 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -8,7 +8,6 @@ #include #include -#include struct apei_exec_context; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index a30bc313787b..694c486a12ed 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 386a9fe497b4..ef28613d5192 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -12,7 +12,6 @@ #include #include #include -#include /* ACPI NVS regions, APEI may use it */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 244be2affea7..064b8b365060 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index ad0d6de938f3..13ec6283bf59 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -22,7 +22,6 @@ * */ #include -#include #include "psb_drv.h" #include "psb_intel_reg.h" diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 41838eaa799c..d4ae48b04cf2 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -38,7 +38,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ intel_ringbuffer.o \ intel_overlay.o \ intel_sprite.o \ - intel_opregion.o \ intel_sideband.o \ intel_uncore.o \ dvo_ch7xxx.o \ @@ -51,7 +50,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915-$(CONFIG_COMPAT) += i915_ioc32.o -i915-$(CONFIG_ACPI) += intel_acpi.o +i915-$(CONFIG_ACPI) += intel_acpi.o intel_opregion.o i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ccdbecca070d..7f37b838802e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2336,8 +2336,8 @@ extern void intel_i2c_reset(struct drm_device *dev); /* intel_opregion.c */ struct intel_encoder; -extern int intel_opregion_setup(struct drm_device *dev); #ifdef CONFIG_ACPI +extern int intel_opregion_setup(struct drm_device *dev); extern void intel_opregion_init(struct drm_device *dev); extern void intel_opregion_fini(struct drm_device *dev); extern void intel_opregion_asle_intr(struct drm_device *dev); @@ -2346,6 +2346,7 @@ extern int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, extern int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state); #else +static inline int intel_opregion_setup(struct drm_device *dev) { return 0; } static inline void intel_opregion_init(struct drm_device *dev) { return; } static inline void intel_opregion_fini(struct drm_device *dev) { return; } static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6d69a9bad865..9a8804bee5cd 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -28,7 +28,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h new file mode 100644 index 000000000000..2be858018c7f --- /dev/null +++ b/include/acpi/acpi_io.h @@ -0,0 +1,17 @@ +#ifndef _ACPI_IO_H_ +#define _ACPI_IO_H_ + +#include + +static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, + acpi_size size) +{ + return ioremap_cache(phys, size); +} + +void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); + +int acpi_os_map_generic_address(struct acpi_generic_address *addr); +void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); + +#endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d9099b15b472..726a6aa62b64 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -42,6 +42,7 @@ #include #include #include +#include #include static inline acpi_handle acpi_device_handle(struct acpi_device *adev) diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h deleted file mode 100644 index 2a5a1391ce72..000000000000 --- a/include/linux/acpi_io.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ACPI_IO_H_ -#define _ACPI_IO_H_ - -#include -#include /* FIXME: inclusion should be removed */ - -static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, - acpi_size size) -{ - return ioremap_cache(phys, size); -} - -void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); - -int acpi_os_map_generic_address(struct acpi_generic_address *addr); -void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); - -#endif -- cgit v1.2.3 From 9d24622ced329e35e2349ef419355a87d94be61f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:52:19 +0800 Subject: ACPI / IBFT: Fix incorrect inclusion in iSCSI boot firmware module To avoid build problems and breaking dependencies between ACPI header files, should not be included directly by code outside of the ACPI core subsystem, but this is done by the ACPI iSCSI Boot Firmware code. The iBFT specification doesn't mention whether or not it can appear on a non-ACPI platform, but is says that ACPI 3.0b defines the mechanism. The current CONFIG_ISCSI_IBFT_FIND code doesn't use the ACPI tables API to locate the table, so it doesn't rely on CONFIG_ACPI directly. However, since iBFT is is an ACPI-based mechanism (please refer to the documentation link below for more information), it should be correct to make CONFIG_ISCSI_IBFT_FIND depend on CONFIG_ACPI (even though the table location can be implemented without using ACPI tables API). After that change, include/linux/iscsi_ibft.h can be modified to include instead of as appropriate. References: http://www.microsoft.com/whdc/system/platform/firmware/ibft.mspx Cc: Konrad Rzeszutek Wilk Cc: Peter Jones Signed-off-by: Lv Zheng [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/firmware/Kconfig | 2 +- include/linux/iscsi_ibft.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 074787281c94..a6ef6acaa1c8 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -110,7 +110,7 @@ config DMI_SYSFS config ISCSI_IBFT_FIND bool "iSCSI Boot Firmware Table Attributes" - depends on X86 + depends on X86 && ACPI default n help This option enables the kernel to find the region of memory diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h index 82f9673c2527..605cc5c333d9 100644 --- a/include/linux/iscsi_ibft.h +++ b/include/linux/iscsi_ibft.h @@ -21,7 +21,7 @@ #ifndef ISCSI_IBFT_H #define ISCSI_IBFT_H -#include /* FIXME: inclusion should be removed */ +#include /* * Logical location of iSCSI Boot Format Table. -- cgit v1.2.3 From cad1525a5e7443cd93368a22e5b7571c373c8cc0 Mon Sep 17 00:00:00 2001 From: Al Stone Date: Wed, 4 Dec 2013 12:59:11 -0700 Subject: ACPI: remove trailing whitespace Minor cleanup: remove some extra trailing white space. Signed-off-by: Al Stone Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 2 +- drivers/acpi/processor_idle.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 064b8b365060..26c111341ead 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1278,7 +1278,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) jiffies = MAX_SCHEDULE_TIMEOUT; else jiffies = msecs_to_jiffies(timeout); - + ret = down_timeout(sem, jiffies); if (ret) status = AE_TIME; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d2d44e0190a3..a0cc5ef4f06f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -596,7 +596,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) case ACPI_STATE_C2: if (!cx->address) break; - cx->valid = 1; + cx->valid = 1; break; case ACPI_STATE_C3: -- cgit v1.2.3 From 95df812dbdc350bfcf31e247e9100c378a472480 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Thu, 5 Dec 2013 23:42:38 +0800 Subject: ACPI / table: Replace '1' with specific error return values After commit 7f8f97c3cc (ACPI: acpi_table_parse() now returns success/fail, not count), acpi_table_parse() returns '1' when it is unable to find the table, but it should return a negative error code in that case. Make it return -ENODEV instead. Fix the same problem in acpi_table_init() analogously. Signed-off-by: Hanjun Guo [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index d67a1fe07f0e..4ec44258e4ff 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -306,7 +306,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) early_acpi_os_unmap_memory(table, tbl_size); return 0; } else - return 1; + return -ENODEV; } /* @@ -351,7 +351,7 @@ int __init acpi_table_init(void) status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); if (ACPI_FAILURE(status)) - return 1; + return -EINVAL; check_multiple_madt(); return 0; -- cgit v1.2.3 From 4ef54410ca6e7e5f32d67c5fb8094ae07460814a Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Fri, 6 Dec 2013 00:03:40 +0800 Subject: ACPI / dock: Drop redundant acpi_disabled check acpi_dock_init() is only called from acpi_scan_init() and the code logic shows that it doesn't need to check acpi_disabled: acpi_init(); if (acpi_disabled) return; acpi_scan_init(); acpi_dock_init(); if (acpi_disabled) /* redundant */ return; Signed-off-by: Hanjun Guo [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 9ab9e783a894..c2090c023102 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -896,9 +896,6 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) void __init acpi_dock_init(void) { - if (acpi_disabled) - return; - /* look for dock stations and bays */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); -- cgit v1.2.3 From 100eb0b04293fbb7af689ff7ddfe8fc8a46ab65c Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Fri, 6 Dec 2013 00:03:41 +0800 Subject: ACPI / sleep: Drop redundant acpi_disabled check acpi_sleep_init() is only called from acpi_bus_init() and the code logic shows that it doesn't need to check acpi_disabled: acpi_init(); if (acpi_disabled) return; acpi_bus_init(); acpi_sleep_init(); if (acpi_disabled) return 0; Signed-off-by: Hanjun Guo [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index ea9cc373ffd8..cb889c715e14 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -802,9 +802,6 @@ int __init acpi_sleep_init(void) char *pos = supported; int i; - if (acpi_disabled) - return 0; - acpi_sleep_dmi_check(); sleep_states[ACPI_STATE_S0] = 1; -- cgit v1.2.3 From 6dd7aca824df3bd2f9c684b9dc68ee00afb065e8 Mon Sep 17 00:00:00 2001 From: Al Stone Date: Thu, 5 Dec 2013 11:14:16 -0700 Subject: ACPI: correct minor typos Correct "coolign" to "cooling" and "*_ptg" to "*_pctg" as intended. This changes comment text only. Signed-off-by: Al Stone Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_thermal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index f95e7584d6e6..e003663b2f8e 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -183,14 +183,14 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) #endif -/* thermal coolign device callbacks */ +/* thermal cooling device callbacks */ static int acpi_processor_max_state(struct acpi_processor *pr) { int max_state = 0; /* * There exists four states according to - * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 + * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3 */ max_state += cpufreq_get_max_state(pr->id); if (pr->flags.throttling) -- cgit v1.2.3 From d0a7edbb6608d05b0718a0949be914067b5980fb Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 6 Dec 2013 15:36:26 +0800 Subject: ACPI / processor: use ACPI_COMPANION() to get ACPI device Use ACPI_COMPANION() to get an ACPI device instead of acpi_bus_get_device() in the processor driver. Signed-off-by: Lan Tianyu [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 146ab7e2b81d..c1c35623550f 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -224,9 +224,9 @@ static int __acpi_processor_start(struct acpi_device *device) static int acpi_processor_start(struct device *dev) { - struct acpi_device *device; + struct acpi_device *device = ACPI_COMPANION(dev); - if (acpi_bus_get_device(ACPI_HANDLE(dev), &device)) + if (!device) return -ENODEV; return __acpi_processor_start(device); @@ -234,10 +234,10 @@ static int acpi_processor_start(struct device *dev) static int acpi_processor_stop(struct device *dev) { - struct acpi_device *device; + struct acpi_device *device = ACPI_COMPANION(dev); struct acpi_processor *pr; - if (acpi_bus_get_device(ACPI_HANDLE(dev), &device)) + if (!device) return 0; acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, -- cgit v1.2.3 From 8eaa29f92a66c92ade1ad663d14d975d776ef492 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 12 Dec 2013 18:08:17 +0800 Subject: ACPI / Button: Fix enabling button GPEs twice Button GPEs have been enabled in the acpi_wake_device_init() during boot and the button driver enables them for the second time. Consequently, it is necessary to do # echo disable > /sys/firmware/acpi/interrupts/gpeXXX twice in a row to disable those GPEs via sysfs. This patch is to remove the GPE enabling code from the button driver to avoid the problem. Signed-off-by: Lan Tianyu [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c971929d75c2..5401e9a98b35 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -101,7 +101,6 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; - bool wakeup_enabled; }; static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); @@ -407,16 +406,6 @@ static int acpi_button_add(struct acpi_device *device) lid_device = device; } - if (device->wakeup.flags.valid) { - /* Button's GPE is run-wake GPE */ - acpi_enable_gpe(device->wakeup.gpe_device, - device->wakeup.gpe_number); - if (!device_may_wakeup(&device->dev)) { - device_set_wakeup_enable(&device->dev, true); - button->wakeup_enabled = true; - } - } - printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); return 0; @@ -433,13 +422,6 @@ static int acpi_button_remove(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); - if (device->wakeup.flags.valid) { - acpi_disable_gpe(device->wakeup.gpe_device, - device->wakeup.gpe_number); - if (button->wakeup_enabled) - device_set_wakeup_enable(&device->dev, false); - } - acpi_button_remove_fs(device); input_unregister_device(button->input); kfree(button); -- cgit v1.2.3 From 42b946bb35ef0057f13887dec5f081df0ba8840a Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 12 Dec 2013 18:08:52 +0800 Subject: ACPI / EC: disable GPE before removing GPE handler Adjust the order of disabling the EC GPE and removing its handler to avoid unhandled events. Signed-off-by: Lan Tianyu [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ba5b56db9d27..7dac048e8f07 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -779,9 +779,9 @@ static int ec_install_handlers(struct acpi_ec *ec) pr_err("Fail in evaluating the _REG object" " of EC device. Broken bios is suspected.\n"); } else { + acpi_disable_gpe(NULL, ec->gpe); acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); - acpi_disable_gpe(NULL, ec->gpe); return -ENODEV; } } -- cgit v1.2.3 From 43575faab3967b7b48aeb1c30f823b8233517552 Mon Sep 17 00:00:00 2001 From: Al Stone Date: Mon, 16 Dec 2013 17:01:37 -0700 Subject: ACPI / processor: initialize a variable to silence compiler warning In acpi_processor_resume(), the variable resumed_bm_rld is being used without being initialized, so initialize it. Signed-off-by: Al Stone Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index a0cc5ef4f06f..799644c3888c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -211,7 +211,7 @@ static int acpi_processor_suspend(void) static void acpi_processor_resume(void) { - u32 resumed_bm_rld; + u32 resumed_bm_rld = 0; acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld); if (resumed_bm_rld == saved_bm_rld) -- cgit v1.2.3 From 0039735e960e1f39e777aab7087d438507d9819f Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 20 Dec 2013 00:51:37 +0900 Subject: ACPI / video: Fix typo in video_detect.c Correct "**retyurn_value" to "**return_value". Signed-off-by: Masanari Iida Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video_detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 84875fd4c74f..f0447d3daf2c 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -50,7 +50,7 @@ static bool acpi_video_caps_checked; static acpi_status acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, - void **retyurn_value) + void **return_value) { long *cap = context; -- cgit v1.2.3 From 2d4054d8422462cb2771fdb4eb1925df55d2b320 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Dec 2013 17:09:12 +0100 Subject: ACPI: Blacklist Win8 OSI for some HP laptop 2013 models The BIOS on recent HP laptops behaves differently with Win8 OSI, e.g. no backlight control and no rfkill are available. List them in the blacklist as a workaround. This patch tries to reduce the added items by matching "G1" suffix, e.g. machines are named like "HP ProBook 430 G1". References: https://bugzilla.novell.com/show_bug.cgi?id=856294 Signed-off-by: Takashi Iwai Signed-off-by: Rafael J. Wysocki --- drivers/acpi/blacklist.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 078c4f7fe2dd..40c91f5052ef 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -323,6 +323,56 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"), }, }, + { + .callback = dmi_disable_osi_win8, + .ident = "HP ProBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "HP EliteBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "HP ZBook 14", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "HP ZBook 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "HP ZBook 17", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"), + }, + }, + { + .callback = dmi_disable_osi_win8, + .ident = "HP EliteBook 8780w", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"), + }, + }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. -- cgit v1.2.3 From 007bea098b869945a462420a1f9d442ff169f722 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Wed, 18 Dec 2013 10:32:39 -0800 Subject: intel_pstate: Add setting voltage value for baytrail P states. Baytrail requires setting P state and voltage pairs when adjusting the requested P state. Add function for retrieving the valid voltage values and modify *_set_pstate() functions to caluclate the appropriate voltage for the requested P state. Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 58 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 5f1cbae36961..c84b280238a4 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -35,6 +35,7 @@ #define SAMPLE_COUNT 3 #define BYT_RATIOS 0x66a +#define BYT_VIDS 0x66b #define FRAC_BITS 8 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) @@ -64,6 +65,12 @@ struct pstate_data { int turbo_pstate; }; +struct vid_data { + int32_t min; + int32_t max; + int32_t ratio; +}; + struct _pid { int setpoint; int32_t integral; @@ -82,6 +89,7 @@ struct cpudata { struct timer_list timer; struct pstate_data pstate; + struct vid_data vid; struct _pid pid; int min_pstate_count; @@ -106,7 +114,8 @@ struct pstate_funcs { int (*get_max)(void); int (*get_min)(void); int (*get_turbo)(void); - void (*set)(int pstate); + void (*set)(struct cpudata*, int pstate); + void (*get_vid)(struct cpudata *); }; struct cpu_defaults { @@ -358,6 +367,42 @@ static int byt_get_max_pstate(void) return (value >> 16) & 0xFF; } +static void byt_set_pstate(struct cpudata *cpudata, int pstate) +{ + u64 val; + int32_t vid_fp; + u32 vid; + + val = pstate << 8; + if (limits.no_turbo) + val |= (u64)1 << 32; + + vid_fp = cpudata->vid.min + mul_fp( + int_tofp(pstate - cpudata->pstate.min_pstate), + cpudata->vid.ratio); + + vid_fp = clamp_t(int32_t, vid_fp, cpudata->vid.min, cpudata->vid.max); + vid = fp_toint(vid_fp); + + val |= vid; + + wrmsrl(MSR_IA32_PERF_CTL, val); +} + +static void byt_get_vid(struct cpudata *cpudata) +{ + u64 value; + + rdmsrl(BYT_VIDS, value); + cpudata->vid.min = int_tofp((value >> 8) & 0x7f); + cpudata->vid.max = int_tofp((value >> 16) & 0x7f); + cpudata->vid.ratio = div_fp( + cpudata->vid.max - cpudata->vid.min, + int_tofp(cpudata->pstate.max_pstate - + cpudata->pstate.min_pstate)); +} + + static int core_get_min_pstate(void) { u64 value; @@ -384,7 +429,7 @@ static int core_get_turbo_pstate(void) return ret; } -static void core_set_pstate(int pstate) +static void core_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; @@ -425,7 +470,8 @@ static struct cpu_defaults byt_params = { .get_max = byt_get_max_pstate, .get_min = byt_get_min_pstate, .get_turbo = byt_get_max_pstate, - .set = core_set_pstate, + .set = byt_set_pstate, + .get_vid = byt_get_vid, }, }; @@ -462,7 +508,7 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) cpu->pstate.current_pstate = pstate; - pstate_funcs.set(pstate); + pstate_funcs.set(cpu, pstate); } static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) @@ -488,6 +534,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) cpu->pstate.max_pstate = pstate_funcs.get_max(); cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); + if (pstate_funcs.get_vid) + pstate_funcs.get_vid(cpu); + /* * goto max pstate so we don't slow up boot if we are built-in if we are * a module we will take care of it during normal operation @@ -776,6 +825,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) pstate_funcs.get_min = funcs->get_min; pstate_funcs.get_turbo = funcs->get_turbo; pstate_funcs.set = funcs->set; + pstate_funcs.get_vid = funcs->get_vid; } #if IS_ENABLED(CONFIG_ACPI) -- cgit v1.2.3 From 91a4cd4f3d8169d7398f9123683f64575927c682 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Tue, 17 Dec 2013 09:42:07 -0800 Subject: intel_pstate: Remove periodic P state boost Remove the periodic P state boost. This code required for some corner case benchmark tests. The calculation of the required P state was incorrect/inaccurate and would not allow P state increase. This was fixed by a combination of commits: 2134ed4 cpufreq / intel_pstate: Change to scale off of max P-state d253d2a intel_pstate: Improve accuracy by not truncating until final result References: https://bugzilla.kernel.org/show_bug.cgi?id=64271 Reported-by: Doug Smythies Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index c84b280238a4..41e21bb01c9c 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -92,8 +92,6 @@ struct cpudata { struct vid_data vid; struct _pid pid; - int min_pstate_count; - u64 prev_aperf; u64 prev_mperf; int sample_ptr; @@ -617,15 +615,6 @@ static void intel_pstate_timer_func(unsigned long __data) intel_pstate_sample(cpu); intel_pstate_adjust_busy_pstate(cpu); - - if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) { - cpu->min_pstate_count++; - if (!(cpu->min_pstate_count % 5)) { - intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate); - } - } else - cpu->min_pstate_count = 0; - intel_pstate_set_sample_time(cpu); } -- cgit v1.2.3 From 717e5d458e3bfca495a38dca61c64f274c049e46 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 10 Dec 2013 14:37:41 +0100 Subject: PM / Runtime: Implement the pm_generic_runtime functions for CONFIG_PM The pm_generic_runtime_suspend|resume functions were implemented within CONFIG_PM_RUNTIME. As we also may use runtime PM callbacks during system suspend, to put devices into low power state, we need to move the implementation of pm_generic_runtime_suspend|resume to CONFIG_PM. This change gives a power domain provision to invoke a platform driver's runtime PM callback from a power domain's system PM callback. This were earlier prevented by the platform bus, since it uses the pm_generic_runtime_suspend|resume functions as runtime PM callbacks. Cc: Kevin Hilman Cc: Alan Stern Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/generic_ops.c | 4 ++-- include/linux/pm_runtime.h | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 5ee030a864f9..a2e55bfdf572 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -10,7 +10,7 @@ #include #include -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM /** * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. * @dev: Device to suspend. @@ -48,7 +48,7 @@ int pm_generic_runtime_resume(struct device *dev) return ret; } EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); -#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ #ifdef CONFIG_PM_SLEEP /** diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 6fa7cea25da9..16c9a62fa1c0 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -23,6 +23,14 @@ usage_count */ #define RPM_AUTO 0x08 /* Use autosuspend_delay */ +#ifdef CONFIG_PM +extern int pm_generic_runtime_suspend(struct device *dev); +extern int pm_generic_runtime_resume(struct device *dev); +#else +static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } +static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } +#endif + #ifdef CONFIG_PM_RUNTIME extern struct workqueue_struct *pm_wq; @@ -37,8 +45,6 @@ extern void pm_runtime_enable(struct device *dev); extern void __pm_runtime_disable(struct device *dev, bool check_resume); extern void pm_runtime_allow(struct device *dev); extern void pm_runtime_forbid(struct device *dev); -extern int pm_generic_runtime_suspend(struct device *dev); -extern int pm_generic_runtime_resume(struct device *dev); extern void pm_runtime_no_callbacks(struct device *dev); extern void pm_runtime_irq_safe(struct device *dev); extern void __pm_runtime_use_autosuspend(struct device *dev, bool use); @@ -142,8 +148,6 @@ static inline bool pm_runtime_active(struct device *dev) { return true; } static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } static inline bool pm_runtime_enabled(struct device *dev) { return false; } -static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } -static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } static inline void pm_runtime_no_callbacks(struct device *dev) {} static inline void pm_runtime_irq_safe(struct device *dev) {} -- cgit v1.2.3 From b4f6b3a59460ad16e1b260d6b866e8328f690edb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 11 Dec 2013 22:12:26 +0000 Subject: cpufreq: Make ARM big.LITTLE switcher depend on ARM The patch currently under review to enable ARM cpufreq drivers for ARM64 which is useful due to the large amount of shared IP between ARM and ARM64 SoCs. However the big.LITTLE switcher relies on an architecture interface to build which is not present on ARM64. Add a dependency until that is resolved. Signed-off-by: Mark Brown Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index ce52ed949249..0a141109fd29 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -4,7 +4,7 @@ config ARM_BIG_LITTLE_CPUFREQ tristate "Generic ARM big LITTLE CPUfreq driver" - depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK + depends on ARM && ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK help This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. -- cgit v1.2.3 From 109df086e002f253569de47e3a709403d3388a02 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 11 Dec 2013 22:12:27 +0000 Subject: cpufreq: Select PM_OPP rather than depending on it PM_OPP is a helper library used by several of the existing cpufreq drivers. Some of the drivers select this symbol while others depend on it and rely on the architecture to enable it. Make this behaviour more consistent and obvious by having all the drivers select the symbol. This will also allow better build coverage of the affected drivers. Signed-off-by: Mark Brown Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig | 3 ++- drivers/cpufreq/Kconfig.arm | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 38093e272377..386dbc9ccdfd 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -181,7 +181,8 @@ config CPU_FREQ_GOV_CONSERVATIVE config GENERIC_CPUFREQ_CPU0 tristate "Generic CPU0 cpufreq driver" - depends on HAVE_CLK && REGULATOR && PM_OPP && OF + depends on HAVE_CLK && REGULATOR && OF + select PM_OPP help This adds a generic cpufreq driver for CPU0 frequency management. It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0a141109fd29..456ba5e1781c 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -4,7 +4,8 @@ config ARM_BIG_LITTLE_CPUFREQ tristate "Generic ARM big LITTLE CPUfreq driver" - depends on ARM && ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK + depends on ARM && ARM_CPU_TOPOLOGY && HAVE_CLK + select PM_OPP help This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. @@ -54,7 +55,8 @@ config ARM_EXYNOS5250_CPUFREQ config ARM_EXYNOS5440_CPUFREQ bool "SAMSUNG EXYNOS5440" depends on SOC_EXYNOS5440 - depends on HAVE_CLK && PM_OPP && OF + depends on HAVE_CLK && OF + select PM_OPP default y help This adds the CPUFreq driver for Samsung EXYNOS5440 -- cgit v1.2.3 From 249135d1a2ea3c1719c48d31351413d55d2fdef4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 15 Dec 2013 04:10:11 -0800 Subject: PNPACPI: check return value of pnp_add_device() pnp_add_device() may fail so we need to handle errors and avoid leaking memory. Also, do not use ACPI-specific return codes (AE_OK) but rather standard one (0). Signed-off-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/pnp/pnpacpi/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 14655a0f0431..4bd4c54ad205 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -242,6 +242,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) struct pnp_dev *dev; char *pnpid; struct acpi_hardware_id *id; + int error; /* Skip devices that are already bound */ if (device->physical_node_count) @@ -300,10 +301,16 @@ static int __init pnpacpi_add_device(struct acpi_device *device) /* clear out the damaged flags */ if (!dev->active) pnp_init_resources(dev); - pnp_add_device(dev); + + error = pnp_add_device(dev); + if (error) { + put_device(&dev->dev); + return error; + } + num++; - return AE_OK; + return 0; } static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, -- cgit v1.2.3 From d22ddcbc4fb7a483d0721eddfda3f0558821d372 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 29 Dec 2013 15:25:35 +0100 Subject: ACPI / hotplug: Add demand_offline hotplug profile flag Add a new ACPI hotplug profile flag, demand_offline, such that if set for the given ACPI device object's scan handler, it will cause acpi_scan_hot_remove() to check if that device object's physical companions are offline upfront and fail the hot removal if that is not the case. That flag will be useful to overcome a problem with containers on some system where they can only be hot-removed after some cleanup operations carried out by user space, which needs to be notified of the container hot-removal before the kernel attempts to offline devices in the container. In those cases the current implementation of acpi_scan_hot_remove() is not sufficient, because it first tries to offline the devices in the container and only if that is suffcessful it tries to offline the container itself. As a result, the container hot-removal notification is not delivered to user space at the right time. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 41 +++++++++++++++++++++++++++++++++++++---- include/acpi/acpi_bus.h | 3 ++- 2 files changed, 39 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5383c81a8a1b..65243b9dd868 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -126,6 +126,24 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); +static bool acpi_scan_is_offline(struct acpi_device *adev) +{ + struct acpi_device_physical_node *pn; + bool offline = true; + + mutex_lock(&adev->physical_node_lock); + + list_for_each_entry(pn, &adev->physical_node_list, node) + if (device_supports_offline(pn->dev) && !pn->dev->offline) { + kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); + offline = false; + break; + } + + mutex_unlock(&adev->physical_node_lock); + return offline; +} + static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p) { @@ -196,12 +214,11 @@ static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, return AE_OK; } -static int acpi_scan_hot_remove(struct acpi_device *device) +static int acpi_scan_try_to_offline(struct acpi_device *device) { acpi_handle handle = device->handle; - struct device *errdev; + struct device *errdev = NULL; acpi_status status; - unsigned long long sta; /* * Carry out two passes here and ignore errors in the first pass, @@ -212,7 +229,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) * * If the first pass is successful, the second one isn't needed, though. */ - errdev = NULL; status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)false, (void **)&errdev); @@ -241,6 +257,23 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return -EBUSY; } } + return 0; +} + +static int acpi_scan_hot_remove(struct acpi_device *device) +{ + acpi_handle handle = device->handle; + unsigned long long sta; + acpi_status status; + + if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) { + if (!acpi_scan_is_offline(device)) + return -EBUSY; + } else { + int error = acpi_scan_try_to_offline(device); + if (error) + return error; + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Hot-removing device %s...\n", dev_name(&device->dev))); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7135fe3d6daa..48d302501539 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,8 +91,9 @@ struct acpi_device; struct acpi_hotplug_profile { struct kobject kobj; - bool enabled:1; int (*scan_dependent)(struct acpi_device *adev); + bool enabled:1; + bool demand_offline:1; }; static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile( -- cgit v1.2.3 From caa73ea158de9419f08e456f2716c71d1f06012a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 29 Dec 2013 15:25:48 +0100 Subject: ACPI / hotplug / driver core: Handle containers in a special way ACPI container devices require special hotplug handling, at least on some systems, since generally user space needs to carry out system-specific cleanup before it makes sense to offline devices in the container. However, the current ACPI hotplug code for containers first attempts to offline devices in the container and only then it notifies user space of the container offline. Moreover, after commit 202317a573b2 (ACPI / scan: Add acpi_device objects for all device nodes in the namespace), ACPI device objects representing containers are present as long as the ACPI namespace nodes corresponding to them are present, which may be forever, even if the container devices are physically detached from the system (the return values of the corresponding _STA methods change in those cases, but generally the namespace nodes themselves are still there). Thus it is useful to introduce entities representing containers that will go away during container hot-unplug. The goal of this change is to address both the above issues. The idea is to create a "companion" container system device for each of the ACPI container device objects during the initial namespace scan or on a hotplug event making the container present. That system device will be unregistered on container removal. A new bus type for container devices is added for this purpose, because device offline and online operations need to be defined for them. The online operation is a trivial function that is always successful and the offline uses a callback pointed to by the container device's offline member. For ACPI containers that callback simply walks the list of ACPI device objects right below the container object (its children) and checks if all of their physical companion devices are offline. If that's not the case, it returns -EBUSY and the container system devivce cannot be put offline. Consequently, to put the container system device offline, it is necessary to put all of the physical devices depending on its ACPI companion object offline beforehand. Container system devices created for ACPI container objects are initially online. They are created by the container ACPI scan handler whose hotplug.demand_offline flag is set. That causes acpi_scan_hot_remove() to check if the companion container system device is offline before attempting to remove an ACPI container or any devices below it. If the check fails, a KOBJ_CHANGE uevent is emitted for the container system device in question and user space is expected to offline all devices below the container and the container itself in response to it. Then, user space can finalize the removal of the container with the help of its ACPI device object's eject attribute in sysfs. Tested-by: Yasuaki Ishimatsu Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman --- drivers/acpi/container.c | 48 +++++++++++++++++++++++++++++++++++++++++++---- drivers/acpi/internal.h | 1 + drivers/acpi/scan.c | 8 +++++--- drivers/base/Makefile | 2 +- drivers/base/base.h | 1 + drivers/base/container.c | 44 +++++++++++++++++++++++++++++++++++++++++++ drivers/base/init.c | 1 + include/linux/container.h | 25 ++++++++++++++++++++++++ 8 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 drivers/base/container.c create mode 100644 include/linux/container.h (limited to 'drivers') diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 83d232c10f13..0b6ae6eb5c4a 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -27,8 +27,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include - -#include "internal.h" +#include #include "internal.h" @@ -44,16 +43,56 @@ static const struct acpi_device_id container_device_ids[] = { {"", 0}, }; +static int acpi_container_offline(struct container_dev *cdev) +{ + struct acpi_device *adev = ACPI_COMPANION(&cdev->dev); + struct acpi_device *child; + + /* Check all of the dependent devices' physical companions. */ + list_for_each_entry(child, &adev->children, node) + if (!acpi_scan_is_offline(child, false)) + return -EBUSY; + + return 0; +} + +static void acpi_container_release(struct device *dev) +{ + kfree(to_container_dev(dev)); +} + static int container_device_attach(struct acpi_device *adev, const struct acpi_device_id *not_used) { - kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); + struct container_dev *cdev; + struct device *dev; + int ret; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->offline = acpi_container_offline; + dev = &cdev->dev; + dev->bus = &container_subsys; + dev_set_name(dev, "%s", dev_name(&adev->dev)); + ACPI_COMPANION_SET(dev, adev); + dev->release = acpi_container_release; + ret = device_register(dev); + if (ret) + return ret; + + adev->driver_data = dev; return 1; } static void container_device_detach(struct acpi_device *adev) { - kobject_uevent(&adev->dev.kobj, KOBJ_OFFLINE); + struct device *dev = acpi_driver_data(adev); + + adev->driver_data = NULL; + if (dev) + device_unregister(dev); } static struct acpi_scan_handler container_handler = { @@ -62,6 +101,7 @@ static struct acpi_scan_handler container_handler = { .detach = container_device_detach, .hotplug = { .enabled = true, + .demand_offline = true, }, }; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index b125fdb0b30c..3375129bb5b7 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {} #endif bool acpi_queue_hotplug_work(struct work_struct *work); +bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); /* -------------------------------------------------------------------------- Device Node Initialization / Removal diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 65243b9dd868..32b340171d41 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -126,7 +126,7 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); -static bool acpi_scan_is_offline(struct acpi_device *adev) +bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) { struct acpi_device_physical_node *pn; bool offline = true; @@ -135,7 +135,9 @@ static bool acpi_scan_is_offline(struct acpi_device *adev) list_for_each_entry(pn, &adev->physical_node_list, node) if (device_supports_offline(pn->dev) && !pn->dev->offline) { - kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); + if (uevent) + kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); + offline = false; break; } @@ -267,7 +269,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_status status; if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) { - if (!acpi_scan_is_offline(device)) + if (!acpi_scan_is_offline(device, true)) return -EBUSY; } else { int error = acpi_scan_try_to_offline(device); diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 94e8a80e87f8..d08c9d3b1d37 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -4,7 +4,7 @@ obj-y := core.o bus.o dd.o syscore.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o \ - topology.o + topology.o container.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o obj-$(CONFIG_DMA_CMA) += dma-contiguous.o obj-y += power/ diff --git a/drivers/base/base.h b/drivers/base/base.h index 2cbc6774f4cd..24f424249d9b 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -100,6 +100,7 @@ static inline int hypervisor_init(void) { return 0; } #endif extern int platform_bus_init(void); extern void cpu_dev_init(void); +extern void container_dev_init(void); struct kobject *virtual_device_parent(struct device *dev); diff --git a/drivers/base/container.c b/drivers/base/container.c new file mode 100644 index 000000000000..ecbfbe2e908f --- /dev/null +++ b/drivers/base/container.c @@ -0,0 +1,44 @@ +/* + * System bus type for containers. + * + * Copyright (C) 2013, Intel Corporation + * Author: Rafael J. Wysocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#include "base.h" + +#define CONTAINER_BUS_NAME "container" + +static int trivial_online(struct device *dev) +{ + return 0; +} + +static int container_offline(struct device *dev) +{ + struct container_dev *cdev = to_container_dev(dev); + + return cdev->offline ? cdev->offline(cdev) : 0; +} + +struct bus_type container_subsys = { + .name = CONTAINER_BUS_NAME, + .dev_name = CONTAINER_BUS_NAME, + .online = trivial_online, + .offline = container_offline, +}; + +void __init container_dev_init(void) +{ + int ret; + + ret = subsys_system_register(&container_subsys, NULL); + if (ret) + pr_err("%s() failed: %d\n", __func__, ret); +} diff --git a/drivers/base/init.c b/drivers/base/init.c index c16f0b808a17..da033d3bab3c 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -33,4 +33,5 @@ void __init driver_init(void) platform_bus_init(); cpu_dev_init(); memory_dev_init(); + container_dev_init(); } diff --git a/include/linux/container.h b/include/linux/container.h new file mode 100644 index 000000000000..3c03e6fd2035 --- /dev/null +++ b/include/linux/container.h @@ -0,0 +1,25 @@ +/* + * Definitions for container bus type. + * + * Copyright (C) 2013, Intel Corporation + * Author: Rafael J. Wysocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +/* drivers/base/power/container.c */ +extern struct bus_type container_subsys; + +struct container_dev { + struct device dev; + int (*offline)(struct container_dev *cdev); +}; + +static inline struct container_dev *to_container_dev(struct device *dev) +{ + return container_of(dev, struct container_dev, dev); +} -- cgit v1.2.3 From a65ac52041cccaf598995bc44340849027f1d79b Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:10 +0800 Subject: ACPI: introduce helper interfaces for _DSM method There are several drivers making use of ACPI _DSM method to detect and invoke device specific methods. Currently every driver has implemented its private version to support ACPI _DSM method. So this patch introduces three helper functions to support ACPI _DSM method, which will be used to replace open-coded versions. It helps to simplify code and improve code readability. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/utils.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 26 +++++++++++++ 2 files changed, 123 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 6d408bfbbb1d..bcb2ed9e03aa 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -574,3 +574,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) return status; } + +/** + * acpi_evaluate_dsm - evaluate device's _DSM method + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes + * @rev: revision number of requested function + * @func: requested function number + * @argv4: the function specific parameter + * + * Evaluate device's _DSM method with specified UUID, revision id and + * function number. Caller needs to free the returned object. + * + * Though ACPI defines the fourth parameter for _DSM should be a package, + * some old BIOSes do expect a buffer or an integer etc. + */ +union acpi_object * +acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func, + union acpi_object *argv4) +{ + acpi_status ret; + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object params[4]; + struct acpi_object_list input = { + .count = 4, + .pointer = params, + }; + + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = 16; + params[0].buffer.pointer = (char *)uuid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = rev; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + if (argv4) { + params[3] = *argv4; + } else { + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + } + + ret = acpi_evaluate_object(handle, "_DSM", &input, &buf); + if (ACPI_SUCCESS(ret)) + return (union acpi_object *)buf.pointer; + + if (ret != AE_NOT_FOUND) + acpi_handle_warn(handle, + "failed to evaluate _DSM (0x%x)\n", ret); + + return NULL; +} +EXPORT_SYMBOL(acpi_evaluate_dsm); + +/** + * acpi_check_dsm - check if _DSM method supports requested functions. + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes at least + * @rev: revision number of requested functions + * @funcs: bitmap of requested functions + * @exclude: excluding special value, used to support i915 and nouveau + * + * Evaluate device's _DSM method to check whether it supports requested + * functions. Currently only support 64 functions at maximum, should be + * enough for now. + */ +bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) +{ + int i; + u64 mask = 0; + union acpi_object *obj; + + if (funcs == 0) + return false; + + obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); + if (!obj) + return false; + + /* For compatibility, old BIOSes may return an integer */ + if (obj->type == ACPI_TYPE_INTEGER) + mask = obj->integer.value; + else if (obj->type == ACPI_TYPE_BUFFER) + for (i = 0; i < obj->buffer.length && i < 8; i++) + mask |= (((u8)obj->buffer.pointer[i]) << (i * 8)); + ACPI_FREE(obj); + + /* + * Bit 0 indicates whether there's support for any functions other than + * function 0 for the specified UUID and revision. + */ + if ((mask & 0x1) && (mask & funcs) == funcs) + return true; + + return false; +} +EXPORT_SYMBOL(acpi_check_dsm); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ddabed1f51c2..dd9b5edc7630 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -66,6 +66,32 @@ bool acpi_ata_match(acpi_handle handle); bool acpi_bay_match(acpi_handle handle); bool acpi_dock_match(acpi_handle handle); +bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs); +union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, + int rev, int func, union acpi_object *argv4); + +static inline union acpi_object * +acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func, + union acpi_object *argv4, acpi_object_type type) +{ + union acpi_object *obj; + + obj = acpi_evaluate_dsm(handle, uuid, rev, func, argv4); + if (obj && obj->type != type) { + ACPI_FREE(obj); + obj = NULL; + } + + return obj; +} + +#define ACPI_INIT_DSM_ARGV4(cnt, eles) \ + { \ + .package.type = ACPI_TYPE_PACKAGE, \ + .package.count = (cnt), \ + .package.elements = (eles) \ + } + #ifdef CONFIG_ACPI #include -- cgit v1.2.3 From 54e5bb46597e5eba63e460a1f96eb2021dc71fec Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:12 +0800 Subject: PCI / pci-label: release allocated ACPI object on error recovery path Function dsm_get_label() leaks the returned ACPI object if obj->package.count is not 2, so fix the possible memory leak. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-label.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index d51f45aa669e..f6e01a500d79 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -233,11 +233,7 @@ dsm_get_label(acpi_handle handle, int func, return -1; obj = (union acpi_object *)output->pointer; - - switch (obj->type) { - case ACPI_TYPE_PACKAGE: - if (obj->package.count != 2) - break; + if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2) { len = obj->package.elements[0].integer.value; if (buf) { if (attribute == ACPI_ATTR_INDEX_SHOW) @@ -250,10 +246,10 @@ dsm_get_label(acpi_handle handle, int func, } kfree(output->pointer); return len; - break; - default: - kfree(output->pointer); } + + kfree(output->pointer); + return -1; } -- cgit v1.2.3 From 1d0fcef732832432aee47cb75bf4a2cb3107be64 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:13 +0800 Subject: ACPI / PCI: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in pci-label driver. Also enforce more strict checks on objects returned by _DSM method. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-label.c | 121 ++++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index f6e01a500d79..f12dcd1dc208 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -195,80 +195,58 @@ enum acpi_attr_enum { static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) { int len; - len = utf16s_to_utf8s((const wchar_t *)obj-> - package.elements[1].string.pointer, - obj->package.elements[1].string.length, + len = utf16s_to_utf8s((const wchar_t *)obj->string.pointer, + obj->string.length, UTF16_LITTLE_ENDIAN, buf, PAGE_SIZE); buf[len] = '\n'; } static int -dsm_get_label(acpi_handle handle, int func, - struct acpi_buffer *output, - char *buf, enum acpi_attr_enum attribute) +dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) { - struct acpi_object_list input; - union acpi_object params[4]; - union acpi_object *obj; - int len = 0; - - int err; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(device_label_dsm_uuid); - params[0].buffer.pointer = (char *)device_label_dsm_uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x02; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - err = acpi_evaluate_object(handle, "_DSM", &input, output); - if (err) + acpi_handle handle; + union acpi_object *obj, *tmp; + int len = -1; + + handle = ACPI_HANDLE(dev); + if (!handle) return -1; - obj = (union acpi_object *)output->pointer; - if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2) { - len = obj->package.elements[0].integer.value; + obj = acpi_evaluate_dsm(handle, device_label_dsm_uuid, 0x2, + DEVICE_LABEL_DSM, NULL); + if (!obj) + return -1; + + tmp = obj->package.elements; + if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && + tmp[0].type == ACPI_TYPE_INTEGER && + tmp[1].type == ACPI_TYPE_STRING) { + len = tmp[0].integer.value; if (buf) { - if (attribute == ACPI_ATTR_INDEX_SHOW) + /* + * This second string element is optional even when + * this _DSM is implemented; when not implemented, + * this entry must return a null string. + */ + if (attr == ACPI_ATTR_INDEX_SHOW) scnprintf(buf, PAGE_SIZE, "%llu\n", - obj->package.elements[0].integer.value); - else if (attribute == ACPI_ATTR_LABEL_SHOW) - dsm_label_utf16s_to_utf8s(obj, buf); - kfree(output->pointer); - return strlen(buf); + tmp->integer.value); + else if (attr == ACPI_ATTR_LABEL_SHOW) + dsm_label_utf16s_to_utf8s(tmp + 1, buf); + len = strlen(buf) > 0 ? strlen(buf) : -1; } - kfree(output->pointer); - return len; } - kfree(output->pointer); + ACPI_FREE(obj); - return -1; + return len; } static bool device_has_dsm(struct device *dev) { - acpi_handle handle; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - - handle = ACPI_HANDLE(dev); - - if (!handle) - return FALSE; - - if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL, - ACPI_ATTR_NONE) > 0) - return TRUE; - - return FALSE; + return dsm_get_label(dev, NULL, ACPI_ATTR_NONE) > 0; } static umode_t @@ -287,44 +265,13 @@ acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) static ssize_t acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle handle; - int length; - - handle = ACPI_HANDLE(dev); - - if (!handle) - return -1; - - length = dsm_get_label(handle, DEVICE_LABEL_DSM, - &output, buf, ACPI_ATTR_LABEL_SHOW); - - if (length < 1) - return -1; - - return length; + return dsm_get_label(dev, buf, ACPI_ATTR_LABEL_SHOW); } static ssize_t acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle handle; - int length; - - handle = ACPI_HANDLE(dev); - - if (!handle) - return -1; - - length = dsm_get_label(handle, DEVICE_LABEL_DSM, - &output, buf, ACPI_ATTR_INDEX_SHOW); - - if (length < 0) - return -1; - - return length; - + return dsm_get_label(dev, buf, ACPI_ATTR_INDEX_SHOW); } static struct device_attribute acpi_attr_label = { -- cgit v1.2.3 From 2fc59fe2ecdca56a68728b6091590c07bb3e358d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:14 +0800 Subject: PCI / pci-label: treat PCI label with index 0 as valid label Current pci-label driver detects ACPI label by checking label index returned by ACPI _DSM method, and treats it as valid if label index is positive. According to ACPI Firmware specification 3.1, zero is also an valid label index. So change code to detect availability of ACPI slot label by checking availaiblity of ACPI _DSM function for PCI label. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/pci/pci-label.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index f12dcd1dc208..0260b14c8d94 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -187,7 +187,6 @@ static const char device_label_dsm_uuid[] = { }; enum acpi_attr_enum { - ACPI_ATTR_NONE = 0, ACPI_ATTR_LABEL_SHOW, ACPI_ATTR_INDEX_SHOW, }; @@ -222,20 +221,16 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 && tmp[0].type == ACPI_TYPE_INTEGER && tmp[1].type == ACPI_TYPE_STRING) { - len = tmp[0].integer.value; - if (buf) { - /* - * This second string element is optional even when - * this _DSM is implemented; when not implemented, - * this entry must return a null string. - */ - if (attr == ACPI_ATTR_INDEX_SHOW) - scnprintf(buf, PAGE_SIZE, "%llu\n", - tmp->integer.value); - else if (attr == ACPI_ATTR_LABEL_SHOW) - dsm_label_utf16s_to_utf8s(tmp + 1, buf); - len = strlen(buf) > 0 ? strlen(buf) : -1; - } + /* + * The second string element is optional even when + * this _DSM is implemented; when not implemented, + * this entry must return a null string. + */ + if (attr == ACPI_ATTR_INDEX_SHOW) + scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value); + else if (attr == ACPI_ATTR_LABEL_SHOW) + dsm_label_utf16s_to_utf8s(tmp + 1, buf); + len = strlen(buf) > 0 ? strlen(buf) : -1; } ACPI_FREE(obj); @@ -246,7 +241,14 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) static bool device_has_dsm(struct device *dev) { - return dsm_get_label(dev, NULL, ACPI_ATTR_NONE) > 0; + acpi_handle handle; + + handle = ACPI_HANDLE(dev); + if (!handle) + return false; + + return !!acpi_check_dsm(handle, device_label_dsm_uuid, 0x2, + 1 << DEVICE_LABEL_DSM); } static umode_t -- cgit v1.2.3 From 529139c9736ac71040e589c32ba87d35cc8cbf8f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:16 +0800 Subject: ACPI / TPM: match node name instead of full path when searching for TPM device When searching ACPI object for TPM device, it should match current ACPI object name instead of the full path. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/char/tpm/tpm_ppi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index e1f3337a0cf9..1e9cc11ac76a 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -30,7 +30,7 @@ static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) { + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer))) { if (strstr(buffer.pointer, context) != NULL) { *return_value = handle; status = AE_CTRL_TERMINATE; -- cgit v1.2.3 From 84b1667dea233d2af29b5138bfd2d70417cfa720 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:17 +0800 Subject: ACPI / TPM: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in TPM driver. This patch also help to get rid of following warning messages: [ 163.509575] ACPI Error: Incorrect return type [Buffer] requested [Package] (20130517/nsxfeval-135) But there is still an warning left. [ 181.637366] ACPI Warning: \_SB_.IIO0.LPC0.TPM_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20130517/nsarguments-95) Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/char/tpm/tpm_ppi.c | 404 ++++++++++++++++----------------------------- 1 file changed, 145 insertions(+), 259 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 1e9cc11ac76a..d542ac6d0ae0 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -2,15 +2,6 @@ #include #include "tpm.h" -static const u8 tpm_ppi_uuid[] = { - 0xA6, 0xFA, 0xDD, 0x3D, - 0x1B, 0x36, - 0xB4, 0x4E, - 0xA4, 0x24, - 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 -}; -static char *tpm_device_name = "TPM"; - #define TPM_PPI_REVISION_ID 1 #define TPM_PPI_FN_VERSION 1 #define TPM_PPI_FN_SUBREQ 2 @@ -24,250 +15,185 @@ static char *tpm_device_name = "TPM"; #define PPI_VS_REQ_END 255 #define PPI_VERSION_LEN 3 +static const u8 tpm_ppi_uuid[] = { + 0xA6, 0xFA, 0xDD, 0x3D, + 0x1B, 0x36, + 0xB4, 0x4E, + 0xA4, 0x24, + 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 +}; + +static char *tpm_device_name = "TPM"; +static char tpm_ppi_version[PPI_VERSION_LEN + 1]; +static acpi_handle tpm_ppi_handle; + static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, void **return_value) { acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer))) { - if (strstr(buffer.pointer, context) != NULL) { - *return_value = handle; - status = AE_CTRL_TERMINATE; + status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + if (ACPI_FAILURE(status)) + return AE_OK; + + if (strstr(buffer.pointer, context) != NULL) { + union acpi_object *obj; + + /* Cache version string */ + obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, + NULL, ACPI_TYPE_STRING); + if (obj) { + strlcpy(tpm_ppi_version, obj->string.pointer, + PPI_VERSION_LEN + 1); + ACPI_FREE(obj); } - kfree(buffer.pointer); + + *return_value = handle; + status = AE_CTRL_TERMINATE; } + kfree(buffer.pointer); return status; } -static inline void ppi_assign_params(union acpi_object params[4], - u64 function_num) +static inline union acpi_object * +tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4) { - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(tpm_ppi_uuid); - params[0].buffer.pointer = (char *)tpm_ppi_uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = TPM_PPI_REVISION_ID; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = function_num; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; + BUG_ON(!tpm_ppi_handle); + return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, func, argv4, type); } static ssize_t tpm_show_ppi_version(struct device *dev, struct device_attribute *attr, char *buf) { - acpi_handle handle; - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object params[4]; - union acpi_object *obj; - - input.count = 4; - ppi_assign_params(params, TPM_PPI_FN_VERSION); - input.pointer = params; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ppi_callback, NULL, - tpm_device_name, &handle); - if (ACPI_FAILURE(status)) - return -ENXIO; - - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_STRING); - if (ACPI_FAILURE(status)) - return -ENOMEM; - obj = (union acpi_object *)output.pointer; - status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); - kfree(output.pointer); - return status; + return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version); } static ssize_t tpm_show_ppi_request(struct device *dev, struct device_attribute *attr, char *buf) { - acpi_handle handle; - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object params[4]; - union acpi_object *ret_obj; - - input.count = 4; - ppi_assign_params(params, TPM_PPI_FN_GETREQ); - input.pointer = params; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ppi_callback, NULL, - tpm_device_name, &handle); - if (ACPI_FAILURE(status)) + ssize_t size = -EINVAL; + union acpi_object *obj; + + obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); + if (!obj) return -ENXIO; - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_PACKAGE); - if (ACPI_FAILURE(status)) - return -ENOMEM; /* * output.pointer should be of package type, including two integers. * The first is function return code, 0 means success and 1 means * error. The second is pending TPM operation requested by the OS, 0 * means none and >0 means operation value. */ - ret_obj = ((union acpi_object *)output.pointer)->package.elements; - if (ret_obj->type == ACPI_TYPE_INTEGER) { - if (ret_obj->integer.value) { - status = -EFAULT; - goto cleanup; - } - ret_obj++; - if (ret_obj->type == ACPI_TYPE_INTEGER) - status = scnprintf(buf, PAGE_SIZE, "%llu\n", - ret_obj->integer.value); + if (obj->package.count == 2 && + obj->package.elements[0].type == ACPI_TYPE_INTEGER && + obj->package.elements[1].type == ACPI_TYPE_INTEGER) { + if (obj->package.elements[0].integer.value) + size = -EFAULT; else - status = -EINVAL; - } else { - status = -EINVAL; + size = scnprintf(buf, PAGE_SIZE, "%llu\n", + obj->package.elements[1].integer.value); } -cleanup: - kfree(output.pointer); - return status; + + ACPI_FREE(obj); + + return size; } static ssize_t tpm_store_ppi_request(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - char version[PPI_VERSION_LEN + 1]; - acpi_handle handle; - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object params[4]; - union acpi_object obj; u32 req; u64 ret; + int func = TPM_PPI_FN_SUBREQ; + union acpi_object *obj, tmp; + union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); - input.count = 4; - ppi_assign_params(params, TPM_PPI_FN_VERSION); - input.pointer = params; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ppi_callback, NULL, - tpm_device_name, &handle); - if (ACPI_FAILURE(status)) - return -ENXIO; - - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_STRING); - if (ACPI_FAILURE(status)) - return -ENOMEM; - strlcpy(version, - ((union acpi_object *)output.pointer)->string.pointer, - PPI_VERSION_LEN + 1); - kfree(output.pointer); - output.length = ACPI_ALLOCATE_BUFFER; - output.pointer = NULL; /* * the function to submit TPM operation request to pre-os environment * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ - if (strcmp(version, "1.1") == -1) - params[2].integer.value = TPM_PPI_FN_SUBREQ; - else - params[2].integer.value = TPM_PPI_FN_SUBREQ2; + if (strcmp(tpm_ppi_version, "1.1") >= 0) + func = TPM_PPI_FN_SUBREQ2; + /* * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS * accept buffer/string/integer type, but some BIOS accept buffer/ * string/package type. For PPI version 1.0 and 1.1, use buffer type * for compatibility, and use package type since 1.2 according to spec. */ - if (strcmp(version, "1.2") == -1) { - params[3].type = ACPI_TYPE_BUFFER; - params[3].buffer.length = sizeof(req); - sscanf(buf, "%d", &req); - params[3].buffer.pointer = (char *)&req; + if (strcmp(tpm_ppi_version, "1.2") < 0) { + if (sscanf(buf, "%d", &req) != 1) + return -EINVAL; + argv4.type = ACPI_TYPE_BUFFER; + argv4.buffer.length = sizeof(req); + argv4.buffer.pointer = (u8 *)&req; } else { - params[3].package.count = 1; - obj.type = ACPI_TYPE_INTEGER; - sscanf(buf, "%llu", &obj.integer.value); - params[3].package.elements = &obj; + tmp.type = ACPI_TYPE_INTEGER; + if (sscanf(buf, "%llu", &tmp.integer.value) != 1) + return -EINVAL; + } + + obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); + if (!obj) { + return -ENXIO; + } else { + ret = obj->integer.value; + ACPI_FREE(obj); } - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_INTEGER); - if (ACPI_FAILURE(status)) - return -ENOMEM; - ret = ((union acpi_object *)output.pointer)->integer.value; if (ret == 0) - status = (acpi_status)count; - else if (ret == 1) - status = -EPERM; - else - status = -EFAULT; - kfree(output.pointer); - return status; + return (acpi_status)count; + + return (ret == 1) ? -EPERM : -EFAULT; } static ssize_t tpm_show_ppi_transition_action(struct device *dev, struct device_attribute *attr, char *buf) { - char version[PPI_VERSION_LEN + 1]; - acpi_handle handle; - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object params[4]; u32 ret; - char *info[] = { + acpi_status status; + union acpi_object *obj = NULL; + union acpi_object tmp = { + .buffer.type = ACPI_TYPE_BUFFER, + .buffer.length = 0, + .buffer.pointer = NULL + }; + + static char *info[] = { "None", "Shutdown", "Reboot", "OS Vendor-specific", "Error", }; - input.count = 4; - ppi_assign_params(params, TPM_PPI_FN_VERSION); - input.pointer = params; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ppi_callback, NULL, - tpm_device_name, &handle); - if (ACPI_FAILURE(status)) - return -ENXIO; - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_STRING); - if (ACPI_FAILURE(status)) - return -ENOMEM; - strlcpy(version, - ((union acpi_object *)output.pointer)->string.pointer, - PPI_VERSION_LEN + 1); /* * PPI spec defines params[3].type as empty package, but some platforms * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for * compatibility, define params[3].type as buffer, if PPI version < 1.2 */ - if (strcmp(version, "1.2") == -1) { - params[3].type = ACPI_TYPE_BUFFER; - params[3].buffer.length = 0; - params[3].buffer.pointer = NULL; + if (strcmp(tpm_ppi_version, "1.2") < 0) + obj = &tmp; + obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); + if (!obj) { + return -ENXIO; + } else { + ret = obj->integer.value; + ACPI_FREE(obj); } - params[2].integer.value = TPM_PPI_FN_GETACT; - kfree(output.pointer); - output.length = ACPI_ALLOCATE_BUFFER; - output.pointer = NULL; - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_INTEGER); - if (ACPI_FAILURE(status)) - return -ENOMEM; - ret = ((union acpi_object *)output.pointer)->integer.value; + if (ret < ARRAY_SIZE(info) - 1) status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); else status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ARRAY_SIZE(info)-1]); - kfree(output.pointer); return status; } @@ -275,27 +201,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev, struct device_attribute *attr, char *buf) { - acpi_handle handle; - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object params[4]; - union acpi_object *ret_obj; - u64 req; - - input.count = 4; - ppi_assign_params(params, TPM_PPI_FN_GETRSP); - input.pointer = params; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ppi_callback, NULL, - tpm_device_name, &handle); - if (ACPI_FAILURE(status)) + acpi_status status = -EINVAL; + union acpi_object *obj, *ret_obj; + u64 req, res; + + obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); + if (!obj) return -ENXIO; - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_PACKAGE); - if (ACPI_FAILURE(status)) - return -ENOMEM; /* * parameter output.pointer should be of package type, including * 3 integers. The first means function return code, the second means @@ -303,115 +216,81 @@ static ssize_t tpm_show_ppi_response(struct device *dev, * the most recent TPM operation request. Only if the first is 0, and * the second integer is not 0, the response makes sense. */ - ret_obj = ((union acpi_object *)output.pointer)->package.elements; - if (ret_obj->type != ACPI_TYPE_INTEGER) { - status = -EINVAL; + ret_obj = obj->package.elements; + if (obj->package.count < 3 || + ret_obj[0].type != ACPI_TYPE_INTEGER || + ret_obj[1].type != ACPI_TYPE_INTEGER || + ret_obj[2].type != ACPI_TYPE_INTEGER) goto cleanup; - } - if (ret_obj->integer.value) { + + if (ret_obj[0].integer.value) { status = -EFAULT; goto cleanup; } - ret_obj++; - if (ret_obj->type != ACPI_TYPE_INTEGER) { - status = -EINVAL; - goto cleanup; - } - if (ret_obj->integer.value) { - req = ret_obj->integer.value; - ret_obj++; - if (ret_obj->type != ACPI_TYPE_INTEGER) { - status = -EINVAL; - goto cleanup; - } - if (ret_obj->integer.value == 0) + + req = ret_obj[1].integer.value; + res = ret_obj[2].integer.value; + if (req) { + if (res == 0) status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, "0: Success"); - else if (ret_obj->integer.value == 0xFFFFFFF0) + else if (res == 0xFFFFFFF0) status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, "0xFFFFFFF0: User Abort"); - else if (ret_obj->integer.value == 0xFFFFFFF1) + else if (res == 0xFFFFFFF1) status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, "0xFFFFFFF1: BIOS Failure"); - else if (ret_obj->integer.value >= 1 && - ret_obj->integer.value <= 0x00000FFF) + else if (res >= 1 && res <= 0x00000FFF) status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", - req, ret_obj->integer.value, - "Corresponding TPM error"); + req, res, "Corresponding TPM error"); else status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", - req, ret_obj->integer.value, - "Error"); + req, res, "Error"); } else { status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", - ret_obj->integer.value, "No Recent Request"); + req, "No Recent Request"); } + cleanup: - kfree(output.pointer); + ACPI_FREE(obj); return status; } static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) { - char *str = buf; - char version[PPI_VERSION_LEN + 1]; - acpi_handle handle; - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object params[4]; - union acpi_object obj; int i; u32 ret; - char *info[] = { + char *str = buf; + union acpi_object *obj, tmp; + union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp); + + static char *info[] = { "Not implemented", "BIOS only", "Blocked for OS by BIOS", "User required", "User not required", }; - input.count = 4; - ppi_assign_params(params, TPM_PPI_FN_VERSION); - input.pointer = params; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ppi_callback, NULL, - tpm_device_name, &handle); - if (ACPI_FAILURE(status)) - return -ENXIO; - status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, - ACPI_TYPE_STRING); - if (ACPI_FAILURE(status)) - return -ENOMEM; - - strlcpy(version, - ((union acpi_object *)output.pointer)->string.pointer, - PPI_VERSION_LEN + 1); - kfree(output.pointer); - output.length = ACPI_ALLOCATE_BUFFER; - output.pointer = NULL; - if (strcmp(version, "1.2") == -1) + if (strcmp(tpm_ppi_version, "1.2") < 0) return -EPERM; - params[2].integer.value = TPM_PPI_FN_GETOPR; - params[3].package.count = 1; - obj.type = ACPI_TYPE_INTEGER; - params[3].package.elements = &obj; + tmp.integer.type = ACPI_TYPE_INTEGER; for (i = start; i <= end; i++) { - obj.integer.value = i; - status = acpi_evaluate_object_typed(handle, "_DSM", - &input, &output, ACPI_TYPE_INTEGER); - if (ACPI_FAILURE(status)) + tmp.integer.value = i; + obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); + if (!obj) { return -ENOMEM; + } else { + ret = obj->integer.value; + ACPI_FREE(obj); + } - ret = ((union acpi_object *)output.pointer)->integer.value; if (ret > 0 && ret < ARRAY_SIZE(info)) str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", i, ret, info[ret]); - kfree(output.pointer); - output.length = ACPI_ALLOCATE_BUFFER; - output.pointer = NULL; } + return str - buf; } @@ -453,6 +332,13 @@ static struct attribute_group ppi_attr_grp = { int tpm_add_ppi(struct kobject *parent) { + /* Cache TPM ACPI handle and version string */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + ppi_callback, NULL, + tpm_device_name, &tpm_ppi_handle); + if (tpm_ppi_handle == NULL) + return -ENODEV; + return sysfs_create_group(parent, &ppi_attr_grp); } -- cgit v1.2.3 From 1569a4c4cebaf358eff12633830baeaf6507fed0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:18 +0800 Subject: ACPI / TPM: detect PPI features by checking availability of _DSM functions Detecting physical presence interface features by checking availbility of corresponding ACPI _DSM functions, it should be more accurate than checking TPM version number. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/char/tpm/tpm_ppi.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index d542ac6d0ae0..117fab6daf39 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -23,39 +23,31 @@ static const u8 tpm_ppi_uuid[] = { 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 }; -static char *tpm_device_name = "TPM"; static char tpm_ppi_version[PPI_VERSION_LEN + 1]; static acpi_handle tpm_ppi_handle; static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, void **return_value) { - acpi_status status = AE_OK; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; - status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); - if (ACPI_FAILURE(status)) + if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, + 1 << TPM_PPI_FN_VERSION)) return AE_OK; - if (strstr(buffer.pointer, context) != NULL) { - union acpi_object *obj; - - /* Cache version string */ - obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, - TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, - NULL, ACPI_TYPE_STRING); - if (obj) { - strlcpy(tpm_ppi_version, obj->string.pointer, - PPI_VERSION_LEN + 1); - ACPI_FREE(obj); - } - - *return_value = handle; - status = AE_CTRL_TERMINATE; + /* Cache version string */ + obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, + NULL, ACPI_TYPE_STRING); + if (obj) { + strlcpy(tpm_ppi_version, obj->string.pointer, + PPI_VERSION_LEN + 1); + ACPI_FREE(obj); } - kfree(buffer.pointer); - return status; + *return_value = handle; + + return AE_CTRL_TERMINATE; } static inline union acpi_object * @@ -118,7 +110,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev, * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ - if (strcmp(tpm_ppi_version, "1.1") >= 0) + if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, + 1 << TPM_PPI_FN_SUBREQ2)) func = TPM_PPI_FN_SUBREQ2; /* @@ -272,7 +265,8 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) "User not required", }; - if (strcmp(tpm_ppi_version, "1.2") < 0) + if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, + 1 << TPM_PPI_FN_GETOPR)) return -EPERM; tmp.integer.type = ACPI_TYPE_INTEGER; @@ -334,8 +328,7 @@ int tpm_add_ppi(struct kobject *parent) { /* Cache TPM ACPI handle and version string */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - ppi_callback, NULL, - tpm_device_name, &tpm_ppi_handle); + ppi_callback, NULL, NULL, &tpm_ppi_handle); if (tpm_ppi_handle == NULL) return -ENODEV; -- cgit v1.2.3 From ea547d7db031e0cb010911470cbf5ba17e27eab0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:19 +0800 Subject: ACPI / i2c-hid: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in i2c-hid driver. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/hid/i2c-hid/i2c-hid.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 5f7e55f4b7f0..d22668f7d982 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -850,37 +850,23 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, }; - union acpi_object params[4]; - struct acpi_object_list input; + union acpi_object *obj; struct acpi_device *adev; - unsigned long long value; acpi_handle handle; handle = ACPI_HANDLE(&client->dev); if (!handle || acpi_bus_get_device(handle, &adev)) return -ENODEV; - input.count = ARRAY_SIZE(params); - input.pointer = params; - - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(i2c_hid_guid); - params[0].buffer.pointer = i2c_hid_guid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 1; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = 1; /* HID function */ - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_DSM", &input, - &value))) { + obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL, + ACPI_TYPE_INTEGER); + if (!obj) { dev_err(&client->dev, "device _DSM execution failed\n"); return -ENODEV; } - pdata->hid_descriptor_address = value; + pdata->hid_descriptor_address = obj->integer.value; + ACPI_FREE(obj); return 0; } -- cgit v1.2.3 From d5c3d79e5ec6219fb20bf358d1e1bbaea1c36591 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:20 +0800 Subject: ACPI / i915: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in i915 driver. Function intel_dsm() is used to check functions supported by ACPI _DSM method, but it has strange check for special value 0x80000002. After digging into nouveau driver, I think the check is copied from nouveau driver and is useless for i915 driver, so remove it. Acked-by: Daniel Vetter Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/gpu/drm/i915/intel_acpi.c | 144 ++++++++------------------------------ 1 file changed, 30 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index dfff0907f70e..1bfac94adb34 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -12,8 +12,6 @@ #include "i915_drv.h" #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ - -#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */ #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ static struct intel_dsm_priv { @@ -28,61 +26,6 @@ static const u8 intel_dsm_guid[] = { 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c }; -static int intel_dsm(acpi_handle handle, int func) -{ - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - union acpi_object params[4]; - union acpi_object *obj; - u32 result; - int ret = 0; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(intel_dsm_guid); - params[0].buffer.pointer = (char *)intel_dsm_guid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = INTEL_DSM_REVISION_ID; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - ret = acpi_evaluate_object(handle, "_DSM", &input, &output); - if (ret) { - DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); - return ret; - } - - obj = (union acpi_object *)output.pointer; - - result = 0; - switch (obj->type) { - case ACPI_TYPE_INTEGER: - result = obj->integer.value; - break; - - case ACPI_TYPE_BUFFER: - if (obj->buffer.length == 4) { - result = (obj->buffer.pointer[0] | - (obj->buffer.pointer[1] << 8) | - (obj->buffer.pointer[2] << 16) | - (obj->buffer.pointer[3] << 24)); - break; - } - default: - ret = -EINVAL; - break; - } - if (result == 0x80000002) - ret = -ENODEV; - - kfree(output.pointer); - return ret; -} - static char *intel_dsm_port_name(u8 id) { switch (id) { @@ -137,83 +80,56 @@ static char *intel_dsm_mux_type(u8 type) static void intel_dsm_platform_mux_info(void) { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - union acpi_object params[4]; - union acpi_object *pkg; - int i, ret; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(intel_dsm_guid); - params[0].buffer.pointer = (char *)intel_dsm_guid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = INTEL_DSM_REVISION_ID; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input, - &output); - if (ret) { - DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); - goto out; + int i; + union acpi_object *pkg, *connector_count; + + pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid, + INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, + NULL, ACPI_TYPE_PACKAGE); + if (!pkg) { + DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); + return; } - pkg = (union acpi_object *)output.pointer; - - if (pkg->type == ACPI_TYPE_PACKAGE) { - union acpi_object *connector_count = &pkg->package.elements[0]; - DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", - (unsigned long long)connector_count->integer.value); - for (i = 1; i < pkg->package.count; i++) { - union acpi_object *obj = &pkg->package.elements[i]; - union acpi_object *connector_id = - &obj->package.elements[0]; - union acpi_object *info = &obj->package.elements[1]; - DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", - (unsigned long long)connector_id->integer.value); - DRM_DEBUG_DRIVER(" port id: %s\n", - intel_dsm_port_name(info->buffer.pointer[0])); - DRM_DEBUG_DRIVER(" display mux info: %s\n", - intel_dsm_mux_type(info->buffer.pointer[1])); - DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", - intel_dsm_mux_type(info->buffer.pointer[2])); - DRM_DEBUG_DRIVER(" hpd mux info: %s\n", - intel_dsm_mux_type(info->buffer.pointer[3])); - } + connector_count = &pkg->package.elements[0]; + DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", + (unsigned long long)connector_count->integer.value); + for (i = 1; i < pkg->package.count; i++) { + union acpi_object *obj = &pkg->package.elements[i]; + union acpi_object *connector_id = &obj->package.elements[0]; + union acpi_object *info = &obj->package.elements[1]; + DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", + (unsigned long long)connector_id->integer.value); + DRM_DEBUG_DRIVER(" port id: %s\n", + intel_dsm_port_name(info->buffer.pointer[0])); + DRM_DEBUG_DRIVER(" display mux info: %s\n", + intel_dsm_mux_type(info->buffer.pointer[1])); + DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", + intel_dsm_mux_type(info->buffer.pointer[2])); + DRM_DEBUG_DRIVER(" hpd mux info: %s\n", + intel_dsm_mux_type(info->buffer.pointer[3])); } -out: - kfree(output.pointer); + ACPI_FREE(pkg); } static bool intel_dsm_pci_probe(struct pci_dev *pdev) { acpi_handle dhandle; - int ret; dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) return false; - if (!acpi_has_method(dhandle, "_DSM")) { + if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID, + 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { DRM_DEBUG_KMS("no _DSM method for intel device\n"); return false; } - ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS); - if (ret < 0) { - DRM_DEBUG_KMS("failed to get supported _DSM functions\n"); - return false; - } - intel_dsm_priv.dhandle = dhandle; - intel_dsm_platform_mux_info(); + return true; } -- cgit v1.2.3 From 4988d0aeb6843b7070e406f8e6cb095c74e5f136 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:21 +0800 Subject: nouveau / ACPI: fix memory leak in ACPI _DSM related code Fix memory leak in function nouveau_optimus_dsm() and nouveau_dsm(). Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index ba0183fb84f3..3f721e317fef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -111,6 +111,7 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t * if (obj->type == ACPI_TYPE_INTEGER) if (obj->integer.value == 0x80000002) { + kfree(output.pointer); return -ENODEV; } @@ -157,8 +158,10 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) obj = (union acpi_object *)output.pointer; if (obj->type == ACPI_TYPE_INTEGER) - if (obj->integer.value == 0x80000002) + if (obj->integer.value == 0x80000002) { + kfree(output.pointer); return -ENODEV; + } if (obj->type == ACPI_TYPE_BUFFER) { if (obj->buffer.length == 4 && result) { -- cgit v1.2.3 From b072e53b0a27a885d8be3d08c8d8758292762f39 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:38:22 +0800 Subject: ACPI / nouveau: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in nouveau driver. After analyzing the ACPI _DSM related code, I changed nouveau_optimus_dsm() to expect a buffer and nouveau_dsm() to expect an integer only. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/gpu/drm/nouveau/core/subdev/mxm/base.c | 48 +++------ drivers/gpu/drm/nouveau/nouveau_acpi.c | 136 +++++++------------------ 2 files changed, 54 insertions(+), 130 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c index 129120473f6c..13c5af88a601 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c @@ -87,55 +87,39 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version) 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 }; u32 mxms_args[] = { 0x00000000 }; - union acpi_object args[4] = { - /* _DSM MUID */ - { .buffer.type = 3, - .buffer.length = sizeof(muid), - .buffer.pointer = muid, - }, - /* spec says this can be zero to mean "highest revision", but - * of course there's at least one bios out there which fails - * unless you pass in exactly the version it supports.. - */ - { .integer.type = ACPI_TYPE_INTEGER, - .integer.value = (version & 0xf0) << 4 | (version & 0x0f), - }, - /* MXMS function */ - { .integer.type = ACPI_TYPE_INTEGER, - .integer.value = 0x00000010, - }, - /* Pointer to MXMS arguments */ - { .buffer.type = ACPI_TYPE_BUFFER, - .buffer.length = sizeof(mxms_args), - .buffer.pointer = (char *)mxms_args, - }, + union acpi_object argv4 = { + .buffer.type = ACPI_TYPE_BUFFER, + .buffer.length = sizeof(mxms_args), + .buffer.pointer = (char *)mxms_args, }; - struct acpi_object_list list = { ARRAY_SIZE(args), args }; - struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_handle handle; - int ret; + int rev; handle = ACPI_HANDLE(&device->pdev->dev); if (!handle) return false; - ret = acpi_evaluate_object(handle, "_DSM", &list, &retn); - if (ret) { - nv_debug(mxm, "DSM MXMS failed: %d\n", ret); + /* + * spec says this can be zero to mean "highest revision", but + * of course there's at least one bios out there which fails + * unless you pass in exactly the version it supports.. + */ + rev = (version & 0xf0) << 4 | (version & 0x0f); + obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4); + if (!obj) { + nv_debug(mxm, "DSM MXMS failed\n"); return false; } - obj = retn.pointer; if (obj->type == ACPI_TYPE_BUFFER) { mxm->mxms = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); - } else - if (obj->type == ACPI_TYPE_INTEGER) { + } else if (obj->type == ACPI_TYPE_INTEGER) { nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); } - kfree(obj); + ACPI_FREE(obj); return mxm->mxms != NULL; } #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 3f721e317fef..879a8b474bfe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -78,127 +78,66 @@ static const char nouveau_op_dsm_muid[] = { static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - union acpi_object params[4]; + int i; union acpi_object *obj; - int i, err; char args_buff[4]; + union acpi_object argv4 = { + .buffer.type = ACPI_TYPE_BUFFER, + .buffer.length = 4, + .buffer.pointer = args_buff + }; - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(nouveau_op_dsm_muid); - params[0].buffer.pointer = (char *)nouveau_op_dsm_muid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x00000100; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_BUFFER; - params[3].buffer.length = 4; /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ for (i = 0; i < 4; i++) args_buff[i] = (arg >> i * 8) & 0xFF; - params[3].buffer.pointer = args_buff; - err = acpi_evaluate_object(handle, "_DSM", &input, &output); - if (err) { - printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); - return err; - } - - obj = (union acpi_object *)output.pointer; - - if (obj->type == ACPI_TYPE_INTEGER) - if (obj->integer.value == 0x80000002) { - kfree(output.pointer); - return -ENODEV; - } - - if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length == 4 && result) { - *result = 0; + *result = 0; + obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100, + func, &argv4, ACPI_TYPE_BUFFER); + if (!obj) { + acpi_handle_info(handle, "failed to evaluate _DSM\n"); + return AE_ERROR; + } else { + if (obj->buffer.length == 4) { *result |= obj->buffer.pointer[0]; *result |= (obj->buffer.pointer[1] << 8); *result |= (obj->buffer.pointer[2] << 16); *result |= (obj->buffer.pointer[3] << 24); } + ACPI_FREE(obj); } - kfree(output.pointer); return 0; } -static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) +static int nouveau_dsm(acpi_handle handle, int func, int arg) { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - union acpi_object params[4]; + int ret = 0; union acpi_object *obj; - int err; - - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = sizeof(nouveau_dsm_muid); - params[0].buffer.pointer = (char *)nouveau_dsm_muid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = 0x00000102; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_INTEGER; - params[3].integer.value = arg; - - err = acpi_evaluate_object(handle, "_DSM", &input, &output); - if (err) { - printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); - return err; - } - - obj = (union acpi_object *)output.pointer; - - if (obj->type == ACPI_TYPE_INTEGER) - if (obj->integer.value == 0x80000002) { - kfree(output.pointer); - return -ENODEV; - } - - if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length == 4 && result) { - *result = 0; - *result |= obj->buffer.pointer[0]; - *result |= (obj->buffer.pointer[1] << 8); - *result |= (obj->buffer.pointer[2] << 16); - *result |= (obj->buffer.pointer[3] << 24); - } + union acpi_object argv4 = { + .integer.type = ACPI_TYPE_INTEGER, + .integer.value = arg, + }; + + obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102, + func, &argv4, ACPI_TYPE_INTEGER); + if (!obj) { + acpi_handle_info(handle, "failed to evaluate _DSM\n"); + return AE_ERROR; + } else { + if (obj->integer.value == 0x80000002) + ret = -ENODEV; + ACPI_FREE(obj); } - kfree(output.pointer); - return 0; -} - -/* Returns 1 if a DSM function is usable and 0 otherwise */ -static int nouveau_test_dsm(acpi_handle test_handle, - int (*dsm_func)(acpi_handle, int, int, uint32_t *), - int sfnc) -{ - u32 result = 0; - - /* Function 0 returns a Buffer containing available functions. The args - * parameter is ignored for function 0, so just put 0 in it */ - if (dsm_func(test_handle, 0, 0, &result)) - return 0; - - /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If - * the n-th bit is enabled, function n is supported */ - return result & 1 && result & (1 << sfnc); + return ret; } static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) { mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); - return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); + return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id); } static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) @@ -208,7 +147,7 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero arg = NOUVEAU_DSM_POWER_SPEED; else arg = NOUVEAU_DSM_POWER_STAMINA; - nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL); + nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg); return 0; } @@ -268,11 +207,12 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) nouveau_dsm_priv.other_handle = dhandle; return false; } - if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) + if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, + 1 << NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; - if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, - NOUVEAU_DSM_OPTIMUS_CAPS)) + if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100, + 1 << NOUVEAU_DSM_OPTIMUS_CAPS)) retval |= NOUVEAU_DSM_HAS_OPT; if (retval & NOUVEAU_DSM_HAS_OPT) { -- cgit v1.2.3 From 7ede9f8a1805b26b3141730c9deaea8bc95a64bc Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 19 Dec 2013 20:47:46 +0800 Subject: ACPI / extlog: replace open-coded _DSM code with helper functions Use helper functions to simplify _DSM related code in acpi_extlog driver. Also mark initialization data and functions with __init and __initdata to reduce memory footprint. Signed-off-by: Jiang Liu Tested-by: Chen, Gong Reviewed-by: Chen, Gong Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_extlog.c | 61 +++++++++------------------------------------- 1 file changed, 12 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index a6869e110ce5..928c4db83ddf 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -20,11 +20,9 @@ #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ #define EXTLOG_DSM_REV 0x0 -#define EXTLOG_FN_QUERY 0x0 #define EXTLOG_FN_ADDR 0x1 #define FLAG_OS_OPTIN BIT(0) -#define EXTLOG_QUERY_L1_EXIST BIT(1) #define ELOG_ENTRY_VALID (1ULL<<63) #define ELOG_ENTRY_LEN 0x1000 @@ -43,7 +41,7 @@ struct extlog_l1_head { u8 rev1[12]; }; -static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; +static u8 extlog_dsm_uuid[] __initdata = "663E35AF-CC10-41A4-88EA-5470AF055295"; /* L1 table related physical address */ static u64 elog_base; @@ -153,62 +151,27 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, return NOTIFY_DONE; } -static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) +static bool __init extlog_get_l1addr(void) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_object_list input; - union acpi_object params[4], *obj; u8 uuid[16]; - int i; + acpi_handle handle; + union acpi_object *obj; acpi_str_to_uuid(extlog_dsm_uuid, uuid); - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = 16; - params[0].buffer.pointer = uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = rev; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) - return -1; - - *ret = 0; - obj = (union acpi_object *)buf.pointer; - if (obj->type == ACPI_TYPE_INTEGER) { - *ret = obj->integer.value; - } else if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length <= 8) { - for (i = 0; i < obj->buffer.length; i++) - *ret |= (obj->buffer.pointer[i] << (i * 8)); - } - } - kfree(buf.pointer); - - return 0; -} - -static bool extlog_get_l1addr(void) -{ - acpi_handle handle; - u64 ret; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return false; - - if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) || - !(ret & EXTLOG_QUERY_L1_EXIST)) + if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR)) return false; - - if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) + obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV, + EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER); + if (!obj) { return false; + } else { + l1_dirbase = obj->integer.value; + ACPI_FREE(obj); + } - l1_dirbase = ret; /* Spec says L1 directory must be 4K aligned, bail out if it isn't */ if (l1_dirbase & ((1 << 12) - 1)) { pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", -- cgit v1.2.3 From 75365d04cd2d6fe04c9c52c69fd97b2d0a6c82ba Mon Sep 17 00:00:00 2001 From: Levente Kurusa Date: Thu, 19 Dec 2013 16:03:36 +0100 Subject: PNP / card: add missing put_device() call This is required so that we give up the last reference to the device. Signed-off-by: Levente Kurusa Signed-off-by: Rafael J. Wysocki --- drivers/pnp/card.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index bc00693d0c79..874c236ac1a7 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -239,6 +239,7 @@ int pnp_add_card(struct pnp_card *card) error = device_register(&card->dev); if (error) { dev_err(&card->dev, "could not register (err=%d)\n", error); + put_device(&card->dev); return error; } -- cgit v1.2.3 From 66e162b3931be6362bb6885ecc422d192f748145 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 14:43:05 +0530 Subject: ACPI / OSL: Mark the function acpi_table_checksum() as static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marks the function acpi_table_checksum() as static in osl.c because it is not used outside this file. This eliminates the following warning in osl.c: drivers/acpi/osl.c:547:11: warning: no previous prototype for ‘acpi_table_checksum’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 26c111341ead..7865a8069340 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -540,7 +540,7 @@ static u64 acpi_tables_addr; static int all_tables_size; /* Copied from acpica/tbutils.c:acpi_tb_checksum() */ -u8 __init acpi_table_checksum(u8 *buffer, u32 length) +static u8 __init acpi_table_checksum(u8 *buffer, u32 length) { u8 sum = 0; u8 *end = buffer + length; -- cgit v1.2.3 From 679c581b4a399f519155bf1d976f05d14b5717c3 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 14:45:00 +0530 Subject: ACPI / NVS: Include appropriate header file in nvs.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include header file internal.h in nvs.c because functions suspend_nvs_free(), suspend_nvs_alloc(), suspend_nvs_save() and suspend_nvs_restore() have their prototype declaration in internal.h. This eliminates the following warnings in nvs.c: drivers/acpi/nvs.c:128:6: warning: no previous prototype for ‘suspend_nvs_free’ [-Wmissing-prototypes] drivers/acpi/nvs.c:152:5: warning: no previous prototype for ‘suspend_nvs_alloc’ [-Wmissing-prototypes] drivers/acpi/nvs.c:169:5: warning: no previous prototype for ‘suspend_nvs_save’ [-Wmissing-prototypes] drivers/acpi/nvs.c:201:6: warning: no previous prototype for ‘suspend_nvs_restore’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/nvs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index ef28613d5192..de4fe03873c5 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -13,6 +13,8 @@ #include #include +#include "internal.h" + /* ACPI NVS regions, APEI may use it */ struct nvs_region { -- cgit v1.2.3 From 49894d8d5ac19224520f6bec213bbeb120f7eb70 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 14:46:41 +0530 Subject: ACPI / EC: Mark the function acpi_ec_add_debugfs() as static in ec_sys.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark the function acpi_ec_add_debugfs() as static in ec_sys.c because it is not used outside this file. This eliminates the following warning in ec_sys.c: drivers/acpi/ec_sys.c:108:5: warning: no previous prototype for ‘acpi_ec_add_debugfs’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 4e7b798900f2..b4c216bab22b 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -105,7 +105,7 @@ static const struct file_operations acpi_ec_io_ops = { .llseek = default_llseek, }; -int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) +static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) { struct dentry *dev_dir; char name[64]; -- cgit v1.2.3 From e22e58a473296f8f4d0ff9ff6743ef05d2c2aaa4 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 14:48:19 +0530 Subject: ACPI / PCI: Include appropriate header file in pci_slot.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes appropriate header file linux/pci-acpi.h in pci_slot.c because functions acpi_pci_slot_enumerate(), acpi_pci_slot_remove() and acpi_pci_slot_init() have their prototype declaratons in linux/pci-acpi.h. This eliminates the following warnings in pci_slot.c: drivers/acpi/pci_slot.c:162:6: warning: no previous prototype for ‘acpi_pci_slot_enumerate’ [-Wmissing-prototypes] drivers/acpi/pci_slot.c:174:6: warning: no previous prototype for ‘acpi_pci_slot_remove’ [-Wmissing-prototypes] drivers/acpi/pci_slot.c:215:13: warning: no previous prototype for ‘acpi_pci_slot_init’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_slot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index d678a180ca2a..139d9e479370 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -35,6 +35,7 @@ #include #include #include +#include static bool debug; static int check_sta_before_sun; -- cgit v1.2.3 From c071b6040c442de247a537c977ea13f97b6df6f8 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 14:58:31 +0530 Subject: ACPI / PCI: Include appropriate header file in pci_link.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes appropriate header file internal.h in pci_link.c because function acpi_pci_link_init() has its prototype declaration in internal.h. This eliminates the following warning in pci_link.c: drivers/acpi/pci_link.c:874:13: warning: no previous prototype for ‘acpi_pci_link_init’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_link.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index ea6b8d16dcc8..9418c7a1f786 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -41,6 +41,8 @@ #include #include +#include "internal.h" + #define PREFIX "ACPI: " #define _COMPONENT ACPI_PCI_COMPONENT -- cgit v1.2.3 From 3f9eed5c044743e781d7d76202666f346cf3e757 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 15:00:04 +0530 Subject: ACPI / dock: Include appropriate header file in dock.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes appropriate header file internal.h in dock.c because function acpi_dock_init() has its prototype declaration in internal.h. This eliminates the following warning in dock.c: drivers/acpi/dock.c:899:13: warning: no previous prototype for ‘acpi_dock_init’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c2090c023102..38c2e325f325 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -33,6 +33,8 @@ #include #include +#include "internal.h" + #define PREFIX "ACPI: " #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" -- cgit v1.2.3 From b8a0b0d199307eca0e99c30a06c9ed85a7f49678 Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 15:02:14 +0530 Subject: ACPI / EC: Remove unused functions and add prototype declaration in internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the prototype declarations of functions acpi_ec_add_query_handler() and acpi_ec_remove_query_handler() in header file internal.h and removes unused functions ec_burst_enable() and ec_burst_disable() in ec.c. This eliminates the following warnings in ec.c: drivers/acpi/ec.c:393:5: warning: no previous prototype for ‘ec_burst_enable’ [-Wmissing-prototypes] drivers/acpi/ec.c:402:5: warning: no previous prototype for ‘ec_burst_disable’ [-Wmissing-prototypes] drivers/acpi/ec.c:531:5: warning: no previous prototype for ‘acpi_ec_add_query_handler’ [-Wmissing-prototypes] drivers/acpi/ec.c:552:6: warning: no previous prototype for ‘acpi_ec_remove_query_handler’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 25 ------------------------- drivers/acpi/internal.h | 9 +++++++++ 2 files changed, 9 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ff40120e930e..47b1111afc90 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -90,10 +90,6 @@ static unsigned int ec_storm_threshold __read_mostly = 8; module_param(ec_storm_threshold, uint, 0644); MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); -/* If we find an EC via the ECDT, we need to keep a ptr to its context */ -/* External interfaces use first EC only, so remember */ -typedef int (*acpi_ec_query_func) (void *data); - struct acpi_ec_query_handler { struct list_head node; acpi_ec_query_func func; @@ -386,27 +382,6 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) return acpi_ec_transaction(ec, &t); } -/* - * Externally callable EC access functions. For now, assume 1 EC only - */ -int ec_burst_enable(void) -{ - if (!first_ec) - return -ENODEV; - return acpi_ec_burst_enable(first_ec); -} - -EXPORT_SYMBOL(ec_burst_enable); - -int ec_burst_disable(void) -{ - if (!first_ec) - return -ENODEV; - return acpi_ec_burst_disable(first_ec); -} - -EXPORT_SYMBOL(ec_burst_disable); - int ec_read(u8 addr, u8 *val) { int err; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a29739c0ba79..8ef9787dead4 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -127,12 +127,21 @@ struct acpi_ec { extern struct acpi_ec *first_ec; +/* If we find an EC via the ECDT, we need to keep a ptr to its context */ +/* External interfaces use first EC only, so remember */ +typedef int (*acpi_ec_query_func) (void *data); + int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); void acpi_ec_unblock_transactions_early(void); +int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data); +void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); + /*-------------------------------------------------------------------------- Suspend/Resume -- cgit v1.2.3 From 6a368751d54ed80e6ba868c29a04ad5118fe104b Mon Sep 17 00:00:00 2001 From: Rashika Date: Tue, 17 Dec 2013 15:04:17 +0530 Subject: ACPI / proc: Include appropriate header file in proc.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include appropriate header file internal.h in proc.c because function acpi_sleep_proc_init() has its prototype declaration in internal.h. This eliminates the following warning in proc.c: drivers/acpi/proc.c:148:12: warning: no previous prototype for ‘acpi_sleep_proc_init’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/acpi/proc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index db061bfd95a8..50fe34ffe932 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -7,6 +7,7 @@ #include #include "sleep.h" +#include "internal.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT -- cgit v1.2.3 From 62c6dae02d4fe2bfa6bc699ae456ff1c50d10bd0 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Sat, 14 Dec 2013 18:50:56 +0530 Subject: PNP: Mark the function pnp_build_option() as static in resource.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch marks the function pnp_build_option() as static in resource.c because it is not used outside this file. Thus, it also eliminates the following warning in resource.c: drivers/pnp/resource.c:34:20: warning: no previous prototype for ‘pnp_build_option’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki --- drivers/pnp/resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index d95e101ffb43..bacddd102ae9 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -31,7 +31,7 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some * option registration */ -struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type, +static struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type, unsigned int option_flags) { struct pnp_option *option; -- cgit v1.2.3 From 998be8ee53f1197c37cbe792e2c0ac70b2f86ca8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 3 Jan 2014 15:51:39 +0530 Subject: cpufreq: arm-big-little: Make driver dependent on CONFIG_BIG_LITTLE The arm_big_little cpufreq driver is only used by ARM bigLITTLE platforms and hence must depend on CONFIG_BIG_LITTLE. This was highlighted by Russell earlier when he reported this issue: drivers/built-in.o: In function `bL_cpufreq_set_rate': powercap_sys.c:(.text+0x5ed9a0): undefined reference to `bL_switch_request_cb' Reported-by: Russell King Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig.arm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 456ba5e1781c..3275e9cab1cc 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -4,7 +4,7 @@ config ARM_BIG_LITTLE_CPUFREQ tristate "Generic ARM big LITTLE CPUfreq driver" - depends on ARM && ARM_CPU_TOPOLOGY && HAVE_CLK + depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK select PM_OPP help This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. -- cgit v1.2.3 From 2b2ec67fa390ff7355432035132d32270aca4c3c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 3 Jan 2014 14:57:35 +0530 Subject: cpufreq: s3c2440: Remove hardware.h inclusion The contents of this header file are not referenced in the driver. Remove its inclusion. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/s3c2440-cpufreq.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c index 72b2cc8a5a85..717ef04ec90e 100644 --- a/drivers/cpufreq/s3c2440-cpufreq.c +++ b/drivers/cpufreq/s3c2440-cpufreq.c @@ -22,8 +22,6 @@ #include #include -#include - #include #include -- cgit v1.2.3 From 8f82b196866c4c3ec4cdc687667707d442d0c23b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 3 Jan 2014 14:57:36 +0530 Subject: cpufreq: s3c2440: Staticize local variables Local variables used only in this file are made static. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/s3c2440-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c index 717ef04ec90e..f84ed10755b5 100644 --- a/drivers/cpufreq/s3c2440-cpufreq.c +++ b/drivers/cpufreq/s3c2440-cpufreq.c @@ -53,7 +53,7 @@ static inline int within_khz(unsigned long a, unsigned long b) * specified in @cfg. The values are stored in @cfg for later use * by the relevant set routine if the request settings can be reached. */ -int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) +static int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) { unsigned int hdiv, pdiv; unsigned long hclk, fclk, armclk; @@ -240,7 +240,7 @@ static int s3c2440_cpufreq_calctable(struct s3c_cpufreq_config *cfg, return ret; } -struct s3c_cpufreq_info s3c2440_cpufreq_info = { +static struct s3c_cpufreq_info s3c2440_cpufreq_info = { .max = { .fclk = 400000000, .hclk = 133333333, -- cgit v1.2.3 From 87ae97f10c0d20cb5d9fc24c60eb1d1726d448c9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 3 Jan 2014 14:57:37 +0530 Subject: cpufreq: s3c24xx: Staticize local variable Local variable used only in this file is made static. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/s3c24xx-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 485088253358..35fa697e615a 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -509,7 +509,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board) return 0; } -int __init s3c_cpufreq_auto_io(void) +static int __init s3c_cpufreq_auto_io(void) { int ret; -- cgit v1.2.3 From 6f1e4efd882eccca10bac45b77e14bcb4979dc54 Mon Sep 17 00:00:00 2001 From: Jane Li Date: Fri, 3 Jan 2014 17:17:41 +0800 Subject: cpufreq: Fix timer/workqueue corruption by protecting reading governor_enabled When a CPU is hot removed we'll cancel all the delayed work items via gov_cancel_work(). Sometimes the delayed work function determines that it should adjust the delay for all other CPUs that the policy is managing. If this scenario occurs, the canceling CPU will cancel its own work but queue up the other CPUs works to run. Commit 3617f2 (cpufreq: Fix timer/workqueue corruption due to double queueing) has tried to fix this, but reading governor_enabled is not protected by cpufreq_governor_lock. Even though od_dbs_timer() checks governor_enabled before gov_queue_work(), this scenario may occur. For example: CPU0 CPU1 ---- ---- cpu_down() ... __cpufreq_remove_dev() od_dbs_timer() __cpufreq_governor() policy->governor_enabled policy->governor_enabled = false; cpufreq_governor_dbs() case CPUFREQ_GOV_STOP: gov_cancel_work(dbs_data, policy); cpu0 work is canceled timer is canceled cpu1 work is canceled gov_queue_work(*, *, true); cpu0 work queued cpu1 work queued cpu2 work queued ... cpu1 work is canceled cpu2 work is canceled ... At the end of the GOV_STOP case cpu0 still has a work queued to run although the code is expecting all of the works to be canceled. __cpufreq_remove_dev() will then proceed to re-initialize all the other CPUs works except for the CPU that is going down. The CPUFREQ_GOV_START case in cpufreq_governor_dbs() will trample over the queued work and debugobjects will spit out a warning: WARNING: at lib/debugobjects.c:260 debug_print_object+0x94/0xbc() ODEBUG: init active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x14 Modules linked in: CPU: 1 PID: 1205 Comm: sh Tainted: G W 3.10.0 #200 [] (unwind_backtrace+0x0/0xf8) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (warn_slowpath_common+0x4c/0x68) [] (warn_slowpath_common+0x4c/0x68) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt+0x30/0x40) from [] (debug_print_object+0x94/0xbc) [] (debug_print_object+0x94/0xbc) from [] (__debug_object_init+0xc8/0x3c0) [] (__debug_object_init+0xc8/0x3c0) from [] (init_timer_key+0x20/0x104) [] (init_timer_key+0x20/0x104) from [] (cpufreq_governor_dbs+0x1dc/0x68c) [] (cpufreq_governor_dbs+0x1dc/0x68c) from [] (__cpufreq_governor+0x80/0x1b0) [] (__cpufreq_governor+0x80/0x1b0) from [] (__cpufreq_remove_dev.isra.12+0x22c/0x380) [] (__cpufreq_remove_dev.isra.12+0x22c/0x380) from [] (cpufreq_cpu_callback+0x48/0x5c) [] (cpufreq_cpu_callback+0x48/0x5c) from [] (notifier_call_chain+0x44/0x84) [] (notifier_call_chain+0x44/0x84) from [] (__cpu_notify+0x2c/0x48) [] (__cpu_notify+0x2c/0x48) from [] (_cpu_down+0x80/0x258) [] (_cpu_down+0x80/0x258) from [] (cpu_down+0x28/0x3c) [] (cpu_down+0x28/0x3c) from [] (store_online+0x30/0x74) [] (store_online+0x30/0x74) from [] (dev_attr_store+0x18/0x24) [] (dev_attr_store+0x18/0x24) from [] (sysfs_write_file+0x100/0x180) [] (sysfs_write_file+0x100/0x180) from [] (vfs_write+0xbc/0x184) [] (vfs_write+0xbc/0x184) from [] (SyS_write+0x40/0x68) [] (SyS_write+0x40/0x68) from [] (ret_fast_syscall+0x0/0x48) In gov_queue_work(), lock cpufreq_governor_lock before gov_queue_work, and unlock it after __gov_queue_work(). In this way, governor_enabled is guaranteed not changed in gov_queue_work(). Signed-off-by: Jane Li Acked-by: Viresh Kumar Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 +- drivers/cpufreq/cpufreq_governor.c | 6 +++++- drivers/cpufreq/cpufreq_governor.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8d19f7c06010..a42e6aec4aad 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -39,7 +39,7 @@ static struct cpufreq_driver *cpufreq_driver; static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_RWLOCK(cpufreq_driver_lock); -static DEFINE_MUTEX(cpufreq_governor_lock); +DEFINE_MUTEX(cpufreq_governor_lock); static LIST_HEAD(cpufreq_policy_list); #ifdef CONFIG_HOTPLUG_CPU diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index e6be63561fa6..ba43991ba98a 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -119,8 +119,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, { int i; + mutex_lock(&cpufreq_governor_lock); if (!policy->governor_enabled) - return; + goto out_unlock; if (!all_cpus) { /* @@ -135,6 +136,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, for_each_cpu(i, policy->cpus) __gov_queue_work(i, dbs_data, delay); } + +out_unlock: + mutex_unlock(&cpufreq_governor_lock); } EXPORT_SYMBOL_GPL(gov_queue_work); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index b5f2b8618949..bfb9ae14142c 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -257,6 +257,8 @@ static ssize_t show_sampling_rate_min_gov_pol \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ } +extern struct mutex cpufreq_governor_lock; + void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); bool need_load_eval(struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate); -- cgit v1.2.3 From 26ab1c62b6e1ed4720d533320d646866027ade09 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 24 Dec 2013 15:35:24 +0530 Subject: cpufreq: exynos5250: Set APLL rate using CCF API Use common clock framework (CCF) APIs to set the clock rates instead of direct register manipulation. This now updates the sysfs entry (cpuinfo_cur_freq) correctly which did not reflect the correct value until now. While at it clean up the PLL s-div parameter setting as it is handled by the PLL driver. Signed-off-by: Sachin Kamat Acked-by: Viresh Kumar Reviewed-by: Lukasz Majewski Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/exynos5250-cpufreq.c | 74 +++++------------------------------- 1 file changed, 10 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c index 8feda86fe42c..86fb1a105601 100644 --- a/drivers/cpufreq/exynos5250-cpufreq.c +++ b/drivers/cpufreq/exynos5250-cpufreq.c @@ -102,12 +102,12 @@ static void set_clkdiv(unsigned int div_index) cpu_relax(); } -static void set_apll(unsigned int new_index, - unsigned int old_index) +static void set_apll(unsigned int index) { - unsigned int tmp, pdiv; + unsigned int tmp; + unsigned int freq = apll_freq_5250[index].freq; - /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ + /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ clk_set_parent(moutcore, mout_mpll); do { @@ -116,24 +116,9 @@ static void set_apll(unsigned int new_index, tmp &= 0x7; } while (tmp != 0x2); - /* 2. Set APLL Lock time */ - pdiv = ((apll_freq_5250[new_index].mps >> 8) & 0x3f); - - __raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK); + clk_set_rate(mout_apll, freq * 1000); - /* 3. Change PLL PMS values */ - tmp = __raw_readl(EXYNOS5_APLL_CON0); - tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0)); - tmp |= apll_freq_5250[new_index].mps; - __raw_writel(tmp, EXYNOS5_APLL_CON0); - - /* 4. wait_lock_time */ - do { - cpu_relax(); - tmp = __raw_readl(EXYNOS5_APLL_CON0); - } while (!(tmp & (0x1 << 29))); - - /* 5. MUX_CORE_SEL = APLL */ + /* MUX_CORE_SEL = APLL */ clk_set_parent(moutcore, mout_apll); do { @@ -141,55 +126,17 @@ static void set_apll(unsigned int new_index, tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU); tmp &= (0x7 << 16); } while (tmp != (0x1 << 16)); - -} - -static bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index) -{ - unsigned int old_pm = apll_freq_5250[old_index].mps >> 8; - unsigned int new_pm = apll_freq_5250[new_index].mps >> 8; - - return (old_pm == new_pm) ? 0 : 1; } static void exynos5250_set_frequency(unsigned int old_index, unsigned int new_index) { - unsigned int tmp; - if (old_index > new_index) { - if (!exynos5250_pms_change(old_index, new_index)) { - /* 1. Change the system clock divider values */ - set_clkdiv(new_index); - /* 2. Change just s value in apll m,p,s value */ - tmp = __raw_readl(EXYNOS5_APLL_CON0); - tmp &= ~(0x7 << 0); - tmp |= apll_freq_5250[new_index].mps & 0x7; - __raw_writel(tmp, EXYNOS5_APLL_CON0); - - } else { - /* Clock Configuration Procedure */ - /* 1. Change the system clock divider values */ - set_clkdiv(new_index); - /* 2. Change the apll m,p,s value */ - set_apll(new_index, old_index); - } + set_clkdiv(new_index); + set_apll(new_index); } else if (old_index < new_index) { - if (!exynos5250_pms_change(old_index, new_index)) { - /* 1. Change just s value in apll m,p,s value */ - tmp = __raw_readl(EXYNOS5_APLL_CON0); - tmp &= ~(0x7 << 0); - tmp |= apll_freq_5250[new_index].mps & 0x7; - __raw_writel(tmp, EXYNOS5_APLL_CON0); - /* 2. Change the system clock divider values */ - set_clkdiv(new_index); - } else { - /* Clock Configuration Procedure */ - /* 1. Change the apll m,p,s value */ - set_apll(new_index, old_index); - /* 2. Change the system clock divider values */ - set_clkdiv(new_index); - } + set_apll(new_index); + set_clkdiv(new_index); } } @@ -222,7 +169,6 @@ int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) info->volt_table = exynos5250_volt_table; info->freq_table = exynos5250_freq_table; info->set_freq = exynos5250_set_frequency; - info->need_apll_change = exynos5250_pms_change; return 0; -- cgit v1.2.3 From f7ba3b41e27129575201f0f9656e83fb67e86c3b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 2 Dec 2013 11:04:12 +0530 Subject: cpufreq: Introduce cpufreq_notify_post_transition() This introduces a new routine cpufreq_notify_post_transition() which can be used to send POSTCHANGE notification for new freq with or without both {PRE|POST}CHANGE notifications for last freq. This is useful at multiple places, especially for sending transition failure notifications. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 14 ++++++++++++++ include/linux/cpufreq.h | 2 ++ 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a42e6aec4aad..a123a731ec4e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -320,6 +320,20 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_notify_transition); +/* Do post notifications when there are chances that transition has failed */ +void cpufreq_notify_post_transition(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed) +{ + cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); + if (!transition_failed) + return; + + swap(freqs->old, freqs->new); + cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE); +} +EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); + /********************************************************************* * SYSFS INTERFACE * diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index dc196bbcf227..88aa0f342e85 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -306,6 +306,8 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); void cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state); +void cpufreq_notify_post_transition(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, int transition_failed); #else /* CONFIG_CPU_FREQ */ static inline int cpufreq_register_notifier(struct notifier_block *nb, -- cgit v1.2.3 From ab1b1c4e8223f9ee66aa93aaf64c36e77cadffac Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 2 Dec 2013 11:04:13 +0530 Subject: cpufreq: send new set of notification for transition failures In the current code, if we fail during a frequency transition, we simply send the POSTCHANGE notification with the old frequency. This isn't enough. One of the core users of these notifications is the code responsible for keeping loops_per_jiffy aligned with frequency changes. And mostly it is written as: if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { update-loops-per-jiffy... } So, suppose we are changing to a higher frequency and failed during transition, then following will happen: - CPUFREQ_PRECHANGE notification with freq-new > freq-old - CPUFREQ_POSTCHANGE notification with freq-new == freq-old The first one will update loops_per_jiffy and second one will do nothing. Even if we send the 2nd notification by exchanging values of freq-new and old, some users of these notifications might get unstable. This can be fixed by simply calling cpufreq_notify_post_transition() with error code and this routine will take care of sending notifications in the correct order. Signed-off-by: Viresh Kumar [rjw: Folded 3 patches into one, rebased unicore2 changes] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 13 ++----------- drivers/cpufreq/pcc-cpufreq.c | 18 +++++++----------- drivers/cpufreq/powernow-k8.c | 7 +------ drivers/cpufreq/unicore2-cpufreq.c | 16 +++++++--------- 4 files changed, 17 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a123a731ec4e..d533c205eea4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1739,17 +1739,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, pr_err("%s: Failed to change cpu frequency: %d\n", __func__, retval); - if (notify) { - /* - * Notify with old freq in case we failed to change - * frequency - */ - if (retval) - freqs.new = freqs.old; - - cpufreq_notify_transition(policy, &freqs, - CPUFREQ_POSTCHANGE); - } + if (notify) + cpufreq_notify_post_transition(policy, &freqs, retval); } out: diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index e2b4f40ff69a..1c0f1067af73 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -213,6 +213,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, cpu, target_freq, (pcch_virt_addr + pcc_cpu_data->input_offset)); + freqs.old = policy->cur; freqs.new = target_freq; cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); @@ -228,25 +229,20 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); status = ioread16(&pcch_hdr->status); + iowrite16(0, &pcch_hdr->status); + + cpufreq_notify_post_transition(policy, &freqs, status != CMD_COMPLETE); + spin_unlock(&pcc_lock); + if (status != CMD_COMPLETE) { pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", cpu, status); - goto cmd_incomplete; + return -EINVAL; } - iowrite16(0, &pcch_hdr->status); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); - spin_unlock(&pcc_lock); return 0; - -cmd_incomplete: - freqs.new = freqs.old; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); - iowrite16(0, &pcch_hdr->status); - spin_unlock(&pcc_lock); - return -EINVAL; } static int pcc_get_offset(int cpu) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 0023c7d40a51..e10b646634d7 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -964,14 +964,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, cpufreq_cpu_put(policy); cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - res = transition_fid_vid(data, fid, vid); - if (res) - freqs.new = freqs.old; - else - freqs.new = find_khz_freq_from_fid(data->currfid); + cpufreq_notify_post_transition(policy, &freqs, res); - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); return res; } diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index 653ae2955b55..86f6cfec2e09 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -46,20 +46,18 @@ static int ucv2_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int cur = ucv2_getspeed(0); struct cpufreq_freqs freqs; struct clk *mclk = clk_get(NULL, "MAIN_CLK"); + int ret; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - - if (!clk_set_rate(mclk, target_freq * 1000)) { - freqs.old = cur; - freqs.new = target_freq; - } + freqs.old = policy->cur; + freqs.new = target_freq; - cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + ret = clk_set_rate(mclk, target_freq * 1000); + cpufreq_notify_post_transition(policy, &freqs, ret); - return 0; + return ret; } static int __init ucv2_cpu_init(struct cpufreq_policy *policy) -- cgit v1.2.3 From de2d1a7e9310c4d1464faf469c737f08b5608600 Mon Sep 17 00:00:00 2001 From: tangchen Date: Mon, 6 Jan 2014 16:43:54 +0800 Subject: ACPI / tables: Check if id is NULL in acpi_table_parse() strncmp() does not check if the params are NULL. In acpi_table_parse(), if @id is NULL, the kernel will panic. Signed-off-by: Tang Chen Acked-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 4ec44258e4ff..a17619bfb57b 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -293,7 +293,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) if (acpi_disabled) return -ENODEV; - if (!handler) + if (!id || !handler) return -EINVAL; if (strncmp(id, ACPI_SIG_MADT, 4) == 0) -- cgit v1.2.3 From f8a571b2a128a1697624c1b132f3af07848ebbcf Mon Sep 17 00:00:00 2001 From: tangchen Date: Mon, 6 Jan 2014 16:47:59 +0800 Subject: ACPI / tables: Return proper error codes from acpi_table_parse() and fix comment. The comment about return value of acpi_table_parse() is incorrect. This patch fix it. Since all callers only check if the function succeeded or not, this patch simplifies the semantics by returning -errno for all failure cases. This will also simply the comment. As suggested by Toshi Kani , also change the stub in linux/acpi.h to return -ENODEV. Signed-off-by: Tang Chen Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 5 +++-- include/linux/acpi.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index a17619bfb57b..5837f857ac2e 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -278,12 +278,13 @@ acpi_table_parse_madt(enum acpi_madt_type id, /** * acpi_table_parse - find table with @id, run @handler on it - * * @id: table id to find * @handler: handler to run * * Scan the ACPI System Descriptor Table (STD) for a table matching @id, - * run @handler on it. Return 0 if table found, return on if not. + * run @handler on it. + * + * Return 0 if table found, -errno if not. */ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 726a6aa62b64..7aaf7315d33d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -461,7 +461,7 @@ struct acpi_table_header; static inline int acpi_table_parse(char *id, int (*handler)(struct acpi_table_header *)) { - return -1; + return -ENODEV; } static inline int acpi_nvs_register(__u64 start, __u64 size) -- cgit v1.2.3 From b4573d1d657aae28bedf3a9a1f5367e09c80d1d6 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 19 Dec 2013 09:16:47 -0500 Subject: cpufreq: imx6q: correct VDDSOC/PU voltage scaling when cpufreq is changed on i.MX6Q, cpu freq change need to follow below flows: 1. each setpoint has different VDDARM, VDDSOC/PU voltage, get the setpoint table from dts; 2. when cpu freq is scaling up, need to increase VDDSOC/PU voltage before VDDARM, if VDDPU is off, no need to change it; 3. when cpu freq is scaling down, need to decrease VDDARM voltage before VDDSOC/PU, if VDDPU is off, no need to change it; normally dts will pass vddsoc/pu freq/volt info to kernel, if not, will use fixed value for vddsoc/pu voltage setting. Signed-off-by: Anson Huang Acked-by: Shawn Guo Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/imx6q-cpufreq.c | 106 +++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 4b3f18e5f36b..c29198fbc9b7 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -35,6 +35,9 @@ static struct device *cpu_dev; static struct cpufreq_frequency_table *freq_table; static unsigned int transition_latency; +static u32 *imx6_soc_volt; +static u32 soc_opp_count; + static unsigned int imx6q_get_speed(unsigned int cpu) { return clk_get_rate(arm_clk) / 1000; @@ -69,23 +72,22 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) /* scaling up? scale voltage before frequency */ if (new_freq > old_freq) { + ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); + if (ret) { + dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); + return ret; + } + ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); + if (ret) { + dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); + return ret; + } ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); return ret; } - - /* - * Need to increase vddpu and vddsoc for safety - * if we are about to run at 1.2 GHz. - */ - if (new_freq == FREQ_1P2_GHZ / 1000) { - regulator_set_voltage_tol(pu_reg, - PU_SOC_VOLTAGE_HIGH, 0); - regulator_set_voltage_tol(soc_reg, - PU_SOC_VOLTAGE_HIGH, 0); - } } /* @@ -120,12 +122,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) "failed to scale vddarm down: %d\n", ret); ret = 0; } - - if (old_freq == FREQ_1P2_GHZ / 1000) { - regulator_set_voltage_tol(pu_reg, - PU_SOC_VOLTAGE_NORMAL, 0); - regulator_set_voltage_tol(soc_reg, - PU_SOC_VOLTAGE_NORMAL, 0); + ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); + if (ret) { + dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret); + ret = 0; + } + ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); + if (ret) { + dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret); + ret = 0; } } @@ -153,6 +158,9 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) struct dev_pm_opp *opp; unsigned long min_volt, max_volt; int num, ret; + const struct property *prop; + const __be32 *val; + u32 nr, i, j; cpu_dev = get_cpu_device(0); if (!cpu_dev) { @@ -201,9 +209,61 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) goto put_node; } + /* Make imx6_soc_volt array's size same as arm opp number */ + imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL); + if (imx6_soc_volt == NULL) { + ret = -ENOMEM; + goto free_freq_table; + } + + prop = of_find_property(np, "fsl,soc-operating-points", NULL); + if (!prop || !prop->value) + goto soc_opp_out; + + /* + * Each OPP is a set of tuples consisting of frequency and + * voltage like . + */ + nr = prop->length / sizeof(u32); + if (nr % 2 || (nr / 2) < num) + goto soc_opp_out; + + for (j = 0; j < num; j++) { + val = prop->value; + for (i = 0; i < nr / 2; i++) { + unsigned long freq = be32_to_cpup(val++); + unsigned long volt = be32_to_cpup(val++); + if (freq_table[j].frequency == freq) { + imx6_soc_volt[soc_opp_count++] = volt; + break; + } + } + } + +soc_opp_out: + /* use fixed soc opp volt if no valid soc opp info found in dtb */ + if (soc_opp_count != num) { + dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value!\n"); + for (j = 0; j < num; j++) + imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL; + if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ) + imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH; + } + if (of_property_read_u32(np, "clock-latency", &transition_latency)) transition_latency = CPUFREQ_ETERNAL; + /* + * Calculate the ramp time for max voltage change in the + * VDDSOC and VDDPU regulators. + */ + ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); + if (ret > 0) + transition_latency += ret * 1000; + ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); + if (ret > 0) + transition_latency += ret * 1000; + /* * OPP is maintained in order of increasing frequency, and * freq_table initialised from OPP is therefore sorted in the @@ -221,18 +281,6 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) if (ret > 0) transition_latency += ret * 1000; - /* Count vddpu and vddsoc latency in for 1.2 GHz support */ - if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) { - ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL, - PU_SOC_VOLTAGE_HIGH); - if (ret > 0) - transition_latency += ret * 1000; - ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL, - PU_SOC_VOLTAGE_HIGH); - if (ret > 0) - transition_latency += ret * 1000; - } - ret = cpufreq_register_driver(&imx6q_cpufreq_driver); if (ret) { dev_err(cpu_dev, "failed register driver: %d\n", ret); -- cgit v1.2.3 From 1d0eaae9b55e1ff2cfa2217b73af2027e07ca480 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 20 Dec 2013 10:12:16 +0800 Subject: cpufreq: imx6q-cpufreq driver is reused on i.MX6 series SoCs The imx6q-cpufreq driver nowadays is not only running on imx6q but also other i.MX6 series SoCs like imx6dl and imx6sl. Update Kconfig prompt and help text to make it clear to users. Signed-off-by: Shawn Guo Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig.arm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 3275e9cab1cc..0468ad147301 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -81,11 +81,11 @@ config ARM_HIGHBANK_CPUFREQ If in doubt, say N. config ARM_IMX6Q_CPUFREQ - tristate "Freescale i.MX6Q cpufreq support" - depends on SOC_IMX6Q + tristate "Freescale i.MX6 cpufreq support" + depends on ARCH_MXC depends on REGULATOR_ANATOP help - This adds cpufreq driver support for Freescale i.MX6Q SOC. + This adds cpufreq driver support for Freescale i.MX6 series SoCs. If in doubt, say N. -- cgit v1.2.3 From 20b7cbe2981013cbe449cc642cefc101e23d0f8e Mon Sep 17 00:00:00 2001 From: John Tobias Date: Thu, 19 Dec 2013 22:56:28 -0800 Subject: cpufreq: imx6q: add of_init_opp_table Add a routine check to see if the platform supplied the OPP table. Incase there's no OPP table exist, it will try to initialise it. It's been tested on iMX6SL board where the platform doesn't have an OPP table. Signed-off-by: John Tobias Acked-by: Shawn Guo Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/imx6q-cpufreq.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index c29198fbc9b7..564a26523ebc 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -195,12 +195,25 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) goto put_node; } - /* We expect an OPP table supplied by platform */ + /* + * We expect an OPP table supplied by platform. + * Just, incase the platform did not supply the OPP + * table, it will try to get it. + */ num = dev_pm_opp_get_opp_count(cpu_dev); if (num < 0) { - ret = num; - dev_err(cpu_dev, "no OPP table is found: %d\n", ret); - goto put_node; + ret = of_init_opp_table(cpu_dev); + if (ret < 0) { + dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); + goto put_node; + } + + num = dev_pm_opp_get_opp_count(cpu_dev); + if (num < 0) { + ret = num; + dev_err(cpu_dev, "no OPP table is found: %d\n", ret); + goto put_node; + } } ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); -- cgit v1.2.3 From ae6b427132ba39d023e332e7d920e9931ff05313 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 3 Dec 2013 11:20:45 +0530 Subject: cpufreq: Mark ARM drivers with CPUFREQ_NEED_INITIAL_FREQ_CHECK flag Sometimes boot loaders set CPU frequency to a value outside of frequency table present with cpufreq core. In such cases CPU might be unstable if it has to run on that frequency for long duration of time and so its better to set it to a frequency which is specified in frequency table. On some systems we can't really say what frequency we're running at the moment and so for these we shouldn't check if we are running at a frequency present in frequency table. And so we really can't force this for all the cpufreq drivers. Hence we are created another flag here: CPUFREQ_NEED_INITIAL_FREQ_CHECK that will be marked by platforms which want to go for this check at boot time. Initially this is done for all ARM platforms but others may follow if required. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/arm_big_little.c | 3 ++- drivers/cpufreq/davinci-cpufreq.c | 2 +- drivers/cpufreq/dbx500-cpufreq.c | 3 ++- drivers/cpufreq/exynos-cpufreq.c | 2 +- drivers/cpufreq/exynos5440-cpufreq.c | 3 ++- drivers/cpufreq/imx6q-cpufreq.c | 1 + drivers/cpufreq/integrator-cpufreq.c | 1 + drivers/cpufreq/kirkwood-cpufreq.c | 1 + drivers/cpufreq/omap-cpufreq.c | 2 +- drivers/cpufreq/pxa2xx-cpufreq.c | 1 + drivers/cpufreq/pxa3xx-cpufreq.c | 1 + drivers/cpufreq/s3c2416-cpufreq.c | 2 +- drivers/cpufreq/s3c24xx-cpufreq.c | 2 +- drivers/cpufreq/s3c64xx-cpufreq.c | 2 +- drivers/cpufreq/s5pv210-cpufreq.c | 2 +- drivers/cpufreq/sa1100-cpufreq.c | 2 +- drivers/cpufreq/sa1110-cpufreq.c | 2 +- drivers/cpufreq/spear-cpufreq.c | 2 +- drivers/cpufreq/tegra-cpufreq.c | 1 + include/linux/cpufreq.h | 9 +++++++++ 20 files changed, 31 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index 5519933813ea..72f87e9317e3 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -488,7 +488,8 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy) static struct cpufreq_driver bL_cpufreq_driver = { .name = "arm-big-little", .flags = CPUFREQ_STICKY | - CPUFREQ_HAVE_GOVERNOR_PER_POLICY, + CPUFREQ_HAVE_GOVERNOR_PER_POLICY | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = bL_cpufreq_set_target, .get = bL_cpufreq_get_rate, diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 5e8a854381b7..04f3390a7a2c 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c @@ -126,7 +126,7 @@ static int davinci_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver davinci_driver = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = davinci_verify_speed, .target_index = davinci_target, .get = davinci_getspeed, diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 0e67ab96321a..21d9898e000c 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c @@ -48,7 +48,8 @@ static int dbx500_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver dbx500_cpufreq_driver = { - .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS, + .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = dbx500_cpufreq_target, .get = dbx500_cpufreq_getspeed, diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index f3c22874da75..85e67dc6d072 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -218,7 +218,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver exynos_driver = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = exynos_target, .get = exynos_getspeed, diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index 76bef8b078cb..ffe6faea3a5f 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -312,7 +312,8 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver exynos_driver = { - .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION, + .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = exynos_target, .get = exynos_getspeed, diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 564a26523ebc..2938257b8c19 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -143,6 +143,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver imx6q_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = imx6q_set_target, .get = imx6q_get_speed, diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c index 7d8ab000d317..0e27844e8c2d 100644 --- a/drivers/cpufreq/integrator-cpufreq.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -190,6 +190,7 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver integrator_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = integrator_verify_policy, .target = integrator_set_target, .get = integrator_get, diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index 0767a4e29dfe..eb7abe345b50 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -97,6 +97,7 @@ static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver kirkwood_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .get = kirkwood_cpufreq_get_cpu_frequency, .verify = cpufreq_generic_frequency_table_verify, .target_index = kirkwood_cpufreq_target, diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index a0acd0bfba40..5de1e5f73eca 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -162,7 +162,7 @@ static int omap_cpu_exit(struct cpufreq_policy *policy) } static struct cpufreq_driver omap_driver = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = omap_target, .get = omap_getspeed, diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 0a0f4369636a..a9195a86b069 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -423,6 +423,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver pxa_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = pxa_set_target, .init = pxa_cpufreq_init, diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index 93840048dd11..3785687e9d70 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -201,6 +201,7 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver pxa3xx_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = pxa3xx_cpufreq_set, .init = pxa3xx_cpufreq_init, diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index 8d904a00027b..826b8be23099 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -481,7 +481,7 @@ err_hclk: } static struct cpufreq_driver s3c2416_cpufreq_driver = { - .flags = 0, + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = s3c2416_cpufreq_set_target, .get = s3c2416_cpufreq_get_speed, diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 35fa697e615a..6a1bf96deec0 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -448,7 +448,7 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy) #endif static struct cpufreq_driver s3c24xx_driver = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .target = s3c_cpufreq_target, .get = s3c_cpufreq_get, .init = s3c_cpufreq_init, diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 67e302eeefec..8435f45d7e9d 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -226,7 +226,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) } static struct cpufreq_driver s3c64xx_cpufreq_driver = { - .flags = 0, + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = s3c64xx_cpufreq_set_target, .get = s3c64xx_cpufreq_get_speed, diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index e3973dae28a7..ccd548c6f0c1 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -560,7 +560,7 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this, } static struct cpufreq_driver s5pv210_driver = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = s5pv210_target, .get = s5pv210_getspeed, diff --git a/drivers/cpufreq/sa1100-cpufreq.c b/drivers/cpufreq/sa1100-cpufreq.c index 623da742f8e7..728eab77e8e0 100644 --- a/drivers/cpufreq/sa1100-cpufreq.c +++ b/drivers/cpufreq/sa1100-cpufreq.c @@ -201,7 +201,7 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy) } static struct cpufreq_driver sa1100_driver __refdata = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = sa1100_target, .get = sa11x0_getspeed, diff --git a/drivers/cpufreq/sa1110-cpufreq.c b/drivers/cpufreq/sa1110-cpufreq.c index 2c2b2e601d13..546376719d8f 100644 --- a/drivers/cpufreq/sa1110-cpufreq.c +++ b/drivers/cpufreq/sa1110-cpufreq.c @@ -312,7 +312,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) /* sa1110_driver needs __refdata because it must remain after init registers * it with cpufreq_register_driver() */ static struct cpufreq_driver sa1110_driver __refdata = { - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = sa1110_target, .get = sa11x0_getspeed, diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index 45ea4c094542..c7525fe33407 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -162,7 +162,7 @@ static int spear_cpufreq_init(struct cpufreq_policy *policy) static struct cpufreq_driver spear_cpufreq_driver = { .name = "cpufreq-spear", - .flags = CPUFREQ_STICKY, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = spear_cpufreq_target, .get = spear_cpufreq_get, diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c index b7309c37033d..01b5578ffecf 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra-cpufreq.c @@ -214,6 +214,7 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy) } static struct cpufreq_driver tegra_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = tegra_target, .get = tegra_getspeed, diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 88aa0f342e85..91b8c84e8cd0 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -252,6 +252,15 @@ struct cpufreq_driver { */ #define CPUFREQ_ASYNC_NOTIFICATION (1 << 4) +/* + * Set by drivers which want cpufreq core to check if CPU is running at a + * frequency present in freq-table exposed by the driver. For these drivers if + * CPU is found running at an out of table freq, we will try to set it to a freq + * from the table. And if that fails, we will stop further boot process by + * issuing a BUG_ON(). + */ +#define CPUFREQ_NEED_INITIAL_FREQ_CHECK (1 << 5) + int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); -- cgit v1.2.3 From d3916691c90dfc9f08328d5cef8181e9ea508c55 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 3 Dec 2013 11:20:46 +0530 Subject: cpufreq: Make sure CPU is running on a freq from freq-table Sometimes boot loaders set CPU frequency to a value outside of frequency table present with cpufreq core. In such cases CPU might be unstable if it has to run on that frequency for long duration of time and so its better to set it to a frequency which is specified in freq-table. This also makes cpufreq stats inconsistent as cpufreq-stats would fail to register because current frequency of CPU isn't found in freq-table. Because we don't want this change to affect boot process badly, we go for the next freq which is >= policy->cur ('cur' must be set by now, otherwise we will end up setting freq to lowest of the table as 'cur' is initialized to zero). In case current frequency doesn't match any frequency from freq-table, we throw warnings to user, so that user can get this fixed in their bootloaders or freq-tables. Reported-by: Carlos Hernandez Reported-and-tested-by: Nishanth Menon Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/cpufreq/freq_table.c | 22 ++++++++++++++++++++++ include/linux/cpufreq.h | 2 ++ 3 files changed, 64 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d533c205eea4..3509ca04b5bb 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1073,6 +1073,46 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, } } + /* + * Sometimes boot loaders set CPU frequency to a value outside of + * frequency table present with cpufreq core. In such cases CPU might be + * unstable if it has to run on that frequency for long duration of time + * and so its better to set it to a frequency which is specified in + * freq-table. This also makes cpufreq stats inconsistent as + * cpufreq-stats would fail to register because current frequency of CPU + * isn't found in freq-table. + * + * Because we don't want this change to effect boot process badly, we go + * for the next freq which is >= policy->cur ('cur' must be set by now, + * otherwise we will end up setting freq to lowest of the table as 'cur' + * is initialized to zero). + * + * We are passing target-freq as "policy->cur - 1" otherwise + * __cpufreq_driver_target() would simply fail, as policy->cur will be + * equal to target-freq. + */ + if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK) + && has_target()) { + /* Are we running at unknown frequency ? */ + ret = cpufreq_frequency_table_get_index(policy, policy->cur); + if (ret == -EINVAL) { + /* Warn user and fix it */ + pr_warn("%s: CPU%d: Running at unlisted freq: %u KHz\n", + __func__, policy->cpu, policy->cur); + ret = __cpufreq_driver_target(policy, policy->cur - 1, + CPUFREQ_RELATION_L); + + /* + * Reaching here after boot in a few seconds may not + * mean that system will remain stable at "unknown" + * frequency for longer duration. Hence, a BUG_ON(). + */ + BUG_ON(ret); + pr_warn("%s: CPU%d: Unlisted initial frequency changed to: %u KHz\n", + __func__, policy->cpu, policy->cur); + } + } + /* related cpus should atleast have policy->cpus */ cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 3458d27f63b4..a8ac0427fbfe 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -178,7 +178,29 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); +int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, + unsigned int freq) +{ + struct cpufreq_frequency_table *table; + int i; + + table = cpufreq_frequency_get_table(policy->cpu); + if (unlikely(!table)) { + pr_debug("%s: Unable to find frequency table\n", __func__); + return -ENOENT; + } + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + if (table[i].frequency == freq) + return i; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); + static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); + /** * show_available_freqs - show available frequencies for the specified CPU */ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 91b8c84e8cd0..aaf800eb9dd2 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -450,6 +450,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation, unsigned int *index); +int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, + unsigned int freq); void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); -- cgit v1.2.3 From d568b6f71df1c8bd2fc2b051cf03f613a65ffad6 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 28 Nov 2013 13:42:42 +0100 Subject: cpufreq: exynos: Convert exynos-cpufreq to platform driver To make the driver multiplatform-friendly, unconditional initialization in an initcall is replaced with a platform driver probed only if respective platform device is registered. Tested at: Exynos4210 (TRATS) and Exynos4412 (TRATS2) Signed-off-by: Lukasz Majewski Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Reviewed-by: Sachin Kamat Tested-by: Sachin Kamat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- arch/arm/mach-exynos/common.c | 5 +++++ arch/arm/mach-exynos/common.h | 1 + arch/arm/mach-exynos/mach-exynos4-dt.c | 1 + arch/arm/mach-exynos/mach-exynos5-dt.c | 1 + drivers/cpufreq/exynos-cpufreq.c | 13 +++++++++++-- 5 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 61d2906ccefb..151043653a3f 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -303,6 +303,11 @@ void __init exynos_cpuidle_init(void) platform_device_register(&exynos_cpuidle); } +void __init exynos_cpufreq_init(void) +{ + platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); +} + void __init exynos_init_late(void) { if (of_machine_is_compatible("samsung,exynos5440")) diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index ff9b6a9419b0..3f0333438819 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -22,6 +22,7 @@ void exynos_init_io(void); void exynos4_restart(enum reboot_mode mode, const char *cmd); void exynos5_restart(enum reboot_mode mode, const char *cmd); void exynos_cpuidle_init(void); +void exynos_cpufreq_init(void); void exynos_init_late(void); void exynos_firmware_init(void); diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index 4603e6bd424b..d3e54b7644d7 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c @@ -22,6 +22,7 @@ static void __init exynos4_dt_machine_init(void) { exynos_cpuidle_init(); + exynos_cpufreq_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 1fe075a70c1e..602c5d7111d0 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -44,6 +44,7 @@ static void __init exynos5_dt_machine_init(void) } exynos_cpuidle_init(); + exynos_cpufreq_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 85e67dc6d072..f7c322c7d7ed 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -232,7 +233,7 @@ static struct cpufreq_driver exynos_driver = { #endif }; -static int __init exynos_cpufreq_init(void) +static int exynos_cpufreq_probe(struct platform_device *pdev) { int ret = -EINVAL; @@ -281,4 +282,12 @@ err_vdd_arm: kfree(exynos_info); return -EINVAL; } -late_initcall(exynos_cpufreq_init); + +static struct platform_driver exynos_cpufreq_platdrv = { + .driver = { + .name = "exynos-cpufreq", + .owner = THIS_MODULE, + }, + .probe = exynos_cpufreq_probe, +}; +module_platform_driver(exynos_cpufreq_platdrv); -- cgit v1.2.3 From e20e1d0ac02308e2211306fc67abcd0b2668fb8b Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 11 Dec 2013 19:38:32 -0500 Subject: powernow-k6: disable cache when changing frequency I found out that a system with k6-3+ processor is unstable during network server load. The system locks up or the network card stops receiving. The reason for the instability is the CPU frequency scaling. During frequency transition the processor is in "EPM Stop Grant" state. The documentation says that the processor doesn't respond to inquiry requests in this state. Consequently, coherency of processor caches and bus master devices is not maintained, causing the system instability. This patch flushes the cache during frequency transition. It fixes the instability. Other minor changes: * u64 invalue changed to unsigned long because the variable is 32-bit * move the logic to set the multiplier to a separate function powernow_k6_set_cpu_multiplier * preserve lower 5 bits of the powernow port instead of 4 (the voltage field has 5 bits) * mask interrupts when reading the multiplier, so that the port is not open during other activity (running other kernel code with the port open shouldn't cause any misbehavior, but we should better be safe and keep the port closed) This patch should be backported to all stable kernels. If it doesn't apply cleanly, change it, or ask me to change it. Signed-off-by: Mikulas Patocka Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernow-k6.c | 56 ++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index 643e7952cad3..1332b72f373a 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -44,23 +44,58 @@ static struct cpufreq_frequency_table clock_ratio[] = { /** * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier * - * Returns the current setting of the frequency multiplier. Core clock + * Returns the current setting of the frequency multiplier. Core clock * speed is frequency of the Front-Side Bus multiplied with this value. */ static int powernow_k6_get_cpu_multiplier(void) { - u64 invalue = 0; + unsigned long invalue = 0; u32 msrval; + local_irq_disable(); + msrval = POWERNOW_IOPORT + 0x1; wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ invalue = inl(POWERNOW_IOPORT + 0x8); msrval = POWERNOW_IOPORT + 0x0; wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + local_irq_enable(); + return clock_ratio[(invalue >> 5)&7].driver_data; } +static void powernow_k6_set_cpu_multiplier(unsigned int best_i) +{ + unsigned long outvalue, invalue; + unsigned long msrval; + unsigned long cr0; + + /* we now need to transform best_i to the BVC format, see AMD#23446 */ + + /* + * The processor doesn't respond to inquiry cycles while changing the + * frequency, so we must disable cache. + */ + local_irq_disable(); + cr0 = read_cr0(); + write_cr0(cr0 | X86_CR0_CD); + wbinvd(); + + outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5); + + msrval = POWERNOW_IOPORT + 0x1; + wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ + invalue = inl(POWERNOW_IOPORT + 0x8); + invalue = invalue & 0x1f; + outvalue = outvalue | invalue; + outl(outvalue, (POWERNOW_IOPORT + 0x8)); + msrval = POWERNOW_IOPORT + 0x0; + wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + + write_cr0(cr0); + local_irq_enable(); +} /** * powernow_k6_target - set the PowerNow! multiplier @@ -71,8 +106,6 @@ static int powernow_k6_get_cpu_multiplier(void) static int powernow_k6_target(struct cpufreq_policy *policy, unsigned int best_i) { - unsigned long outvalue = 0, invalue = 0; - unsigned long msrval; struct cpufreq_freqs freqs; if (clock_ratio[best_i].driver_data > max_multiplier) { @@ -85,18 +118,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy, cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - /* we now need to transform best_i to the BVC format, see AMD#23446 */ - - outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5); - - msrval = POWERNOW_IOPORT + 0x1; - wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ - invalue = inl(POWERNOW_IOPORT + 0x8); - invalue = invalue & 0xf; - outvalue = outvalue | invalue; - outl(outvalue , (POWERNOW_IOPORT + 0x8)); - msrval = POWERNOW_IOPORT + 0x0; - wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + powernow_k6_set_cpu_multiplier(best_i); cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); @@ -125,7 +147,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) } /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 200000; + policy->cpuinfo.transition_latency = 500000; return cpufreq_table_validate_and_show(policy, clock_ratio); } -- cgit v1.2.3 From d82b922a4acc1781d368aceac2f9da43b038cab2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 11 Dec 2013 19:38:53 -0500 Subject: powernow-k6: correctly initialize default parameters The powernow-k6 driver used to read the initial multiplier from the powernow register. However, there is a problem with this: * If there was a frequency transition before, the multiplier read from the register corresponds to the current multiplier. * If there was no frequency transition since reset, the field in the register always reads as zero, regardless of the current multiplier that is set using switches on the mainboard and that the CPU is running at. The zero value corresponds to multiplier 4.5, so as a consequence, the powernow-k6 driver always assumes multiplier 4.5. For example, if we have 550MHz CPU with bus frequency 100MHz and multiplier 5.5, the powernow-k6 driver thinks that the multiplier is 4.5 and bus frequency is 122MHz. The powernow-k6 driver then sets the multiplier to 4.5, underclocking the CPU to 450MHz, but reports the current frequency as 550MHz. There is no reliable way how to read the initial multiplier. I modified the driver so that it contains a table of known frequencies (based on parameters of existing CPUs and some common overclocking schemes) and sets the multiplier according to the frequency. If the frequency is unknown (because of unusual overclocking or underclocking), the user must supply the bus speed and maximum multiplier as module parameters. This patch should be backported to all stable kernels. If it doesn't apply cleanly, change it, or ask me to change it. Signed-off-by: Mikulas Patocka Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernow-k6.c | 76 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index 1332b72f373a..16359ab2c459 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -26,6 +26,14 @@ static unsigned int busfreq; /* FSB, in 10 kHz */ static unsigned int max_multiplier; +static unsigned int param_busfreq = 0; +static unsigned int param_max_multiplier = 0; + +module_param_named(max_multiplier, param_max_multiplier, uint, S_IRUGO); +MODULE_PARM_DESC(max_multiplier, "Maximum multiplier (allowed values: 20 30 35 40 45 50 55 60)"); + +module_param_named(bus_frequency, param_busfreq, uint, S_IRUGO); +MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz"); /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ static struct cpufreq_frequency_table clock_ratio[] = { @@ -40,6 +48,27 @@ static struct cpufreq_frequency_table clock_ratio[] = { {0, CPUFREQ_TABLE_END} }; +static const struct { + unsigned freq; + unsigned mult; +} usual_frequency_table[] = { + { 400000, 40 }, // 100 * 4 + { 450000, 45 }, // 100 * 4.5 + { 475000, 50 }, // 95 * 5 + { 500000, 50 }, // 100 * 5 + { 506250, 45 }, // 112.5 * 4.5 + { 533500, 55 }, // 97 * 5.5 + { 550000, 55 }, // 100 * 5.5 + { 562500, 50 }, // 112.5 * 5 + { 570000, 60 }, // 95 * 6 + { 600000, 60 }, // 100 * 6 + { 618750, 55 }, // 112.5 * 5.5 + { 660000, 55 }, // 120 * 5.5 + { 675000, 60 }, // 112.5 * 6 + { 720000, 60 }, // 120 * 6 +}; + +#define FREQ_RANGE 3000 /** * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier @@ -125,17 +154,56 @@ static int powernow_k6_target(struct cpufreq_policy *policy, return 0; } - static int powernow_k6_cpu_init(struct cpufreq_policy *policy) { unsigned int i, f; + unsigned khz; if (policy->cpu != 0) return -ENODEV; - /* get frequencies */ - max_multiplier = powernow_k6_get_cpu_multiplier(); - busfreq = cpu_khz / max_multiplier; + max_multiplier = 0; + khz = cpu_khz; + for (i = 0; i < ARRAY_SIZE(usual_frequency_table); i++) { + if (khz >= usual_frequency_table[i].freq - FREQ_RANGE && + khz <= usual_frequency_table[i].freq + FREQ_RANGE) { + khz = usual_frequency_table[i].freq; + max_multiplier = usual_frequency_table[i].mult; + break; + } + } + if (param_max_multiplier) { + for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { + if (clock_ratio[i].driver_data == param_max_multiplier) { + max_multiplier = param_max_multiplier; + goto have_max_multiplier; + } + } + printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n"); + return -EINVAL; + } + + if (!max_multiplier) { + printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz); + printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n"); + return -EOPNOTSUPP; + } + +have_max_multiplier: + param_max_multiplier = max_multiplier; + + if (param_busfreq) { + if (param_busfreq >= 50000 && param_busfreq <= 150000) { + busfreq = param_busfreq / 10; + goto have_busfreq; + } + printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n"); + return -EINVAL; + } + + busfreq = khz / max_multiplier; +have_busfreq: + param_busfreq = busfreq * 10; /* table init */ for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { -- cgit v1.2.3 From 22c73795b101597051924556dce019385a1e2fa0 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 11 Dec 2013 19:39:19 -0500 Subject: powernow-k6: reorder frequencies This patch reorders reported frequencies from the highest to the lowest, just like in other frequency drivers. Signed-off-by: Mikulas Patocka Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernow-k6.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c index 16359ab2c459..b9a444e358b5 100644 --- a/drivers/cpufreq/powernow-k6.c +++ b/drivers/cpufreq/powernow-k6.c @@ -37,17 +37,20 @@ MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz"); /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ static struct cpufreq_frequency_table clock_ratio[] = { - {45, /* 000 -> 4.5x */ 0}, + {60, /* 110 -> 6.0x */ 0}, + {55, /* 011 -> 5.5x */ 0}, {50, /* 001 -> 5.0x */ 0}, + {45, /* 000 -> 4.5x */ 0}, {40, /* 010 -> 4.0x */ 0}, - {55, /* 011 -> 5.5x */ 0}, - {20, /* 100 -> 2.0x */ 0}, - {30, /* 101 -> 3.0x */ 0}, - {60, /* 110 -> 6.0x */ 0}, {35, /* 111 -> 3.5x */ 0}, + {30, /* 101 -> 3.0x */ 0}, + {20, /* 100 -> 2.0x */ 0}, {0, CPUFREQ_TABLE_END} }; +static const u8 index_to_register[8] = { 6, 3, 1, 0, 2, 7, 5, 4 }; +static const u8 register_to_index[8] = { 3, 2, 4, 1, 7, 6, 0, 5 }; + static const struct { unsigned freq; unsigned mult; @@ -91,7 +94,7 @@ static int powernow_k6_get_cpu_multiplier(void) local_irq_enable(); - return clock_ratio[(invalue >> 5)&7].driver_data; + return clock_ratio[register_to_index[(invalue >> 5)&7]].driver_data; } static void powernow_k6_set_cpu_multiplier(unsigned int best_i) @@ -111,7 +114,7 @@ static void powernow_k6_set_cpu_multiplier(unsigned int best_i) write_cr0(cr0 | X86_CR0_CD); wbinvd(); - outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5); + outvalue = (1<<12) | (1<<10) | (1<<9) | (index_to_register[best_i]<<5); msrval = POWERNOW_IOPORT + 0x1; wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ -- cgit v1.2.3 From d8254e0e72c8cc6131f789f8645338b719f57648 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 7 Jan 2014 00:16:37 +0100 Subject: PNPBIOS: check return value of pnp_add_device() pnp_add_device() may fail so we need to handle errors and avoid leaking memory. Also, when pnp_alloc_dev fails, return -ENOMEM rather than -1. Signed-off-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/pnp/pnpbios/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 9b86a01af631..074569e77d22 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -312,18 +312,19 @@ static int __init insert_device(struct pnp_bios_node *node) struct list_head *pos; struct pnp_dev *dev; char id[8]; + int error; /* check if the device is already added */ list_for_each(pos, &pnpbios_protocol.devices) { dev = list_entry(pos, struct pnp_dev, protocol_list); if (dev->number == node->handle) - return -1; + return -EEXIST; } pnp_eisa_id_to_string(node->eisa_id & PNP_EISA_ID_MASK, id); dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id); if (!dev) - return -1; + return -ENOMEM; pnpbios_parse_data_stream(dev, node); dev->active = pnp_is_active(dev); @@ -342,7 +343,12 @@ static int __init insert_device(struct pnp_bios_node *node) if (!dev->active) pnp_init_resources(dev); - pnp_add_device(dev); + error = pnp_add_device(dev); + if (error) { + put_device(&dev->dev); + return error; + } + pnpbios_interface_attach_device(node); return 0; -- cgit v1.2.3 From 158204397034f088bfd505eeee281f7072da1c24 Mon Sep 17 00:00:00 2001 From: Bin Shi Date: Fri, 3 Jan 2014 14:08:54 +0800 Subject: apm-emulation: add hibernation APM events to support suspend2disk Some embedded systems use hibernation for fast boot. and in it, some software components need to handle specific things before hibernation and after restore. So it needs to capture the apm status about these pm events. Currently apm just supports suspend to ram, but not suspend to disk, so here add logic about hibernation apm events. Signed-off-by: Bin Shi Signed-off-by: Barry Song Signed-off-by: Jiri Kosina --- drivers/char/apm-emulation.c | 11 +++++++++-- include/uapi/linux/apm_bios.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 46118f845948..dd9dfa15e9d1 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -531,6 +531,7 @@ static int apm_suspend_notifier(struct notifier_block *nb, { struct apm_user *as; int err; + unsigned long apm_event; /* short-cut emergency suspends */ if (atomic_read(&userspace_notification_inhibit)) @@ -538,6 +539,9 @@ static int apm_suspend_notifier(struct notifier_block *nb, switch (event) { case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + apm_event = (event == PM_SUSPEND_PREPARE) ? + APM_USER_SUSPEND : APM_USER_HIBERNATION; /* * Queue an event to all "writer" users that we want * to suspend and need their ack. @@ -550,7 +554,7 @@ static int apm_suspend_notifier(struct notifier_block *nb, as->writer && as->suser) { as->suspend_state = SUSPEND_PENDING; atomic_inc(&suspend_acks_pending); - queue_add_event(&as->queue, APM_USER_SUSPEND); + queue_add_event(&as->queue, apm_event); } } @@ -601,11 +605,14 @@ static int apm_suspend_notifier(struct notifier_block *nb, return notifier_from_errno(err); case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + apm_event = (event == PM_POST_SUSPEND) ? + APM_NORMAL_RESUME : APM_HIBERNATION_RESUME; /* * Anyone on the APM queues will think we're still suspended. * Send a message so everyone knows we're now awake again. */ - queue_event(APM_NORMAL_RESUME); + queue_event(apm_event); /* * Finally, wake up anyone who is sleeping on the suspend. diff --git a/include/uapi/linux/apm_bios.h b/include/uapi/linux/apm_bios.h index 724f409adae0..df79bca1b898 100644 --- a/include/uapi/linux/apm_bios.h +++ b/include/uapi/linux/apm_bios.h @@ -67,6 +67,8 @@ struct apm_bios_info { #define APM_USER_SUSPEND 0x000a #define APM_STANDBY_RESUME 0x000b #define APM_CAPABILITY_CHANGE 0x000c +#define APM_USER_HIBERNATION 0x000d +#define APM_HIBERNATION_RESUME 0x000e /* * Error codes -- cgit v1.2.3 From ec9c9c2ec1d164f3c5f3c9ac41f43de40040e43c Mon Sep 17 00:00:00 2001 From: Emil Goode Date: Tue, 7 Jan 2014 17:24:55 +0100 Subject: ACPI / thermal: remove const from thermal_zone_device_ops declaration The following commit introduced the requirement to not declare thermal_zone_device_ops structs as const in order to allow changing the .get_temp callback. commit 4e5e4705bf69ea450f58fc709ac5888f321a9299 Author: Eduardo Valentin Date: Wed Jul 3 15:35:39 2013 -0400 thermal: introduce device tree parser Modify acpi_thermal_zone_ops to follow the new requirement. Signed-off-by: Emil Goode Acked-by: Eduardo Valentin [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 0d9f46b5ae6d..9eaf3bf013f0 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -862,7 +862,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, return acpi_thermal_cooling_device_cb(thermal, cdev, false); } -static const struct thermal_zone_device_ops acpi_thermal_zone_ops = { +static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, -- cgit v1.2.3 From 5076f00504c62489b63197392856b9bad1ebcbd5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:43:12 +0800 Subject: ACPICA: Debug output: Fix a couple of small output issues. 1) Fix utcache to use the proper return macros in order to maintain the function nesting level. 2) Enable the function nesting level for all ACPI applications instead of just acpiexec. Linux kernel behaviour is not affected by this patch as Linux doesn't use ACPICA object cache mechanism currently. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utcache.c | 12 ++++++------ drivers/acpi/acpica/utdebug.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 366bfec4b770..cacd2fd9e665 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -248,12 +248,12 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) ACPI_FUNCTION_NAME(os_acquire_object); if (!cache) { - return (NULL); + return_PTR(NULL); } status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { - return (NULL); + return_PTR(NULL); } ACPI_MEM_TRACKING(cache->requests++); @@ -276,7 +276,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { - return (NULL); + return_PTR(NULL); } /* Clear (zero) the previously used Object */ @@ -299,15 +299,15 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { - return (NULL); + return_PTR(NULL); } object = ACPI_ALLOCATE_ZEROED(cache->object_size); if (!object) { - return (NULL); + return_PTR(NULL); } } - return (object); + return_PTR(object); } #endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 03ae8affe48f..d971c8631263 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -194,9 +194,9 @@ acpi_debug_print(u32 requested_debug_level, */ acpi_os_printf("%9s-%04ld ", module_name, line_number); -#ifdef ACPI_EXEC_APP +#ifdef ACPI_APPLICATION /* - * For acpi_exec only, emit the thread ID and nesting level. + * For acpi_exec/iASL only, emit the thread ID and nesting level. * Note: nesting level is really only useful during a single-thread * execution. Otherwise, multiple threads will keep resetting the * level. -- cgit v1.2.3 From 5af2b6351b3cc0dadd6888928005a61f2667c80d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:43:18 +0800 Subject: ACPICA: Disassembler: Improve pathname support for emitted External() statements. This change adds full pathname support for external names that have been resolved internally by the inclusion of additional ACPI tables (via the iASL -e option). Without this change, the disassembler can emit multiple externals for the same object, or it become confused when the Scope() operator is used on an external object. Linux kernel behaviour is not affected as the structure changes and the new invocations are only used by compiler and disassembler which are not shipped in the kernel currently. Reported-by: Michael Tsirkin Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 9 +++++---- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dswload.c | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 53ed1a8ba4f0..d95ca5449ace 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1038,15 +1038,16 @@ struct acpi_external_list { struct acpi_external_list *next; u32 value; u16 length; + u16 flags; u8 type; - u8 flags; - u8 resolved; - u8 emitted; }; /* Values for Flags field above */ -#define ACPI_IPATH_ALLOCATED 0x01 +#define ACPI_EXT_RESOLVED_REFERENCE 0x01 /* Object was resolved during cross ref */ +#define ACPI_EXT_ORIGIN_FROM_FILE 0x02 /* External came from a file */ +#define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ +#define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ struct acpi_external_file { char *path; diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 2d4c07322576..e7a57c554e84 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -105,7 +105,7 @@ acpi_ds_create_external_region(acpi_status lookup_status, * operation_region not found. Generate an External for it, and * insert the name into the namespace. */ - acpi_dm_add_to_external_list(op, path, ACPI_TYPE_REGION, 0); + acpi_dm_add_op_to_external_list(op, path, ACPI_TYPE_REGION, 0, 0); status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION, ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, node); diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 95e681a36f9c..2dbe109727c8 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -181,8 +181,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, * Target of Scope() not found. Generate an External for it, and * insert the name into the namespace. */ - acpi_dm_add_to_external_list(op, path, ACPI_TYPE_DEVICE, - 0); + acpi_dm_add_op_to_external_list(op, path, + ACPI_TYPE_DEVICE, 0, 0); status = acpi_ns_lookup(walk_state->scope_info, path, object_type, ACPI_IMODE_LOAD_PASS1, -- cgit v1.2.3 From bb3fec146c8561441db058db07b3fbdd7fe7e1df Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 8 Jan 2014 13:43:23 +0800 Subject: ACPICA: Remove unused ACPI_FREE_BUFFER macro. No functional change. This macro is no longer used by ACPICA and it is not public. Also update comments related to the use of ACPI_ALLOCATE_BUFFER and the use of acpi_os_free (kfree is equivalent and prefered in the kernel) to free the buffer. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsxfeval.c | 23 +++++++++++++---------- drivers/acpi/acpica/utalloc.c | 10 +++++++--- include/acpi/actypes.h | 12 ++---------- 3 files changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index e973e311f856..1f0c28ba50df 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -84,7 +84,7 @@ acpi_evaluate_object_typed(acpi_handle handle, acpi_object_type return_type) { acpi_status status; - u8 must_free = FALSE; + u8 free_buffer_on_error = FALSE; ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed); @@ -95,14 +95,13 @@ acpi_evaluate_object_typed(acpi_handle handle, } if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { - must_free = TRUE; + free_buffer_on_error = TRUE; } /* Evaluate the object */ - status = - acpi_evaluate_object(handle, pathname, external_params, - return_buffer); + status = acpi_evaluate_object(handle, pathname, + external_params, return_buffer); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -135,11 +134,15 @@ acpi_evaluate_object_typed(acpi_handle handle, pointer)->type), acpi_ut_get_type_name(return_type))); - if (must_free) { - - /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ - - ACPI_FREE_BUFFER(*return_buffer); + if (free_buffer_on_error) { + /* + * Free a buffer created via ACPI_ALLOCATE_BUFFER. + * Note: We use acpi_os_free here because acpi_os_allocate was used + * to allocate the buffer. This purposefully bypasses the + * (optionally enabled) allocation tracking mechanism since we + * only want to track internal allocations. + */ + acpi_os_free(return_buffer->pointer); return_buffer->pointer = NULL; } diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 814267f52715..1851762fc5b5 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -302,9 +302,13 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, return (AE_BUFFER_OVERFLOW); case ACPI_ALLOCATE_BUFFER: - - /* Allocate a new buffer */ - + /* + * Allocate a new buffer. We directectly call acpi_os_allocate here to + * purposefully bypass the (optionally enabled) internal allocation + * tracking mechanism since we only want to track internal + * allocations. Note: The caller should use acpi_os_free to free this + * buffer created via ACPI_ALLOCATE_BUFFER. + */ buffer->pointer = acpi_os_allocate(required_length); break; diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 809b1a0fee7f..68a3ada689c9 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -928,22 +928,14 @@ struct acpi_object_list { * Miscellaneous common Data Structures used by the interfaces */ #define ACPI_NO_BUFFER 0 -#define ACPI_ALLOCATE_BUFFER (acpi_size) (-1) -#define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (-2) +#define ACPI_ALLOCATE_BUFFER (acpi_size) (-1) /* Let ACPICA allocate buffer */ +#define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (-2) /* For internal use only (enables tracking) */ struct acpi_buffer { acpi_size length; /* Length in bytes of the buffer */ void *pointer; /* pointer to buffer */ }; -/* - * Free a buffer created in an struct acpi_buffer via ACPI_ALLOCATE_BUFFER. - * Note: We use acpi_os_free here because acpi_os_allocate was used to allocate - * the buffer. This purposefully bypasses the internal allocation tracking - * mechanism (if it is enabled). - */ -#define ACPI_FREE_BUFFER(b) acpi_os_free((b).pointer) - /* * name_type for acpi_get_name */ -- cgit v1.2.3 From 671cc68dc61f029d44b43a681356078e02d8dab8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 8 Jan 2014 13:43:34 +0800 Subject: ACPICA: Back port and refine validation of the XSDT root table. Some platforms contain an XSDT that is ill-formed or otherwise invalid (such as containing some or all entries that are NULL pointers). This change adds a new function to validate the XSDT before actually using it. If the XSDT is found to be invalid, ACPICA will now fall back to using the RSDT instead. This feature is already in the Linux kernel. When it is back ported to ACPICA, code is refined to follow ACPICA coding style and this patch is the generation of the integration. Original-by: Zhao Yakui Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbutils.c | 210 ++++++++++++++++++++++++------------------ include/acpi/actbl.h | 3 + 2 files changed, 123 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 3d6bb83aa7e7..ee6067062cdc 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -49,69 +49,11 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ +static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address); + static acpi_physical_address acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); -/******************************************************************************* - * - * FUNCTION: acpi_tb_check_xsdt - * - * PARAMETERS: address - Pointer to the XSDT - * - * RETURN: status - * AE_OK - XSDT is okay - * AE_NO_MEMORY - can't map XSDT - * AE_INVALID_TABLE_LENGTH - invalid table length - * AE_NULL_ENTRY - XSDT has NULL entry - * - * DESCRIPTION: validate XSDT -******************************************************************************/ - -static acpi_status -acpi_tb_check_xsdt(acpi_physical_address address) -{ - struct acpi_table_header *table; - u32 length; - u64 xsdt_entry_address; - u8 *table_entry; - u32 table_count; - int i; - - table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); - if (!table) - return AE_NO_MEMORY; - - length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - if (length < sizeof(struct acpi_table_header)) - return AE_INVALID_TABLE_LENGTH; - - table = acpi_os_map_memory(address, length); - if (!table) - return AE_NO_MEMORY; - - /* Calculate the number of tables described in XSDT */ - table_count = - (u32) ((table->length - - sizeof(struct acpi_table_header)) / sizeof(u64)); - table_entry = - ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); - for (i = 0; i < table_count; i++) { - ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry); - if (!xsdt_entry_address) { - /* XSDT has NULL entry */ - break; - } - table_entry += sizeof(u64); - } - acpi_os_unmap_memory(table, length); - - if (i < table_count) - return AE_NULL_ENTRY; - else - return AE_OK; -} - #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * @@ -383,7 +325,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT */ - if (table_entry_size == sizeof(u32)) { + if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) { /* * 32-bit platform, RSDT: Return 32-bit table entry * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return @@ -413,6 +355,87 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) } } +/******************************************************************************* + * + * FUNCTION: acpi_tb_validate_xsdt + * + * PARAMETERS: address - Physical address of the XSDT (from RSDP) + * + * RETURN: Status. AE_OK if the table appears to be valid. + * + * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does + * not contain any NULL entries. A problem that is seen in the + * field is that the XSDT exists, but is actually useless because + * of one or more (or all) NULL entries. + * + ******************************************************************************/ + +static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address) +{ + struct acpi_table_header *table; + u8 *next_entry; + acpi_physical_address address; + u32 length; + u32 entry_count; + acpi_status status; + u32 i; + + /* Get the XSDT length */ + + table = + acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header)); + if (!table) { + return (AE_NO_MEMORY); + } + + length = table->length; + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + + /* + * Minimum XSDT length is the size of the standard ACPI header + * plus one physical address entry + */ + if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) { + return (AE_INVALID_TABLE_LENGTH); + } + + /* Map the entire XSDT */ + + table = acpi_os_map_memory(xsdt_address, length); + if (!table) { + return (AE_NO_MEMORY); + } + + /* Get the number of entries and pointer to first entry */ + + status = AE_OK; + next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); + entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) / + ACPI_XSDT_ENTRY_SIZE); + + /* Validate each entry (physical address) within the XSDT */ + + for (i = 0; i < entry_count; i++) { + address = + acpi_tb_get_root_table_entry(next_entry, + ACPI_XSDT_ENTRY_SIZE); + if (!address) { + + /* Detected a NULL entry, XSDT is invalid */ + + status = AE_NULL_ENTRY; + break; + } + + next_entry += ACPI_XSDT_ENTRY_SIZE; + } + + /* Unmap table */ + + acpi_os_unmap_memory(table, length); + return (status); +} + /******************************************************************************* * * FUNCTION: acpi_tb_parse_root_table @@ -438,16 +461,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) u32 table_count; struct acpi_table_header *table; acpi_physical_address address; - acpi_physical_address uninitialized_var(rsdt_address); u32 length; u8 *table_entry; acpi_status status; ACPI_FUNCTION_TRACE(tb_parse_root_table); - /* - * Map the entire RSDP and extract the address of the RSDT or XSDT - */ + /* Map the entire RSDP and extract the address of the RSDT or XSDT */ + rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); if (!rsdp) { return_ACPI_STATUS(AE_NO_MEMORY); @@ -459,22 +480,20 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) /* Differentiate between RSDT and XSDT root tables */ - if (rsdp->revision > 1 && rsdp->xsdt_physical_address + if ((rsdp->revision > 1) && rsdp->xsdt_physical_address && !acpi_rsdt_forced) { /* - * Root table is an XSDT (64-bit physical addresses). We must use the - * XSDT if the revision is > 1 and the XSDT pointer is present, as per - * the ACPI specification. + * RSDP contains an XSDT (64-bit physical addresses). We must use + * the XSDT if the revision is > 1 and the XSDT pointer is present, + * as per the ACPI specification. */ address = (acpi_physical_address) rsdp->xsdt_physical_address; - table_entry_size = sizeof(u64); - rsdt_address = (acpi_physical_address) - rsdp->rsdt_physical_address; + table_entry_size = ACPI_XSDT_ENTRY_SIZE; } else { /* Root table is an RSDT (32-bit physical addresses) */ address = (acpi_physical_address) rsdp->rsdt_physical_address; - table_entry_size = sizeof(u32); + table_entry_size = ACPI_RSDT_ENTRY_SIZE; } /* @@ -483,15 +502,25 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); - if (table_entry_size == sizeof(u64)) { - if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) { - /* XSDT has NULL entry, RSDT is used */ - address = rsdt_address; - table_entry_size = sizeof(u32); - ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, " - "using RSDT")); + /* + * If it is present, validate the XSDT for access/size and ensure + * that all table entries are at least non-NULL + */ + if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) { + status = acpi_tb_validate_xsdt(address); + if (ACPI_FAILURE(status)) { + ACPI_BIOS_WARNING((AE_INFO, + "XSDT is invalid (%s), using RSDT", + acpi_format_exception(status))); + + /* Fall back to the RSDT */ + + address = + (acpi_physical_address) rsdp->rsdt_physical_address; + table_entry_size = ACPI_RSDT_ENTRY_SIZE; } } + /* Map the RSDT/XSDT table header to get the full table length */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); @@ -501,12 +530,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_tb_print_table_header(address, table); - /* Get the length of the full table, verify length and map entire table */ - + /* + * Validate length of the table, and map entire table. + * Minimum length table must contain at least one entry. + */ length = table->length; acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - if (length < sizeof(struct acpi_table_header)) { + if (length < (sizeof(struct acpi_table_header) + table_entry_size)) { ACPI_BIOS_ERROR((AE_INFO, "Invalid table length 0x%X in RSDT/XSDT", length)); @@ -526,22 +557,21 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) return_ACPI_STATUS(status); } - /* Calculate the number of tables described in the root table */ + /* Get the number of entries and pointer to first entry */ table_count = (u32)((table->length - sizeof(struct acpi_table_header)) / table_entry_size); + table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); + /* * First two entries in the table array are reserved for the DSDT * and FACS, which are not actually present in the RSDT/XSDT - they * come from the FADT */ - table_entry = - ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); acpi_gbl_root_table_list.current_table_count = 2; - /* - * Initialize the root table array from the RSDT/XSDT - */ + /* Initialize the root table array from the RSDT/XSDT */ + for (i = 0; i < table_count; i++) { if (acpi_gbl_root_table_list.current_table_count >= acpi_gbl_root_table_list.max_table_count) { @@ -584,7 +614,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. address, NULL, i); - /* Special case for FADT - get the DSDT and FACS */ + /* Special case for FADT - validate it then get the DSDT and FACS */ if (ACPI_COMPARE_NAME (&acpi_gbl_root_table_list.tables[i].signature, diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 94970880126f..325aeae1fa99 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -182,6 +182,9 @@ struct acpi_table_xsdt { u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ }; +#define ACPI_RSDT_ENTRY_SIZE (sizeof (u32)) +#define ACPI_XSDT_ENTRY_SIZE (sizeof (u64)) + /******************************************************************************* * * FACS - Firmware ACPI Control Structure (FACS) -- cgit v1.2.3 From fab4610583855d544394320d47fccb43305a6398 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 8 Jan 2014 13:43:40 +0800 Subject: ACPICA: Cleanup the option of forcing the use of the RSDT. This change adds a runtime option that will force ACPICA to use the RSDT instead of the XSDT. Although the ACPI spec requires that an XSDT be used instead of the RSDT, the XSDT has been found to be corrupt or ill-formed on some machines. This option is already in the Linux kernel. When it is back ported to ACPICA, code is re-written to follow ACPICA coding style. This patch is the generation of the integration. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- arch/ia64/kernel/acpi.c | 1 - arch/x86/kernel/acpi/boot.c | 3 +-- drivers/acpi/acpica/acglobal.h | 8 ++++++++ drivers/acpi/acpica/tbutils.c | 10 +++++----- include/acpi/acpixf.h | 16 ++++++++-------- 5 files changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 59d52e3aef12..28dc6ba6690a 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -61,7 +61,6 @@ #define PREFIX "ACPI: " -u32 acpi_rsdt_forced; unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 6c0b43bd024b..0b0b91b83d51 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -46,7 +46,6 @@ #include "sleep.h" /* To include x86_acpi_suspend_lowlevel */ static int __initdata acpi_force = 0; -u32 acpi_rsdt_forced; int acpi_disabled; EXPORT_SYMBOL(acpi_disabled); @@ -1564,7 +1563,7 @@ static int __init parse_acpi(char *arg) } /* acpi=rsdt use RSDT instead of XSDT */ else if (strcmp(arg, "rsdt") == 0) { - acpi_rsdt_forced = 1; + acpi_gbl_do_not_use_xsdt = TRUE; } /* "acpi=noirq" disables ACPI interrupt routing */ else if (strcmp(arg, "noirq") == 0) { diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index e9f1fc7f99c7..cffb45742aa5 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -118,6 +118,14 @@ bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); +/* + * Optionally ignore an XSDT if present and use the RSDT instead. + * Although the ACPI specification requires that an XSDT be used instead + * of the RSDT, the XSDT has been found to be corrupt or ill-formed on + * some machines. Default behavior is to use the XSDT if present. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE); + /* * Optionally truncate I/O addresses to 16 bits. Provides compatibility * with other ACPI implementations. NOTE: During ACPICA initialization, diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index ee6067062cdc..6412d3c301cb 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -478,10 +478,10 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) ACPI_CAST_PTR(struct acpi_table_header, rsdp)); - /* Differentiate between RSDT and XSDT root tables */ + /* Use XSDT if present and not overridden. Otherwise, use RSDT */ - if ((rsdp->revision > 1) && rsdp->xsdt_physical_address - && !acpi_rsdt_forced) { + if ((rsdp->revision > 1) && + rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) { /* * RSDP contains an XSDT (64-bit physical addresses). We must use * the XSDT if the revision is > 1 and the XSDT pointer is present, @@ -503,8 +503,8 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); /* - * If it is present, validate the XSDT for access/size and ensure - * that all table entries are at least non-NULL + * If it is present and used, validate the XSDT for access/size + * and ensure that all table entries are at least non-NULL */ if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) { status = acpi_tb_validate_xsdt(address); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 4278aba96503..30b01f889538 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -54,7 +54,6 @@ #include extern u8 acpi_gbl_permanent_mmap; -extern u32 acpi_rsdt_forced; /* * Globals that are publically available @@ -72,17 +71,18 @@ extern u32 acpi_dbg_layer; /* ACPICA runtime options */ -extern u8 acpi_gbl_enable_interpreter_slack; extern u8 acpi_gbl_all_methods_serialized; -extern u8 acpi_gbl_create_osi_method; -extern u8 acpi_gbl_use_default_register_widths; -extern acpi_name acpi_gbl_trace_method_name; -extern u32 acpi_gbl_trace_flags; -extern bool acpi_gbl_enable_aml_debug_object; extern u8 acpi_gbl_copy_dsdt_locally; -extern u8 acpi_gbl_truncate_io_addresses; +extern u8 acpi_gbl_create_osi_method; extern u8 acpi_gbl_disable_auto_repair; extern u8 acpi_gbl_disable_ssdt_table_load; +extern u8 acpi_gbl_do_not_use_xsdt; +extern bool acpi_gbl_enable_aml_debug_object; +extern u8 acpi_gbl_enable_interpreter_slack; +extern u32 acpi_gbl_trace_flags; +extern acpi_name acpi_gbl_trace_method_name; +extern u8 acpi_gbl_truncate_io_addresses; +extern u8 acpi_gbl_use_default_register_widths; /* * Hardware-reduced prototypes. All interfaces that use these macros will -- cgit v1.2.3 From 0249ed2444d65d65fc3f3f64f398f1ad0b7e54cd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:43:46 +0800 Subject: ACPICA: Add option to favor 32-bit FADT addresses. This change adds an option to favor 32-bit FADT addresses when there is a conflict between the 32-bit and 64-bit versions of the same address. The default behavior is to use the 64-bit version in accordance with the ACPI specification. This can now be overridden via the AcpiGbl_Use32BitFadtAddresses flag. Lv Zheng. Also, the "Convert FADT" and "Verify FADT" functions have been merged to simplify the code, make it easier to understand, and make it easier to maintain. Bob Moore. References: https://bugs.acpica.org/show_bug.cgi?id=885 References: https://bugs.acpica.org/show_bug.cgi?id=993 Original-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 10 ++ drivers/acpi/acpica/tbfadt.c | 335 ++++++++++++++++++++++------------------- include/acpi/acpixf.h | 1 + 3 files changed, 194 insertions(+), 152 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index cffb45742aa5..268699879904 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -126,6 +126,16 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE); +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE); + /* * Optionally truncate I/O addresses to 16 bits. Provides compatibility * with other ACPI implementations. NOTE: During ACPICA initialization, diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 9d99f2189693..8f89263ac47e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -56,10 +56,11 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, static void acpi_tb_convert_fadt(void); -static void acpi_tb_validate_fadt(void); - static void acpi_tb_setup_fadt_registers(void); +static u64 +acpi_tb_select_address(char *register_name, u32 address32, u64 address64); + /* Table for conversion of FADT to common internal format and FADT validation */ typedef struct acpi_fadt_info { @@ -175,6 +176,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = { * space_id - ACPI Space ID for this register * byte_width - Width of this register * address - Address of the register + * register_name - ASCII name of the ACPI register * * RETURN: None * @@ -218,6 +220,68 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, generic_address->access_width = 0; /* Access width ANY */ } +/******************************************************************************* + * + * FUNCTION: acpi_tb_select_address + * + * PARAMETERS: register_name - ASCII name of the ACPI register + * address32 - 32-bit address of the register + * address64 - 64-bit address of the register + * + * RETURN: The resolved 64-bit address + * + * DESCRIPTION: Select between 32-bit and 64-bit versions of addresses within + * the FADT. Used for the FACS and DSDT addresses. + * + * NOTES: + * + * Check for FACS and DSDT address mismatches. An address mismatch between + * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and + * DSDT/X_DSDT) could be a corrupted address field or it might indicate + * the presence of two FACS or two DSDT tables. + * + * November 2013: + * By default, as per the ACPICA specification, a valid 64-bit address is + * used regardless of the value of the 32-bit address. However, this + * behavior can be overridden via the acpi_gbl_use32_bit_fadt_addresses flag. + * + ******************************************************************************/ + +static u64 +acpi_tb_select_address(char *register_name, u32 address32, u64 address64) +{ + + if (!address64) { + + /* 64-bit address is zero, use 32-bit address */ + + return ((u64)address32); + } + + if (address32 && (address64 != (u64)address32)) { + + /* Address mismatch between 32-bit and 64-bit versions */ + + ACPI_BIOS_WARNING((AE_INFO, + "32/64X %s address mismatch in FADT: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + register_name, address32, + ACPI_FORMAT_UINT64(address64), + acpi_gbl_use32_bit_fadt_addresses ? 32 : + 64)); + + /* 32-bit address override */ + + if (acpi_gbl_use32_bit_fadt_addresses) { + return ((u64)address32); + } + } + + /* Default is to use the 64-bit address */ + + return (address64); +} + /******************************************************************************* * * FUNCTION: acpi_tb_parse_fadt @@ -331,10 +395,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) acpi_tb_convert_fadt(); - /* Validate FADT values now, before we make any changes */ - - acpi_tb_validate_fadt(); - /* Initialize the global ACPI register structures */ acpi_tb_setup_fadt_registers(); @@ -344,65 +404,54 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * * FUNCTION: acpi_tb_convert_fadt * - * PARAMETERS: None, uses acpi_gbl_FADT + * PARAMETERS: none - acpi_gbl_FADT is used. * * RETURN: None * * DESCRIPTION: Converts all versions of the FADT to a common internal format. - * Expand 32-bit addresses to 64-bit as necessary. + * Expand 32-bit addresses to 64-bit as necessary. Also validate + * important fields within the FADT. * - * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), - * and must contain a copy of the actual FADT. + * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), and must + * contain a copy of the actual BIOS-provided FADT. * * Notes on 64-bit register addresses: * * After this FADT conversion, later ACPICA code will only use the 64-bit "X" * fields of the FADT for all ACPI register addresses. * - * The 64-bit "X" fields are optional extensions to the original 32-bit FADT + * The 64-bit X fields are optional extensions to the original 32-bit FADT * V1.0 fields. Even if they are present in the FADT, they are optional and * are unused if the BIOS sets them to zero. Therefore, we must copy/expand - * 32-bit V1.0 fields if the corresponding X field is zero. + * 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is + * originally zero. * - * For ACPI 1.0 FADTs, all 32-bit address fields are expanded to the - * corresponding "X" fields in the internal FADT. + * For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address + * fields are expanded to the corresponding 64-bit X fields in the internal + * common FADT. * * For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded - * to the corresponding 64-bit X fields. For compatibility with other ACPI - * implementations, we ignore the 64-bit field if the 32-bit field is valid, - * regardless of whether the host OS is 32-bit or 64-bit. + * to the corresponding 64-bit X fields, if the 64-bit field is originally + * zero. Adhering to the ACPI specification, we completely ignore the 32-bit + * field if the 64-bit field is valid, regardless of whether the host OS is + * 32-bit or 64-bit. + * + * Possible additional checks: + * (acpi_gbl_FADT.pm1_event_length >= 4) + * (acpi_gbl_FADT.pm1_control_length >= 2) + * (acpi_gbl_FADT.pm_timer_length >= 4) + * Gpe block lengths must be multiple of 2 * ******************************************************************************/ static void acpi_tb_convert_fadt(void) { + char *name; struct acpi_generic_address *address64; u32 address32; + u8 length; u32 i; - /* - * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. - * Later code will always use the X 64-bit field. Also, check for an - * address mismatch between the 32-bit and 64-bit address fields - * (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate - * the presence of two FACS or two DSDT tables. - */ - if (!acpi_gbl_FADT.Xfacs) { - acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; - } else if (acpi_gbl_FADT.facs && - (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { - ACPI_WARNING((AE_INFO, - "32/64 FACS address mismatch in FADT - two FACS tables!")); - } - - if (!acpi_gbl_FADT.Xdsdt) { - acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; - } else if (acpi_gbl_FADT.dsdt && - (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { - ACPI_WARNING((AE_INFO, - "32/64 DSDT address mismatch in FADT - two DSDT tables!")); - } - /* * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which * should be zero are indeed zero. This will workaround BIOSs that @@ -421,119 +470,24 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.boot_flags = 0; } - /* Update the local FADT table header length */ - - acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); - /* - * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" - * generic address structures as necessary. Later code will always use - * the 64-bit address structures. - * - * March 2009: - * We now always use the 32-bit address if it is valid (non-null). This - * is not in accordance with the ACPI specification which states that - * the 64-bit address supersedes the 32-bit version, but we do this for - * compatibility with other ACPI implementations. Most notably, in the - * case where both the 32 and 64 versions are non-null, we use the 32-bit - * version. This is the only address that is guaranteed to have been - * tested by the BIOS manufacturer. + * Now we can update the local FADT length to the length of the + * current FADT version as defined by the ACPI specification. + * Thus, we will have a common FADT internally. */ - for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - address32 = *ACPI_ADD_PTR(u32, - &acpi_gbl_FADT, - fadt_info_table[i].address32); - - address64 = ACPI_ADD_PTR(struct acpi_generic_address, - &acpi_gbl_FADT, - fadt_info_table[i].address64); - - /* - * If both 32- and 64-bit addresses are valid (non-zero), - * they must match. - */ - if (address64->address && address32 && - (address64->address != (u64)address32)) { - ACPI_BIOS_ERROR((AE_INFO, - "32/64X address mismatch in FADT/%s: " - "0x%8.8X/0x%8.8X%8.8X, using 32", - fadt_info_table[i].name, address32, - ACPI_FORMAT_UINT64(address64-> - address))); - } - - /* Always use 32-bit address if it is valid (non-null) */ - - if (address32) { - /* - * Copy the 32-bit address to the 64-bit GAS structure. The - * Space ID is always I/O for 32-bit legacy address fields - */ - acpi_tb_init_generic_address(address64, - ACPI_ADR_SPACE_SYSTEM_IO, - *ACPI_ADD_PTR(u8, - &acpi_gbl_FADT, - fadt_info_table - [i].length), - (u64) address32, - fadt_info_table[i].name); - } - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_fadt - * - * PARAMETERS: table - Pointer to the FADT to be validated - * - * RETURN: None - * - * DESCRIPTION: Validate various important fields within the FADT. If a problem - * is found, issue a message, but no status is returned. - * Used by both the table manager and the disassembler. - * - * Possible additional checks: - * (acpi_gbl_FADT.pm1_event_length >= 4) - * (acpi_gbl_FADT.pm1_control_length >= 2) - * (acpi_gbl_FADT.pm_timer_length >= 4) - * Gpe block lengths must be multiple of 2 - * - ******************************************************************************/ - -static void acpi_tb_validate_fadt(void) -{ - char *name; - struct acpi_generic_address *address64; - u8 length; - u32 i; + acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); /* - * Check for FACS and DSDT address mismatches. An address mismatch between - * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and - * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables. + * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Later ACPICA code will always use the X 64-bit field. */ - if (acpi_gbl_FADT.facs && - (acpi_gbl_FADT.Xfacs != (u64)acpi_gbl_FADT.facs)) { - ACPI_BIOS_WARNING((AE_INFO, - "32/64X FACS address mismatch in FADT - " - "0x%8.8X/0x%8.8X%8.8X, using 32", - acpi_gbl_FADT.facs, - ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs))); - - acpi_gbl_FADT.Xfacs = (u64)acpi_gbl_FADT.facs; - } - - if (acpi_gbl_FADT.dsdt && - (acpi_gbl_FADT.Xdsdt != (u64)acpi_gbl_FADT.dsdt)) { - ACPI_BIOS_WARNING((AE_INFO, - "32/64X DSDT address mismatch in FADT - " - "0x%8.8X/0x%8.8X%8.8X, using 32", - acpi_gbl_FADT.dsdt, - ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt))); + acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS", + acpi_gbl_FADT.facs, + acpi_gbl_FADT.Xfacs); - acpi_gbl_FADT.Xdsdt = (u64)acpi_gbl_FADT.dsdt; - } + acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", + acpi_gbl_FADT.dsdt, + acpi_gbl_FADT.Xdsdt); /* If Hardware Reduced flag is set, we are all done */ @@ -545,17 +499,94 @@ static void acpi_tb_validate_fadt(void) for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { /* - * Generate pointer to the 64-bit address, get the register - * length (width) and the register name + * Get the 32-bit and 64-bit addresses, as well as the register + * length and register name. */ + address32 = *ACPI_ADD_PTR(u32, + &acpi_gbl_FADT, + fadt_info_table[i].address32); + address64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, fadt_info_table[i].address64); - length = - *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, - fadt_info_table[i].length); + + length = *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table[i].length); + name = fadt_info_table[i].name; + /* + * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. Later code will always use + * the 64-bit address structures. + * + * November 2013: + * Now always use the 64-bit address if it is valid (non-zero), in + * accordance with the ACPI specification which states that a 64-bit + * address supersedes the 32-bit version. This behavior can be + * overridden by the acpi_gbl_use32_bit_fadt_addresses flag. + * + * During 64-bit address construction and verification, + * these cases are handled: + * + * Address32 zero, Address64 [don't care] - Use Address64 + * + * Address32 non-zero, Address64 zero - Copy/use Address32 + * Address32 non-zero == Address64 non-zero - Use Address64 + * Address32 non-zero != Address64 non-zero - Warning, use Address64 + * + * Override: if acpi_gbl_use32_bit_fadt_addresses is TRUE, and: + * Address32 non-zero != Address64 non-zero - Warning, copy/use Address32 + * + * Note: space_id is always I/O for 32-bit legacy address fields + */ + if (address32) { + if (!address64->address) { + + /* 64-bit address is zero, use 32-bit address */ + + acpi_tb_init_generic_address(address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table + [i]. + length), + (u64)address32, + name); + } else if (address64->address != (u64)address32) { + + /* Address mismatch */ + + ACPI_BIOS_WARNING((AE_INFO, + "32/64X address mismatch in FADT/%s: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + name, address32, + ACPI_FORMAT_UINT64 + (address64->address), + acpi_gbl_use32_bit_fadt_addresses + ? 32 : 64)); + + if (acpi_gbl_use32_bit_fadt_addresses) { + + /* 32-bit address override */ + + acpi_tb_init_generic_address(address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR + (u8, + &acpi_gbl_FADT, + fadt_info_table + [i]. + length), + (u64) + address32, + name); + } + } + } + /* * For each extended field, check for length mismatch between the * legacy length field and the corresponding 64-bit X length field. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 30b01f889538..01ba80b1f91f 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -82,6 +82,7 @@ extern u8 acpi_gbl_enable_interpreter_slack; extern u32 acpi_gbl_trace_flags; extern acpi_name acpi_gbl_trace_method_name; extern u8 acpi_gbl_truncate_io_addresses; +extern u8 acpi_gbl_use32_bit_fadt_addresses; extern u8 acpi_gbl_use_default_register_widths; /* -- cgit v1.2.3 From 4bec3d80a0c596cbde846cfb424058e1374ad6ff Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:10 +0800 Subject: ACPICA: Improve exception handling for GPE block installation. 1) Return an actual status value from acpi_ev_get_gpe_xrupt_block. 2) Don't clobber the status when exiting acpi_ev_install_gpe_block. References: https://bugs.acpica.org/show_bug.cgi?id=1019 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acevents.h | 4 +++- drivers/acpi/acpica/evgpeblk.c | 8 ++++---- drivers/acpi/acpica/evgpeutil.c | 24 +++++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 41abe552c7a3..073830512d84 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -149,7 +149,9 @@ acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); -struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number); +acpi_status +acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, + struct acpi_gpe_xrupt_info **gpe_xrupt_block); acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt); diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index a9e76bc4ad97..a31e549e64cc 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -87,9 +87,9 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, return_ACPI_STATUS(status); } - gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block(interrupt_number); - if (!gpe_xrupt_block) { - status = AE_NO_MEMORY; + status = + acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block); + if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -112,7 +112,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, acpi_os_release_lock(acpi_gbl_gpe_lock, flags); unlock_and_exit: - status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index d3f5e1e2a2b1..4d764e847a08 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -197,8 +197,9 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * FUNCTION: acpi_ev_get_gpe_xrupt_block * * PARAMETERS: interrupt_number - Interrupt for a GPE block + * gpe_xrupt_block - Where the block is returned * - * RETURN: A GPE interrupt block + * RETURN: Status * * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt * block per unique interrupt level used for GPEs. Should be @@ -207,7 +208,9 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * ******************************************************************************/ -struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) +acpi_status +acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, + struct acpi_gpe_xrupt_info ** gpe_xrupt_block) { struct acpi_gpe_xrupt_info *next_gpe_xrupt; struct acpi_gpe_xrupt_info *gpe_xrupt; @@ -221,7 +224,8 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt) { if (next_gpe_xrupt->interrupt_number == interrupt_number) { - return_PTR(next_gpe_xrupt); + *gpe_xrupt_block = next_gpe_xrupt; + return_ACPI_STATUS(AE_OK); } next_gpe_xrupt = next_gpe_xrupt->next; @@ -231,7 +235,7 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); if (!gpe_xrupt) { - return_PTR(NULL); + return_ACPI_STATUS(AE_NO_MEMORY); } gpe_xrupt->interrupt_number = interrupt_number; @@ -250,6 +254,7 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) } else { acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); /* Install new interrupt handler if not SCI_INT */ @@ -259,14 +264,15 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) acpi_ev_gpe_xrupt_handler, gpe_xrupt); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not install GPE interrupt handler at level 0x%X", - interrupt_number)); - return_PTR(NULL); + ACPI_EXCEPTION((AE_INFO, status, + "Could not install GPE interrupt handler at level 0x%X", + interrupt_number)); + return_ACPI_STATUS(status); } } - return_PTR(gpe_xrupt); + *gpe_xrupt_block = gpe_xrupt; + return_ACPI_STATUS(AE_OK); } /******************************************************************************* -- cgit v1.2.3 From 87beb7e828c24fe4d8af5490120bf2847a9b3b2b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:15 +0800 Subject: ACPICA: Update several debug statements - no functional change. Update the format and information emitted from several debug output statements. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsutils.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index ade44e49deb4..d7f53fb2979a 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -727,27 +727,26 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, index++; } - index--; + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "NumOperands %d, ArgCount %d, Index %d\n", + walk_state->num_operands, arg_count, index)); - /* It is the appropriate order to get objects from the Result stack */ + /* Create the interpreter arguments, in reverse order */ + index--; for (i = 0; i < arg_count; i++) { arg = arguments[index]; - - /* Force the filling of the operand stack in inverse order */ - - walk_state->operand_index = (u8) index; + walk_state->operand_index = (u8)index; status = acpi_ds_create_operand(walk_state, arg, index); if (ACPI_FAILURE(status)) { goto cleanup; } - index--; - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Arg #%u (%p) done, Arg1=%p\n", index, arg, - first_arg)); + "Created Arg #%u (%p) %u args total\n", + index, arg, arg_count)); + index--; } return_ACPI_STATUS(status); -- cgit v1.2.3 From 0f607cb59efd702630e30e7eeb17adca5b3eda3c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:21 +0800 Subject: ACPICA: Enhance ACPI warning for memory/IO address conflicts. This change improves the warning message when a system address conflicts with an existing operation region. It now emits the region address range in addition to the input (system) address range. Reported-by: Prarit Bhargava Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utaddress.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index e0a2e2779c2e..2c2b6ae5dfc4 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -224,10 +224,11 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id, while (range_info) { /* - * Check if the requested Address/Length overlaps this address_range. - * Four cases to consider: + * Check if the requested address/length overlaps this + * address range. There are four cases to consider: * - * 1) Input address/length is contained completely in the address range + * 1) Input address/length is contained completely in the + * address range * 2) Input address/length overlaps range at the range start * 3) Input address/length overlaps range at the range end * 4) Input address/length completely encompasses the range @@ -244,11 +245,17 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id, region_node); ACPI_WARNING((AE_INFO, - "0x%p-0x%p %s conflicts with Region %s %d", + "%s range 0x%p-0x%p conflicts with OpRegion 0x%p-0x%p (%s)", + acpi_ut_get_region_name(space_id), ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, end_address), - acpi_ut_get_region_name(space_id), - pathname, overlap_count)); + ACPI_CAST_PTR(void, + range_info-> + start_address), + ACPI_CAST_PTR(void, + range_info-> + end_address), + pathname)); ACPI_FREE(pathname); } } -- cgit v1.2.3 From 20c40de0595e8683b56085c4c91be66734d06f5a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:26 +0800 Subject: ACPICA: Parser: Updates/fixes for debug output. Major changes in this patch are made to improve the debug output mode of the compiler. Linux kernel behaviour is not affected as the change only applies to the compiler which is not shipped in the Linux kernel. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psopinfo.c | 49 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index 9ba5301e5751..d7bba3c7ce56 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -71,6 +71,8 @@ static const u8 acpi_gbl_argument_count[] = const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) { + const char *opcode_name = "Unknown AML opcode"; + ACPI_FUNCTION_NAME(ps_get_opcode_info); /* @@ -92,11 +94,54 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) return (&acpi_gbl_aml_op_info [acpi_gbl_long_op_index[(u8)opcode]]); } +#ifdef ACPI_ASL_COMPILER +#include "asldefine.h" + + switch (opcode) { + case AML_RAW_DATA_BYTE: + opcode_name = "-Raw Data Byte-"; + break; + + case AML_RAW_DATA_WORD: + opcode_name = "-Raw Data Word-"; + break; + + case AML_RAW_DATA_DWORD: + opcode_name = "-Raw Data Dword-"; + break; + + case AML_RAW_DATA_QWORD: + opcode_name = "-Raw Data Qword-"; + break; + + case AML_RAW_DATA_BUFFER: + opcode_name = "-Raw Data Buffer-"; + break; + + case AML_RAW_DATA_CHAIN: + opcode_name = "-Raw Data Buffer Chain-"; + break; + + case AML_PACKAGE_LENGTH: + opcode_name = "-Package Length-"; + break; + + case AML_UNASSIGNED_OPCODE: + opcode_name = "-Unassigned Opcode-"; + break; + + case AML_DEFAULT_ARG_OP: + opcode_name = "-Default Arg-"; + break; + + default: + break; + } +#endif /* Unknown AML opcode */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Unknown AML opcode [%4.4X]\n", opcode)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%4.4X]\n", opcode_name, opcode)); return (&acpi_gbl_aml_op_info[_UNK]); } -- cgit v1.2.3 From 5d4de9af84332490fb06c8785ae03d95eaa4e8f1 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:32 +0800 Subject: ACPICA: Conditionally define a local variable that is used for debug only. This patch improves the relationship between the opcode debugging information and CONFIG_ACPI_DEBUG enablement. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psopinfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index d7bba3c7ce56..b0c9787dbe61 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -71,7 +71,9 @@ static const u8 acpi_gbl_argument_count[] = const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) { +#ifdef ACPI_DEBUG_OUTPUT const char *opcode_name = "Unknown AML opcode"; +#endif ACPI_FUNCTION_NAME(ps_get_opcode_info); @@ -94,7 +96,7 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) return (&acpi_gbl_aml_op_info [acpi_gbl_long_op_index[(u8)opcode]]); } -#ifdef ACPI_ASL_COMPILER +#if defined ACPI_ASL_COMPILER && defined ACPI_DEBUG_OUTPUT #include "asldefine.h" switch (opcode) { -- cgit v1.2.3 From 1a2c478371d6050e438a6960f0e3bf68f21a748d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:38 +0800 Subject: ACPICA: Add an error message if the Debugger fails initialization. Previously, only status was returned. Linux kernel behaviour is not affected as the changes only apply to the debugger which is currently not shipped in the kernel. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utxfinit.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 75efea0539c1..246ef68681f4 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -122,8 +122,16 @@ acpi_status __init acpi_initialize_subsystem(void) /* If configured, initialize the AML debugger */ - ACPI_DEBUGGER_EXEC(status = acpi_db_initialize()); - return_ACPI_STATUS(status); +#ifdef ACPI_DEBUGGER + status = acpi_db_initialize(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "During Debugger initialization")); + return_ACPI_STATUS(status); + } +#endif + + return_ACPI_STATUS(AE_OK); } ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_subsystem) -- cgit v1.2.3 From 06d186010ccfbaed6981991d221bd7769b891537 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 8 Jan 2014 13:44:51 +0800 Subject: ACPICA: Interpreter: Add additional debug info for an error case. Emit the name of the namespace node for the error case when there is no subobject attached to the node. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exresnte.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index acd34f599313..7ca6925a87ca 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -124,7 +124,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, } if (!source_desc) { - ACPI_ERROR((AE_INFO, "No object attached to node %p", node)); + ACPI_ERROR((AE_INFO, "No object attached to node [%4.4s] %p", + node->name.ascii, node)); return_ACPI_STATUS(AE_AML_NO_OPERAND); } -- cgit v1.2.3 From ed6069445dbfd765d0b652aba8589eb8a6a0a197 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 8 Jan 2014 13:44:56 +0800 Subject: ACPICA: Linuxize: Cleanup spaces after special macro invocations. This patch reflects the improvment of a cleanup step which is performed in the release process. There are still spaces in the "linuxized" ACPICA files after special macro invocations. This is because indent treats comments and pre-processor directives as spaces, thus we need to skip them. Before applying this patch, cleanup code will search from keyword back to end of line and wipe spaces between them. After applying this patch, cleanup code will search to the end of the macro invocations, skip "empty lines", "comments" and "pre-processor directives", then wipe the spaces between the new line and the first non-spaces characters. Following improvements are thus achieved in the release automation by this commit which are originally maintained manually: - acpi_status acpi_ev_remove_global_lock_handler(void); +acpi_status acpi_ev_remove_global_lock_handler(void); - acpi_status +acpi_status acpi_ev_match_gpe_method(acpi_handle obj_handle, - acpi_status acpi_subsystem_status(void); +acpi_status acpi_subsystem_status(void); - acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, +acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, - acpi_status +acpi_status acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout); - acpi_status +acpi_status acpi_get_sleep_type_data(u8 sleep_state, u8 *slp_typ_a, u8 *slp_typ_b); - acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); +acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); Some empty lines are restored by this commit due to the change of the removal implementation. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 1 - drivers/acpi/acpica/acevents.h | 5 ++--- drivers/acpi/acpica/utglobal.c | 4 ---- include/acpi/acpixf.h | 20 +++----------------- 4 files changed, 5 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index a9fd0b872062..2bf3ca2b8a7a 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -113,7 +113,6 @@ void acpi_db_display_handlers(void); ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)) - ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void)) /* diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 073830512d84..0fb0adf435d6 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -71,9 +71,8 @@ acpi_status acpi_ev_init_global_lock_handler(void); ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_acquire_global_lock(u16 timeout)) - ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_release_global_lock(void)) - acpi_status acpi_ev_remove_global_lock_handler(void); +acpi_status acpi_ev_remove_global_lock_handler(void); /* * evgpe - Low-level GPE support @@ -133,7 +132,7 @@ acpi_status acpi_ev_gpe_initialize(void); ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_ev_update_gpes(acpi_owner_id table_owner_id)) - acpi_status +acpi_status acpi_ev_match_gpe_method(acpi_handle obj_handle, u32 level, void *context, void **return_value); diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 81f9a9584451..030cb0dc673c 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -388,11 +388,7 @@ acpi_status acpi_ut_init_globals(void) /* Public globals */ ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) - ACPI_EXPORT_SYMBOL(acpi_dbg_level) - ACPI_EXPORT_SYMBOL(acpi_dbg_layer) - ACPI_EXPORT_SYMBOL(acpi_gpe_count) - ACPI_EXPORT_SYMBOL(acpi_current_gpe_count) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 01ba80b1f91f..cfe929b23d8a 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -131,10 +131,9 @@ acpi_status __init acpi_terminate(void); * Miscellaneous global interfaces */ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void)) #ifdef ACPI_FUTURE_USAGE - acpi_status acpi_subsystem_status(void); +acpi_status acpi_subsystem_status(void); #endif #ifdef ACPI_FUTURE_USAGE @@ -279,16 +278,13 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_sci_handler(acpi_sci_handler address)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_install_global_event_handler (acpi_gbl_event_handler handler, void *context)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_install_fixed_event_handler(u32 acpi_event, @@ -296,12 +292,10 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status handler, void *context)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_fixed_event_handler(u32 acpi_event, acpi_event_handler handler)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_install_gpe_handler(acpi_handle gpe_device, @@ -310,15 +304,14 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_gpe_handler address, void *context)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, u32 gpe_number, acpi_gpe_handler address)) acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, - acpi_notify_handler handler, - void *context); + acpi_notify_handler handler, + void *context); acpi_status acpi_remove_notify_handler(acpi_handle device, @@ -367,7 +360,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_event(u32 event, u32 flags)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_clear_event(u32 event)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status @@ -405,20 +397,16 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status parent_device, acpi_handle gpe_device, u32 gpe_number)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_gpe_status(acpi_handle gpe_device, u32 gpe_number, acpi_event_status *event_status)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status @@ -432,7 +420,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status *gpe_block_address, u32 register_count, u32 interrupt_number)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)) @@ -533,7 +520,6 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status #ifdef ACPI_FUTURE_USAGE ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer_resolution(u32 *resolution)) - ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer(u32 *ticks)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status -- cgit v1.2.3 From 71487f3ffd77a33a5335e8350e8828daa0941c28 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 8 Jan 2014 13:45:02 +0800 Subject: ACPICA: Utilities: Cleanup declarations of the acpi_gbl_debug_file global. This global is acting as an OSL global variable, implemented in the oswinxf.c and osunixxf.c. This patch cleans up the definition of this variable so that new utilities do not need to define it in order to link. Linux kernel behaviour is not affected as the changes only applies to the ACPICA userspace utilities which are not shipped in the kernel currently. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 12 ++++++++++++ include/acpi/platform/acenv.h | 9 +++++++++ 2 files changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 268699879904..24db8e153bf0 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -500,6 +500,18 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects; #endif /* ACPI_DEBUGGER */ +/***************************************************************************** + * + * Application globals + * + ****************************************************************************/ + +#ifdef ACPI_APPLICATION + +ACPI_FILE ACPI_INIT_GLOBAL(acpi_gbl_debug_file, NULL); + +#endif /* ACPI_APPLICATION */ + /***************************************************************************** * * Info/help support diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 9c9031381792..b402eb67af83 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -395,4 +395,13 @@ typedef char *va_list; #endif /* ACPI_USE_SYSTEM_CLIBRARY */ +#ifndef ACPI_FILE +#ifdef ACPI_APPLICATION +#include +#define ACPI_FILE FILE * +#else +#define ACPI_FILE void * +#endif /* ACPI_APPLICATION */ +#endif /* ACPI_FILE */ + #endif /* __ACENV_H__ */ -- cgit v1.2.3 From 7ca380f60626d90cdd17cc60de5e756422e35b2a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 20 Dec 2013 19:47:26 +0100 Subject: ACPI / cpuidle: fix max idle state handling with hotplug CPU support acpi_processor_hotplug() calls acpi_processor_setup_cpuidle_cx() without calling acpi_processor_setup_cpuidle_states() first so it is possible that dev->state_count becomes different from drv->state_count (in case of SMP system with unsupported C2/C3 states + enabled CPU hotplug and num_online_cpus() becoming > 1). The driver code assumes that cpuidle core will handle such cases but currently this is untrue (dev->state_count is used only for handling cpuidle state sysfs entries and drv->state_count is used for all other cases) and will not be fixed in the future as dev->state_count is planned to be removed. Fix the issue by checking for the max supported idle state in C2/C3 state's ->enter handler (acpi_idle_enter_simple() for C2/C3 and acpi_idle_enter_bm() for C3 + bm_check flag set) and setting the C1 state (instead of higher states) when needed. Also remove no longer needed max idle state checks from acpi_processor_setup_cpuidle_[states,cx](). Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Cc: Len Brown Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 644516d9bde6..45e3b81d6c29 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -785,6 +785,13 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); +#endif + if (cx->entry_method == ACPI_CSTATE_FFH) { if (current_set_polling_and_test()) return -EINVAL; @@ -831,6 +838,13 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); +#endif + if (!cx->bm_sts_skip && acpi_idle_bm_check()) { if (drv->safe_state_index >= 0) { return drv->states[drv->safe_state_index].enter(dev, @@ -932,12 +946,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, if (!cx->valid) continue; -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) - continue; -#endif per_cpu(acpi_cstate[count], dev->cpu) = cx; count++; @@ -987,13 +995,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) if (!cx->valid) continue; -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) - continue; -#endif - state = &drv->states[count]; snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); -- cgit v1.2.3 From 130a5f692425e6237229598a8624da0a247f33d5 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 20 Dec 2013 19:47:27 +0100 Subject: ACPI / cpuidle: remove dev->state_count setting dev->state_count is now always equal to drv->state_count and drv->state_count no longer can change during driver's lifetime so the default dev->state_count initialization in cpuidle_enable_device() (called from cpuidle_register_device()) can be used instead. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Cc: Len Brown Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 45e3b81d6c29..23c80e1372a9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -953,8 +953,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, break; } - dev->state_count = count; - if (!count) return -EINVAL; -- cgit v1.2.3 From dbf87ab89fbd14b723b7282de635bc70f4996342 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 20 Dec 2013 19:47:28 +0100 Subject: intel_idle: do C1E promotion disable quirk for hotplugged CPUs If the system is booted with some CPUs offline C1E promotion disable quirk won't be applied because on_each_cpu() in intel_idle_cpuidle_driver_init() operates only on online CPUs. Fix it by adding the C1E promotion disable handling to intel_idle_cpu_init() (which is also called during CPU_ONLINE operation). Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Cc: Len Brown Reviewed-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/idle/intel_idle.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 797ed29a36ea..920232ffb282 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -688,6 +688,9 @@ static int intel_idle_cpu_init(int cpu) if (icpu->auto_demotion_disable_flags) smp_call_function_single(cpu, auto_demotion_disable, NULL, 1); + if (icpu->disable_promotion_to_c1e) + smp_call_function_single(cpu, c1e_promotion_disable, NULL, 1); + return 0; } -- cgit v1.2.3 From 4955a5412cad83da6e994d939bdb4f7887e4585e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 20 Dec 2013 19:47:29 +0100 Subject: intel_idle: remove superfluous dev->state_count initialization intel_idle driver sets dev->state_count to drv->state_count so the default dev->state_count initialization in cpuidle_enable_device() (called from cpuidle_register_device()) can be used instead. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Cc: Len Brown Reviewed-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/idle/intel_idle.c | 29 ----------------------------- 1 file changed, 29 deletions(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 920232ffb282..282186e53290 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -644,39 +644,10 @@ static int __init intel_idle_cpuidle_driver_init(void) */ static int intel_idle_cpu_init(int cpu) { - int cstate; struct cpuidle_device *dev; dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); - dev->state_count = 1; - - for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { - int num_substates, mwait_hint, mwait_cstate, mwait_substate; - - if (cpuidle_state_table[cstate].enter == NULL) - break; - - if (cstate + 1 > max_cstate) { - printk(PREFIX "max_cstate %d reached\n", max_cstate); - break; - } - - mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); - mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); - mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); - - /* does the state exist in CPUID.MWAIT? */ - num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) - & MWAIT_SUBSTATE_MASK; - - /* if sub-state in table is not enumerated by CPUID */ - if ((mwait_substate + 1) > num_substates) - continue; - - dev->state_count += 1; - } - dev->cpu = cpu; if (cpuidle_register_device(dev)) { -- cgit v1.2.3 From b981513f806d26b2cc971eb65ced14bede67558b Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jan 2014 16:15:19 +0800 Subject: ACPI / scan: bail out early if failed to parse APIC ID for CPU Enhance ACPI CPU hotplug driver to print clear error message and bail out early if BIOS returns wrong value in ACPI MADT table or _MAT method. Otherwise it will add the CPU device even if failed to get APIC ID and fails any operations against sysfs interface: /sys/devices/system/cpu/cpux/online Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 3c1d6b0c09a4..6ce71b07c197 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -212,7 +212,7 @@ static int acpi_processor_get_info(struct acpi_device *device) union acpi_object object = { 0 }; struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; struct acpi_processor *pr = acpi_driver_data(device); - int cpu_index, device_declaration = 0; + int apic_id, cpu_index, device_declaration = 0; acpi_status status = AE_OK; static int cpu0_initialized; unsigned long long value; @@ -258,18 +258,21 @@ static int acpi_processor_get_info(struct acpi_device *device) device_declaration = 1; pr->acpi_id = value; } - pr->apic_id = acpi_get_apicid(pr->handle, device_declaration, - pr->acpi_id); - cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id); - /* Handle UP system running SMP kernel, with no LAPIC in MADT */ - if (!cpu0_initialized && (cpu_index == -1) && - (num_online_cpus() == 1)) { - cpu_index = 0; + apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id); + if (apic_id < 0) { + acpi_handle_err(pr->handle, "failed to get CPU APIC ID.\n"); + return -ENODEV; } + pr->apic_id = apic_id; - cpu0_initialized = 1; - + cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id); + if (!cpu0_initialized) { + cpu0_initialized = 1; + /* Handle UP system running SMP kernel, with no LAPIC in MADT */ + if ((cpu_index == -1) && (num_online_cpus() == 1)) + cpu_index = 0; + } pr->id = cpu_index; /* @@ -282,6 +285,7 @@ static int acpi_processor_get_info(struct acpi_device *device) if (ret) return ret; } + /* * On some boxes several processors use the same processor bus id. * But they are located in different scope. For example: -- cgit v1.2.3 From 5c551e624abba6782034edd5b9eb58ac6f146b38 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 10 Jan 2014 10:51:53 +0100 Subject: ACPI / sleep: remove panic in case hardware has changed after S4 Some BIOSes change hardware based on the state of a laptop's lid. If the lid is closed, the touchpad is disabled and the checksum changes. Windows 8 no longer aborts resume if the checksum has changed. Signed-off-by: Oliver Neukum [rjw: Use pr_crit() for the message and don't break the string] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 721e949e606e..32f7dee2f16b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -670,11 +670,8 @@ static void acpi_hibernation_leave(void) /* Reprogram control registers */ acpi_leave_sleep_state_prep(ACPI_STATE_S4); /* Check the hardware signature */ - if (facs && s4_hardware_signature != facs->hardware_signature) { - printk(KERN_EMERG "ACPI: Hardware changed while hibernated, " - "cannot resume!\n"); - panic("ACPI S4 hardware signature mismatch"); - } + if (facs && s4_hardware_signature != facs->hardware_signature) + pr_crit("ACPI: Hardware changed while hibernated, success doubtful!\n"); /* Restore the NVS memory area */ suspend_nvs_restore(); /* Allow EC transactions to happen. */ -- cgit v1.2.3 From c713cd7f2d799c50a0721bf51d178ea9567215dd Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 10 Jan 2014 16:00:05 -0800 Subject: ACPI / scan: ACPI device object sysfs attribute for _STA evaluation This patch adds a "status" attribute for an ACPI device. This status attribute shows the value of the _STA object. The _STA object returns current status of an ACPI device: enabled, disabled, functioning, present. Signed-off-by: Srinivas Pandruvada [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 32b340171d41..c0f57ff15024 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -602,6 +602,20 @@ acpi_device_sun_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); +static ssize_t status_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%llu\n", sta); +} +static DEVICE_ATTR_RO(status); + static int acpi_device_setup_files(struct acpi_device *dev) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -657,6 +671,12 @@ static int acpi_device_setup_files(struct acpi_device *dev) dev->pnp.sun = (unsigned long)-1; } + if (acpi_has_method(dev->handle, "_STA")) { + result = device_create_file(&dev->dev, &dev_attr_status); + if (result) + goto end; + } + /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. @@ -712,6 +732,8 @@ static void acpi_device_remove_files(struct acpi_device *dev) device_remove_file(&dev->dev, &dev_attr_adr); device_remove_file(&dev->dev, &dev_attr_modalias); device_remove_file(&dev->dev, &dev_attr_hid); + if (acpi_has_method(dev->handle, "_STA")) + device_remove_file(&dev->dev, &dev_attr_status); if (dev->handle) device_remove_file(&dev->dev, &dev_attr_path); } -- cgit v1.2.3 From 8a6720ec2020f01756154d9c272f88a6af76fb81 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 14 Jan 2014 12:23:40 +0000 Subject: PM / clock_ops: fix up clk prepare/unprepare count The drivers/base/power/clock_ops.c file is causing warnings from the clock driver (as shown below) due to failing to do a clk_prepare() call before enabling a clock. It also fails to check the balance of prepare/unprepare as __pm_clk_remove() do clk_disable_unprepare() call. This bug has probably been in since commit b2476490e ("clk: introduce the common clock framework") as the warning was part of the original commit. It is strange that it has not been noticed (although this has also been coupled with a failure for certain SH builds to not build the necessary glue to use this method of controlling the clocks). In summary, this is probably needed in several stable branches but need advice on which ones. On the Renesas Lager board, this causes numerous warnings of the following and even worse the clock system will not enable clocks, causing drivers that are in development to fail to work: WARNING: CPU: 0 PID: 1 at drivers/clk/clk.c:883 __clk_enable+0x2c/0xa0() Signed-off-by: Ben Dooks Reviewed-by: Ian Molton Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 9d8fde709390..b9dd8fac87d7 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -43,6 +43,7 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) if (IS_ERR(ce->clk)) { ce->status = PCE_STATUS_ERROR; } else { + clk_prepare(ce->clk); ce->status = PCE_STATUS_ACQUIRED; dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); } @@ -99,10 +100,12 @@ static void __pm_clk_remove(struct pm_clock_entry *ce) if (ce->status < PCE_STATUS_ERROR) { if (ce->status == PCE_STATUS_ENABLED) - clk_disable_unprepare(ce->clk); + clk_disable(ce->clk); - if (ce->status >= PCE_STATUS_ACQUIRED) + if (ce->status >= PCE_STATUS_ACQUIRED) { + clk_unprepare(ce->clk); clk_put(ce->clk); + } } kfree(ce->con_id); -- cgit v1.2.3 From afdd3ab315a4454ccb7895ddade2c20bdf91f5c6 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 14 Jan 2014 12:23:41 +0000 Subject: PM / clock_ops: check return of clk_enable() in pm_clk_resume() The clk_enable() call in the pm_clk_resume() call returns an error that is not being checked. If clk_enable() fails then we should not set the state of the clock to PCE_STATUS_ENABLED. Note, the issue of warning the user if this fails has not been addressed in this patch as this is not the only place the driver calls clk_enable(). Signed-off-by: Ben Dooks Reviewed-by: Ian Molton Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index b9dd8fac87d7..cad7190465d6 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -252,6 +252,7 @@ int pm_clk_resume(struct device *dev) struct pm_subsys_data *psd = dev_to_psd(dev); struct pm_clock_entry *ce; unsigned long flags; + int ret; dev_dbg(dev, "%s()\n", __func__); @@ -262,8 +263,9 @@ int pm_clk_resume(struct device *dev) list_for_each_entry(ce, &psd->clock_list, node) { if (ce->status < PCE_STATUS_ERROR) { - clk_enable(ce->clk); - ce->status = PCE_STATUS_ENABLED; + ret = clk_enable(ce->clk); + if (!ret) + ce->status = PCE_STATUS_ENABLED; } } -- cgit v1.2.3 From 5cda3fbb155bff96c971d058ed040d5c85612fd8 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 14 Jan 2014 12:23:42 +0000 Subject: PM / clock_ops: report clock errors from clk_enable() If clk_enable() fails, then print a message so that the user can see what is happening instead of silently failing to enable the clock. Signed-off-by: Ben Dooks Reviewed-by: Ian Molton Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index cad7190465d6..e870bbe9ec4e 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -32,6 +32,21 @@ struct pm_clock_entry { enum pce_status status; }; +/** + * pm_clk_enable - Enable a clock, reporting any errors + * @dev: The device for the given clock + * @clk: The clock being enabled. + */ +static inline int __pm_clk_enable(struct device *dev, struct clk *clk) +{ + int ret = clk_enable(clk); + if (ret) + dev_err(dev, "%s: failed to enable clk %p, error %d\n", + __func__, clk, ret); + + return ret; +} + /** * pm_clk_acquire - Acquire a device clock. * @dev: Device whose clock is to be acquired. @@ -263,7 +278,7 @@ int pm_clk_resume(struct device *dev) list_for_each_entry(ce, &psd->clock_list, node) { if (ce->status < PCE_STATUS_ERROR) { - ret = clk_enable(ce->clk); + ret = __pm_clk_enable(dev, ce->clk); if (!ret) ce->status = PCE_STATUS_ENABLED; } @@ -381,7 +396,7 @@ int pm_clk_resume(struct device *dev) spin_lock_irqsave(&psd->lock, flags); list_for_each_entry(ce, &psd->clock_list, node) - clk_enable(ce->clk); + __pm_clk_enable(dev, ce->clk); spin_unlock_irqrestore(&psd->lock, flags); -- cgit v1.2.3 From 00159a2013269bc0a617de885e4b921349192bd0 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Tue, 14 Jan 2014 14:21:13 -0500 Subject: ACPI / memhotplug: add parameter to disable memory hotplug When booting a kexec/kdump kernel on a system that has specific memory hotplug regions the boot will fail with warnings like: swapper/0: page allocation failure: order:9, mode:0x84d0 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-65.el7.x86_64 #1 Hardware name: QCI QSSC-S4R/QSSC-S4R, BIOS QSSC-S4R.QCI.01.00.S013.032920111005 03/29/2011 0000000000000000 ffff8800341bd8c8 ffffffff815bcc67 ffff8800341bd950 ffffffff8113b1a0 ffff880036339b00 0000000000000009 00000000000084d0 ffff8800341bd950 ffffffff815b87ee 0000000000000000 0000000000000200 Call Trace: [] dump_stack+0x19/0x1b [] warn_alloc_failed+0xf0/0x160 [] ? __alloc_pages_direct_compact+0xac/0x196 [] __alloc_pages_nodemask+0x7ff/0xa00 [] vmemmap_alloc_block+0x62/0xba [] vmemmap_alloc_block_buf+0x15/0x3b [] vmemmap_populate+0xb4/0x21b [] sparse_mem_map_populate+0x27/0x35 [] sparse_add_one_section+0x7a/0x185 [] __add_pages+0xaf/0x240 [] arch_add_memory+0x59/0xd0 [] add_memory+0xb9/0x1b0 [] acpi_memory_device_add+0x18d/0x26d [] acpi_bus_device_attach+0x7d/0xcd [] acpi_ns_walk_namespace+0xc8/0x17f [] ? acpi_bus_type_and_status+0x90/0x90 [] ? acpi_bus_type_and_status+0x90/0x90 [] acpi_walk_namespace+0x95/0xc5 [] acpi_bus_scan+0x8b/0x9d [] acpi_scan_init+0x63/0x160 [] acpi_init+0x25d/0x2a6 [] ? acpi_sleep_proc_init+0x2a/0x2a [] do_one_initcall+0xe2/0x190 [] kernel_init_freeable+0x17c/0x207 [] ? do_early_param+0x88/0x88 [] ? rest_init+0x80/0x80 [] kernel_init+0xe/0x180 [] ret_from_fork+0x7c/0xb0 [] ? rest_init+0x80/0x80 Mem-Info: Node 0 DMA per-cpu: CPU 0: hi: 0, btch: 1 usd: 0 Node 0 DMA32 per-cpu: CPU 0: hi: 42, btch: 7 usd: 0 active_anon:0 inactive_anon:0 isolated_anon:0 active_file:0 inactive_file:0 isolated_file:0 unevictable:0 dirty:0 writeback:0 unstable:0 free:872 slab_reclaimable:13 slab_unreclaimable:1880 mapped:0 shmem:0 pagetables:0 bounce:0 free_cma:0 because the system has run out of memory at boot time. This occurs because of the following sequence in the boot: Main kernel boots and sets E820 map. The second kernel is booted with a map generated by the kdump service using memmap= and memmap=exactmap. These parameters are added to the kernel parameters of the kexec/kdump kernel. The kexec/kdump kernel has limited memory resources so as not to severely impact the main kernel. The system then panics and the kdump/kexec kernel boots (which is a completely new kernel boot). During this boot ACPI is initialized and the kernel (as can be seen above) traverses the ACPI namespace and finds an entry for a memory device to be hotadded. ie) [] __add_pages+0xaf/0x240 [] arch_add_memory+0x59/0xd0 [] add_memory+0xb9/0x1b0 [] acpi_memory_device_add+0x18d/0x26d [] acpi_bus_device_attach+0x7d/0xcd [] acpi_ns_walk_namespace+0xc8/0x17f [] ? acpi_bus_type_and_status+0x90/0x90 [] ? acpi_bus_type_and_status+0x90/0x90 [] acpi_walk_namespace+0x95/0xc5 [] acpi_bus_scan+0x8b/0x9d [] acpi_scan_init+0x63/0x160 [] acpi_init+0x25d/0x2a6 At this point the kernel adds page table information and the the kexec/kdump kernel runs out of memory. This can also be reproduced by using the memmap=exactmap and mem=X parameters on the main kernel and booting. This patchset resolves the problem by adding a kernel parameter, acpi_no_memhotplug, to disable ACPI memory hotplug. Signed-off-by: Prarit Bhargava Acked-by: Vivek Goyal Acked-by: Toshi Kani Acked-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 3 +++ drivers/acpi/acpi_memhotplug.c | 12 ++++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 50680a59a2ff..f87856eafea8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -343,6 +343,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. no: ACPI OperationRegions are not marked as reserved, no further checks are performed. + acpi_no_memhotplug [ACPI] Disable memory hotplug. Useful for kdump + kernels. + add_efi_memmap [EFI; X86] Include EFI memory map in kernel's map of available physical RAM. diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 9aeacdfca410..b67be85ff0fc 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -360,7 +360,19 @@ static void acpi_memory_device_remove(struct acpi_device *device) acpi_memory_device_free(mem_device); } +static bool __initdata acpi_no_memhotplug; + void __init acpi_memory_hotplug_init(void) { + if (acpi_no_memhotplug) + return; + acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); } + +static int __init disable_acpi_memory_hotplug(char *str) +{ + acpi_no_memhotplug = true; + return 1; +} +__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug); -- cgit v1.2.3 From 3d8e00909df96c2d3eace3996748be9c0a437e5a Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 14 Jan 2014 16:46:35 +0800 Subject: ACPI: fix create_modalias() return value handling Currently, create_modalias() handles the output truncated case in an improper way (return -EINVAL). Plus, acpi_device_uevent() and acpi_device_modalias_show() do improper check for the create_modalias() return value as well. This patch fixes create_modalias() to return -EINVAL if there is an output error, return -ENOMEM if the output is truncated, and also fixes both acpi_device_uevent() and acpi_device_modalias_show() to do proper return value check. Signed-off-by: Zhang Rui Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fd39459926b1..c92532158195 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -85,6 +85,9 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, * Creates hid/cid(s) string needed for modalias and uevent * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: * char *modalias: "acpi:IBM0001:ACPI0001" + * Return: 0: no _HID and no _CID + * -EINVAL: output error + * -ENOMEM: output is truncated */ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int size) @@ -101,8 +104,10 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, list_for_each_entry(id, &acpi_dev->pnp.ids, list) { count = snprintf(&modalias[len], size, "%s:", id->id); - if (count < 0 || count >= size) - return -EINVAL; + if (count < 0) + return EINVAL; + if (count >= size) + return -ENOMEM; len += count; size -= count; } @@ -116,10 +121,9 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha struct acpi_device *acpi_dev = to_acpi_device(dev); int len; - /* Device has no HID and no CID or string is >1024 */ len = create_modalias(acpi_dev, buf, 1024); if (len <= 0) - return 0; + return len; buf[len++] = '\n'; return len; } @@ -782,8 +786,8 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENOMEM; len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], sizeof(env->buf) - env->buflen); - if (len >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; + if (len <= 0) + return len; env->buflen += len; return 0; } -- cgit v1.2.3 From 6eb2451f7c43c4a7f84ae7b613ea975317b951f1 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 14 Jan 2014 16:46:36 +0800 Subject: ACPI: add module autoloading support for ACPI enumerated devices An ACPI enumerated device may have its compatible id strings. To support the compatible ACPI ids (acpi_device->pnp.ids), we introduced acpi_driver_match_device() to match the driver->acpi_match_table and acpi_device->pnp.ids. For those drivers, MODULE_DEVICE_TABLE(acpi, xxx) is used to exports the driver module alias in the format of "acpi:device_compatible_ids". But in the mean time, the current code does not export the ACPI compatible strings as part of the module_alias for the ACPI enumerated devices, which will break the module autoloading. Take the following piece of code for example, static const struct acpi_device_id xxx_acpi_match[] = { { "INTABCD", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, xxx_acpi_match); If this piece of code is used in a platform driver for an ACPI enumerated platform device, the platform driver module_alias is "acpi:INTABCD", but the uevent attribute of its platform device node is "platform:INTABCD:00" (PREFIX:platform_device->name). If this piece of code is used in an i2c driver for an ACPI enumerated i2c device, the i2c driver module_alias is "acpi:INTABCD", but the uevent of its i2c device node is "i2c:INTABCD:00" (PREFIX:i2c_client->name). If this piece of code is used in an spi driver for an ACPI enumerated spi device, the spi driver module_alias is "acpi:INTABCD", but the uevent of its spi device node is "spi:INTABCD" (PREFIX:spi_device->modalias). The reason why the module autoloading is not broken for now is that the uevent file of the ACPI device node is "acpi:INTABCD". Thus it is the ACPI device node creation that loads the platform/i2c/spi driver. So this is a problem that will affect us the day when the ACPI bus is removed from device model. This patch introduces two new APIs, one for exporting ACPI ids in uevent MODALIAS field, and another for exporting ACPI ids in device' modalias sysfs attribute. For any bus that supports ACPI enumerated devices, it needs to invoke these two functions for their uevent and modalias attribute. Signed-off-by: Zhang Rui Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 15 ++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c92532158195..680bb5647701 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -116,6 +116,63 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, return len; } +/* + * Creates uevent modalias field for ACPI enumerated devices. + * Because the other buses does not support ACPI HIDs & CIDs. + * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: + * "acpi:IBM0001:ACPI0001" + */ +int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +{ + struct acpi_device *acpi_dev; + int len; + + acpi_dev = ACPI_COMPANION(dev); + if (!acpi_dev) + return -ENODEV; + + /* Fall back to bus specific way of modalias exporting */ + if (list_empty(&acpi_dev->pnp.ids)) + return -ENODEV; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len <= 0) + return len; + env->buflen += len; + return 0; +} +EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); + +/* + * Creates modalias sysfs attribute for ACPI enumerated devices. + * Because the other buses does not support ACPI HIDs & CIDs. + * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: + * "acpi:IBM0001:ACPI0001" + */ +int acpi_device_modalias(struct device *dev, char *buf, int size) +{ + struct acpi_device *acpi_dev; + int len; + + acpi_dev = ACPI_COMPANION(dev); + if (!acpi_dev) + return -ENODEV; + + /* Fall back to bus specific way of modalias exporting */ + if (list_empty(&acpi_dev->pnp.ids)) + return -ENODEV; + + len = create_modalias(acpi_dev, buf, size -1); + if (len <= 0) + return len; + buf[len++] = '\n'; + return len; +} +EXPORT_SYMBOL_GPL(acpi_device_modalias); + static ssize_t acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { struct acpi_device *acpi_dev = to_acpi_device(dev); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d9099b15b472..22325ed24139 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -409,6 +409,9 @@ static inline bool acpi_driver_match_device(struct device *dev, return !!acpi_match_device(drv->acpi_match_table, dev); } +int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); +int acpi_device_modalias(struct device *, char *, int); + #define ACPI_PTR(_ptr) (_ptr) #else /* !CONFIG_ACPI */ @@ -488,6 +491,18 @@ static inline bool acpi_driver_match_device(struct device *dev, return false; } +static inline int acpi_device_uevent_modalias(struct device *dev, + struct kobj_uevent_env *env) +{ + return -ENODEV; +} + +static inline int acpi_device_modalias(struct device *dev, + char *buf, int size) +{ + return -ENODEV; +} + #define ACPI_PTR(_ptr) (NULL) #endif /* !CONFIG_ACPI */ -- cgit v1.2.3 From 8c4ff6d0094a16809a7ecdd49d71cf06b0a51326 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 14 Jan 2014 16:46:37 +0800 Subject: ACPI: fix module autoloading for ACPI enumerated devices ACPI enumerated devices has ACPI style _HID and _CID strings, all of these strings can be used for both driver loading and matching. Currently, in Platform, I2C and SPI bus, the ACPI style driver matching is supported by invoking acpi_driver_match_device() in bus .match() callback. But, the module autoloading is still broken. For example, there is any ACPI device with _HID "INTABCD" that is enumerated to platform bus, and we have a driver that can probe it. The driver exports its module_alias as "acpi:INTABCD" use the following code static const struct acpi_device_id xxx_acpi_match[] = { { "INTABCD", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, xxx_acpi_match); But, unfortunately, the device' modalias is shown as "platform:INTABCD:00", please refer to modalias_show() and platform_uevent() in drivers/base/platform.c. This results in that the driver will not be loaded automatically when the device node is created, because their modalias do not match. This also applies to I2C and SPI bus. With this patch, the device' modalias will be shown as "acpi:INTABCD" as well. Signed-off-by: Zhang Rui Acked-by: Mark Brown Acked-by: Wolfram Sang Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 12 +++++++++++- drivers/i2c/i2c-core.c | 11 +++++++++++ drivers/spi/spi.c | 10 ++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 3a94b799f166..2f4aea2428b2 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -677,7 +677,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct platform_device *pdev = to_platform_device(dev); - int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); + int len; + + len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); + if (len != -ENODEV) + return len; + + len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -699,6 +705,10 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) if (rc != -ENODEV) return rc; + rc = acpi_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; + add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, pdev->name); return 0; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d74c0b34248e..c4c5588ec0fb 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -104,6 +104,11 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); + int rc; + + rc = acpi_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; if (add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, client->name)) @@ -409,6 +414,12 @@ static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); + int len; + + len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); + if (len != -ENODEV) + return len; + return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 349ebba4b199..827ff49d3d4f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -58,6 +58,11 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { const struct spi_device *spi = to_spi_device(dev); + int len; + + len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); + if (len != -ENODEV) + return len; return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias); } @@ -114,6 +119,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); + int rc; + + rc = acpi_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias); return 0; -- cgit v1.2.3 From b9f73067f32531db608e469a9ad20ce631e34550 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 14 Jan 2014 16:46:38 +0800 Subject: platform: introduce OF style 'modalias' support for platform bus Fix a problem that, the platform bus supports the OF style modalias in .uevent() call, but not in its device 'modalias' sysfs attribute. Signed-off-by: Zhang Rui Acked-by: Rob Herring Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 4 ++++ drivers/of/device.c | 3 +++ include/linux/of_device.h | 6 ++++++ 3 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 2f4aea2428b2..bc78848dd59a 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -679,6 +679,10 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, struct platform_device *pdev = to_platform_device(dev); int len; + len = of_device_get_modalias(dev, buf, PAGE_SIZE -1); + if (len != -ENODEV) + return len; + len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; diff --git a/drivers/of/device.c b/drivers/of/device.c index f685e55e0717..dafb9736ab9b 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -85,6 +85,9 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) int cplen, i; ssize_t tsize, csize, repend; + if ((!dev) || (!dev->of_node)) + return -ENODEV; + /* Name & Type */ csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name, dev->of_node->type); diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 82ce324fdce7..8d7dd6768cb7 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -64,6 +64,12 @@ static inline int of_driver_match_device(struct device *dev, static inline void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { } +static inline int of_device_get_modalias(struct device *dev, + char *str, ssize_t len) +{ + return -ENODEV; +} + static inline int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) { -- cgit v1.2.3 From 5650cef2ea4c660a3d38bb1ac44e9169d310f366 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 6 Jan 2014 21:30:12 +0100 Subject: cpufreq: speedstep: remove unused speedstep_get_state The only caller of speedstep_get_state() was removed in commit d4019f0a92ab ("cpufreq: move freq change notifications to cpufreq core"). So building speedstep-smi.o now triggers a GCC warning: drivers/cpufreq/speedstep-smi.c:148:12: warning: 'speedstep_get_state' defined but not used [-Wunused-function] Remove this unused function. Signed-off-by: Paul Bolle Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/speedstep-smi.c | 32 -------------------------------- 1 file changed, 32 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index 0f5326d6f79f..998c17b42200 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c @@ -140,38 +140,6 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) return result; } -/** - * speedstep_get_state - set the SpeedStep state - * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) - * - */ -static int speedstep_get_state(void) -{ - u32 function = GET_SPEEDSTEP_STATE; - u32 result, state, edi, command, dummy; - - command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - - pr_debug("trying to determine current setting with command %x " - "at port %x\n", command, smi_port); - - __asm__ __volatile__( - "push %%ebp\n" - "out %%al, (%%dx)\n" - "pop %%ebp\n" - : "=a" (result), - "=b" (state), "=D" (edi), - "=c" (dummy), "=d" (dummy), "=S" (dummy) - : "a" (command), "b" (function), "c" (0), - "d" (smi_port), "S" (0), "D" (0) - ); - - pr_debug("state is %x, result is %x\n", state, result); - - return state & 1; -} - - /** * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) -- cgit v1.2.3 From fcd7af917abba798cd954419030142e95139359f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 7 Jan 2014 07:10:10 +0530 Subject: cpufreq: stats: handle cpufreq_unregister_driver() and suspend/resume properly There are several problems with cpufreq stats in the way it handles cpufreq_unregister_driver() and suspend/resume.. - We must not lose data collected so far when suspend/resume happens and so stats directories must not be removed/allocated during these operations, which is done currently. - cpufreq_stat has registered notifiers with both cpufreq and hotplug. It adds sysfs stats directory with a cpufreq notifier: CPUFREQ_NOTIFY and removes this directory with a notifier from hotplug core. In case cpufreq_unregister_driver() is called (on rmmod cpufreq driver), stats directories per cpu aren't removed as CPUs are still online. The only call cpufreq_stats gets is cpufreq_stats_update_policy_cpu() for all CPUs except the last of each policy. And pointer to stat information is stored in the entry for last CPU in the per-cpu cpufreq_stats_table. But policy structure would be freed inside cpufreq core and so that will result in memory leak inside cpufreq stats (as we are never freeing memory for stats). Now if we again insert the module cpufreq_register_driver() will be called and we will again allocate stats data and put it on for first CPU of every policy. In case we only have a single CPU per policy, we will return with a error from cpufreq_stats_create_table() due to this code: if (per_cpu(cpufreq_stats_table, cpu)) return -EBUSY; And so probably cpufreq stats directory would not show up anymore (as it was added inside last policies->kobj which doesn't exist anymore). I haven't tested it, though. Also the values in stats files wouldn't be refreshed as we are using the earlier stats structure. - CPUFREQ_NOTIFY is called from cpufreq_set_policy() which is called for scenarios where we don't really want cpufreq_stat_notifier_policy() to get called. For example whenever we are changing anything related to a policy: min/max/current freq, etc. cpufreq_set_policy() is called and so cpufreq stats is notified. Where we don't do any useful stuff other than simply returning with -EBUSY from cpufreq_stats_create_table(). And so this isn't the right notifier that cpufreq stats.. Due to all above reasons this patch does following changes: - Add new notifiers CPUFREQ_CREATE_POLICY and CPUFREQ_REMOVE_POLICY, which are only called when policy is created/destroyed. They aren't called for suspend/resume paths.. - Use these notifiers in cpufreq_stat_notifier_policy() to create/destory stats sysfs entries. And so cpufreq_unregister_driver() or suspend/resume shouldn't be a problem for cpufreq_stats. - Return early from cpufreq_stat_cpu_callback() for suspend/resume sequence, so that we don't free stats structure. Acked-by: Nicolas Pitre Tested-by: Nicolas Pitre Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 5 +++++ drivers/cpufreq/cpufreq_stats.c | 24 +++++++++++++++++------- include/linux/cpufreq.h | 2 ++ 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3509ca04b5bb..1afbe52d6782 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -943,6 +943,9 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy) struct kobject *kobj; struct completion *cmp; + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_REMOVE_POLICY, policy); + down_read(&policy->rwsem); kobj = &policy->kobj; cmp = &policy->kobj_unregister; @@ -1148,6 +1151,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, ret = cpufreq_add_dev_interface(policy, dev); if (ret) goto err_out_unregister; + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_CREATE_POLICY, policy); } write_lock_irqsave(&cpufreq_driver_lock, flags); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 4cf0d2805cb2..0f7156252453 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -277,7 +277,7 @@ static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) static int cpufreq_stat_notifier_policy(struct notifier_block *nb, unsigned long val, void *data) { - int ret; + int ret = 0; struct cpufreq_policy *policy = data; struct cpufreq_frequency_table *table; unsigned int cpu = policy->cpu; @@ -287,15 +287,21 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, return 0; } - if (val != CPUFREQ_NOTIFY) - return 0; table = cpufreq_frequency_get_table(cpu); if (!table) return 0; - ret = cpufreq_stats_create_table(policy, table); - if (ret) - return ret; - return 0; + + if (val == CPUFREQ_CREATE_POLICY) + ret = cpufreq_stats_create_table(policy, table); + else if (val == CPUFREQ_REMOVE_POLICY) { + /* This might already be freed by cpu hotplug notifier */ + if (per_cpu(cpufreq_stats_table, cpu)) { + cpufreq_stats_free_sysfs(cpu); + cpufreq_stats_free_table(cpu); + } + } + + return ret; } static int cpufreq_stat_notifier_trans(struct notifier_block *nb, @@ -340,6 +346,10 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, { unsigned int cpu = (unsigned long)hcpu; + /* Don't free/allocate stats during suspend/resume */ + if (action & CPU_TASKS_FROZEN) + return 0; + switch (action) { case CPU_DOWN_PREPARE: cpufreq_stats_free_sysfs(cpu); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index aaf800eb9dd2..bb727eb98ed5 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -308,6 +308,8 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy) #define CPUFREQ_NOTIFY (2) #define CPUFREQ_START (3) #define CPUFREQ_UPDATE_POLICY_CPU (4) +#define CPUFREQ_CREATE_POLICY (5) +#define CPUFREQ_REMOVE_POLICY (6) #ifdef CONFIG_CPU_FREQ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); -- cgit v1.2.3 From 027cc2e4a6127fdf29e17a422aacb5ecd9830cbb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 7 Jan 2014 07:10:11 +0530 Subject: cpufreq: stats: remove hotplug notifiers Either CPUs are hot-unplugged or suspend/resume occurs, cpufreq core will send notifications to cpufreq-stats and stats structure and sysfs entries would be correctly handled.. And so we don't actually need hotcpu notifiers in cpufreq-stats anymore. We were only handling cpu hot-unplug events here and that are already taken care of by POLICY notifiers. Acked-by: Nicolas Pitre Tested-by: Nicolas Pitre Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_stats.c | 38 ++------------------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 0f7156252453..8fa58440ea95 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -294,11 +294,8 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, if (val == CPUFREQ_CREATE_POLICY) ret = cpufreq_stats_create_table(policy, table); else if (val == CPUFREQ_REMOVE_POLICY) { - /* This might already be freed by cpu hotplug notifier */ - if (per_cpu(cpufreq_stats_table, cpu)) { - cpufreq_stats_free_sysfs(cpu); - cpufreq_stats_free_table(cpu); - } + cpufreq_stats_free_sysfs(cpu); + cpufreq_stats_free_table(cpu); } return ret; @@ -340,33 +337,6 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, return 0; } -static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - - /* Don't free/allocate stats during suspend/resume */ - if (action & CPU_TASKS_FROZEN) - return 0; - - switch (action) { - case CPU_DOWN_PREPARE: - cpufreq_stats_free_sysfs(cpu); - break; - case CPU_DEAD: - cpufreq_stats_free_table(cpu); - break; - } - return NOTIFY_OK; -} - -/* priority=1 so this will get called before cpufreq_remove_dev */ -static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { - .notifier_call = cpufreq_stat_cpu_callback, - .priority = 1, -}; - static struct notifier_block notifier_policy_block = { .notifier_call = cpufreq_stat_notifier_policy }; @@ -386,14 +356,11 @@ static int __init cpufreq_stats_init(void) if (ret) return ret; - register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); - ret = cpufreq_register_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); if (ret) { cpufreq_unregister_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER); - unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) cpufreq_stats_free_table(cpu); return ret; @@ -409,7 +376,6 @@ static void __exit cpufreq_stats_exit(void) CPUFREQ_POLICY_NOTIFIER); cpufreq_unregister_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); - unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { cpufreq_stats_free_table(cpu); cpufreq_stats_free_sysfs(cpu); -- cgit v1.2.3 From 2d13594dcb7eaa41fa180e8a3b27a8f10845381f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 7 Jan 2014 07:10:12 +0530 Subject: cpufreq: stats: free table and remove sysfs entry in a single routine We don't have code paths now where we need to do these two things separately, so it is better do them in a single routine. Just as they are allocated in a single routine. Acked-by: Nicolas Pitre Tested-by: Nicolas Pitre Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_stats.c | 50 ++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 8fa58440ea95..9dd58835456e 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -151,40 +151,32 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } -/* should be called late in the CPU removal sequence so that the stats - * memory is still available in case someone tries to use it. - */ -static void cpufreq_stats_free_table(unsigned int cpu) +static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (stat) { - pr_debug("%s: Free stat table\n", __func__); - kfree(stat->time_in_state); - kfree(stat); - per_cpu(cpufreq_stats_table, cpu) = NULL; - } + if (!stat) + return; + + pr_debug("%s: Free stat table\n", __func__); + + sysfs_remove_group(&policy->kobj, &stats_attr_group); + kfree(stat->time_in_state); + kfree(stat); + per_cpu(cpufreq_stats_table, policy->cpu) = NULL; } -/* must be called early in the CPU removal sequence (before - * cpufreq_remove_dev) so that policy is still valid. - */ -static void cpufreq_stats_free_sysfs(unsigned int cpu) +static void cpufreq_stats_free_table(unsigned int cpu) { - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy; + policy = cpufreq_cpu_get(cpu); if (!policy) return; - if (!cpufreq_frequency_get_table(cpu)) - goto put_ref; - - if (!policy_is_shared(policy)) { - pr_debug("%s: Free sysfs stat\n", __func__); - sysfs_remove_group(&policy->kobj, &stats_attr_group); - } + if (cpufreq_frequency_get_table(policy->cpu)) + __cpufreq_stats_free_table(policy); -put_ref: cpufreq_cpu_put(policy); } @@ -293,10 +285,8 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, if (val == CPUFREQ_CREATE_POLICY) ret = cpufreq_stats_create_table(policy, table); - else if (val == CPUFREQ_REMOVE_POLICY) { - cpufreq_stats_free_sysfs(cpu); - cpufreq_stats_free_table(cpu); - } + else if (val == CPUFREQ_REMOVE_POLICY) + __cpufreq_stats_free_table(policy); return ret; } @@ -376,10 +366,8 @@ static void __exit cpufreq_stats_exit(void) CPUFREQ_POLICY_NOTIFIER); cpufreq_unregister_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); - for_each_online_cpu(cpu) { + for_each_online_cpu(cpu) cpufreq_stats_free_table(cpu); - cpufreq_stats_free_sysfs(cpu); - } } MODULE_AUTHOR("Zou Nan hai "); -- cgit v1.2.3 From b3f9ff88db6e149086dc111e5652106005fd5923 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 7 Jan 2014 07:10:13 +0530 Subject: cpufreq: stats: create sysfs entries when cpufreq_stats is a module When cpufreq_stats is compiled in as a module, cpufreq driver would have already been registered. And so the CPUFREQ_CREATE_POLICY notifiers wouldn't be called for it. Hence no sysfs entries for stats. :( This patch calls cpufreq_stats_create_table() for each online CPU from cpufreq_stats_init() and so if policy is already created for CPUx then we will register sysfs stats for it. When its not compiled as module, we will return early as policy wouldn't be found for any of the CPUs. Acked-by: Nicolas Pitre Tested-by: Nicolas Pitre Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_stats.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 9dd58835456e..5793e1447fb1 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -180,7 +180,7 @@ static void cpufreq_stats_free_table(unsigned int cpu) cpufreq_cpu_put(policy); } -static int cpufreq_stats_create_table(struct cpufreq_policy *policy, +static int __cpufreq_stats_create_table(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { unsigned int i, j, count = 0, ret = 0; @@ -253,6 +253,26 @@ error_get_fail: return ret; } +static void cpufreq_stats_create_table(unsigned int cpu) +{ + struct cpufreq_policy *policy; + struct cpufreq_frequency_table *table; + + /* + * "likely(!policy)" because normally cpufreq_stats will be registered + * before cpufreq driver + */ + policy = cpufreq_cpu_get(cpu); + if (likely(!policy)) + return; + + table = cpufreq_frequency_get_table(policy->cpu); + if (likely(table)) + __cpufreq_stats_create_table(policy, table); + + cpufreq_cpu_put(policy); +} + static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) { struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, @@ -284,7 +304,7 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, return 0; if (val == CPUFREQ_CREATE_POLICY) - ret = cpufreq_stats_create_table(policy, table); + ret = __cpufreq_stats_create_table(policy, table); else if (val == CPUFREQ_REMOVE_POLICY) __cpufreq_stats_free_table(policy); @@ -346,6 +366,9 @@ static int __init cpufreq_stats_init(void) if (ret) return ret; + for_each_online_cpu(cpu) + cpufreq_stats_create_table(cpu); + ret = cpufreq_register_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); if (ret) { -- cgit v1.2.3 From 652ed95d5fa6074b3c4ea245deb0691f1acb6656 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 9 Jan 2014 20:38:43 +0530 Subject: cpufreq: introduce cpufreq_generic_get() routine CPUFreq drivers that use clock frameworks interface,i.e. clk_get_rate(), to get CPUs clk rate, have similar sort of code used in most of them. This patch adds a generic ->get() which will do the same thing for them. All those drivers are required to now is to set .get to cpufreq_generic_get() and set their clk pointer in policy->clk during ->init(). Acked-by: Hans-Christian Egtvedt Acked-by: Shawn Guo Acked-by: Linus Walleij Acked-by: Shawn Guo Acked-by: Stephen Warren Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/at32ap-cpufreq.c | 17 ++++--------- drivers/cpufreq/cpufreq-cpu0.c | 8 ++---- drivers/cpufreq/cpufreq.c | 26 ++++++++++++++----- drivers/cpufreq/davinci-cpufreq.c | 14 +++------- drivers/cpufreq/dbx500-cpufreq.c | 19 ++------------ drivers/cpufreq/exynos-cpufreq.c | 10 +++----- drivers/cpufreq/exynos5440-cpufreq.c | 33 ++++++++++-------------- drivers/cpufreq/imx6q-cpufreq.c | 8 ++---- drivers/cpufreq/loongson2_cpufreq.c | 15 ++++------- drivers/cpufreq/omap-cpufreq.c | 32 ++++++++--------------- drivers/cpufreq/ppc-corenet-cpufreq.c | 17 +++---------- drivers/cpufreq/s3c24xx-cpufreq.c | 10 +++----- drivers/cpufreq/s3c64xx-cpufreq.c | 33 +++++++++--------------- drivers/cpufreq/s5pv210-cpufreq.c | 21 +++++---------- drivers/cpufreq/spear-cpufreq.c | 8 ++---- drivers/cpufreq/tegra-cpufreq.c | 48 ++++++----------------------------- drivers/cpufreq/unicore2-cpufreq.c | 19 +++++--------- include/linux/cpufreq.h | 3 +++ 18 files changed, 112 insertions(+), 229 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c index 7c03dd84f66a..a1c79f549edb 100644 --- a/drivers/cpufreq/at32ap-cpufreq.c +++ b/drivers/cpufreq/at32ap-cpufreq.c @@ -21,17 +21,8 @@ #include #include -static struct clk *cpuclk; static struct cpufreq_frequency_table *freq_table; -static unsigned int at32_get_speed(unsigned int cpu) -{ - /* No SMP support */ - if (cpu) - return 0; - return (unsigned int)((clk_get_rate(cpuclk) + 500) / 1000); -} - static unsigned int ref_freq; static unsigned long loops_per_jiffy_ref; @@ -39,7 +30,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) { unsigned int old_freq, new_freq; - old_freq = at32_get_speed(0); + old_freq = policy->cur; new_freq = freq_table[index].frequency; if (!ref_freq) { @@ -50,7 +41,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) if (old_freq < new_freq) boot_cpu_data.loops_per_jiffy = cpufreq_scale( loops_per_jiffy_ref, ref_freq, new_freq); - clk_set_rate(cpuclk, new_freq * 1000); + clk_set_rate(policy->clk, new_freq * 1000); if (new_freq < old_freq) boot_cpu_data.loops_per_jiffy = cpufreq_scale( loops_per_jiffy_ref, ref_freq, new_freq); @@ -61,6 +52,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) static int at32_cpufreq_driver_init(struct cpufreq_policy *policy) { unsigned int frequency, rate, min_freq; + static struct clk *cpuclk; int retval, steps, i; if (policy->cpu != 0) @@ -103,6 +95,7 @@ static int at32_cpufreq_driver_init(struct cpufreq_policy *policy) frequency /= 2; } + policy->clk = cpuclk; freq_table[steps - 1].frequency = CPUFREQ_TABLE_END; retval = cpufreq_table_validate_and_show(policy, freq_table); @@ -123,7 +116,7 @@ static struct cpufreq_driver at32_driver = { .init = at32_cpufreq_driver_init, .verify = cpufreq_generic_frequency_table_verify, .target_index = at32_set_target, - .get = at32_get_speed, + .get = cpufreq_generic_get, .flags = CPUFREQ_STICKY, }; diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index 0faf756f6197..bb7b3082efb3 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -30,11 +30,6 @@ static struct clk *cpu_clk; static struct regulator *cpu_reg; static struct cpufreq_frequency_table *freq_table; -static unsigned int cpu0_get_speed(unsigned int cpu) -{ - return clk_get_rate(cpu_clk) / 1000; -} - static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; @@ -100,6 +95,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) static int cpu0_cpufreq_init(struct cpufreq_policy *policy) { + policy->clk = cpu_clk; return cpufreq_generic_init(policy, freq_table, transition_latency); } @@ -107,7 +103,7 @@ static struct cpufreq_driver cpu0_cpufreq_driver = { .flags = CPUFREQ_STICKY, .verify = cpufreq_generic_frequency_table_verify, .target_index = cpu0_set_target, - .get = cpu0_get_speed, + .get = cpufreq_generic_get, .init = cpu0_cpufreq_init, .exit = cpufreq_generic_exit, .name = "generic_cpu0", diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1afbe52d6782..d7efdfe0c12c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -176,6 +176,20 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_generic_init); +unsigned int cpufreq_generic_get(unsigned int cpu) +{ + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); + + if (!policy || IS_ERR(policy->clk)) { + pr_err("%s: No %s associated to cpu: %d\n", __func__, + policy ? "clk" : "policy", cpu); + return 0; + } + + return clk_get_rate(policy->clk) / 1000; +} +EXPORT_SYMBOL_GPL(cpufreq_generic_get); + struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) { struct cpufreq_policy *policy = NULL; @@ -1068,6 +1082,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, goto err_set_policy_cpu; } + write_lock_irqsave(&cpufreq_driver_lock, flags); + for_each_cpu(j, policy->cpus) + per_cpu(cpufreq_cpu_data, j) = policy; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + if (cpufreq_driver->get) { policy->cur = cpufreq_driver->get(policy->cpu); if (!policy->cur) { @@ -1142,11 +1161,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, } #endif - write_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu(j, policy->cpus) - per_cpu(cpufreq_cpu_data, j) = policy; - write_unlock_irqrestore(&cpufreq_driver_lock, flags); - if (!frozen) { ret = cpufreq_add_dev_interface(policy, dev); if (ret) @@ -1174,12 +1188,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, return 0; err_out_unregister: +err_get_freq: write_lock_irqsave(&cpufreq_driver_lock, flags); for_each_cpu(j, policy->cpus) per_cpu(cpufreq_cpu_data, j) = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); -err_get_freq: if (cpufreq_driver->exit) cpufreq_driver->exit(policy); err_set_policy_cpu: diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 04f3390a7a2c..2cf33848d86e 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c @@ -58,14 +58,6 @@ static int davinci_verify_speed(struct cpufreq_policy *policy) return 0; } -static unsigned int davinci_getspeed(unsigned int cpu) -{ - if (cpu) - return 0; - - return clk_get_rate(cpufreq.armclk) / 1000; -} - static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) { struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data; @@ -73,7 +65,7 @@ static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) unsigned int old_freq, new_freq; int ret = 0; - old_freq = davinci_getspeed(0); + old_freq = policy->cur; new_freq = pdata->freq_table[idx].frequency; /* if moving to higher frequency, up the voltage beforehand */ @@ -116,6 +108,8 @@ static int davinci_cpu_init(struct cpufreq_policy *policy) return result; } + policy->clk = cpufreq.armclk; + /* * Time measurement across the target() function yields ~1500-1800us * time taken with no drivers on notification list. @@ -129,7 +123,7 @@ static struct cpufreq_driver davinci_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = davinci_verify_speed, .target_index = davinci_target, - .get = davinci_getspeed, + .get = cpufreq_generic_get, .init = davinci_cpu_init, .exit = cpufreq_generic_exit, .name = "davinci", diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 21d9898e000c..412a78bb0c94 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c @@ -26,24 +26,9 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy, return clk_set_rate(armss_clk, freq_table[index].frequency * 1000); } -static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu) -{ - int i = 0; - unsigned long freq = clk_get_rate(armss_clk) / 1000; - - /* The value is rounded to closest frequency in the defined table. */ - while (freq_table[i + 1].frequency != CPUFREQ_TABLE_END) { - if (freq < freq_table[i].frequency + - (freq_table[i + 1].frequency - freq_table[i].frequency) / 2) - return freq_table[i].frequency; - i++; - } - - return freq_table[i].frequency; -} - static int dbx500_cpufreq_init(struct cpufreq_policy *policy) { + policy->clk = armss_clk; return cpufreq_generic_init(policy, freq_table, 20 * 1000); } @@ -52,7 +37,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = { CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = dbx500_cpufreq_target, - .get = dbx500_cpufreq_getspeed, + .get = cpufreq_generic_get, .init = dbx500_cpufreq_init, .name = "DBX500", .attr = cpufreq_generic_attr, diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index f7c322c7d7ed..4ee3804637be 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -31,11 +31,6 @@ static unsigned int locking_frequency; static bool frequency_locked; static DEFINE_MUTEX(cpufreq_lock); -static unsigned int exynos_getspeed(unsigned int cpu) -{ - return clk_get_rate(exynos_info->cpu_clk) / 1000; -} - static int exynos_cpufreq_get_index(unsigned int freq) { struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; @@ -215,6 +210,7 @@ static struct notifier_block exynos_cpufreq_nb = { static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) { + policy->clk = exynos_info->cpu_clk; return cpufreq_generic_init(policy, exynos_info->freq_table, 100000); } @@ -222,7 +218,7 @@ static struct cpufreq_driver exynos_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = exynos_target, - .get = exynos_getspeed, + .get = cpufreq_generic_get, .init = exynos_cpufreq_cpu_init, .exit = cpufreq_generic_exit, .name = "exynos_cpufreq", @@ -264,7 +260,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_vdd_arm; } - locking_frequency = exynos_getspeed(0); + locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000; register_pm_notifier(&exynos_cpufreq_nb); diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index ffe6faea3a5f..49b756015316 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -100,7 +100,6 @@ struct exynos_dvfs_data { struct resource *mem; int irq; struct clk *cpu_clk; - unsigned int cur_frequency; unsigned int latency; struct cpufreq_frequency_table *freq_table; unsigned int freq_count; @@ -165,7 +164,7 @@ static int init_div_table(void) return 0; } -static void exynos_enable_dvfs(void) +static void exynos_enable_dvfs(unsigned int cur_frequency) { unsigned int tmp, i, cpu; struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; @@ -184,18 +183,18 @@ static void exynos_enable_dvfs(void) /* Set initial performance index */ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) - if (freq_table[i].frequency == dvfs_info->cur_frequency) + if (freq_table[i].frequency == cur_frequency) break; if (freq_table[i].frequency == CPUFREQ_TABLE_END) { dev_crit(dvfs_info->dev, "Boot up frequency not supported\n"); /* Assign the highest frequency */ i = 0; - dvfs_info->cur_frequency = freq_table[i].frequency; + cur_frequency = freq_table[i].frequency; } dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ", - dvfs_info->cur_frequency); + cur_frequency); for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) { tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); @@ -209,11 +208,6 @@ static void exynos_enable_dvfs(void) dvfs_info->base + XMU_DVFS_CTRL); } -static unsigned int exynos_getspeed(unsigned int cpu) -{ - return dvfs_info->cur_frequency; -} - static int exynos_target(struct cpufreq_policy *policy, unsigned int index) { unsigned int tmp; @@ -222,7 +216,7 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int index) mutex_lock(&cpufreq_lock); - freqs.old = dvfs_info->cur_frequency; + freqs.old = policy->cur; freqs.new = freq_table[index].frequency; cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); @@ -250,7 +244,7 @@ static void exynos_cpufreq_work(struct work_struct *work) goto skip_work; mutex_lock(&cpufreq_lock); - freqs.old = dvfs_info->cur_frequency; + freqs.old = policy->cur; cur_pstate = __raw_readl(dvfs_info->base + XMU_P_STATUS); if (cur_pstate >> C0_3_PSTATE_VALID_SHIFT & 0x1) @@ -260,10 +254,9 @@ static void exynos_cpufreq_work(struct work_struct *work) if (likely(index < dvfs_info->freq_count)) { freqs.new = freq_table[index].frequency; - dvfs_info->cur_frequency = freqs.new; } else { dev_crit(dvfs_info->dev, "New frequency out of range\n"); - freqs.new = dvfs_info->cur_frequency; + freqs.new = freqs.old; } cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); @@ -307,6 +300,7 @@ static void exynos_sort_descend_freq_table(void) static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) { + policy->clk = dvfs_info->cpu_clk; return cpufreq_generic_init(policy, dvfs_info->freq_table, dvfs_info->latency); } @@ -316,7 +310,7 @@ static struct cpufreq_driver exynos_driver = { CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = exynos_target, - .get = exynos_getspeed, + .get = cpufreq_generic_get, .init = exynos_cpufreq_cpu_init, .exit = cpufreq_generic_exit, .name = CPUFREQ_NAME, @@ -336,6 +330,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) int ret = -EINVAL; struct device_node *np; struct resource res; + unsigned int cur_frequency; np = pdev->dev.of_node; if (!np) @@ -392,13 +387,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_free_table; } - dvfs_info->cur_frequency = clk_get_rate(dvfs_info->cpu_clk); - if (!dvfs_info->cur_frequency) { + cur_frequency = clk_get_rate(dvfs_info->cpu_clk); + if (!cur_frequency) { dev_err(dvfs_info->dev, "Failed to get clock rate\n"); ret = -EINVAL; goto err_free_table; } - dvfs_info->cur_frequency /= 1000; + cur_frequency /= 1000; INIT_WORK(&dvfs_info->irq_work, exynos_cpufreq_work); ret = devm_request_irq(dvfs_info->dev, dvfs_info->irq, @@ -415,7 +410,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_free_table; } - exynos_enable_dvfs(); + exynos_enable_dvfs(cur_frequency); ret = cpufreq_register_driver(&exynos_driver); if (ret) { dev_err(dvfs_info->dev, diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 2938257b8c19..ce69059be1fc 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -38,11 +38,6 @@ static unsigned int transition_latency; static u32 *imx6_soc_volt; static u32 soc_opp_count; -static unsigned int imx6q_get_speed(unsigned int cpu) -{ - return clk_get_rate(arm_clk) / 1000; -} - static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; @@ -139,6 +134,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) static int imx6q_cpufreq_init(struct cpufreq_policy *policy) { + policy->clk = arm_clk; return cpufreq_generic_init(policy, freq_table, transition_latency); } @@ -146,7 +142,7 @@ static struct cpufreq_driver imx6q_cpufreq_driver = { .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = imx6q_set_target, - .get = imx6q_get_speed, + .get = cpufreq_generic_get, .init = imx6q_cpufreq_init, .exit = cpufreq_generic_exit, .name = "imx6q-cpufreq", diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index a43609218105..b6581abc9207 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -24,8 +24,6 @@ static uint nowait; -static struct clk *cpuclk; - static void (*saved_cpu_wait) (void); static int loongson2_cpu_freq_notifier(struct notifier_block *nb, @@ -44,11 +42,6 @@ static int loongson2_cpu_freq_notifier(struct notifier_block *nb, return 0; } -static unsigned int loongson2_cpufreq_get(unsigned int cpu) -{ - return clk_get_rate(cpuclk); -} - /* * Here we notify other drivers of the proposed change and the final change. */ @@ -69,13 +62,14 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, set_cpus_allowed_ptr(current, &cpus_allowed); /* setting the cpu frequency */ - clk_set_rate(cpuclk, freq); + clk_set_rate(policy->clk, freq); return 0; } static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) { + static struct clk *cpuclk; int i; unsigned long rate; int ret; @@ -104,13 +98,14 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) return ret; } + policy->clk = cpuclk; return cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0); } static int loongson2_cpufreq_exit(struct cpufreq_policy *policy) { cpufreq_frequency_table_put_attr(policy->cpu); - clk_put(cpuclk); + clk_put(policy->clk); return 0; } @@ -119,7 +114,7 @@ static struct cpufreq_driver loongson2_cpufreq_driver = { .init = loongson2_cpufreq_cpu_init, .verify = cpufreq_generic_frequency_table_verify, .target_index = loongson2_cpufreq_target, - .get = loongson2_cpufreq_get, + .get = cpufreq_generic_get, .exit = loongson2_cpufreq_exit, .attr = cpufreq_generic_attr, }; diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5de1e5f73eca..590f5b66d181 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -36,21 +36,9 @@ static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); -static struct clk *mpu_clk; static struct device *mpu_dev; static struct regulator *mpu_reg; -static unsigned int omap_getspeed(unsigned int cpu) -{ - unsigned long rate; - - if (cpu >= NR_CPUS) - return 0; - - rate = clk_get_rate(mpu_clk) / 1000; - return rate; -} - static int omap_target(struct cpufreq_policy *policy, unsigned int index) { int r, ret; @@ -58,11 +46,11 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) unsigned long freq, volt = 0, volt_old = 0, tol = 0; unsigned int old_freq, new_freq; - old_freq = omap_getspeed(policy->cpu); + old_freq = policy->cur; new_freq = freq_table[index].frequency; freq = new_freq * 1000; - ret = clk_round_rate(mpu_clk, freq); + ret = clk_round_rate(policy->clk, freq); if (IS_ERR_VALUE(ret)) { dev_warn(mpu_dev, "CPUfreq: Cannot find matching frequency for %lu\n", @@ -100,7 +88,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) } } - ret = clk_set_rate(mpu_clk, new_freq * 1000); + ret = clk_set_rate(policy->clk, new_freq * 1000); /* scaling down? scale voltage after frequency */ if (mpu_reg && (new_freq < old_freq)) { @@ -108,7 +96,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) if (r < 0) { dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", __func__); - clk_set_rate(mpu_clk, old_freq * 1000); + clk_set_rate(policy->clk, old_freq * 1000); return r; } } @@ -126,9 +114,9 @@ static int omap_cpu_init(struct cpufreq_policy *policy) { int result; - mpu_clk = clk_get(NULL, "cpufreq_ck"); - if (IS_ERR(mpu_clk)) - return PTR_ERR(mpu_clk); + policy->clk = clk_get(NULL, "cpufreq_ck"); + if (IS_ERR(policy->clk)) + return PTR_ERR(policy->clk); if (!freq_table) { result = dev_pm_opp_init_cpufreq_table(mpu_dev, &freq_table); @@ -149,7 +137,7 @@ static int omap_cpu_init(struct cpufreq_policy *policy) freq_table_free(); fail: - clk_put(mpu_clk); + clk_put(policy->clk); return result; } @@ -157,7 +145,7 @@ static int omap_cpu_exit(struct cpufreq_policy *policy) { cpufreq_frequency_table_put_attr(policy->cpu); freq_table_free(); - clk_put(mpu_clk); + clk_put(policy->clk); return 0; } @@ -165,7 +153,7 @@ static struct cpufreq_driver omap_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = omap_target, - .get = omap_getspeed, + .get = cpufreq_generic_get, .init = omap_cpu_init, .exit = omap_cpu_exit, .name = "omap", diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c index 3f7be46d2b27..051000f44ca2 100644 --- a/drivers/cpufreq/ppc-corenet-cpufreq.c +++ b/drivers/cpufreq/ppc-corenet-cpufreq.c @@ -24,12 +24,10 @@ /** * struct cpu_data - per CPU data struct - * @clk: the clk of CPU * @parent: the parent node of cpu clock * @table: frequency table */ struct cpu_data { - struct clk *clk; struct device_node *parent; struct cpufreq_frequency_table *table; }; @@ -81,13 +79,6 @@ static inline const struct cpumask *cpu_core_mask(int cpu) } #endif -static unsigned int corenet_cpufreq_get_speed(unsigned int cpu) -{ - struct cpu_data *data = per_cpu(cpu_data, cpu); - - return clk_get_rate(data->clk) / 1000; -} - /* reduce the duplicated frequencies in frequency table */ static void freq_table_redup(struct cpufreq_frequency_table *freq_table, int count) @@ -158,8 +149,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_np; } - data->clk = of_clk_get(np, 0); - if (IS_ERR(data->clk)) { + policy->clk = of_clk_get(np, 0); + if (IS_ERR(policy->clk)) { pr_err("%s: no clock information\n", __func__); goto err_nomem2; } @@ -255,7 +246,7 @@ static int corenet_cpufreq_target(struct cpufreq_policy *policy, struct cpu_data *data = per_cpu(cpu_data, policy->cpu); parent = of_clk_get(data->parent, data->table[index].driver_data); - return clk_set_parent(data->clk, parent); + return clk_set_parent(policy->clk, parent); } static struct cpufreq_driver ppc_corenet_cpufreq_driver = { @@ -265,7 +256,7 @@ static struct cpufreq_driver ppc_corenet_cpufreq_driver = { .exit = __exit_p(corenet_cpufreq_cpu_exit), .verify = cpufreq_generic_frequency_table_verify, .target_index = corenet_cpufreq_target, - .get = corenet_cpufreq_get_speed, + .get = cpufreq_generic_get, .attr = cpufreq_generic_attr, }; diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 6a1bf96deec0..25069741b507 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -355,11 +355,6 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, return -EINVAL; } -static unsigned int s3c_cpufreq_get(unsigned int cpu) -{ - return clk_get_rate(clk_arm) / 1000; -} - struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) { struct clk *clk; @@ -373,6 +368,7 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) static int s3c_cpufreq_init(struct cpufreq_policy *policy) { + policy->clk = clk_arm; return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); } @@ -408,7 +404,7 @@ static int s3c_cpufreq_suspend(struct cpufreq_policy *policy) { suspend_pll.frequency = clk_get_rate(_clk_mpll); suspend_pll.driver_data = __raw_readl(S3C2410_MPLLCON); - suspend_freq = s3c_cpufreq_get(0) * 1000; + suspend_freq = clk_get_rate(clk_arm); return 0; } @@ -450,7 +446,7 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy) static struct cpufreq_driver s3c24xx_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .target = s3c_cpufreq_target, - .get = s3c_cpufreq_get, + .get = cpufreq_generic_get, .init = s3c_cpufreq_init, .suspend = s3c_cpufreq_suspend, .resume = s3c_cpufreq_resume, diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 8435f45d7e9d..c4226de079ab 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -19,7 +19,6 @@ #include #include -static struct clk *armclk; static struct regulator *vddarm; static unsigned long regulator_latency; @@ -54,14 +53,6 @@ static struct cpufreq_frequency_table s3c64xx_freq_table[] = { }; #endif -static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu) -{ - if (cpu != 0) - return 0; - - return clk_get_rate(armclk) / 1000; -} - static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { @@ -69,7 +60,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int old_freq, new_freq; int ret; - old_freq = clk_get_rate(armclk) / 1000; + old_freq = clk_get_rate(policy->clk) / 1000; new_freq = s3c64xx_freq_table[index].frequency; dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data]; @@ -86,7 +77,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, } #endif - ret = clk_set_rate(armclk, new_freq * 1000); + ret = clk_set_rate(policy->clk, new_freq * 1000); if (ret < 0) { pr_err("Failed to set rate %dkHz: %d\n", new_freq, ret); @@ -101,7 +92,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, if (ret != 0) { pr_err("Failed to set VDDARM for %dkHz: %d\n", new_freq, ret); - if (clk_set_rate(armclk, old_freq * 1000) < 0) + if (clk_set_rate(policy->clk, old_freq * 1000) < 0) pr_err("Failed to restore original clock rate\n"); return ret; @@ -110,7 +101,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, #endif pr_debug("Set actual frequency %lukHz\n", - clk_get_rate(armclk) / 1000); + clk_get_rate(policy->clk) / 1000); return 0; } @@ -169,11 +160,11 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) return -ENODEV; } - armclk = clk_get(NULL, "armclk"); - if (IS_ERR(armclk)) { + policy->clk = clk_get(NULL, "armclk"); + if (IS_ERR(policy->clk)) { pr_err("Unable to obtain ARMCLK: %ld\n", - PTR_ERR(armclk)); - return PTR_ERR(armclk); + PTR_ERR(policy->clk)); + return PTR_ERR(policy->clk); } #ifdef CONFIG_REGULATOR @@ -193,7 +184,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) unsigned long r; /* Check for frequencies we can generate */ - r = clk_round_rate(armclk, freq->frequency * 1000); + r = clk_round_rate(policy->clk, freq->frequency * 1000); r /= 1000; if (r != freq->frequency) { pr_debug("%dkHz unsupported by clock\n", @@ -203,7 +194,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) /* If we have no regulator then assume startup * frequency is the maximum we can support. */ - if (!vddarm && freq->frequency > s3c64xx_cpufreq_get_speed(0)) + if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000) freq->frequency = CPUFREQ_ENTRY_INVALID; freq++; @@ -219,7 +210,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy) pr_err("Failed to configure frequency table: %d\n", ret); regulator_put(vddarm); - clk_put(armclk); + clk_put(policy->clk); } return ret; @@ -229,7 +220,7 @@ static struct cpufreq_driver s3c64xx_cpufreq_driver = { .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = s3c64xx_cpufreq_set_target, - .get = s3c64xx_cpufreq_get_speed, + .get = cpufreq_generic_get, .init = s3c64xx_cpufreq_driver_init, .name = "s3c", }; diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index ccd548c6f0c1..55a8e9fa9435 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -23,7 +23,6 @@ #include #include -static struct clk *cpu_clk; static struct clk *dmc0_clk; static struct clk *dmc1_clk; static DEFINE_MUTEX(set_freq_lock); @@ -164,14 +163,6 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) __raw_writel(tmp1, reg); } -static unsigned int s5pv210_getspeed(unsigned int cpu) -{ - if (cpu) - return 0; - - return clk_get_rate(cpu_clk) / 1000; -} - static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) { unsigned long reg; @@ -193,7 +184,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) goto exit; } - old_freq = s5pv210_getspeed(0); + old_freq = policy->cur; new_freq = s5pv210_freq_table[index].frequency; /* Finding current running level index */ @@ -471,9 +462,9 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) unsigned long mem_type; int ret; - cpu_clk = clk_get(NULL, "armclk"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); + policy->clk = clk_get(NULL, "armclk"); + if (IS_ERR(policy->clk)) + return PTR_ERR(policy->clk); dmc0_clk = clk_get(NULL, "sclk_dmc0"); if (IS_ERR(dmc0_clk)) { @@ -516,7 +507,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) out_dmc1: clk_put(dmc0_clk); out_dmc0: - clk_put(cpu_clk); + clk_put(policy->clk); return ret; } @@ -563,7 +554,7 @@ static struct cpufreq_driver s5pv210_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = s5pv210_target, - .get = s5pv210_getspeed, + .get = cpufreq_generic_get, .init = s5pv210_cpu_init, .name = "s5pv210", #ifdef CONFIG_PM diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index c7525fe33407..5c86e3fa5593 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -30,11 +30,6 @@ static struct { u32 cnt; } spear_cpufreq; -static unsigned int spear_cpufreq_get(unsigned int cpu) -{ - return clk_get_rate(spear_cpufreq.clk) / 1000; -} - static struct clk *spear1340_cpu_get_possible_parent(unsigned long newfreq) { struct clk *sys_pclk; @@ -156,6 +151,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, static int spear_cpufreq_init(struct cpufreq_policy *policy) { + policy->clk = spear_cpufreq.clk; return cpufreq_generic_init(policy, spear_cpufreq.freq_tbl, spear_cpufreq.transition_latency); } @@ -165,7 +161,7 @@ static struct cpufreq_driver spear_cpufreq_driver = { .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = spear_cpufreq_target, - .get = spear_cpufreq_get, + .get = cpufreq_generic_get, .init = spear_cpufreq_init, .exit = cpufreq_generic_exit, .attr = cpufreq_generic_attr, diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c index 01b5578ffecf..e652c1bd8d0f 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra-cpufreq.c @@ -47,21 +47,9 @@ static struct clk *pll_x_clk; static struct clk *pll_p_clk; static struct clk *emc_clk; -static unsigned long target_cpu_speed[NUM_CPUS]; static DEFINE_MUTEX(tegra_cpu_lock); static bool is_suspended; -static unsigned int tegra_getspeed(unsigned int cpu) -{ - unsigned long rate; - - if (cpu >= NUM_CPUS) - return 0; - - rate = clk_get_rate(cpu_clk) / 1000; - return rate; -} - static int tegra_cpu_clk_set_rate(unsigned long rate) { int ret; @@ -103,9 +91,6 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, { int ret = 0; - if (tegra_getspeed(0) == rate) - return ret; - /* * Vote on memory bus frequency based on cpu frequency * This sets the minimum frequency, display or avp may request higher @@ -125,33 +110,16 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, return ret; } -static unsigned long tegra_cpu_highest_speed(void) -{ - unsigned long rate = 0; - int i; - - for_each_online_cpu(i) - rate = max(rate, target_cpu_speed[i]); - return rate; -} - static int tegra_target(struct cpufreq_policy *policy, unsigned int index) { - unsigned int freq; - int ret = 0; + int ret = -EBUSY; mutex_lock(&tegra_cpu_lock); - if (is_suspended) - goto out; - - freq = freq_table[index].frequency; + if (!is_suspended) + ret = tegra_update_cpu_speed(policy, + freq_table[index].frequency); - target_cpu_speed[policy->cpu] = freq; - - ret = tegra_update_cpu_speed(policy, tegra_cpu_highest_speed()); - -out: mutex_unlock(&tegra_cpu_lock); return ret; } @@ -165,7 +133,8 @@ static int tegra_pm_notify(struct notifier_block *nb, unsigned long event, is_suspended = true; pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n", freq_table[0].frequency); - tegra_update_cpu_speed(policy, freq_table[0].frequency); + if (clk_get_rate(cpu_clk) / 1000 != freq_table[0].frequency) + tegra_update_cpu_speed(policy, freq_table[0].frequency); cpufreq_cpu_put(policy); } else if (event == PM_POST_SUSPEND) { is_suspended = false; @@ -189,8 +158,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy) clk_prepare_enable(emc_clk); clk_prepare_enable(cpu_clk); - target_cpu_speed[policy->cpu] = tegra_getspeed(policy->cpu); - /* FIXME: what's the actual transition time? */ ret = cpufreq_generic_init(policy, freq_table, 300 * 1000); if (ret) { @@ -202,6 +169,7 @@ static int tegra_cpu_init(struct cpufreq_policy *policy) if (policy->cpu == 0) register_pm_notifier(&tegra_cpu_pm_notifier); + policy->clk = cpu_clk; return 0; } @@ -217,7 +185,7 @@ static struct cpufreq_driver tegra_cpufreq_driver = { .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, .verify = cpufreq_generic_frequency_table_verify, .target_index = tegra_target, - .get = tegra_getspeed, + .get = cpufreq_generic_get, .init = tegra_cpu_init, .exit = tegra_cpu_exit, .name = "tegra", diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c index 86f6cfec2e09..36cc330b8747 100644 --- a/drivers/cpufreq/unicore2-cpufreq.c +++ b/drivers/cpufreq/unicore2-cpufreq.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -33,28 +34,18 @@ static int ucv2_verify_speed(struct cpufreq_policy *policy) return 0; } -static unsigned int ucv2_getspeed(unsigned int cpu) -{ - struct clk *mclk = clk_get(NULL, "MAIN_CLK"); - - if (cpu) - return 0; - return clk_get_rate(mclk)/1000; -} - static int ucv2_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { struct cpufreq_freqs freqs; - struct clk *mclk = clk_get(NULL, "MAIN_CLK"); int ret; freqs.old = policy->cur; freqs.new = target_freq; cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); - ret = clk_set_rate(mclk, target_freq * 1000); + ret = clk_set_rate(policy->mclk, target_freq * 1000); cpufreq_notify_post_transition(policy, &freqs, ret); return ret; @@ -64,9 +55,13 @@ static int __init ucv2_cpu_init(struct cpufreq_policy *policy) { if (policy->cpu != 0) return -EINVAL; + policy->min = policy->cpuinfo.min_freq = 250000; policy->max = policy->cpuinfo.max_freq = 1000000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->clk = clk_get(NULL, "MAIN_CLK"); + if (IS_ERR(policy->clk)) + return PTR_ERR(policy->clk); return 0; } @@ -74,7 +69,7 @@ static struct cpufreq_driver ucv2_driver = { .flags = CPUFREQ_STICKY, .verify = ucv2_verify_speed, .target = ucv2_target, - .get = ucv2_getspeed, + .get = cpufreq_generic_get, .init = ucv2_cpu_init, .name = "UniCore-II", }; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bb727eb98ed5..422f10561e0b 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -11,6 +11,7 @@ #ifndef _LINUX_CPUFREQ_H #define _LINUX_CPUFREQ_H +#include #include #include #include @@ -66,6 +67,7 @@ struct cpufreq_policy { unsigned int cpu; /* cpu nr of CPU managing this policy */ unsigned int last_cpu; /* cpu nr of previous CPU that managed * this policy */ + struct clk *clk; struct cpufreq_cpuinfo cpuinfo;/* see above */ unsigned int min; /* in kHz */ @@ -470,6 +472,7 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu); int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table); +unsigned int cpufreq_generic_get(unsigned int cpu); int cpufreq_generic_init(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, unsigned int transition_latency); -- cgit v1.2.3 From b69880f9ccf7e13b2e2cb38f49a2451d7aa548b3 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 16 Jan 2014 10:32:25 -0800 Subject: intel_pstate: Add trace point to report internal state. Add perf trace event "power:pstate_sample" to report driver state to aid in diagnosing issues reported against intel_pstate. Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 24 +++++++++++++++++++ include/trace/events/power.h | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index fe91dad8f5e2..7e257b233602 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -51,6 +51,8 @@ static inline int32_t div_fp(int32_t x, int32_t y) return div_s64((int64_t)x << FRAC_BITS, (int64_t)y); } +static u64 energy_divisor; + struct sample { int32_t core_pct_busy; u64 aperf; @@ -559,6 +561,7 @@ static inline void intel_pstate_sample(struct cpudata *cpu) rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); + cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; @@ -603,6 +606,7 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) ctl = pid_calc(pid, busy_scaled); steps = abs(ctl); + if (ctl < 0) intel_pstate_pstate_increase(cpu, steps); else @@ -612,9 +616,24 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; + struct sample *sample; + u64 energy; intel_pstate_sample(cpu); + + sample = &cpu->samples[cpu->sample_ptr]; + rdmsrl(MSR_PKG_ENERGY_STATUS, energy); + intel_pstate_adjust_busy_pstate(cpu); + + trace_pstate_sample(fp_toint(sample->core_pct_busy), + fp_toint(intel_pstate_get_scaled_busy(cpu)), + cpu->pstate.current_pstate, + sample->mperf, + sample->aperf, + div64_u64(energy, energy_divisor), + sample->freq); + intel_pstate_set_sample_time(cpu); } @@ -894,6 +913,7 @@ static int __init intel_pstate_init(void) int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_info; + u64 units; if (no_load) return -ENODEV; @@ -927,8 +947,12 @@ static int __init intel_pstate_init(void) if (rc) goto out; + rdmsrl(MSR_RAPL_POWER_UNIT, units); + energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */ + intel_pstate_debug_expose_params(); intel_pstate_sysfs_expose_params(); + return rc; out: get_online_cpus(); diff --git a/include/trace/events/power.h b/include/trace/events/power.h index cda100d6762d..9e9475c85de5 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -35,6 +35,59 @@ DEFINE_EVENT(cpu, cpu_idle, TP_ARGS(state, cpu_id) ); +TRACE_EVENT(pstate_sample, + + TP_PROTO(u32 core_busy, + u32 scaled_busy, + u32 state, + u64 mperf, + u64 aperf, + u32 energy, + u32 freq + ), + + TP_ARGS(core_busy, + scaled_busy, + state, + mperf, + aperf, + energy, + freq + ), + + TP_STRUCT__entry( + __field(u32, core_busy) + __field(u32, scaled_busy) + __field(u32, state) + __field(u64, mperf) + __field(u64, aperf) + __field(u32, energy) + __field(u32, freq) + + ), + + TP_fast_assign( + __entry->core_busy = core_busy; + __entry->scaled_busy = scaled_busy; + __entry->state = state; + __entry->mperf = mperf; + __entry->aperf = aperf; + __entry->energy = energy; + __entry->freq = freq; + ), + + TP_printk("core_busy=%lu scaled=%lu state=%lu mperf=%llu aperf=%llu energy=%lu freq=%lu ", + (unsigned long)__entry->core_busy, + (unsigned long)__entry->scaled_busy, + (unsigned long)__entry->state, + (unsigned long long)__entry->mperf, + (unsigned long long)__entry->aperf, + (unsigned long)__entry->energy, + (unsigned long)__entry->freq + ) + +); + /* This file can get included multiple times, TRACE_HEADER_MULTI_READ at top */ #ifndef _PWR_EVENT_AVOID_DOUBLE_DEFINING #define _PWR_EVENT_AVOID_DOUBLE_DEFINING -- cgit v1.2.3 From 6f19efc0a1ca08bc61841b971d8b85ab505d95c8 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 20 Dec 2013 15:24:49 +0100 Subject: cpufreq: Add boost frequency support in core This commit adds boost frequency support in cpufreq core (Hardware & Software). Some SoCs (like Exynos4 - e.g. 4x12) allow setting frequency above its normal operation limits. Such mode shall be only used for a short time. Overclocking (boost) support is essentially provided by platform dependent cpufreq driver. This commit unifies support for SW and HW (Intel) overclocking solutions in the core cpufreq driver. Previously the "boost" sysfs attribute was defined in the ACPI processor driver code. By default boost is disabled. One global attribute is available at: /sys/devices/system/cpu/cpufreq/boost. It only shows up when cpufreq driver supports overclocking. Under the hood frequencies dedicated for boosting are marked with a special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table. It is the user's concern to enable/disable overclocking with a proper call to sysfs. The cpufreq_boost_trigger_state() function is defined non static on purpose. It is used later with thermal subsystem to provide automatic enable/disable of the BOOST feature. Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 118 ++++++++++++++++++++++++++++++++++++++++++- drivers/cpufreq/freq_table.c | 56 +++++++++++++++++--- include/linux/cpufreq.h | 24 +++++++++ 3 files changed, 190 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d7efdfe0c12c..08ca8c9f41cd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -352,6 +352,33 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition); /********************************************************************* * SYSFS INTERFACE * *********************************************************************/ +ssize_t show_boost(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled); +} + +static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + int ret, enable; + + ret = sscanf(buf, "%d", &enable); + if (ret != 1 || enable < 0 || enable > 1) + return -EINVAL; + + if (cpufreq_boost_trigger_state(enable)) { + pr_err("%s: Cannot %s BOOST!\n", __func__, + enable ? "enable" : "disable"); + return -EINVAL; + } + + pr_debug("%s: cpufreq BOOST %s\n", __func__, + enable ? "enabled" : "disabled"); + + return count; +} +define_one_global_rw(boost); static struct cpufreq_governor *__find_governor(const char *str_governor) { @@ -2183,6 +2210,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = { .notifier_call = cpufreq_cpu_callback, }; +/********************************************************************* + * BOOST * + *********************************************************************/ +static int cpufreq_boost_set_sw(int state) +{ + struct cpufreq_frequency_table *freq_table; + struct cpufreq_policy *policy; + int ret = -EINVAL; + + list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + freq_table = cpufreq_frequency_get_table(policy->cpu); + if (freq_table) { + ret = cpufreq_frequency_table_cpuinfo(policy, + freq_table); + if (ret) { + pr_err("%s: Policy frequency update failed\n", + __func__); + break; + } + policy->user_policy.max = policy->max; + __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); + } + } + + return ret; +} + +int cpufreq_boost_trigger_state(int state) +{ + unsigned long flags; + int ret = 0; + + if (cpufreq_driver->boost_enabled == state) + return 0; + + write_lock_irqsave(&cpufreq_driver_lock, flags); + cpufreq_driver->boost_enabled = state; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + ret = cpufreq_driver->set_boost(state); + if (ret) { + write_lock_irqsave(&cpufreq_driver_lock, flags); + cpufreq_driver->boost_enabled = !state; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + pr_err("%s: Cannot %s BOOST\n", __func__, + state ? "enable" : "disable"); + } + + return ret; +} + +int cpufreq_boost_supported(void) +{ + if (likely(cpufreq_driver)) + return cpufreq_driver->boost_supported; + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_boost_supported); + +int cpufreq_boost_enabled(void) +{ + return cpufreq_driver->boost_enabled; +} +EXPORT_SYMBOL_GPL(cpufreq_boost_enabled); + /********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************/ @@ -2223,9 +2317,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_driver = driver_data; write_unlock_irqrestore(&cpufreq_driver_lock, flags); + if (cpufreq_boost_supported()) { + /* + * Check if driver provides function to enable boost - + * if not, use cpufreq_boost_set_sw as default + */ + if (!cpufreq_driver->set_boost) + cpufreq_driver->set_boost = cpufreq_boost_set_sw; + + ret = cpufreq_sysfs_create_file(&boost.attr); + if (ret) { + pr_err("%s: cannot register global BOOST sysfs file\n", + __func__); + goto err_null_driver; + } + } + ret = subsys_interface_register(&cpufreq_interface); if (ret) - goto err_null_driver; + goto err_boost_unreg; if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { int i; @@ -2252,6 +2362,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) return 0; err_if_unreg: subsys_interface_unregister(&cpufreq_interface); +err_boost_unreg: + if (cpufreq_boost_supported()) + cpufreq_sysfs_remove_file(&boost.attr); err_null_driver: write_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; @@ -2278,6 +2391,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) pr_debug("unregistering driver %s\n", driver->name); subsys_interface_unregister(&cpufreq_interface); + if (cpufreq_boost_supported()) + cpufreq_sysfs_remove_file(&boost.attr); + unregister_hotcpu_notifier(&cpufreq_cpu_notifier); down_write(&cpufreq_rwsem); diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index a8ac0427fbfe..8e54f97899ba 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -32,6 +32,10 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, continue; } + if (!cpufreq_boost_enabled() + && table[i].driver_data == CPUFREQ_BOOST_FREQ) + continue; + pr_debug("table entry %u: %u kHz, %u driver_data\n", i, freq, table[i].driver_data); if (freq < min_freq) @@ -204,7 +208,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); /** * show_available_freqs - show available frequencies for the specified CPU */ -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, + bool show_boost) { unsigned int i = 0; unsigned int cpu = policy->cpu; @@ -219,6 +224,20 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { if (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue; + /* + * show_boost = true and driver_data = BOOST freq + * display BOOST freqs + * + * show_boost = false and driver_data = BOOST freq + * show_boost = true and driver_data != BOOST freq + * continue - do not display anything + * + * show_boost = false and driver_data != BOOST freq + * display NON BOOST freqs + */ + if (show_boost ^ (table[i].driver_data == CPUFREQ_BOOST_FREQ)) + continue; + count += sprintf(&buf[count], "%d ", table[i].frequency); } count += sprintf(&buf[count], "\n"); @@ -227,16 +246,39 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) } -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { - .attr = { .name = "scaling_available_frequencies", - .mode = 0444, - }, - .show = show_available_freqs, -}; +#define cpufreq_attr_available_freq(_name) \ +struct freq_attr cpufreq_freq_attr_##_name##_freqs = \ +__ATTR_RO(_name##_frequencies) + +/** + * show_scaling_available_frequencies - show available normal frequencies for + * the specified CPU + */ +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, + char *buf) +{ + return show_available_freqs(policy, buf, false); +} +cpufreq_attr_available_freq(scaling_available); EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); +/** + * show_available_boost_freqs - show available boost frequencies for + * the specified CPU + */ +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, + char *buf) +{ + return show_available_freqs(policy, buf, true); +} +cpufreq_attr_available_freq(scaling_boost); +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs); + struct freq_attr *cpufreq_generic_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, +#ifdef CONFIG_CPU_FREQ_BOOST_SW + &cpufreq_freq_attr_scaling_boost_freqs, +#endif NULL, }; EXPORT_SYMBOL_GPL(cpufreq_generic_attr); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 422f10561e0b..4d89e0e6f9cc 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -227,6 +227,11 @@ struct cpufreq_driver { int (*suspend) (struct cpufreq_policy *policy); int (*resume) (struct cpufreq_policy *policy); struct freq_attr **attr; + + /* platform specific boost support code */ + bool boost_supported; + bool boost_enabled; + int (*set_boost) (int state); }; /* flags */ @@ -435,6 +440,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative; #define CPUFREQ_ENTRY_INVALID ~0 #define CPUFREQ_TABLE_END ~1 +#define CPUFREQ_BOOST_FREQ ~2 struct cpufreq_frequency_table { unsigned int driver_data; /* driver specific data, not used by core */ @@ -460,6 +466,24 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); +#ifdef CONFIG_CPU_FREQ +int cpufreq_boost_trigger_state(int state); +int cpufreq_boost_supported(void); +int cpufreq_boost_enabled(void); +#else +static inline int cpufreq_boost_trigger_state(int state) +{ + return 0; +} +static inline int cpufreq_boost_supported(void) +{ + return 0; +} +static inline int cpufreq_boost_enabled(void) +{ + return 0; +} +#endif /* the following funtion is for cpufreq core use only */ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu); -- cgit v1.2.3 From cfc9c8ed03e4d908f2388af8815f44c87b503aaf Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 20 Dec 2013 15:24:50 +0100 Subject: acpi-cpufreq: Adjust the code to use the common boost attribute Modify acpi-cpufreq's hardware-based boost solution to work with the common cpufreq boost framework. Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Acked-by: Viresh Kumar [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 86 ++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index caf41ebea184..79e5608e71b5 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data; static struct cpufreq_driver acpi_cpufreq_driver; static unsigned int acpi_pstate_strict; -static bool boost_enabled, boost_supported; static struct msr __percpu *msrs; static bool boost_state(unsigned int cpu) @@ -133,49 +132,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask) wrmsr_on_cpus(cpumask, msr_addr, msrs); } -static ssize_t _store_boost(const char *buf, size_t count) +static int _store_boost(int val) { - int ret; - unsigned long val = 0; - - if (!boost_supported) - return -EINVAL; - - ret = kstrtoul(buf, 10, &val); - if (ret || (val > 1)) - return -EINVAL; - - if ((val && boost_enabled) || (!val && !boost_enabled)) - return count; - get_online_cpus(); - boost_set_msrs(val, cpu_online_mask); - put_online_cpus(); - - boost_enabled = val; pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis"); - return count; -} - -static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - return _store_boost(buf, count); -} - -static ssize_t show_global_boost(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", boost_enabled); + return 0; } -static struct global_attr global_boost = __ATTR(boost, 0644, - show_global_boost, - store_global_boost); - static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); @@ -186,15 +152,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf) cpufreq_freq_attr_ro(freqdomain_cpus); #ifdef CONFIG_X86_ACPI_CPUFREQ_CPB +static ssize_t store_boost(const char *buf, size_t count) +{ + int ret; + unsigned long val = 0; + + if (!acpi_cpufreq_driver.boost_supported) + return -EINVAL; + + ret = kstrtoul(buf, 10, &val); + if (ret || (val > 1)) + return -EINVAL; + + _store_boost((int) val); + + return count; +} + static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, size_t count) { - return _store_boost(buf, count); + return store_boost(buf, count); } static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf) { - return sprintf(buf, "%u\n", boost_enabled); + return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled); } cpufreq_freq_attr_rw(cpb); @@ -554,7 +537,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action, switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - boost_set_msrs(boost_enabled, cpumask); + boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask); break; case CPU_DOWN_PREPARE: @@ -911,6 +894,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .resume = acpi_cpufreq_resume, .name = "acpi-cpufreq", .attr = acpi_cpufreq_attr, + .set_boost = _store_boost, }; static void __init acpi_cpufreq_boost_init(void) @@ -921,33 +905,22 @@ static void __init acpi_cpufreq_boost_init(void) if (!msrs) return; - boost_supported = true; - boost_enabled = boost_state(0); - + acpi_cpufreq_driver.boost_supported = true; + acpi_cpufreq_driver.boost_enabled = boost_state(0); get_online_cpus(); /* Force all MSRs to the same value */ - boost_set_msrs(boost_enabled, cpu_online_mask); + boost_set_msrs(acpi_cpufreq_driver.boost_enabled, + cpu_online_mask); register_cpu_notifier(&boost_nb); put_online_cpus(); - } else - global_boost.attr.mode = 0444; - - /* We create the boost file in any case, though for systems without - * hardware support it will be read-only and hardwired to return 0. - */ - if (cpufreq_sysfs_create_file(&(global_boost.attr))) - pr_warn(PFX "could not register global boost sysfs file\n"); - else - pr_debug("registered global boost sysfs file\n"); + } } static void __exit acpi_cpufreq_boost_exit(void) { - cpufreq_sysfs_remove_file(&(global_boost.attr)); - if (msrs) { unregister_cpu_notifier(&boost_nb); @@ -993,12 +966,11 @@ static int __init acpi_cpufreq_init(void) *iter = &cpb; } #endif + acpi_cpufreq_boost_init(); ret = cpufreq_register_driver(&acpi_cpufreq_driver); if (ret) free_acpi_perf_data(); - else - acpi_cpufreq_boost_init(); return ret; } -- cgit v1.2.3 From 2fb4719b25602a03fb6c7da77d029db03103663d Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 20 Dec 2013 15:24:51 +0100 Subject: cpufreq / boost: Kconfig: Support for software-managed BOOST Add CONFIG_CPU_FREQ_BOOST_SW Kconfig option such that software-managed boost is enabled only after selecting "EXYNOS Frequency Overclocking - Software". It also depends on the thermal subsystem to be compiled in, which is necessary for disabling boost and cooling down the device when overheating is detected. Software-managed boost _MUST_ _NOT_ be enabled without thermal subsystem with properly defined overheating temperature thresholds. This option doesn't affect the x86's hardware-driven boost support in the acpi-cpufreq driver. Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Acked-by: Viresh Kumar [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig | 4 ++++ drivers/cpufreq/Kconfig.arm | 15 +++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 386dbc9ccdfd..d100926aca0a 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -20,6 +20,10 @@ if CPU_FREQ config CPU_FREQ_GOV_COMMON bool +config CPU_FREQ_BOOST_SW + bool + depends on THERMAL + config CPU_FREQ_STAT tristate "CPU frequency translation statistics" default y diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0468ad147301..31297499a60a 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -66,6 +66,21 @@ config ARM_EXYNOS5440_CPUFREQ If in doubt, say N. +config ARM_EXYNOS_CPU_FREQ_BOOST_SW + bool "EXYNOS Frequency Overclocking - Software" + depends on ARM_EXYNOS_CPUFREQ + select CPU_FREQ_BOOST_SW + select EXYNOS_THERMAL + help + This driver supports software managed overclocking (BOOST). + It allows usage of special frequencies for Samsung Exynos + processors if thermal conditions are appropriate. + + It reguires, for safe operation, thermal framework with properly + defined trip points. + + If in doubt, say N. + config ARM_HIGHBANK_CPUFREQ tristate "Calxeda Highbank-based" depends on ARCH_HIGHBANK -- cgit v1.2.3 From c683c2c96315d4bfed40f96d6fb3d35513f74632 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 20 Dec 2013 15:24:52 +0100 Subject: cpufreq: exynos: Extend Exynos cpufreq driver to support boost The cpufreq_driver's boost_supported flag is true only when boost support is explicitly enabled. Boost related attributes are exported only under the same condition. Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/exynos-cpufreq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 4ee3804637be..fcd2914d081a 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -223,6 +223,9 @@ static struct cpufreq_driver exynos_driver = { .exit = cpufreq_generic_exit, .name = "exynos_cpufreq", .attr = cpufreq_generic_attr, +#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW + .boost_supported = true, +#endif #ifdef CONFIG_PM .suspend = exynos_cpufreq_suspend, .resume = exynos_cpufreq_resume, -- cgit v1.2.3 From d2228b91fc7709fddeb34450c0ce059fe0a19c60 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 20 Dec 2013 15:24:54 +0100 Subject: cpufreq: exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ Add a special driver data flag (CPUFREQ_BOOST_FREQ) to indicate a frequency that can be only enabled for BOOST mode. This frequency will be used only for limited time, since running with it for too long may cause the target device to overheat. Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Acked-by: Viresh Kumar [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/exynos4x12-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index efad5e657f6f..77ae129b2d9d 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c @@ -32,7 +32,7 @@ static unsigned int exynos4x12_volt_table[] = { }; static struct cpufreq_frequency_table exynos4x12_freq_table[] = { - {L0, CPUFREQ_ENTRY_INVALID}, + {CPUFREQ_BOOST_FREQ, 1500 * 1000}, {L1, 1400 * 1000}, {L2, 1300 * 1000}, {L3, 1200 * 1000}, -- cgit v1.2.3 From 4f11b85a5f2cc279860da3b9977a9586ff2df167 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 20 Dec 2013 15:24:55 +0100 Subject: thermal: exynos: boost: Automatic enable/disable of BOOST feature (at Exynos4412) This patch provides auto disable/enable operation for boost. It uses already present thermal infrastructure to provide BOOST hysteresis. The TMU data is modified to work properly with or without BOOST. Hence, the two first trip points with corresponding clip frequencies are adjusted. The first one is reduced from 85 to 70 degrees and the clip frequency is increased to 1.4 GHz from 800 MHz. This trip point is in fact responsible for providing BOOST hysteresis. When temperature exceeds 70 deg, the maximal non BOOST frequency for Exynos4412 is imposed. Since the first trigger level has been "stolen" for BOOST, the second one needs to be a compromise for the previously used two for non BOOST configuration. The 95 deg with modified clip freq (to 400 MHz) should provide a good balance between cooling down the overheated device and throughput on an acceptable level. Two last trigger levels are not modified since, they cause platform shutdown on emergency overheat to happen. The third trip point passage results in SW managed shut down of the system. If the last trip point is crossed, the PMU HW generates the power off signal. Signed-off-by: Lukasz Majewski Signed-off-by: Myungjoo Ham Acked-by: Eduardo Valentin Reviewed-by: Zhang Rui [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/thermal/samsung/exynos_tmu_data.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c index 073c292baa53..476b768c633e 100644 --- a/drivers/thermal/samsung/exynos_tmu_data.c +++ b/drivers/thermal/samsung/exynos_tmu_data.c @@ -131,8 +131,8 @@ static const struct exynos_tmu_registers exynos4412_tmu_registers = { #define EXYNOS4412_TMU_DATA \ .threshold_falling = 10, \ - .trigger_levels[0] = 85, \ - .trigger_levels[1] = 103, \ + .trigger_levels[0] = 70, \ + .trigger_levels[1] = 95, \ .trigger_levels[2] = 110, \ .trigger_levels[3] = 120, \ .trigger_enable[0] = true, \ @@ -155,12 +155,12 @@ static const struct exynos_tmu_registers exynos4412_tmu_registers = { .second_point_trim = 85, \ .default_temp_offset = 50, \ .freq_tab[0] = { \ - .freq_clip_max = 800 * 1000, \ - .temp_level = 85, \ + .freq_clip_max = 1400 * 1000, \ + .temp_level = 70, \ }, \ .freq_tab[1] = { \ - .freq_clip_max = 200 * 1000, \ - .temp_level = 103, \ + .freq_clip_max = 400 * 1000, \ + .temp_level = 95, \ }, \ .freq_tab_count = 2, \ .registers = &exynos4412_tmu_registers, \ -- cgit v1.2.3