From 7884084f3bcc98adfbd8b90a2bd6bcf10c4df2cd Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Tue, 3 Nov 2015 17:34:17 -0500 Subject: cpuidle,x86: increase forced cut-off for polling to 20us The cpuidle menu governor has a forced cut-off for polling at 5us, in order to deal with firmware that gives the OS bad information on cpuidle states, leading to the system spending way too much time in polling. However, at least one x86 CPU family (Atom) has chips that have a 20us break-even point for C1. Forcing the polling cut-off to less than that wastes performance and power. Increase the polling cut-off to 20us. Systems with a lower C1 latency will be found in the states table by the menu governor, which will pick those states as appropriate. Signed-off-by: Rik van Riel Acked-by: Arjan van de Ven Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 22e4463..ecc242a 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -330,7 +330,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon. */ - if (data->next_timer_us > 5 && + if (data->next_timer_us > 20 && !drv->states[CPUIDLE_DRIVER_STATE_START].disabled && dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; -- cgit v0.10.2 From a9ceb78bc75ca47972096372ff3d48648b16317a Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Tue, 3 Nov 2015 17:34:18 -0500 Subject: cpuidle,menu: use interactivity_req to disable polling The menu governor carefully figures out how much time we typically sleep for an estimated sleep interval, or whether there is a repeating pattern going on, and corrects that estimate for the CPU load. Then it proceeds to ignore that information when determining whether or not to consider polling. This is not a big deal on most x86 CPUs, which have very low C1 latencies, and the patch should not have any effect on those CPUs. However, certain CPUs (eg. Atom) have much higher C1 latencies, and it would be good to not waste performance and power on those CPUs if we are expecting a very low wakeup latency. Disable polling based on the estimated interactivity requirement, not on the time to the next timer interrupt. Signed-off-by: Rik van Riel Acked-by: Arjan van de Ven Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index ecc242a..b1a5573 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -330,7 +330,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon. */ - if (data->next_timer_us > 20 && + if (interactivity_req > 20 && !drv->states[CPUIDLE_DRIVER_STATE_START].disabled && dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; -- cgit v0.10.2 From efddfd90fb7f5ba3c7d1bff923a3626a78eee553 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Tue, 3 Nov 2015 17:34:19 -0500 Subject: cpuidle,menu: smooth out measured_us calculation The cpuidle state tables contain the maximum exit latency for each cpuidle state. On x86, that is the exit latency for when the entire package goes into that same idle state. However, a lot of the time we only go into the core idle state, not the package idle state. This means we see a much smaller exit latency. We have no way to detect whether we went into the core or package idle state while idle, and that is ok. However, the current menu_update logic does have the potential to trip up the repeating pattern detection in get_typical_interval. If the system is experiencing an exit latency near the idle state's exit latency, some of the samples will have exit_us subtracted, while others will not. This turns a repeating pattern into mush, potentially breaking get_typical_interval. Furthermore, for smaller sleep intervals, we know the chance that all the cores in the package went to the same idle state are fairly small. Dividing the measured_us by two, instead of subtracting the full exit latency when hitting a small measured_us, will reduce the error. Signed-off-by: Rik van Riel Acked-by: Arjan van de Ven Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index b1a5573..7b0971d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -404,8 +404,10 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) measured_us = cpuidle_get_last_residency(dev); /* Deduct exit latency */ - if (measured_us > target->exit_latency) + if (measured_us > 2 * target->exit_latency) measured_us -= target->exit_latency; + else + measured_us /= 2; /* Make sure our coefficients do not exceed unity */ if (measured_us > data->next_timer_us) -- cgit v0.10.2 From deaa51465105a7eda19a627b10372f4f7c51a4df Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Nov 2015 07:59:01 +0530 Subject: PM / OPP: Add debugfs support This patch adds debugfs support to OPP layer to export OPPs and their properties for all the devices. This creates a top level directory: /sys/kernel/debug/opp and then device specific directories (based on device names) inside it. For example: 'cpu0', 'cpu1', etc.. If multiple devices share the OPP table, then the real directory is created only for the first device. For all others, links are created to the real directory. Inside the device specific directory, a separate directory is created for each OPP. And within that files per opp property. Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/Makefile b/drivers/base/power/opp/Makefile index 33c1e18..19837ef 100644 --- a/drivers/base/power/opp/Makefile +++ b/drivers/base/power/opp/Makefile @@ -1,2 +1,3 @@ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG obj-y += core.o cpu.o +obj-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index b8e76f7..6aa172b 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -463,6 +463,7 @@ static void _kfree_list_dev_rcu(struct rcu_head *head) static void _remove_list_dev(struct device_list_opp *list_dev, struct device_opp *dev_opp) { + opp_debug_unregister(list_dev, dev_opp); list_del(&list_dev->node); call_srcu(&dev_opp->srcu_head.srcu, &list_dev->rcu_head, _kfree_list_dev_rcu); @@ -472,6 +473,7 @@ struct device_list_opp *_add_list_dev(const struct device *dev, struct device_opp *dev_opp) { struct device_list_opp *list_dev; + int ret; list_dev = kzalloc(sizeof(*list_dev), GFP_KERNEL); if (!list_dev) @@ -481,6 +483,12 @@ struct device_list_opp *_add_list_dev(const struct device *dev, list_dev->dev = dev; list_add_rcu(&list_dev->node, &dev_opp->dev_list); + /* Create debugfs entries for the dev_opp */ + ret = opp_debug_register(list_dev, dev_opp); + if (ret) + dev_err(dev, "%s: Failed to register opp debugfs (%d)\n", + __func__, ret); + return list_dev; } @@ -596,6 +604,7 @@ static void _opp_remove(struct device_opp *dev_opp, */ if (notify) srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); + opp_debug_remove_one(opp); list_del_rcu(&opp->node); call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); @@ -673,6 +682,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, { struct dev_pm_opp *opp; struct list_head *head = &dev_opp->opp_list; + int ret; /* * Insert new OPP in order of increasing frequency and discard if @@ -703,6 +713,11 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, new_opp->dev_opp = dev_opp; list_add_rcu(&new_opp->node, head); + ret = opp_debug_create_one(new_opp, dev_opp); + if (ret) + dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n", + __func__, ret); + return 0; } @@ -889,12 +904,14 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) /* OPP to select on device suspend */ if (of_property_read_bool(np, "opp-suspend")) { - if (dev_opp->suspend_opp) + if (dev_opp->suspend_opp) { dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n", __func__, dev_opp->suspend_opp->rate, new_opp->rate); - else + } else { + new_opp->suspend = true; dev_opp->suspend_opp = new_opp; + } } if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max) diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c new file mode 100644 index 0000000..ddfe477 --- /dev/null +++ b/drivers/base/power/opp/debugfs.c @@ -0,0 +1,219 @@ +/* + * Generic OPP debugfs interface + * + * Copyright (C) 2015-2016 Viresh Kumar + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include "opp.h" + +static struct dentry *rootdir; + +static void opp_set_dev_name(const struct device *dev, char *name) +{ + if (dev->parent) + snprintf(name, NAME_MAX, "%s-%s", dev_name(dev->parent), + dev_name(dev)); + else + snprintf(name, NAME_MAX, "%s", dev_name(dev)); +} + +void opp_debug_remove_one(struct dev_pm_opp *opp) +{ + debugfs_remove_recursive(opp->dentry); +} + +int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp) +{ + struct dentry *pdentry = dev_opp->dentry; + struct dentry *d; + char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ + + /* Rate is unique to each OPP, use it to give opp-name */ + snprintf(name, sizeof(name), "opp:%lu", opp->rate); + + /* Create per-opp directory */ + d = debugfs_create_dir(name, pdentry); + if (!d) + return -ENOMEM; + + if (!debugfs_create_bool("available", S_IRUGO, d, &opp->available)) + return -ENOMEM; + + if (!debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic)) + return -ENOMEM; + + if (!debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo)) + return -ENOMEM; + + if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend)) + return -ENOMEM; + + if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) + return -ENOMEM; + + if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->u_volt)) + return -ENOMEM; + + if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->u_volt_min)) + return -ENOMEM; + + if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->u_volt_max)) + return -ENOMEM; + + if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->u_amp)) + return -ENOMEM; + + if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d, + &opp->clock_latency_ns)) + return -ENOMEM; + + opp->dentry = d; + return 0; +} + +static int device_opp_debug_create_dir(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ + const struct device *dev = list_dev->dev; + struct dentry *d; + + opp_set_dev_name(dev, dev_opp->dentry_name); + + /* Create device specific directory */ + d = debugfs_create_dir(dev_opp->dentry_name, rootdir); + if (!d) { + dev_err(dev, "%s: Failed to create debugfs dir\n", __func__); + return -ENOMEM; + } + + list_dev->dentry = d; + dev_opp->dentry = d; + + return 0; +} + +static int device_opp_debug_create_link(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ + const struct device *dev = list_dev->dev; + char name[NAME_MAX]; + struct dentry *d; + + opp_set_dev_name(list_dev->dev, name); + + /* Create device specific directory link */ + d = debugfs_create_symlink(name, rootdir, dev_opp->dentry_name); + if (!d) { + dev_err(dev, "%s: Failed to create link\n", __func__); + return -ENOMEM; + } + + list_dev->dentry = d; + + return 0; +} + +/** + * opp_debug_register - add a device opp node to the debugfs 'opp' directory + * @list_dev: list-dev pointer for device + * @dev_opp: the device-opp being added + * + * Dynamically adds device specific directory in debugfs 'opp' directory. If the + * device-opp is shared with other devices, then links will be created for all + * devices except the first. + * + * Return: 0 on success, otherwise negative error. + */ +int opp_debug_register(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ + if (!rootdir) { + pr_debug("%s: Uninitialized rootdir\n", __func__); + return -EINVAL; + } + + if (dev_opp->dentry) + return device_opp_debug_create_link(list_dev, dev_opp); + + return device_opp_debug_create_dir(list_dev, dev_opp); +} + +static void opp_migrate_dentry(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ + struct device_list_opp *new_dev; + const struct device *dev; + struct dentry *dentry; + + /* Look for next list-dev */ + list_for_each_entry(new_dev, &dev_opp->dev_list, node) + if (new_dev != list_dev) + break; + + /* new_dev is guaranteed to be valid here */ + dev = new_dev->dev; + debugfs_remove_recursive(new_dev->dentry); + + opp_set_dev_name(dev, dev_opp->dentry_name); + + dentry = debugfs_rename(rootdir, list_dev->dentry, rootdir, + dev_opp->dentry_name); + if (!dentry) { + dev_err(dev, "%s: Failed to rename link from: %s to %s\n", + __func__, dev_name(list_dev->dev), dev_name(dev)); + return; + } + + new_dev->dentry = dentry; + dev_opp->dentry = dentry; +} + +/** + * opp_debug_unregister - remove a device opp node from debugfs opp directory + * @list_dev: list-dev pointer for device + * @dev_opp: the device-opp being removed + * + * Dynamically removes device specific directory from debugfs 'opp' directory. + */ +void opp_debug_unregister(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ + if (list_dev->dentry == dev_opp->dentry) { + /* Move the real dentry object under another device */ + if (!list_is_singular(&dev_opp->dev_list)) { + opp_migrate_dentry(list_dev, dev_opp); + goto out; + } + dev_opp->dentry = NULL; + } + + debugfs_remove_recursive(list_dev->dentry); + +out: + list_dev->dentry = NULL; +} + +static int __init opp_debug_init(void) +{ + /* Create /sys/kernel/debug/opp directory */ + rootdir = debugfs_create_dir("opp", NULL); + if (!rootdir) { + pr_err("%s: Failed to create root directory\n", __func__); + return -ENOMEM; + } + + return 0; +} +core_initcall(opp_debug_init); diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 7366b2a..a6bd8d2c 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ extern struct mutex dev_opp_list_lock; * @dynamic: not-created from static DT entries. * @available: true/false - marks if this OPP as available or not * @turbo: true if turbo (boost) OPP + * @suspend: true if suspend OPP * @rate: Frequency in hertz * @u_volt: Target voltage in microvolts corresponding to this OPP * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP @@ -63,6 +65,7 @@ extern struct mutex dev_opp_list_lock; * @dev_opp: points back to the device_opp struct this opp belongs to * @rcu_head: RCU callback head used for deferred freeing * @np: OPP's device node. + * @dentry: debugfs dentry pointer (per opp) * * This structure stores the OPP information for a given device. */ @@ -72,6 +75,7 @@ struct dev_pm_opp { bool available; bool dynamic; bool turbo; + bool suspend; unsigned long rate; unsigned long u_volt; @@ -84,6 +88,10 @@ struct dev_pm_opp { struct rcu_head rcu_head; struct device_node *np; + +#ifdef CONFIG_DEBUG_FS + struct dentry *dentry; +#endif }; /** @@ -91,6 +99,7 @@ struct dev_pm_opp { * @node: list node * @dev: device to which the struct object belongs * @rcu_head: RCU callback head used for deferred freeing + * @dentry: debugfs dentry pointer (per device) * * This is an internal data structure maintaining the list of devices that are * managed by 'struct device_opp'. @@ -99,6 +108,10 @@ struct device_list_opp { struct list_head node; const struct device *dev; struct rcu_head rcu_head; + +#ifdef CONFIG_DEBUG_FS + struct dentry *dentry; +#endif }; /** @@ -114,6 +127,8 @@ struct device_list_opp { * @opp_list: list of opps * @np: struct device_node pointer for opp's DT node. * @shared_opp: OPP is shared between multiple devices. + * @dentry: debugfs dentry pointer of the real device directory (not links). + * @dentry_name: Name of the real dentry. * * This is an internal data structure maintaining the link to opps attached to * a device. This structure is not meant to be shared to users as it is @@ -135,6 +150,11 @@ struct device_opp { unsigned long clock_latency_ns_max; bool shared_opp; struct dev_pm_opp *suspend_opp; + +#ifdef CONFIG_DEBUG_FS + struct dentry *dentry; + char dentry_name[NAME_MAX]; +#endif }; /* Routines internal to opp core */ @@ -143,4 +163,26 @@ struct device_list_opp *_add_list_dev(const struct device *dev, struct device_opp *dev_opp); struct device_node *_of_get_opp_desc_node(struct device *dev); +#ifdef CONFIG_DEBUG_FS +void opp_debug_remove_one(struct dev_pm_opp *opp); +int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp); +int opp_debug_register(struct device_list_opp *list_dev, + struct device_opp *dev_opp); +void opp_debug_unregister(struct device_list_opp *list_dev, + struct device_opp *dev_opp); +#else +static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {} + +static inline int opp_debug_create_one(struct dev_pm_opp *opp, + struct device_opp *dev_opp) +{ return 0; } +static inline int opp_debug_register(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ return 0; } + +static inline void opp_debug_unregister(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ } +#endif /* DEBUG_FS */ + #endif /* __DRIVER_OPP_H__ */ -- cgit v0.10.2 From 1c4d12de2719dfdf27c6dab31e7a5641ee293c94 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Nov 2015 08:10:54 +0530 Subject: PM / OPP: Add "opp-supported-hw" binding We may want to enable only a subset of OPPs, from the bigger list of OPPs, based on what version of the hardware we are running on. This would enable us to not duplicate OPP tables for every version of the hardware we support. To enable that, this patch defines a new property 'opp-supported-hw'. It can support any number of hierarchy levels of the versions the hardware follows. And based on the selected hardware versions, we can pick only the relevant OPPs at runtime. Reviewed-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 0cb44dc..d072fa0 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -123,6 +123,26 @@ Optional properties: - opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in the table should have this. +- opp-supported-hw: This enables us to select only a subset of OPPs from the + larger OPP table, based on what version of the hardware we are running on. We + still can't have multiple nodes with the same opp-hz value in OPP table. + + It's an user defined array containing a hierarchy of hardware version numbers, + supported by the OPP. For example: a platform with hierarchy of three levels + of versions (A, B and C), this field should be like , where X + corresponds to Version hierarchy A, Y corresponds to version hierarchy B and Z + corresponds to version hierarchy C. + + Each level of hierarchy is represented by a 32 bit value, and so there can be + only 32 different supported version per hierarchy. i.e. 1 bit per version. A + value of 0xFFFFFFFF will enable the OPP for all versions for that hierarchy + level. And a value of 0x00000000 will disable the OPP completely, and so we + never want that to happen. + + If 32 values aren't sufficient for a version hierarchy, than that version + hierarchy can be contained in multiple 32 bit values. i.e. in the + above example, Z1 & Z2 refer to the version hierarchy Z. + - status: Marks the node enabled/disabled. Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. @@ -463,3 +483,48 @@ Example 5: Multiple OPP tables }; }; }; + +Example 6: opp-supported-hw +(example: three level hierarchy of versions: cuts, substrate and process) + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-a7"; + ... + + cpu-supply = <&cpu_supply> + operating-points-v2 = <&cpu0_opp_table_slow>; + }; + }; + + opp_table { + compatible = "operating-points-v2"; + status = "okay"; + opp-shared; + + opp00 { + /* + * Supports all substrate and process versions for 0xF + * cuts, i.e. only first four cuts. + */ + opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF> + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 915000 925000>; + ... + }; + + opp01 { + /* + * Supports: + * - cuts: only one, 6th cut (represented by 6th bit). + * - substrate: supports 16 different substrate versions + * - process: supports 9 different process versions + */ + opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0> + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <900000 915000 925000>; + ... + }; + }; +}; -- cgit v0.10.2 From ffdb8cc7a27c89175e541e68e2a73f1f63ab8c6b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Nov 2015 08:10:55 +0530 Subject: PM / OPP: Add {opp-microvolt|opp-microamp}- binding Depending on the version of hardware or its properties, which are only known at runtime, various properties of the OPP can change. For example, an OPP with frequency 1.2 GHz, may have different voltage/current requirements based on the version of the hardware it is running on. In order to not replicate the same OPP tables for varying values of all such fields, this commit introduces the concept of opp-property-. The can be chosen by the platform at runtime, and OPPs will be initialized depending on that name string. Currently support is extended for the following properties: - opp-microvolt- - opp-microamp- If the name string isn't provided by the platform, or if it is provided but doesn't match the properties present in the OPP node, we will fall back to the original properties without the - string, if they are available. Reviewed-by: Stephen Boyd Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index d072fa0..a3e7f0d 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -100,6 +100,14 @@ Optional properties: Entries for multiple regulators must be present in the same order as regulators are specified in device's DT node. +- opp-microvolt-: Named opp-microvolt property. This is exactly similar to + the above opp-microvolt property, but allows multiple voltage ranges to be + provided for the same OPP. At runtime, the platform can pick a and + matching opp-microvolt- property will be enabled for all OPPs. If the + platform doesn't pick a specific or the doesn't match with any + opp-microvolt- properties, then opp-microvolt property shall be used, if + present. + - opp-microamp: The maximum current drawn by the device in microamperes considering system specific parameters (such as transients, process, aging, maximum operating temperature range etc.) as necessary. This may be used to @@ -112,6 +120,9 @@ Optional properties: for few regulators, then this should be marked as zero for them. If it isn't required for any regulator, then this property need not be present. +- opp-microamp-: Named opp-microamp property. Similar to + opp-microvolt- property, but for microamp instead. + - clock-latency-ns: Specifies the maximum possible transition latency (in nanoseconds) for switching to this OPP from any other OPP. @@ -528,3 +539,39 @@ Example 6: opp-supported-hw }; }; }; + +Example 7: opp-microvolt-, opp-microamp-: +(example: device with two possible microvolt ranges: slow and fast) + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-a7"; + ... + + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt-slow = <900000 915000 925000>; + opp-microvolt-fast = <970000 975000 985000>; + opp-microamp-slow = <70000>; + opp-microamp-fast = <71000>; + }; + + opp01 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt-slow = <900000 915000 925000>, /* Supply vcc0 */ + <910000 925000 935000>; /* Supply vcc1 */ + opp-microvolt-fast = <970000 975000 985000>, /* Supply vcc0 */ + <960000 965000 975000>; /* Supply vcc1 */ + opp-microamp = <70000>; /* Will be used for both slow/fast */ + }; + }; +}; -- cgit v0.10.2 From af87a39a5f7cf6ef252b1aec3e2e6508a40e51f1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Nov 2015 08:10:56 +0530 Subject: PM / OPP: Remove 'operating-points-names' binding These aren't used until now by any DT files and wouldn't be used now as we have a better scheme in place now, i.e. opp-property- properties. Remove the (useless) binding without breaking ABI. Reviewed-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index a3e7f0d..24eac9a 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -45,21 +45,10 @@ Devices supporting OPPs must set their "operating-points-v2" property with phandle to a OPP table in their DT node. The OPP core will use this phandle to find the operating points for the device. -Devices may want to choose OPP tables at runtime and so can provide a list of -phandles here. But only *one* of them should be chosen at runtime. This must be -accompanied by a corresponding "operating-points-names" property, to uniquely -identify the OPP tables. - If required, this can be extended for SoC vendor specfic bindings. Such bindings should be documented as Documentation/devicetree/bindings/power/-opp.txt and should have a compatible description like: "operating-points-v2-". -Optional properties: -- operating-points-names: Names of OPP tables (required if multiple OPP - tables are present), to uniquely identify them. The same list must be present - for all the CPUs which are sharing clock/voltage rails and hence the OPP - tables. - * OPP Table Node This describes the OPPs belonging to a device. This node can have following @@ -448,54 +437,7 @@ Example 4: Handling multiple regulators }; }; -Example 5: Multiple OPP tables - -/ { - cpus { - cpu@0 { - compatible = "arm,cortex-a7"; - ... - - cpu-supply = <&cpu_supply> - operating-points-v2 = <&cpu0_opp_table_slow>, <&cpu0_opp_table_fast>; - operating-points-names = "slow", "fast"; - }; - }; - - cpu0_opp_table_slow: opp_table_slow { - compatible = "operating-points-v2"; - status = "okay"; - opp-shared; - - opp00 { - opp-hz = /bits/ 64 <600000000>; - ... - }; - - opp01 { - opp-hz = /bits/ 64 <800000000>; - ... - }; - }; - - cpu0_opp_table_fast: opp_table_fast { - compatible = "operating-points-v2"; - status = "okay"; - opp-shared; - - opp10 { - opp-hz = /bits/ 64 <1000000000>; - ... - }; - - opp11 { - opp-hz = /bits/ 64 <1100000000>; - ... - }; - }; -}; - -Example 6: opp-supported-hw +Example 5: opp-supported-hw (example: three level hierarchy of versions: cuts, substrate and process) / { @@ -540,7 +482,7 @@ Example 6: opp-supported-hw }; }; -Example 7: opp-microvolt-, opp-microamp-: +Example 6: opp-microvolt-, opp-microamp-: (example: device with two possible microvolt ranges: slow and fast) / { -- cgit v0.10.2 From 754dcf35f34698661801ae1d391efa02affe83a7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Nov 2015 08:10:57 +0530 Subject: PM / OPP: Rename OPP nodes as opp@ It would be better to name OPP nodes as opp@ as that will ensure that multiple DT nodes don't contain the same frequency. Of course we expect the writer to name the node with its opp-hz frequency and not any other frequency. And that will let the compile error out if multiple nodes are using the same opp-hz frequency. Suggested-by: Stephen Boyd Reviewed-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 24eac9a..601256f 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -177,20 +177,20 @@ Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. compatible = "operating-points-v2"; opp-shared; - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>; opp-microamp = <70000>; clock-latency-ns = <300000>; opp-suspend; }; - opp01 { + opp@1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <980000 1000000 1010000>; opp-microamp = <80000>; clock-latency-ns = <310000>; }; - opp02 { + opp@1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1025000>; clock-latency-ns = <290000>; @@ -256,20 +256,20 @@ independently. * independently. */ - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>; opp-microamp = <70000>; clock-latency-ns = <300000>; opp-suspend; }; - opp01 { + opp@1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <980000 1000000 1010000>; opp-microamp = <80000>; clock-latency-ns = <310000>; }; - opp02 { + opp@1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1025000>; opp-microamp = <90000; @@ -332,20 +332,20 @@ DVFS state together. compatible = "operating-points-v2"; opp-shared; - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>; opp-microamp = <70000>; clock-latency-ns = <300000>; opp-suspend; }; - opp01 { + opp@1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <980000 1000000 1010000>; opp-microamp = <80000>; clock-latency-ns = <310000>; }; - opp02 { + opp@1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1025000>; opp-microamp = <90000>; @@ -358,20 +358,20 @@ DVFS state together. compatible = "operating-points-v2"; opp-shared; - opp10 { + opp@1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1045000 1050000 1055000>; opp-microamp = <95000>; clock-latency-ns = <400000>; opp-suspend; }; - opp11 { + opp@1400000000 { opp-hz = /bits/ 64 <1400000000>; opp-microvolt = <1075000>; opp-microamp = <100000>; clock-latency-ns = <400000>; }; - opp12 { + opp@1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1010000 1100000 1110000>; opp-microamp = <95000>; @@ -398,7 +398,7 @@ Example 4: Handling multiple regulators compatible = "operating-points-v2"; opp-shared; - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000>, /* Supply 0 */ <960000>, /* Supply 1 */ @@ -411,7 +411,7 @@ Example 4: Handling multiple regulators /* OR */ - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>, /* Supply 0 */ <960000 965000 975000>, /* Supply 1 */ @@ -424,7 +424,7 @@ Example 4: Handling multiple regulators /* OR */ - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <970000 975000 985000>, /* Supply 0 */ <960000 965000 975000>, /* Supply 1 */ @@ -456,7 +456,7 @@ Example 5: opp-supported-hw status = "okay"; opp-shared; - opp00 { + opp@600000000 { /* * Supports all substrate and process versions for 0xF * cuts, i.e. only first four cuts. @@ -467,7 +467,7 @@ Example 5: opp-supported-hw ... }; - opp01 { + opp@800000000 { /* * Supports: * - cuts: only one, 6th cut (represented by 6th bit). @@ -499,7 +499,7 @@ Example 6: opp-microvolt-, opp-microamp-: compatible = "operating-points-v2"; opp-shared; - opp00 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt-slow = <900000 915000 925000>; opp-microvolt-fast = <970000 975000 985000>; @@ -507,7 +507,7 @@ Example 6: opp-microvolt-, opp-microamp-: opp-microamp-fast = <71000>; }; - opp01 { + opp@1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt-slow = <900000 915000 925000>, /* Supply vcc0 */ <910000 925000 935000>; /* Supply vcc1 */ -- cgit v0.10.2 From 2aae9915267e60b6ab7af3777f92ca793992e9b9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Nov 2015 08:10:58 +0530 Subject: ARM: dts: exynos4412: Rename OPP nodes as opp@ OPP bindings got updated to name OPP nodes this way, make changes according to that. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index 294cfe4..40beede 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -64,73 +64,73 @@ compatible = "operating-points-v2"; opp-shared; - opp00 { + opp@200000000 { opp-hz = /bits/ 64 <200000000>; opp-microvolt = <900000>; clock-latency-ns = <200000>; }; - opp01 { + opp@300000000 { opp-hz = /bits/ 64 <300000000>; opp-microvolt = <900000>; clock-latency-ns = <200000>; }; - opp02 { + opp@400000000 { opp-hz = /bits/ 64 <400000000>; opp-microvolt = <925000>; clock-latency-ns = <200000>; }; - opp03 { + opp@500000000 { opp-hz = /bits/ 64 <500000000>; opp-microvolt = <950000>; clock-latency-ns = <200000>; }; - opp04 { + opp@600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = <975000>; clock-latency-ns = <200000>; }; - opp05 { + opp@700000000 { opp-hz = /bits/ 64 <700000000>; opp-microvolt = <987500>; clock-latency-ns = <200000>; }; - opp06 { + opp@800000000 { opp-hz = /bits/ 64 <800000000>; opp-microvolt = <1000000>; clock-latency-ns = <200000>; opp-suspend; }; - opp07 { + opp@900000000 { opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1037500>; clock-latency-ns = <200000>; }; - opp08 { + opp@1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1087500>; clock-latency-ns = <200000>; }; - opp09 { + opp@1100000000 { opp-hz = /bits/ 64 <1100000000>; opp-microvolt = <1137500>; clock-latency-ns = <200000>; }; - opp10 { + opp@1200000000 { opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <1187500>; clock-latency-ns = <200000>; }; - opp11 { + opp@1300000000 { opp-hz = /bits/ 64 <1300000000>; opp-microvolt = <1250000>; clock-latency-ns = <200000>; }; - opp12 { + opp@1400000000 { opp-hz = /bits/ 64 <1400000000>; opp-microvolt = <1287500>; clock-latency-ns = <200000>; }; - opp13 { + opp@1500000000 { opp-hz = /bits/ 64 <1500000000>; opp-microvolt = <1350000>; clock-latency-ns = <200000>; -- cgit v0.10.2 From dc4e7b1fa20a840d2317fcfdaa1064fc09d2afcb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 19 Nov 2015 09:13:56 +0530 Subject: PM / OPP: Add missing doc comments Few doc-style comments were missing, add them. Rearrange another one to match the sequence within the structure. Signed-off-by: Viresh Kumar Acked-by: Pavel Machek Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index a6bd8d2c..b8880c7 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -51,8 +51,8 @@ extern struct mutex dev_opp_list_lock; * are protected by the dev_opp_list_lock for integrity. * IMPORTANT: the opp nodes should be maintained in increasing * order. - * @dynamic: not-created from static DT entries. * @available: true/false - marks if this OPP as available or not + * @dynamic: not-created from static DT entries. * @turbo: true if turbo (boost) OPP * @suspend: true if suspend OPP * @rate: Frequency in hertz @@ -126,7 +126,9 @@ struct device_list_opp { * @dev_list: list of devices that share these OPPs * @opp_list: list of opps * @np: struct device_node pointer for opp's DT node. + * @clock_latency_ns_max: Max clock latency in nanoseconds. * @shared_opp: OPP is shared between multiple devices. + * @suspend_opp: Pointer to OPP to be used during device suspend. * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. * -- cgit v0.10.2 From 013c074f8642d8e815ad670601f8e27155a74b57 Mon Sep 17 00:00:00 2001 From: "Strashko, Grygorii" Date: Tue, 10 Nov 2015 11:42:34 +0200 Subject: PM / sleep: prohibit devices probing during suspend/hibernation It is unsafe [1] if probing of devices will happen during suspend or hibernation and system behavior will be unpredictable in this case. So, let's prohibit device's probing in dpm_prepare() and defer their probing instead. The normal behavior will be restored in dpm_complete(). This patch introduces new DD core APIs: device_block_probing() It will disable probing of devices and defer their probes instead. device_unblock_probing() It will restore normal behavior and trigger re-probing of deferred devices. [1] https://lkml.org/lkml/2015/9/11/554 Signed-off-by: Grygorii Strashko Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/base.h b/drivers/base/base.h index 1782f3a..e05db38 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev, extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); +extern void device_block_probing(void); +extern void device_unblock_probing(void); /* /sys/devices directory */ extern struct kset *devices_kset; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a641cf3..b605f73 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq; static atomic_t deferred_trigger_count = ATOMIC_INIT(0); /* + * In some cases, like suspend to RAM or hibernation, It might be reasonable + * to prohibit probing of devices as it could be unsafe. + * Once defer_all_probes is true all drivers probes will be forcibly deferred. + */ +static bool defer_all_probes; + +/* * deferred_probe_work_func() - Retry probing devices in the active list. */ static void deferred_probe_work_func(struct work_struct *work) @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void) } /** + * device_block_probing() - Block/defere device's probes + * + * It will disable probing of devices and defer their probes instead. + */ +void device_block_probing(void) +{ + defer_all_probes = true; + /* sync with probes to avoid races. */ + wait_for_device_probe(); +} + +/** + * device_unblock_probing() - Unblock/enable device's probes + * + * It will restore normal behavior and trigger re-probing of deferred + * devices. + */ +void device_unblock_probing(void) +{ + defer_all_probes = false; + driver_deferred_probe_trigger(); +} + +/** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. @@ -277,9 +308,20 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); static int really_probe(struct device *dev, struct device_driver *drv) { - int ret = 0; + int ret = -EPROBE_DEFER; int local_trigger_count = atomic_read(&deferred_trigger_count); + if (defer_all_probes) { + /* + * Value of defer_all_probes can be set only by + * device_defer_all_probes_enable() which, in turn, will call + * wait_for_device_probe() right after that to avoid any races. + */ + dev_dbg(dev, "Driver %s force probe deferral\n", drv->name); + driver_deferred_probe_add(dev); + return ret; + } + atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); @@ -393,6 +435,10 @@ int driver_probe_done(void) */ void wait_for_device_probe(void) { + /* wait for the deferred probe workqueue to finish */ + if (driver_deferred_probe_enable) + flush_workqueue(deferred_wq); + /* wait for the known devices to complete their probing */ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); async_synchronize_full(); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1710c26..9d626ac 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -963,6 +963,9 @@ void dpm_complete(pm_message_t state) } list_splice(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); + + /* Allow device probing and trigger re-probing of deferred devices */ + device_unblock_probing(); trace_suspend_resume(TPS("dpm_complete"), state.event, false); } @@ -1624,6 +1627,20 @@ int dpm_prepare(pm_message_t state) trace_suspend_resume(TPS("dpm_prepare"), state.event, true); might_sleep(); + /* + * Give a chance for the known devices to complete their probes, before + * disable probing of devices. This sync point is important at least + * at boot time + hibernation restore. + */ + wait_for_device_probe(); + /* + * It is unsafe if probing of devices will happen during suspend or + * hibernation and system behavior will be unpredictable in this case. + * So, let's prohibit device's probing here and defer their probes + * instead. The normal behavior will be restored in dpm_complete(). + */ + device_block_probing(); + mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_list)) { struct device *dev = to_device(dpm_list.next); -- cgit v0.10.2 From 5de85b9d57aba3ed2e04759e6db3b9e826dd0b06 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 18 Nov 2015 11:48:39 +0100 Subject: PM / runtime: Re-init runtime PM states at probe error and driver unbind There are two common expectations among several subsystems/drivers that deploys runtime PM support, but which isn't met by the driver core. Expectation 1) At ->probe() the subsystem/driver expects the runtime PM status of the device to be RPM_SUSPENDED, which is the initial status being assigned at device registration. This expectation is especially common among some of those subsystems/ drivers that manages devices with an attached PM domain, as those requires the ->runtime_resume() callback at the PM domain level to be invoked during ->probe(). Moreover these subsystems/drivers entirely relies on runtime PM resources being managed at the PM domain level, thus don't implement their own set of runtime PM callbacks. These are two scenarios that suffers from this unmet expectation. i) A failed ->probe() sequence requests probe deferral: ->probe() ... pm_runtime_enable() pm_runtime_get_sync() ... err: pm_runtime_put() pm_runtime_disable() ... As there are no guarantees that such sequence turns the runtime PM status of the device into RPM_SUSPENDED, the re-trying ->probe() may start with the status in RPM_ACTIVE. In such case the runtime PM core won't invoke the ->runtime_resume() callback because of a pm_runtime_get_sync(), as it considers the device to be already runtime resumed. ii) A driver re-bind sequence: At driver unbind, the subsystem/driver's >remove() callback invokes a sequence of runtime PM APIs, to undo actions during ->probe() and to put the device into low power state. ->remove() ... pm_runtime_put() pm_runtime_disable() ... Similar as in the failing ->probe() case, this sequence don't guarantee the runtime PM status of the device to turn into RPM_SUSPENDED. Trying to re-bind the driver thus causes the same issue as when re-trying ->probe(), in the probe deferral scenario. Expectation 2) Drivers that invokes the pm_runtime_irq_safe() API during ->probe(), triggers the runtime PM core to increase the usage count for the device's parent and permanently make it runtime resumed. The usage count is only dropped at device removal, which also allows it to be runtime suspended again. A re-trying ->probe() repeats the call to pm_runtime_irq_safe() and thus once more triggers the usage count of the device's parent to be increased. This leads to not only an imbalance issue of the usage count of the device's parent, but also to keep it runtime resumed permanently even if ->probe() fails. To address these issues, let's change the policy of the driver core to meet these expectations. More precisely, at ->probe() failures and driver unbind, restore the initial states of runtime PM. Although to still allow subsystem's to control PM for devices that doesn't ->probe() successfully, don't restore the initial states unless runtime PM is disabled. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a641cf3..cd2d79b 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -340,6 +340,7 @@ probe_failed: dev_set_drvdata(dev, NULL); if (dev->pm_domain && dev->pm_domain->dismiss) dev->pm_domain->dismiss(dev); + pm_runtime_reinit(dev); switch (ret) { case -EPROBE_DEFER: @@ -695,6 +696,7 @@ static void __device_release_driver(struct device *dev) dev_set_drvdata(dev, NULL); if (dev->pm_domain && dev->pm_domain->dismiss) dev->pm_domain->dismiss(dev); + pm_runtime_reinit(dev); klist_remove(&dev->p->knode_driver); if (dev->bus) diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 998fa6b..8b06193 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -18,6 +18,7 @@ static inline void pm_runtime_early_init(struct device *dev) } extern void pm_runtime_init(struct device *dev); +extern void pm_runtime_reinit(struct device *dev); extern void pm_runtime_remove(struct device *dev); struct wake_irq { @@ -84,6 +85,7 @@ static inline void pm_runtime_early_init(struct device *dev) } static inline void pm_runtime_init(struct device *dev) {} +static inline void pm_runtime_reinit(struct device *dev) {} static inline void pm_runtime_remove(struct device *dev) {} static inline int dpm_sysfs_add(struct device *dev) { return 0; } diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index e1a10a0..ab3fcd9 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1390,18 +1390,32 @@ void pm_runtime_init(struct device *dev) } /** + * pm_runtime_reinit - Re-initialize runtime PM fields in given device object. + * @dev: Device object to re-initialize. + */ +void pm_runtime_reinit(struct device *dev) +{ + if (!pm_runtime_enabled(dev)) { + if (dev->power.runtime_status == RPM_ACTIVE) + pm_runtime_set_suspended(dev); + if (dev->power.irq_safe) { + spin_lock_irq(&dev->power.lock); + dev->power.irq_safe = 0; + spin_unlock_irq(&dev->power.lock); + if (dev->parent) + pm_runtime_put(dev->parent); + } + } +} + +/** * pm_runtime_remove - Prepare for removing a device from device hierarchy. * @dev: Device object being removed from device hierarchy. */ void pm_runtime_remove(struct device *dev) { __pm_runtime_disable(dev, false); - - /* Change the status back to 'suspended' to match the initial status. */ - if (dev->power.runtime_status == RPM_ACTIVE) - pm_runtime_set_suspended(dev); - if (dev->power.irq_safe && dev->parent) - pm_runtime_put(dev->parent); + pm_runtime_reinit(dev); } /** -- cgit v0.10.2 From e399037e06beec6d190a302ff5e4fee4aae77c50 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Thu, 19 Nov 2015 11:05:25 +0800 Subject: ACPI / scan: set status to 0 if _STA failed Some ACPI node's _STA will touch operation region field, since the evaluation of _STA in acpi_bus_type_and_status is very early, the operation region handler is not ready yet. Instead of fail that function and not creating the acpi_device node consequently, set status to 0 so that later when the driver for that device is probing, it can find the acpi_device node and proceed normally. And at that time, the handler for the operation region is ready and its _STA evaluation will succeed, its present status can be checked there. Even there will be no driver using this node later, it doesn't seem hurt to have one more acpi_device node created with status set to 0. This happens on Microsoft Surface 3, where the SPI device node NTRG's _STA touches GPIO fields and the SPI core driver will only enumerate SPI devices from ACPI if the acpi_device node is 1: created; 2: _STA indicates it's present. Note that due to another problem in SPI driver, for NTRG to be actually enumerated, some changes have to be made in the SPI layer, which is addressed by Mika(not send out yet): https://bugzilla.kernel.org/show_bug.cgi?id=104291#c23 Link: https://bugzilla.kernel.org/show_bug.cgi?id=104291 Reported-by: Bastien Nocera Signed-off-by: Aaron Lu Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 78d5f02..ddfed0d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1461,7 +1461,7 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, *type = ACPI_BUS_TYPE_DEVICE; status = acpi_bus_get_status_handle(handle, sta); if (ACPI_FAILURE(status)) - return -ENODEV; + *sta = 0; break; case ACPI_TYPE_PROCESSOR: *type = ACPI_BUS_TYPE_PROCESSOR; -- cgit v0.10.2 From 7b0e1bf171effb71fa946e26d28895219de179cc Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 1 Dec 2015 17:14:13 +0100 Subject: cpupower: Fix precedence issue Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 9cbb7fd..5f9c908 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -106,7 +106,7 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) cpu_top->pkgs++; } } - if (!cpu_top->core_info[0].pkg == -1) + if (!(cpu_top->core_info[0].pkg == -1)) cpu_top->pkgs++; /* Intel's cores count is not consecutively numbered, there may -- cgit v0.10.2 From e51207f0030474958e59bbc7e002f169bdb05c50 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 1 Dec 2015 17:14:14 +0100 Subject: cpupower: Provide STATIC variable in Makefile for debug builds When working on cpupower code, you often want to compile library code into the binary. This allows to execute modified cpupower code, even with library changes without doing "make install" Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 2e2ba2e..0adaf0c 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -47,6 +47,11 @@ NLS ?= true # cpufreq-bench benchmarking tool CPUFREQ_BENCH ?= true +# Do not build libraries, but build the code in statically +# Libraries are still built, otherwise the Makefile code would +# be rather ugly. +export STATIC ?= false + # Prefix to the directories we're installing to DESTDIR ?= @@ -161,6 +166,12 @@ ifeq ($(strip $(CPUFREQ_BENCH)),true) COMPILE_BENCH += compile-bench endif +ifeq ($(strip $(STATIC)),true) + UTIL_OBJS += $(LIB_OBJS) + UTIL_HEADERS += $(LIB_HEADERS) + UTIL_SRC += $(LIB_SRC) +endif + CFLAGS += $(WARNINGS) ifeq ($(strip $(V)),false) @@ -209,7 +220,11 @@ $(OUTPUT)%.o: %.c $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) $(ECHO) " CC " $@ +ifeq ($(strip $(STATIC)),true) + $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lrt -lpci -L$(OUTPUT) -o $@ +else $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ +endif $(QUIET) $(STRIPCMD) $@ $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) @@ -291,7 +306,11 @@ install-bench: @#DESTDIR must be set from outside to survive @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install +ifeq ($(strip $(STATIC)),true) +install: all install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) +else install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) +endif uninstall: - rm -f $(DESTDIR)${libdir}/libcpupower.* diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile index 7ec7021..d0f879b 100644 --- a/tools/power/cpupower/bench/Makefile +++ b/tools/power/cpupower/bench/Makefile @@ -5,9 +5,15 @@ ifneq ($(O),) endif endif +ifeq ($(strip $(STATIC)),true) +LIBS = -L../ -L$(OUTPUT) -lm +OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o \ + $(OUTPUT)../lib/cpufreq.o $(OUTPUT)../lib/sysfs.o +else LIBS = -L../ -L$(OUTPUT) -lm -lcpupower - OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o +endif + CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" $(OUTPUT)%.o : %.c -- cgit v0.10.2 From ce512b84045459f4a6c119a109c950c6bc4a6f3a Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 1 Dec 2015 17:14:15 +0100 Subject: cpupower: Do not analyse offlined cpus Use sysfs_is_cpu_online(cpu) instead of cpufreq_cpu_exists(cpu) to detect offlined cpus. Re-arrange printfs slightly to have a consistent output even if you have multiple CPUs as output and even if offlined cores are in between. Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 0e67643..522b357 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -14,6 +14,7 @@ #include #include "cpufreq.h" +#include "helpers/sysfs.h" #include "helpers/helpers.h" #include "helpers/bitmask.h" @@ -647,11 +648,14 @@ int cmd_freq_info(int argc, char **argv) if (!bitmask_isbitset(cpus_chosen, cpu)) continue; - if (cpufreq_cpu_exists(cpu)) { - printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu); + + printf(_("analyzing CPU %d:\n"), cpu); + + if (sysfs_is_cpu_online(cpu) != 1) { + printf(_(" *is offline\n")); + printf("\n"); continue; } - printf(_("analyzing CPU %d:\n"), cpu); switch (output_param) { case 'b': @@ -693,6 +697,7 @@ int cmd_freq_info(int argc, char **argv) } if (ret) return ret; + printf("\n"); } return ret; } diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 750c1d8..8bf8ab5 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c @@ -12,7 +12,6 @@ #include #include #include -#include #include "helpers/helpers.h" #include "helpers/sysfs.h" @@ -25,8 +24,6 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) unsigned int idlestates, idlestate; char *tmp; - printf(_ ("Analyzing CPU %d:\n"), cpu); - idlestates = sysfs_get_idlestate_count(cpu); if (idlestates == 0) { printf(_("CPU %u: No idle states\n"), cpu); @@ -71,7 +68,6 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) printf(_("Duration: %llu\n"), sysfs_get_idlestate_time(cpu, idlestate)); } - printf("\n"); } static void cpuidle_general_output(void) @@ -189,10 +185,17 @@ int cmd_idle_info(int argc, char **argv) for (cpu = bitmask_first(cpus_chosen); cpu <= bitmask_last(cpus_chosen); cpu++) { - if (!bitmask_isbitset(cpus_chosen, cpu) || - cpufreq_cpu_exists(cpu)) + if (!bitmask_isbitset(cpus_chosen, cpu)) continue; + printf(_("analyzing CPU %d:\n"), cpu); + + if (sysfs_is_cpu_online(cpu) != 1) { + printf(_(" *is offline\n")); + printf("\n"); + continue; + } + switch (output_param) { case 'o': @@ -203,6 +206,7 @@ int cmd_idle_info(int argc, char **argv) cpuidle_cpu_output(cpu, verbose); break; } + printf("\n"); } return EXIT_SUCCESS; } diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c index 10299f2..c7caa8e 100644 --- a/tools/power/cpupower/utils/cpupower-info.c +++ b/tools/power/cpupower/utils/cpupower-info.c @@ -12,7 +12,6 @@ #include #include -#include #include "helpers/helpers.h" #include "helpers/sysfs.h" @@ -83,12 +82,16 @@ int cmd_info(int argc, char **argv) for (cpu = bitmask_first(cpus_chosen); cpu <= bitmask_last(cpus_chosen); cpu++) { - if (!bitmask_isbitset(cpus_chosen, cpu) || - cpufreq_cpu_exists(cpu)) + if (!bitmask_isbitset(cpus_chosen, cpu)) continue; printf(_("analyzing CPU %d:\n"), cpu); + if (sysfs_is_cpu_online(cpu) != 1){ + printf(_(" *is offline\n")); + continue; + } + if (params.perf_bias) { ret = msr_intel_get_perf_bias(cpu); if (ret < 0) { diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index 3e6f374..532f46b 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c @@ -12,7 +12,6 @@ #include #include -#include #include "helpers/helpers.h" #include "helpers/sysfs.h" #include "helpers/bitmask.h" @@ -78,10 +77,15 @@ int cmd_set(int argc, char **argv) for (cpu = bitmask_first(cpus_chosen); cpu <= bitmask_last(cpus_chosen); cpu++) { - if (!bitmask_isbitset(cpus_chosen, cpu) || - cpufreq_cpu_exists(cpu)) + if (!bitmask_isbitset(cpus_chosen, cpu)) continue; + if (sysfs_is_cpu_online(cpu) != 1){ + fprintf(stderr, _("Cannot set values on CPU %d:"), cpu); + fprintf(stderr, _(" *is offline\n")); + continue; + } + if (params.perf_bias) { ret = msr_intel_set_perf_bias(cpu, perf_bias); if (ret) { -- cgit v0.10.2 From 562e5f1a352977f45d0d0ed3279b556d3e41e1ba Mon Sep 17 00:00:00 2001 From: Jacob Tanenbaum Date: Tue, 1 Dec 2015 17:14:16 +0100 Subject: cpupower: rework the "cpupower frequency-info" command this patch makes two changes to the way that "cpupower frequancy-info" operates 1. make it so that querying individual values always returns a message to the user currently cpupower frequency info doesn't return anything to the user when querying an individual value cannot be returned [root@amd-dinar-09 cpupower]# cpupower -c 4 frequency-info -d analyzing CPU 4: [root@amd-dinar-09 cpupower]# I added messages so that each query prints a message to the terminal [root@amd-dinar-09 cpupower]# ./cpupower -c 4 frequency-info -d analyzing CPU 4: no or unknown cpufreq driver is active on this CPU [root@amd-dinar-09 cpupower]# (this is just one example) 2. change debug_output_one() to use the functions already provided by cpufreq-info.c to query individual values of interest. Signed-off-by: Jacob Tanenbaum Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 522b357..c13bc8c 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -245,149 +245,21 @@ static int get_boost_mode(unsigned int cpu) return 0; } -static void debug_output_one(unsigned int cpu) -{ - char *driver; - struct cpufreq_affected_cpus *cpus; - struct cpufreq_available_frequencies *freqs; - unsigned long min, max, freq_kernel, freq_hardware; - unsigned long total_trans, latency; - unsigned long long total_time; - struct cpufreq_policy *policy; - struct cpufreq_available_governors *governors; - struct cpufreq_stats *stats; - - if (cpufreq_cpu_exists(cpu)) - return; - - freq_kernel = cpufreq_get_freq_kernel(cpu); - freq_hardware = cpufreq_get_freq_hardware(cpu); - - driver = cpufreq_get_driver(cpu); - if (!driver) { - printf(_(" no or unknown cpufreq driver is active on this CPU\n")); - } else { - printf(_(" driver: %s\n"), driver); - cpufreq_put_driver(driver); - } - - cpus = cpufreq_get_related_cpus(cpu); - if (cpus) { - printf(_(" CPUs which run at the same hardware frequency: ")); - while (cpus->next) { - printf("%d ", cpus->cpu); - cpus = cpus->next; - } - printf("%d\n", cpus->cpu); - cpufreq_put_related_cpus(cpus); - } - - cpus = cpufreq_get_affected_cpus(cpu); - if (cpus) { - printf(_(" CPUs which need to have their frequency coordinated by software: ")); - while (cpus->next) { - printf("%d ", cpus->cpu); - cpus = cpus->next; - } - printf("%d\n", cpus->cpu); - cpufreq_put_affected_cpus(cpus); - } - - latency = cpufreq_get_transition_latency(cpu); - if (latency) { - printf(_(" maximum transition latency: ")); - print_duration(latency); - printf(".\n"); - } - - if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) { - printf(_(" hardware limits: ")); - print_speed(min); - printf(" - "); - print_speed(max); - printf("\n"); - } - - freqs = cpufreq_get_available_frequencies(cpu); - if (freqs) { - printf(_(" available frequency steps: ")); - while (freqs->next) { - print_speed(freqs->frequency); - printf(", "); - freqs = freqs->next; - } - print_speed(freqs->frequency); - printf("\n"); - cpufreq_put_available_frequencies(freqs); - } - - governors = cpufreq_get_available_governors(cpu); - if (governors) { - printf(_(" available cpufreq governors: ")); - while (governors->next) { - printf("%s, ", governors->governor); - governors = governors->next; - } - printf("%s\n", governors->governor); - cpufreq_put_available_governors(governors); - } - - policy = cpufreq_get_policy(cpu); - if (policy) { - printf(_(" current policy: frequency should be within ")); - print_speed(policy->min); - printf(_(" and ")); - print_speed(policy->max); - - printf(".\n "); - printf(_("The governor \"%s\" may" - " decide which speed to use\n within this range.\n"), - policy->governor); - cpufreq_put_policy(policy); - } - - if (freq_kernel || freq_hardware) { - printf(_(" current CPU frequency is ")); - if (freq_hardware) { - print_speed(freq_hardware); - printf(_(" (asserted by call to hardware)")); - } else - print_speed(freq_kernel); - printf(".\n"); - } - stats = cpufreq_get_stats(cpu, &total_time); - if (stats) { - printf(_(" cpufreq stats: ")); - while (stats) { - print_speed(stats->frequency); - printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time); - stats = stats->next; - if (stats) - printf(", "); - } - cpufreq_put_stats(stats); - total_trans = cpufreq_get_transitions(cpu); - if (total_trans) - printf(" (%lu)\n", total_trans); - else - printf("\n"); - } - get_boost_mode(cpu); - -} - /* --freq / -f */ static int get_freq_kernel(unsigned int cpu, unsigned int human) { unsigned long freq = cpufreq_get_freq_kernel(cpu); - if (!freq) + printf(_(" current CPU frequency: ")); + if (!freq) { + printf(_(" Unable to call to kernel\n")); return -EINVAL; + } if (human) { print_speed(freq); - printf("\n"); } else - printf("%lu\n", freq); + printf("%lu", freq); + printf(_(" (asserted by call to kernel)\n")); return 0; } @@ -397,13 +269,16 @@ static int get_freq_kernel(unsigned int cpu, unsigned int human) static int get_freq_hardware(unsigned int cpu, unsigned int human) { unsigned long freq = cpufreq_get_freq_hardware(cpu); - if (!freq) + printf(_(" current CPU frequency: ")); + if (!freq) { + printf("Unable to call hardware\n"); return -EINVAL; + } if (human) { print_speed(freq); - printf("\n"); } else - printf("%lu\n", freq); + printf("%lu", freq); + printf(_(" (asserted by call to hardware)\n")); return 0; } @@ -412,9 +287,17 @@ static int get_freq_hardware(unsigned int cpu, unsigned int human) static int get_hardware_limits(unsigned int cpu) { unsigned long min, max; - if (cpufreq_get_hardware_limits(cpu, &min, &max)) + + printf(_(" hardware limits: ")); + if (cpufreq_get_hardware_limits(cpu, &min, &max)) { + printf(_("Not Available\n")); return -EINVAL; - printf("%lu %lu\n", min, max); + } + + print_speed(min); + printf(" - "); + print_speed(max); + printf("\n"); return 0; } @@ -423,9 +306,11 @@ static int get_hardware_limits(unsigned int cpu) static int get_driver(unsigned int cpu) { char *driver = cpufreq_get_driver(cpu); - if (!driver) + if (!driver) { + printf(_(" no or unknown cpufreq driver is active on this CPU\n")); return -EINVAL; - printf("%s\n", driver); + } + printf(" driver: %s\n", driver); cpufreq_put_driver(driver); return 0; } @@ -435,9 +320,19 @@ static int get_driver(unsigned int cpu) static int get_policy(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_get_policy(cpu); - if (!policy) + if (!policy) { + printf(_(" Unable to determine current policy\n")); return -EINVAL; - printf("%lu %lu %s\n", policy->min, policy->max, policy->governor); + } + printf(_(" current policy: frequency should be within ")); + print_speed(policy->min); + printf(_(" and ")); + print_speed(policy->max); + + printf(".\n "); + printf(_("The governor \"%s\" may decide which speed to use\n" + " within this range.\n"), + policy->governor); cpufreq_put_policy(policy); return 0; } @@ -448,8 +343,12 @@ static int get_available_governors(unsigned int cpu) { struct cpufreq_available_governors *governors = cpufreq_get_available_governors(cpu); - if (!governors) + + printf(_(" available cpufreq governors: ")); + if (!governors) { + printf(_("Not Available\n")); return -EINVAL; + } while (governors->next) { printf("%s ", governors->governor); @@ -466,8 +365,12 @@ static int get_available_governors(unsigned int cpu) static int get_affected_cpus(unsigned int cpu) { struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); - if (!cpus) + + printf(_(" CPUs which need to have their frequency coordinated by software: ")); + if (!cpus) { + printf(_("Not Available\n")); return -EINVAL; + } while (cpus->next) { printf("%d ", cpus->cpu); @@ -483,8 +386,12 @@ static int get_affected_cpus(unsigned int cpu) static int get_related_cpus(unsigned int cpu) { struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); - if (!cpus) + + printf(_(" CPUs which run at the same hardware frequency: ")); + if (!cpus) { + printf(_("Not Available\n")); return -EINVAL; + } while (cpus->next) { printf("%d ", cpus->cpu); @@ -525,8 +432,12 @@ static int get_freq_stats(unsigned int cpu, unsigned int human) static int get_latency(unsigned int cpu, unsigned int human) { unsigned long latency = cpufreq_get_transition_latency(cpu); - if (!latency) + + printf(_(" maximum transition latency: ")); + if (!latency) { + printf(_(" Cannot determine latency.\n")); return -EINVAL; + } if (human) { print_duration(latency); @@ -536,6 +447,36 @@ static int get_latency(unsigned int cpu, unsigned int human) return 0; } +static void debug_output_one(unsigned int cpu) +{ + struct cpufreq_available_frequencies *freqs; + + get_driver(cpu); + get_related_cpus(cpu); + get_affected_cpus(cpu); + get_latency(cpu, 1); + get_hardware_limits(cpu); + + freqs = cpufreq_get_available_frequencies(cpu); + if (freqs) { + printf(_(" available frequency steps: ")); + while (freqs->next) { + print_speed(freqs->frequency); + printf(", "); + freqs = freqs->next; + } + print_speed(freqs->frequency); + printf("\n"); + cpufreq_put_available_frequencies(freqs); + } + + get_available_governors(cpu); + get_policy(cpu); + if (get_freq_hardware(cpu, 1) < 0) + get_freq_kernel(cpu, 1); + get_boost_mode(cpu); +} + static struct option info_opts[] = { {"debug", no_argument, NULL, 'e'}, {"boost", no_argument, NULL, 'b'}, -- cgit v0.10.2 From e98f033f94f385a9cf498d4e9f2ac1e6198b545a Mon Sep 17 00:00:00 2001 From: Jacob Tanenbaum Date: Tue, 1 Dec 2015 17:14:17 +0100 Subject: cpupower: fix how "cpupower frequency-info" interprets latency the intel-pstate driver does not support the ondemand governor and does not have a valid value in /sys/devices/system/cpu/cpu[x]/cpufreq/cpuinfo_transition_latency. The intel-pstate driver sets cpuinfo_transition_latency to CPUFREQ_ETERNAL (-1), the value written into cpuinfo_transition_latency is defind as an unsigned int so checking the read value against max unsigned int will determine if the value is valid. Signed-off-by: Jacob Tanenbaum Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index c13bc8c..8f3f5bb 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -434,8 +434,8 @@ static int get_latency(unsigned int cpu, unsigned int human) unsigned long latency = cpufreq_get_transition_latency(cpu); printf(_(" maximum transition latency: ")); - if (!latency) { - printf(_(" Cannot determine latency.\n")); + if (!latency || latency == UINT_MAX) { + printf(_(" Cannot determine or is not supported.\n")); return -EINVAL; } -- cgit v0.10.2 From 7b06a6d7bff563d82ddf8769617632f26793a83e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 5 Dec 2015 01:54:47 +0100 Subject: MAINTAINERS: Add an entry for the PM core Add a MAINTAINERS entry for the PM core with myself as the maintainer and linux-pm as the mailing list. This actually documents the current state of things. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/MAINTAINERS b/MAINTAINERS index 69c8a9c..8e4019c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8438,6 +8438,17 @@ F: fs/timerfd.c F: include/linux/timer* F: kernel/time/*timer* +POWER MANAGEMENT CORE +M: "Rafael J. Wysocki" +L: linux-pm@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm +S: Supported +F: drivers/base/power/ +F: include/linux/pm.h +F: include/linux/pm_* +F: include/linux/powercap.h +F: drivers/powercap/ + POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS M: Sebastian Reichel M: Dmitry Eremin-Solenikov -- cgit v0.10.2 From e128c864070055e062f6c90c64c03aad18452ac3 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Dec 2015 09:37:49 +0530 Subject: cpufreq: ondemand: Update sampling rate only for concerned policies We are comparing policy->governor against cpufreq_gov_ondemand to make sure that we update sampling rate only for the concerned CPUs. But that isn't enough. In case of governor_per_policy, there can be multiple instances of ondemand governor and we will always end up updating all of them with current code. What we rather need to do, is to compare dbs_data with poilcy->governor_data, which will match only for the policies governed by dbs_data. This code is also racy as the governor might be getting stopped at that time and we may end up scheduling work for a policy, which we have just disabled. Fix that by protecting the entire function with &od_dbs_cdata.mutex, which will prevent against races with policy START/STOP/etc. After these locks are in place, we can safely get the policy via per-cpu dbs_info. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 03ac6ce..089ca6a 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -252,20 +252,39 @@ static void update_sampling_rate(struct dbs_data *dbs_data, od_tuners->sampling_rate = new_rate = max(new_rate, dbs_data->min_sampling_rate); + /* + * Lock governor so that governor start/stop can't execute in parallel. + */ + mutex_lock(&od_dbs_cdata.mutex); + for_each_online_cpu(cpu) { struct cpufreq_policy *policy; struct od_cpu_dbs_info_s *dbs_info; + struct cpu_dbs_info *cdbs; + struct cpu_common_dbs_info *shared; unsigned long next_sampling, appointed_at; - policy = cpufreq_cpu_get(cpu); - if (!policy) + dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + cdbs = &dbs_info->cdbs; + shared = cdbs->shared; + + /* + * A valid shared and shared->policy means governor hasn't + * stopped or exited yet. + */ + if (!shared || !shared->policy) continue; - if (policy->governor != &cpufreq_gov_ondemand) { - cpufreq_cpu_put(policy); + + policy = shared->policy; + + /* + * Update sampling rate for CPUs whose policy is governed by + * dbs_data. In case of governor_per_policy, only a single + * policy will be governed by dbs_data, otherwise there can be + * multiple policies that are governed by the same dbs_data. + */ + if (dbs_data != policy->governor_data) continue; - } - dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - cpufreq_cpu_put(policy); if (!delayed_work_pending(&dbs_info->cdbs.dwork)) continue; @@ -281,6 +300,8 @@ static void update_sampling_rate(struct dbs_data *dbs_data, } } + + mutex_unlock(&od_dbs_cdata.mutex); } static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf, -- cgit v0.10.2 From e68fe18c5b5442baca162ccf3b273326e6132a51 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Dec 2015 09:37:50 +0530 Subject: cpufreq: ondemand: Work is guaranteed to be pending We are guaranteed to have works scheduled for policy->cpus, as the policy isn't stopped yet. And so there is no need to check that again. Drop it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 089ca6a..08f2aa6 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -286,9 +286,6 @@ static void update_sampling_rate(struct dbs_data *dbs_data, if (dbs_data != policy->governor_data) continue; - if (!delayed_work_pending(&dbs_info->cdbs.dwork)) - continue; - next_sampling = jiffies + usecs_to_jiffies(new_rate); appointed_at = dbs_info->cdbs.dwork.timer.expires; -- cgit v0.10.2 From affde5d06af1e39c2929e36a063e3912f02fc58f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Dec 2015 09:37:51 +0530 Subject: cpufreq: governor: Pass policy as argument to ->gov_dbs_timer() Pass 'policy' as argument to ->gov_dbs_timer() instead of cdbs and dbs_data. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 1fa1deb..606ad74ab 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -115,13 +115,13 @@ static void cs_check_cpu(int cpu, unsigned int load) } } -static unsigned int cs_dbs_timer(struct cpu_dbs_info *cdbs, - struct dbs_data *dbs_data, bool modify_all) +static unsigned int cs_dbs_timer(struct cpufreq_policy *policy, bool modify_all) { + struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; if (modify_all) - dbs_check_cpu(dbs_data, cdbs->shared->policy->cpu); + dbs_check_cpu(dbs_data, policy->cpu); return delay_for_sampling_rate(cs_tuners->sampling_rate); } diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index b260576..cdcb56a 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -253,7 +253,7 @@ static void dbs_timer(struct work_struct *work) if (!need_load_eval(cdbs->shared, sampling_rate)) modify_all = false; - delay = dbs_data->cdata->gov_dbs_timer(cdbs, dbs_data, modify_all); + delay = dbs_data->cdata->gov_dbs_timer(policy, modify_all); gov_queue_work(dbs_data, policy, delay, modify_all); unlock: diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 5621bb0..0c75890 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -209,8 +209,7 @@ struct common_dbs_data { struct cpu_dbs_info *(*get_cpu_cdbs)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu); - unsigned int (*gov_dbs_timer)(struct cpu_dbs_info *cdbs, - struct dbs_data *dbs_data, + unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy, bool modify_all); void (*gov_check_cpu)(int cpu, unsigned int load); int (*init)(struct dbs_data *dbs_data, bool notify); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 08f2aa6..fc0384b 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -191,10 +191,9 @@ static void od_check_cpu(int cpu, unsigned int load) } } -static unsigned int od_dbs_timer(struct cpu_dbs_info *cdbs, - struct dbs_data *dbs_data, bool modify_all) +static unsigned int od_dbs_timer(struct cpufreq_policy *policy, bool modify_all) { - struct cpufreq_policy *policy = cdbs->shared->policy; + struct dbs_data *dbs_data = policy->governor_data; unsigned int cpu = policy->cpu; struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); -- cgit v0.10.2 From 5e4500d8dba16d88b528cf037566b84747ec23f0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Dec 2015 09:37:52 +0530 Subject: cpufreq: governor: initialize/destroy timer_mutex with 'shared' timer_mutex is required to be initialized only while memory for 'shared' is allocated and in a similar way it is required to be destroyed only when memory for 'shared' is freed. There is no need to do the same every time we start/stop the governor. Move code to initialize/destroy timer_mutex to the relevant places. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index cdcb56a..999e1f6 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -287,6 +287,7 @@ static int alloc_common_dbs_info(struct cpufreq_policy *policy, for_each_cpu(j, policy->related_cpus) cdata->get_cpu_cdbs(j)->shared = shared; + mutex_init(&shared->timer_mutex); return 0; } @@ -297,6 +298,8 @@ static void free_common_dbs_info(struct cpufreq_policy *policy, struct cpu_common_dbs_info *shared = cdbs->shared; int j; + mutex_destroy(&shared->timer_mutex); + for_each_cpu(j, policy->cpus) cdata->get_cpu_cdbs(j)->shared = NULL; @@ -433,7 +436,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, shared->policy = policy; shared->time_stamp = ktime_get(); - mutex_init(&shared->timer_mutex); for_each_cpu(j, policy->cpus) { struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); @@ -493,8 +495,6 @@ static int cpufreq_governor_stop(struct cpufreq_policy *policy, mutex_unlock(&shared->timer_mutex); gov_cancel_work(dbs_data, policy); - - mutex_destroy(&shared->timer_mutex); return 0; } -- cgit v0.10.2 From e3f9e299bf94298ddd8beb63c0786a4d7766dc86 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:29 +0200 Subject: device property: always check for fwnode type Currently the property accessors unconditionally fall back to built-in property set as a last resort. Make this strict and return an error in case the type of fwnode is unknown. This is actually a follow up to the commit 4fa7508e9f1c (device property: Return -ENXIO if there is no suitable FW interface). Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index 1325ff2..09e488d 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -135,8 +135,9 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) return of_property_read_bool(to_of_node(fwnode), propname); else if (is_acpi_node(fwnode)) return !acpi_node_prop_get(fwnode, propname, NULL); - - return !!pset_prop_get(to_pset(fwnode), propname); + else if (is_pset(fwnode)) + return !!pset_prop_get(to_pset(fwnode), propname); + return false; } EXPORT_SYMBOL_GPL(fwnode_property_present); @@ -494,9 +495,10 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, else if (is_acpi_node(fwnode)) return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, 1); - - return pset_prop_read_array(to_pset(fwnode), propname, - DEV_PROP_STRING, val, 1); + else if (is_pset(fwnode)) + return pset_prop_read_array(to_pset(fwnode), propname, + DEV_PROP_STRING, val, 1); + return -ENXIO; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); -- cgit v0.10.2 From 61f5e294b89a90e8520c9eaf9a4af787db8911ea Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:30 +0200 Subject: device property: rename helper functions To be in align with the rest of fwnode types we rename the built-in property set ones, i.e. is_pset() -> is_pset_node() to_pset() -> to_pset_node() There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index 09e488d..2e01f3f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -37,14 +37,14 @@ void device_add_property_set(struct device *dev, struct property_set *pset) } EXPORT_SYMBOL_GPL(device_add_property_set); -static inline bool is_pset(struct fwnode_handle *fwnode) +static inline bool is_pset_node(struct fwnode_handle *fwnode) { return fwnode && fwnode->type == FWNODE_PDATA; } -static inline struct property_set *to_pset(struct fwnode_handle *fwnode) +static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode) { - return is_pset(fwnode) ? + return is_pset_node(fwnode) ? container_of(fwnode, struct property_set, fwnode) : NULL; } @@ -135,8 +135,8 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) return of_property_read_bool(to_of_node(fwnode), propname); else if (is_acpi_node(fwnode)) return !acpi_node_prop_get(fwnode, propname, NULL); - else if (is_pset(fwnode)) - return !!pset_prop_get(to_pset(fwnode), propname); + else if (is_pset_node(fwnode)) + return !!pset_prop_get(to_pset_node(fwnode), propname); return false; } EXPORT_SYMBOL_GPL(fwnode_property_present); @@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(device_property_match_string); else if (is_acpi_node(_fwnode_)) \ _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ _val_, _nval_); \ - else if (is_pset(_fwnode_)) \ - _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ + else if (is_pset_node(_fwnode_)) \ + _ret_ = pset_prop_read_array(to_pset_node(_fwnode_), _propname_, \ _proptype_, _val_, _nval_); \ else \ _ret_ = -ENXIO; \ @@ -465,8 +465,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, else if (is_acpi_node(fwnode)) return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, nval); - else if (is_pset(fwnode)) - return pset_prop_read_array(to_pset(fwnode), propname, + else if (is_pset_node(fwnode)) + return pset_prop_read_array(to_pset_node(fwnode), propname, DEV_PROP_STRING, val, nval); return -ENXIO; } @@ -495,8 +495,8 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, else if (is_acpi_node(fwnode)) return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, 1); - else if (is_pset(fwnode)) - return pset_prop_read_array(to_pset(fwnode), propname, + else if (is_pset_node(fwnode)) + return pset_prop_read_array(to_pset_node(fwnode), propname, DEV_PROP_STRING, val, 1); return -ENXIO; } -- cgit v0.10.2 From 318a1971826103ecf560875b17236dd4a93e8c88 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:31 +0200 Subject: device property: refactor built-in properties support Instead of using the type and nval fields we will use length (in bytes) of the value. The sanity check is done in the accessors. The built-in property accessors are split in the same way such as device tree. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index 2e01f3f..86834bd 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -63,45 +63,107 @@ static struct property_entry *pset_prop_get(struct property_set *pset, return NULL; } -static int pset_prop_read_array(struct property_set *pset, const char *name, - enum dev_prop_type type, void *val, size_t nval) +static void *pset_prop_find(struct property_set *pset, const char *propname, + size_t length) { struct property_entry *prop; - unsigned int item_size; + void *pointer; - prop = pset_prop_get(pset, name); + prop = pset_prop_get(pset, propname); + if (!prop) + return ERR_PTR(-EINVAL); + pointer = prop->value.raw_data; + if (!pointer) + return ERR_PTR(-ENODATA); + if (length > prop->length) + return ERR_PTR(-EOVERFLOW); + return pointer; +} + +static int pset_prop_read_u8_array(struct property_set *pset, + const char *propname, + u8 *values, size_t nval) +{ + void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_read_u16_array(struct property_set *pset, + const char *propname, + u16 *values, size_t nval) +{ + void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_read_u32_array(struct property_set *pset, + const char *propname, + u32 *values, size_t nval) +{ + void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_read_u64_array(struct property_set *pset, + const char *propname, + u64 *values, size_t nval) +{ + void *pointer; + size_t length = nval * sizeof(*values); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(values, pointer, length); + return 0; +} + +static int pset_prop_count_elems_of_size(struct property_set *pset, + const char *propname, size_t length) +{ + struct property_entry *prop; + + prop = pset_prop_get(pset, propname); if (!prop) - return -ENODATA; - - if (prop->type != type) - return -EPROTO; - - if (!val) - return prop->nval; - - if (prop->nval < nval) - return -EOVERFLOW; - - switch (type) { - case DEV_PROP_U8: - item_size = sizeof(u8); - break; - case DEV_PROP_U16: - item_size = sizeof(u16); - break; - case DEV_PROP_U32: - item_size = sizeof(u32); - break; - case DEV_PROP_U64: - item_size = sizeof(u64); - break; - case DEV_PROP_STRING: - item_size = sizeof(const char *); - break; - default: return -EINVAL; - } - memcpy(val, prop->value.raw_data, nval * item_size); + + return prop->length / length; +} + +static int pset_prop_read_string_array(struct property_set *pset, + const char *propname, + const char **strings, size_t nval) +{ + void *pointer; + size_t length = nval * sizeof(*strings); + + pointer = pset_prop_find(pset, propname, length); + if (IS_ERR(pointer)) + return PTR_ERR(pointer); + + memcpy(strings, pointer, length); return 0; } @@ -314,6 +376,10 @@ EXPORT_SYMBOL_GPL(device_property_match_string); (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ : of_property_count_elems_of_size((node), (propname), sizeof(type)) +#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \ + (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \ + : pset_prop_count_elems_of_size((node), (propname), sizeof(type)) + #define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ ({ \ int _ret_; \ @@ -324,8 +390,8 @@ EXPORT_SYMBOL_GPL(device_property_match_string); _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ _val_, _nval_); \ else if (is_pset_node(_fwnode_)) \ - _ret_ = pset_prop_read_array(to_pset_node(_fwnode_), _propname_, \ - _proptype_, _val_, _nval_); \ + _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \ + _type_, _val_, _nval_); \ else \ _ret_ = -ENXIO; \ _ret_; \ @@ -466,8 +532,12 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, nval); else if (is_pset_node(fwnode)) - return pset_prop_read_array(to_pset_node(fwnode), propname, - DEV_PROP_STRING, val, nval); + return val ? + pset_prop_read_string_array(to_pset_node(fwnode), + propname, val, nval) : + pset_prop_count_elems_of_size(to_pset_node(fwnode), + propname, + sizeof(const char *)); return -ENXIO; } EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); @@ -496,8 +566,8 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, 1); else if (is_pset_node(fwnode)) - return pset_prop_read_array(to_pset_node(fwnode), propname, - DEV_PROP_STRING, val, 1); + return pset_prop_read_string_array(to_pset_node(fwnode), + propname, val, 1); return -ENXIO; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); diff --git a/include/linux/property.h b/include/linux/property.h index 0a3705a..c29460a 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -144,14 +144,12 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode, /** * struct property_entry - "Built-in" device property representation. * @name: Name of the property. - * @type: Type of the property. - * @nval: Number of items of type @type making up the value. - * @value: Value of the property (an array of @nval items of type @type). + * @length: Length of data making up the value. + * @value: Value of the property (an array of items of the given type). */ struct property_entry { const char *name; - enum dev_prop_type type; - size_t nval; + size_t length; union { void *raw_data; u8 *u8_data; -- cgit v0.10.2 From 66586baba56679baa2da1a10a96ccf15b1e96b95 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:32 +0200 Subject: device property: keep single value inplace We may save a lot of lines of code and space by keeping single values inside the struct property_entry. Refactor the implementation to do so. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index 86834bd..ad3cb09 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -72,7 +72,10 @@ static void *pset_prop_find(struct property_set *pset, const char *propname, prop = pset_prop_get(pset, propname); if (!prop) return ERR_PTR(-EINVAL); - pointer = prop->value.raw_data; + if (prop->is_array) + pointer = prop->pointer.raw_data; + else + pointer = &prop->value.raw_data; if (!pointer) return ERR_PTR(-ENODATA); if (length > prop->length) @@ -167,6 +170,31 @@ static int pset_prop_read_string_array(struct property_set *pset, return 0; } +static int pset_prop_read_string(struct property_set *pset, + const char *propname, const char **strings) +{ + struct property_entry *prop; + const char **pointer; + + prop = pset_prop_get(pset, propname); + if (!prop) + return -EINVAL; + if (!prop->is_string) + return -EILSEQ; + if (prop->is_array) { + pointer = prop->pointer.str; + if (!pointer) + return -ENODATA; + } else { + pointer = &prop->value.str; + if (*pointer && strnlen(*pointer, prop->length) >= prop->length) + return -EILSEQ; + } + + *strings = *pointer; + return 0; +} + static inline struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? @@ -566,8 +594,7 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, val, 1); else if (is_pset_node(fwnode)) - return pset_prop_read_string_array(to_pset_node(fwnode), - propname, val, 1); + return pset_prop_read_string(to_pset_node(fwnode), propname, val); return -ENXIO; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); diff --git a/include/linux/property.h b/include/linux/property.h index c29460a..69a8a08 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -145,19 +145,34 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode, * struct property_entry - "Built-in" device property representation. * @name: Name of the property. * @length: Length of data making up the value. - * @value: Value of the property (an array of items of the given type). + * @is_array: True when the property is an array. + * @is_string: True when property is a string. + * @pointer: Pointer to the property (an array of items of the given type). + * @value: Value of the property (when it is a single item of the given type). */ struct property_entry { const char *name; size_t length; + bool is_array; + bool is_string; union { - void *raw_data; - u8 *u8_data; - u16 *u16_data; - u32 *u32_data; - u64 *u64_data; - const char **str; - } value; + union { + void *raw_data; + u8 *u8_data; + u16 *u16_data; + u32 *u32_data; + u64 *u64_data; + const char **str; + } pointer; + union { + unsigned long long raw_data; + u8 u8_data; + u16 u16_data; + u32 u32_data; + u64 u64_data; + const char *str; + } value; + }; }; /** -- cgit v0.10.2 From a85f420475334caed12b057ddcaa0b58e0b1ebb7 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 30 Nov 2015 17:11:33 +0200 Subject: device property: helper macros for property entry creation Marcos for easier creation of build-in property entries. Signed-off-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/property.h b/include/linux/property.h index 69a8a08..e4f29d8 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -175,6 +175,61 @@ struct property_entry { }; }; +#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ +{ \ + .name = _name_, \ + .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ + .is_array = true, \ + .pointer._type_##_data = _val_, \ +} + +#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_) +#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_) +#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_) +#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) + +#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ +{ \ + .name = _name_, \ + .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ + .is_array = true, \ + .is_string = true, \ + .pointer.str = _val_, \ +} + +#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ +{ \ + .name = _name_, \ + .length = sizeof(_type_), \ + .value._type_##_data = _val_, \ +} + +#define PROPERTY_ENTRY_U8(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER(_name_, u8, _val_) +#define PROPERTY_ENTRY_U16(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER(_name_, u16, _val_) +#define PROPERTY_ENTRY_U32(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER(_name_, u32, _val_) +#define PROPERTY_ENTRY_U64(_name_, _val_) \ + PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) + +#define PROPERTY_ENTRY_STRING(_name_, _val_) \ +{ \ + .name = _name_, \ + .length = sizeof(_val_), \ + .is_string = true, \ + .value.str = _val_, \ +} + +#define PROPERTY_ENTRY_BOOL(_name_) \ +{ \ + .name = _name_, \ +} + /** * struct property_set - Collection of "built-in" device properties. * @fwnode: Handle to be pointed to by the fwnode field of struct device. -- cgit v0.10.2 From 1d656fb757c17e48a8a01bd576d14918701ba55c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:34 +0200 Subject: device property: improve readability of macros There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index ad3cb09..a3538cb 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -400,29 +400,29 @@ int device_property_match_string(struct device *dev, const char *propname, } EXPORT_SYMBOL_GPL(device_property_match_string); -#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ - (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ +#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ + (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ : of_property_count_elems_of_size((node), (propname), sizeof(type)) #define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \ (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \ : pset_prop_count_elems_of_size((node), (propname), sizeof(type)) -#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ -({ \ - int _ret_; \ - if (is_of_node(_fwnode_)) \ - _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ - _type_, _val_, _nval_); \ - else if (is_acpi_node(_fwnode_)) \ - _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ - _val_, _nval_); \ +#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ +({ \ + int _ret_; \ + if (is_of_node(_fwnode_)) \ + _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ + _type_, _val_, _nval_); \ + else if (is_acpi_node(_fwnode_)) \ + _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ + _val_, _nval_); \ else if (is_pset_node(_fwnode_)) \ _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \ _type_, _val_, _nval_); \ - else \ - _ret_ = -ENXIO; \ - _ret_; \ + else \ + _ret_ = -ENXIO; \ + _ret_; \ }) /** diff --git a/include/linux/property.h b/include/linux/property.h index e4f29d8..d1cf208 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -73,8 +73,8 @@ int fwnode_property_match_string(struct fwnode_handle *fwnode, struct fwnode_handle *device_get_next_child_node(struct device *dev, struct fwnode_handle *child); -#define device_for_each_child_node(dev, child) \ - for (child = device_get_next_child_node(dev, NULL); child; \ +#define device_for_each_child_node(dev, child) \ + for (child = device_get_next_child_node(dev, NULL); child; \ child = device_get_next_child_node(dev, child)) void fwnode_handle_put(struct fwnode_handle *fwnode); -- cgit v0.10.2 From 3c60f1149a2fee9ac4ef3cc27bd830e3bd8d2654 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:35 +0200 Subject: device property: return -EINVAL when property isn't found in ACPI Change return code to be in align with OF and built-in device properties error codes. In particular -EINVAL means property is not found. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 88f4306..2aee416 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -346,7 +346,7 @@ void acpi_free_properties(struct acpi_device *adev) * * Return: %0 if property with @name has been found (success), * %-EINVAL if the arguments are invalid, - * %-ENODATA if the property doesn't exist, + * %-EINVAL if the property doesn't exist, * %-EPROTO if the property value type doesn't match @type. */ static int acpi_data_get_property(struct acpi_device_data *data, @@ -360,7 +360,7 @@ static int acpi_data_get_property(struct acpi_device_data *data, return -EINVAL; if (!data->pointer || !data->properties) - return -ENODATA; + return -EINVAL; properties = data->properties; for (i = 0; i < properties->package.count; i++) { @@ -375,13 +375,13 @@ static int acpi_data_get_property(struct acpi_device_data *data, if (!strcmp(name, propname->string.pointer)) { if (type != ACPI_TYPE_ANY && propvalue->type != type) return -EPROTO; - else if (obj) + if (obj) *obj = propvalue; return 0; } } - return -ENODATA; + return -EINVAL; } /** @@ -439,7 +439,7 @@ int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname, * * Return: %0 if array property (package) with @name has been found (success), * %-EINVAL if the arguments are invalid, - * %-ENODATA if the property doesn't exist, + * %-EINVAL if the property doesn't exist, * %-EPROTO if the property is not a package or the type of its elements * doesn't match @type. */ -- cgit v0.10.2 From 362c0b30249e8639489b428ff5acc4a9d81c087f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:36 +0200 Subject: device property: Fallback to secondary fwnode if primary misses the property The struct fwnode has notion of secondary fwnode. This is supposed to used as fallback if the primary firmware interface (DT, ACPI) does not have the property in question. However, the current implementation never checks the secondary node which prevents one to add default "built-in" properties to devices. This patch adds fallback to the secondary fwnode if the primary fwnode returns that the property does not exists. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index a3538cb..ebcbe34 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -214,12 +214,8 @@ bool device_property_present(struct device *dev, const char *propname) } EXPORT_SYMBOL_GPL(device_property_present); -/** - * fwnode_property_present - check if a property of a firmware node is present - * @fwnode: Firmware node whose property to check - * @propname: Name of the property - */ -bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) +static bool __fwnode_property_present(struct fwnode_handle *fwnode, + const char *propname) { if (is_of_node(fwnode)) return of_property_read_bool(to_of_node(fwnode), propname); @@ -229,6 +225,21 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) return !!pset_prop_get(to_pset_node(fwnode), propname); return false; } + +/** + * fwnode_property_present - check if a property of a firmware node is present + * @fwnode: Firmware node whose property to check + * @propname: Name of the property + */ +bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) +{ + bool ret; + + ret = __fwnode_property_present(fwnode, propname); + if (ret == false && fwnode->secondary) + ret = __fwnode_property_present(fwnode->secondary, propname); + return ret; +} EXPORT_SYMBOL_GPL(fwnode_property_present); /** @@ -408,7 +419,7 @@ EXPORT_SYMBOL_GPL(device_property_match_string); (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \ : pset_prop_count_elems_of_size((node), (propname), sizeof(type)) -#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ +#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ ({ \ int _ret_; \ if (is_of_node(_fwnode_)) \ @@ -425,6 +436,17 @@ EXPORT_SYMBOL_GPL(device_property_match_string); _ret_; \ }) +#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ +({ \ + int _ret_; \ + _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \ + _val_, _nval_); \ + if (_ret_ == -EINVAL && _fwnode_->secondary) \ + _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \ + _proptype_, _val_, _nval_); \ + _ret_; \ +}) + /** * fwnode_property_read_u8_array - return a u8 array property of firmware node * @fwnode: Firmware node to get the property of @@ -529,6 +551,41 @@ int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, } EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); +static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode, + const char *propname, + const char **val, size_t nval) +{ + if (is_of_node(fwnode)) + return val ? + of_property_read_string_array(to_of_node(fwnode), + propname, val, nval) : + of_property_count_strings(to_of_node(fwnode), propname); + else if (is_acpi_node(fwnode)) + return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, + val, nval); + else if (is_pset_node(fwnode)) + return val ? + pset_prop_read_string_array(to_pset_node(fwnode), + propname, val, nval) : + pset_prop_count_elems_of_size(to_pset_node(fwnode), + propname, + sizeof(const char *)); + return -ENXIO; +} + +static int __fwnode_property_read_string(struct fwnode_handle *fwnode, + const char *propname, const char **val) +{ + if (is_of_node(fwnode)) + return of_property_read_string(to_of_node(fwnode), propname, val); + else if (is_acpi_node(fwnode)) + return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, + val, 1); + else if (is_pset_node(fwnode)) + return pset_prop_read_string(to_pset_node(fwnode), propname, val); + return -ENXIO; +} + /** * fwnode_property_read_string_array - return string array property of a node * @fwnode: Firmware node to get the property of @@ -551,22 +608,13 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, const char *propname, const char **val, size_t nval) { - if (is_of_node(fwnode)) - return val ? - of_property_read_string_array(to_of_node(fwnode), - propname, val, nval) : - of_property_count_strings(to_of_node(fwnode), propname); - else if (is_acpi_node(fwnode)) - return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, - val, nval); - else if (is_pset_node(fwnode)) - return val ? - pset_prop_read_string_array(to_pset_node(fwnode), - propname, val, nval) : - pset_prop_count_elems_of_size(to_pset_node(fwnode), - propname, - sizeof(const char *)); - return -ENXIO; + int ret; + + ret = __fwnode_property_read_string_array(fwnode, propname, val, nval); + if (ret == -EINVAL && fwnode->secondary) + ret = __fwnode_property_read_string_array(fwnode->secondary, + propname, val, nval); + return ret; } EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); @@ -588,14 +636,13 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); int fwnode_property_read_string(struct fwnode_handle *fwnode, const char *propname, const char **val) { - if (is_of_node(fwnode)) - return of_property_read_string(to_of_node(fwnode), propname, val); - else if (is_acpi_node(fwnode)) - return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, - val, 1); - else if (is_pset_node(fwnode)) - return pset_prop_read_string(to_pset_node(fwnode), propname, val); - return -ENXIO; + int ret; + + ret = __fwnode_property_read_string(fwnode, propname, val); + if (ret == -EINVAL && fwnode->secondary) + ret = __fwnode_property_read_string(fwnode->secondary, + propname, val); + return ret; } EXPORT_SYMBOL_GPL(fwnode_property_read_string); -- cgit v0.10.2 From 13141e1cb842ad6286c1cfa9a6b7c1577478d03b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 30 Nov 2015 17:11:37 +0200 Subject: device property: Take a copy of the property set It is convenient if the property set associated with the device secondary firmware node is a copy of the original. This allows passing property set from a stack for example for devices created dynamically. This also ties the property set lifetime to the associated device. Because of that we provide new function device_remove_property_set() that is used to disassociate and release memory allocated for the property set. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index ebcbe34..0b22c8a 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -19,24 +19,6 @@ #include #include -/** - * device_add_property_set - Add a collection of properties to a device object. - * @dev: Device to add properties to. - * @pset: Collection of properties to add. - * - * Associate a collection of device properties represented by @pset with @dev - * as its secondary firmware node. - */ -void device_add_property_set(struct device *dev, struct property_set *pset) -{ - if (!pset) - return; - - pset->fwnode.type = FWNODE_PDATA; - set_secondary_fwnode(dev, &pset->fwnode); -} -EXPORT_SYMBOL_GPL(device_add_property_set); - static inline bool is_pset_node(struct fwnode_handle *fwnode) { return fwnode && fwnode->type == FWNODE_PDATA; @@ -693,6 +675,179 @@ out: EXPORT_SYMBOL_GPL(fwnode_property_match_string); /** + * pset_free_set - releases memory allocated for copied property set + * @pset: Property set to release + * + * Function takes previously copied property set and releases all the + * memory allocated to it. + */ +static void pset_free_set(struct property_set *pset) +{ + const struct property_entry *prop; + size_t i, nval; + + if (!pset) + return; + + for (prop = pset->properties; prop->name; prop++) { + if (prop->is_array) { + if (prop->is_string && prop->pointer.str) { + nval = prop->length / sizeof(const char *); + for (i = 0; i < nval; i++) + kfree(prop->pointer.str[i]); + } + kfree(prop->pointer.raw_data); + } else if (prop->is_string) { + kfree(prop->value.str); + } + kfree(prop->name); + } + + kfree(pset->properties); + kfree(pset); +} + +static int pset_copy_entry(struct property_entry *dst, + const struct property_entry *src) +{ + const char **d, **s; + size_t i, nval; + + dst->name = kstrdup(src->name, GFP_KERNEL); + if (!dst->name) + return -ENOMEM; + + if (src->is_array) { + if (src->is_string) { + nval = src->length / sizeof(const char *); + dst->pointer.str = kcalloc(nval, sizeof(const char *), + GFP_KERNEL); + if (!dst->pointer.str) + return -ENOMEM; + + d = dst->pointer.str; + s = src->pointer.str; + for (i = 0; i < nval; i++) { + d[i] = kstrdup(s[i], GFP_KERNEL); + if (!d[i] && s[i]) + return -ENOMEM; + } + } else { + dst->pointer.raw_data = kmemdup(src->pointer.raw_data, + src->length, GFP_KERNEL); + if (!dst->pointer.raw_data) + return -ENOMEM; + } + } else if (src->is_string) { + dst->value.str = kstrdup(src->value.str, GFP_KERNEL); + if (!dst->value.str && src->value.str) + return -ENOMEM; + } else { + dst->value.raw_data = src->value.raw_data; + } + + dst->length = src->length; + dst->is_array = src->is_array; + dst->is_string = src->is_string; + + return 0; +} + +/** + * pset_copy_set - copies property set + * @pset: Property set to copy + * + * This function takes a deep copy of the given property set and returns + * pointer to the copy. Call device_free_property_set() to free resources + * allocated in this function. + * + * Return: Pointer to the new property set or error pointer. + */ +static struct property_set *pset_copy_set(const struct property_set *pset) +{ + const struct property_entry *entry; + struct property_set *p; + size_t i, n = 0; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + while (pset->properties[n].name) + n++; + + p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL); + if (!p->properties) { + kfree(p); + return ERR_PTR(-ENOMEM); + } + + for (i = 0; i < n; i++) { + int ret = pset_copy_entry(&p->properties[i], + &pset->properties[i]); + if (ret) { + pset_free_set(p); + return ERR_PTR(ret); + } + } + + return p; +} + +/** + * device_remove_property_set - Remove properties from a device object. + * @dev: Device whose properties to remove. + * + * The function removes properties previously associated to the device + * secondary firmware node with device_add_property_set(). Memory allocated + * to the properties will also be released. + */ +void device_remove_property_set(struct device *dev) +{ + struct fwnode_handle *fwnode; + + fwnode = dev_fwnode(dev); + if (!fwnode) + return; + /* + * Pick either primary or secondary node depending which one holds + * the pset. If there is no real firmware node (ACPI/DT) primary + * will hold the pset. + */ + if (!is_pset_node(fwnode)) + fwnode = fwnode->secondary; + if (!IS_ERR(fwnode) && is_pset_node(fwnode)) + pset_free_set(to_pset_node(fwnode)); + set_secondary_fwnode(dev, NULL); +} +EXPORT_SYMBOL_GPL(device_remove_property_set); + +/** + * device_add_property_set - Add a collection of properties to a device object. + * @dev: Device to add properties to. + * @pset: Collection of properties to add. + * + * Associate a collection of device properties represented by @pset with @dev + * as its secondary firmware node. The function takes a copy of @pset. + */ +int device_add_property_set(struct device *dev, const struct property_set *pset) +{ + struct property_set *p; + + if (!pset) + return -EINVAL; + + p = pset_copy_set(pset); + if (IS_ERR(p)) + return PTR_ERR(p); + + p->fwnode.type = FWNODE_PDATA; + set_secondary_fwnode(dev, &p->fwnode); + return 0; +} +EXPORT_SYMBOL_GPL(device_add_property_set); + +/** * device_get_next_child_node - Return the next child node handle for a device * @dev: Device to find the next child node for. * @child: Handle to one of the device's child nodes or a null handle. diff --git a/include/linux/property.h b/include/linux/property.h index d1cf208..3a8c7d7 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -240,7 +240,8 @@ struct property_set { struct property_entry *properties; }; -void device_add_property_set(struct device *dev, struct property_set *pset); +int device_add_property_set(struct device *dev, const struct property_set *pset); +void device_remove_property_set(struct device *dev); bool device_dma_supported(struct device *dev); -- cgit v0.10.2 From 00bbc1d8e46a92ce7bd80622cf4b09c3b727a741 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 30 Nov 2015 17:11:38 +0200 Subject: driver core: platform: Add support for built-in device properties Make it possible to pass built-in device properties to platform device drivers. This is useful if the system does not have any firmware interface like Device Tree or ACPI which provides these. Properties associated with the platform device will be automatically released when the corresponding device is removed. Suggested-by: Arnd Bergmann Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 1dd6d3b..d77ed0c 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -299,6 +300,22 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, EXPORT_SYMBOL_GPL(platform_device_add_data); /** + * platform_device_add_properties - add built-in properties to a platform device + * @pdev: platform device to add properties to + * @pset: properties to add + * + * The function will take deep copy of the properties in @pset and attach + * the copy to the platform device. The memory associated with properties + * will be freed when the platform device is released. + */ +int platform_device_add_properties(struct platform_device *pdev, + const struct property_set *pset) +{ + return device_add_property_set(&pdev->dev, pset); +} +EXPORT_SYMBOL_GPL(platform_device_add_properties); + +/** * platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding * @@ -409,6 +426,8 @@ void platform_device_del(struct platform_device *pdev) if (r->parent) release_resource(r); } + + device_remove_property_set(&pdev->dev); } } EXPORT_SYMBOL_GPL(platform_device_del); @@ -487,6 +506,12 @@ struct platform_device *platform_device_register_full( if (ret) goto err; + if (pdevinfo->pset) { + ret = platform_device_add_properties(pdev, pdevinfo->pset); + if (ret) + goto err; + } + ret = platform_device_add(pdev); if (ret) { err: diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index dc777be..dba40b1 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -18,6 +18,7 @@ #define PLATFORM_DEVID_AUTO (-2) struct mfd_cell; +struct property_set; struct platform_device { const char *name; @@ -70,6 +71,8 @@ struct platform_device_info { const void *data; size_t size_data; u64 dma_mask; + + const struct property_set *pset; }; extern struct platform_device *platform_device_register_full( const struct platform_device_info *pdevinfo); @@ -167,6 +170,8 @@ extern int platform_device_add_resources(struct platform_device *pdev, unsigned int num); extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size); +extern int platform_device_add_properties(struct platform_device *pdev, + const struct property_set *pset); extern int platform_device_add(struct platform_device *pdev); extern void platform_device_del(struct platform_device *pdev); extern void platform_device_put(struct platform_device *pdev); -- cgit v0.10.2 From 55f89a8a4538803195395bdf347cbba51dcb1906 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 30 Nov 2015 17:11:39 +0200 Subject: driver core: Do not overwrite secondary fwnode with NULL if it is set If multiple devices share single firmware node like it is case with MFD devices, the same firmware node (ACPI) is assigned to all of them. The function also modifies the shared firmware node in order to preserve secondary firmware node of the device in question. If the new device which is sharing the firmware node does not have secondary node it will be NULL which will be assigned to the secondary node of the shared firmware node losing all built-in properties. Prevent this by setting the secondary firmware node only if the replacement is non-NULL. Print also warning if someone tries to overwrite secondary node that has already been assigned. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/core.c b/drivers/base/core.c index b7d56c5..0a8bdad 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2261,7 +2261,10 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) if (fwnode_is_primary(fn)) fn = fn->secondary; - fwnode->secondary = fn; + if (fn) { + WARN_ON(fwnode->secondary); + fwnode->secondary = fn; + } dev->fwnode = fwnode; } else { dev->fwnode = fwnode_is_primary(dev->fwnode) ? -- cgit v0.10.2 From 4d215cabc784990df11fbcca7af70adf53c9ff17 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:40 +0200 Subject: mfd: core: propagate device properties to sub devices drivers In the similar way like we do for the platform data we propagate the device properties. For example, in case of Intel LPSS drivers we may provide a specific property to tell the actual device driver an additional information such as platform name. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 60b60dc..88bd1b1 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -192,6 +193,12 @@ static int mfd_add_device(struct device *parent, int id, goto fail_alias; } + if (cell->pset) { + ret = platform_device_add_properties(pdev, cell->pset); + if (ret) + goto fail_alias; + } + ret = mfd_platform_add_cell(pdev, cell, usage_count); if (ret) goto fail_alias; diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 27dac3f..bc6f7e0 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -17,6 +17,7 @@ #include struct irq_domain; +struct property_set; /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */ struct mfd_cell_acpi_match { @@ -44,6 +45,10 @@ struct mfd_cell { /* platform data passed to the sub devices drivers */ void *platform_data; size_t pdata_size; + + /* device properties passed to the sub devices drivers */ + const struct property_set *pset; + /* * Device Tree compatible string * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details -- cgit v0.10.2 From e15ad2154b6166804fc04487e0398c9aef9e7c97 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 30 Nov 2015 17:11:41 +0200 Subject: mfd: intel-lpss: Add support for passing device properties If the boot firmware does not support ACPI we need a way to pass device configuration information to the drivers. The unified device properties API already supports passing platform data via properties so let's take advantage of that and allow probe drivers to pass set of properties to the host controller driver. In order to do that we need to be able to modify the MFD cell corresponding the host controller, so make the core driver to take copy of the cell instead of using it directly. Then we can assign info->pset to the resulting copy of a cell and let the MFD core to assign that to the resulting device. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 6255513..1743788 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -72,7 +73,7 @@ struct intel_lpss { enum intel_lpss_dev_type type; struct clk *clk; struct clk_lookup *clock; - const struct mfd_cell *cell; + struct mfd_cell *cell; struct device *dev; void __iomem *priv; int devid; @@ -217,6 +218,7 @@ static void intel_lpss_ltr_hide(struct intel_lpss *lpss) static int intel_lpss_assign_devs(struct intel_lpss *lpss) { + const struct mfd_cell *cell; unsigned int type; type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; @@ -224,18 +226,22 @@ static int intel_lpss_assign_devs(struct intel_lpss *lpss) switch (type) { case LPSS_DEV_I2C: - lpss->cell = &intel_lpss_i2c_cell; + cell = &intel_lpss_i2c_cell; break; case LPSS_DEV_UART: - lpss->cell = &intel_lpss_uart_cell; + cell = &intel_lpss_uart_cell; break; case LPSS_DEV_SPI: - lpss->cell = &intel_lpss_spi_cell; + cell = &intel_lpss_spi_cell; break; default: return -ENODEV; } + lpss->cell = devm_kmemdup(lpss->dev, cell, sizeof(*cell), GFP_KERNEL); + if (!lpss->cell) + return -ENOMEM; + lpss->type = type; return 0; @@ -401,6 +407,8 @@ int intel_lpss_probe(struct device *dev, if (ret) return ret; + lpss->cell->pset = info->pset; + intel_lpss_init_dev(lpss); lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index 2c7f8d7..0dcea9e 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -16,12 +16,14 @@ struct device; struct resource; +struct property_set; struct intel_lpss_platform_info { struct resource *mem; int irq; unsigned long clk_rate; const char *clk_con_id; + struct property_set *pset; }; int intel_lpss_probe(struct device *dev, -- cgit v0.10.2 From 028af5941dd870afd5eb6a95c39f25564dcca79a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 30 Nov 2015 17:11:42 +0200 Subject: mfd: intel-lpss: Pass SDA hold time to I2C host controller driver Intel Skylake the LPSS I2C pad circuit has internal delays that require programming non-zero SDA hold time for the I2C host controller. If this is not done communication to slave devices may fail with arbitration lost errors like the one seen below taken from Lenovo Yoga 900: i2c_hid i2c-SYNA2B29:00: Fetching the HID descriptor i2c_hid i2c-SYNA2B29:00: __i2c_hid_command: cmd=20 00 i2c_designware i2c_designware.1: i2c_dw_handle_tx_abort: lost arbitration To fix this we follow what the Windows driver is doing and pass the default SDA hold time of 230 ns to all Intel Skylake host controllers. This still allows the platform to override these values by passing special ACPI methods SSCN and FMCN. Reported-by: Kevin Fenzi Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index b6fd904..06f00d6 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "intel-lpss.h" @@ -25,6 +26,20 @@ static const struct intel_lpss_platform_info spt_info = { .clk_rate = 120000000, }; +static struct property_entry spt_i2c_properties[] = { + PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), + { }, +}; + +static struct property_set spt_i2c_pset = { + .properties = spt_i2c_properties, +}; + +static const struct intel_lpss_platform_info spt_i2c_info = { + .clk_rate = 120000000, + .pset = &spt_i2c_pset, +}; + static const struct intel_lpss_platform_info bxt_info = { .clk_rate = 100000000, }; @@ -35,8 +50,8 @@ static const struct intel_lpss_platform_info bxt_i2c_info = { static const struct acpi_device_id intel_lpss_acpi_ids[] = { /* SPT */ - { "INT3446", (kernel_ulong_t)&spt_info }, - { "INT3447", (kernel_ulong_t)&spt_info }, + { "INT3446", (kernel_ulong_t)&spt_i2c_info }, + { "INT3447", (kernel_ulong_t)&spt_i2c_info }, /* BXT */ { "80860AAC", (kernel_ulong_t)&bxt_i2c_info }, { "80860ABC", (kernel_ulong_t)&bxt_info }, diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 5bfdfcc..a677480 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "intel-lpss.h" @@ -65,6 +66,20 @@ static const struct intel_lpss_platform_info spt_info = { .clk_rate = 120000000, }; +static struct property_entry spt_i2c_properties[] = { + PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), + { }, +}; + +static struct property_set spt_i2c_pset = { + .properties = spt_i2c_properties, +}; + +static const struct intel_lpss_platform_info spt_i2c_info = { + .clk_rate = 120000000, + .pset = &spt_i2c_pset, +}; + static const struct intel_lpss_platform_info spt_uart_info = { .clk_rate = 120000000, .clk_con_id = "baudclk", @@ -121,20 +136,20 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, { } }; -- cgit v0.10.2 From ec14c5395dfbc1d40a49c9f19d2bfde6739d89d5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Nov 2015 17:11:43 +0200 Subject: mfd: intel-lpss: Pass HSUART configuration via properties The HS-UART host controller driver needs to know certain properties like width of the register set if it cannot get that information from ACPI or DT. In order to support non-ACPI systems we pass this information to the driver via device properties. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index a677480..a7136c7 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -80,9 +80,21 @@ static const struct intel_lpss_platform_info spt_i2c_info = { .pset = &spt_i2c_pset, }; +static struct property_entry uart_properties[] = { + PROPERTY_ENTRY_U32("reg-io-width", 4), + PROPERTY_ENTRY_U32("reg-shift", 2), + PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), + { }, +}; + +static struct property_set uart_pset = { + .properties = uart_properties, +}; + static const struct intel_lpss_platform_info spt_uart_info = { .clk_rate = 120000000, .clk_con_id = "baudclk", + .pset = &uart_pset, }; static const struct intel_lpss_platform_info bxt_info = { @@ -92,6 +104,7 @@ static const struct intel_lpss_platform_info bxt_info = { static const struct intel_lpss_platform_info bxt_uart_info = { .clk_rate = 100000000, .clk_con_id = "baudclk", + .pset = &uart_pset, }; static const struct intel_lpss_platform_info bxt_i2c_info = { -- cgit v0.10.2 From 4c5301abbf81f4351416cec1e8a02647d96e6fd1 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 30 Nov 2015 17:11:44 +0200 Subject: i2c: designware: Convert to use unified device property API With ACPI _DSD (introduced in ACPI v5.1) it is now possible to pass device configuration information from ACPI in addition to DT. In order to support this, convert the driver to use the unified device property accessors instead of DT specific. Change to ordering a bit so that we first try platform data and if that's not available look from device properties. ACPI *CNT methods are then used as last resort to override everything else. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Acked-by: Jarkko Nikula Acked-by: Wolfram Sang Signed-off-by: Rafael J. Wysocki diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 809579e..06061b5 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -129,10 +130,10 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) static int dw_i2c_plat_probe(struct platform_device *pdev) { + struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); struct dw_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem; - struct dw_i2c_platform_data *pdata; int irq, r; u32 clk_freq, ht = 0; @@ -156,33 +157,28 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) /* fast mode by default because of legacy reasons */ clk_freq = 400000; - if (has_acpi_companion(&pdev->dev)) { - dw_i2c_acpi_configure(pdev); - } else if (pdev->dev.of_node) { - of_property_read_u32(pdev->dev.of_node, - "i2c-sda-hold-time-ns", &ht); - - of_property_read_u32(pdev->dev.of_node, - "i2c-sda-falling-time-ns", - &dev->sda_falling_time); - of_property_read_u32(pdev->dev.of_node, - "i2c-scl-falling-time-ns", - &dev->scl_falling_time); - - of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &clk_freq); - - /* Only standard mode at 100kHz and fast mode at 400kHz - * are supported. - */ - if (clk_freq != 100000 && clk_freq != 400000) { - dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); - return -EINVAL; - } + if (pdata) { + clk_freq = pdata->i2c_scl_freq; } else { - pdata = dev_get_platdata(&pdev->dev); - if (pdata) - clk_freq = pdata->i2c_scl_freq; + device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", + &ht); + device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns", + &dev->sda_falling_time); + device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns", + &dev->scl_falling_time); + device_property_read_u32(&pdev->dev, "clock-frequency", + &clk_freq); + } + + if (has_acpi_companion(&pdev->dev)) + dw_i2c_acpi_configure(pdev); + + /* + * Only standard mode at 100kHz and fast mode at 400kHz are supported. + */ + if (clk_freq != 100000 && clk_freq != 400000) { + dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); + return -EINVAL; } r = i2c_dw_eval_lock_support(dev); -- cgit v0.10.2 From 4077a387b79f41e262e9e7332a23b24860407b18 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Nov 2015 19:59:29 +0200 Subject: x86/platform/iosf_mbi: Remove duplicate definitions The read and write opcodes are global for all units on SoC and even across Intel SoCs. Remove duplication of corresponding constants. At the same time convert all current users. No functional change. Acked-by: Thomas Gleixner Acked-by: Boon Leong Ong Acked-by: Jacob Pan Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/include/asm/iosf_mbi.h b/arch/x86/include/asm/iosf_mbi.h index b72ad0f..cdc5f63 100644 --- a/arch/x86/include/asm/iosf_mbi.h +++ b/arch/x86/include/asm/iosf_mbi.h @@ -1,5 +1,5 @@ /* - * iosf_mbi.h: Intel OnChip System Fabric MailBox access support + * Intel OnChip System Fabric MailBox access support */ #ifndef IOSF_MBI_SYMS_H @@ -16,6 +16,16 @@ #define MBI_MASK_LO 0x000000FF #define MBI_ENABLE 0xF0 +/* IOSF SB read/write opcodes */ +#define MBI_MMIO_READ 0x00 +#define MBI_MMIO_WRITE 0x01 +#define MBI_CR_READ 0x06 +#define MBI_CR_WRITE 0x07 +#define MBI_REG_READ 0x10 +#define MBI_REG_WRITE 0x11 +#define MBI_ESRAM_READ 0x12 +#define MBI_ESRAM_WRITE 0x13 + /* Baytrail available units */ #define BT_MBI_UNIT_AUNIT 0x00 #define BT_MBI_UNIT_SMC 0x01 @@ -28,50 +38,13 @@ #define BT_MBI_UNIT_SATA 0xA3 #define BT_MBI_UNIT_PCIE 0xA6 -/* Baytrail read/write opcodes */ -#define BT_MBI_AUNIT_READ 0x10 -#define BT_MBI_AUNIT_WRITE 0x11 -#define BT_MBI_SMC_READ 0x10 -#define BT_MBI_SMC_WRITE 0x11 -#define BT_MBI_CPU_READ 0x10 -#define BT_MBI_CPU_WRITE 0x11 -#define BT_MBI_BUNIT_READ 0x10 -#define BT_MBI_BUNIT_WRITE 0x11 -#define BT_MBI_PMC_READ 0x06 -#define BT_MBI_PMC_WRITE 0x07 -#define BT_MBI_GFX_READ 0x00 -#define BT_MBI_GFX_WRITE 0x01 -#define BT_MBI_SMIO_READ 0x06 -#define BT_MBI_SMIO_WRITE 0x07 -#define BT_MBI_USB_READ 0x06 -#define BT_MBI_USB_WRITE 0x07 -#define BT_MBI_SATA_READ 0x00 -#define BT_MBI_SATA_WRITE 0x01 -#define BT_MBI_PCIE_READ 0x00 -#define BT_MBI_PCIE_WRITE 0x01 - /* Quark available units */ #define QRK_MBI_UNIT_HBA 0x00 #define QRK_MBI_UNIT_HB 0x03 #define QRK_MBI_UNIT_RMU 0x04 #define QRK_MBI_UNIT_MM 0x05 -#define QRK_MBI_UNIT_MMESRAM 0x05 #define QRK_MBI_UNIT_SOC 0x31 -/* Quark read/write opcodes */ -#define QRK_MBI_HBA_READ 0x10 -#define QRK_MBI_HBA_WRITE 0x11 -#define QRK_MBI_HB_READ 0x10 -#define QRK_MBI_HB_WRITE 0x11 -#define QRK_MBI_RMU_READ 0x10 -#define QRK_MBI_RMU_WRITE 0x11 -#define QRK_MBI_MM_READ 0x10 -#define QRK_MBI_MM_WRITE 0x11 -#define QRK_MBI_MMESRAM_READ 0x12 -#define QRK_MBI_MMESRAM_WRITE 0x13 -#define QRK_MBI_SOC_READ 0x06 -#define QRK_MBI_SOC_WRITE 0x07 - #if IS_ENABLED(CONFIG_IOSF_MBI) bool iosf_mbi_available(void); diff --git a/arch/x86/platform/atom/punit_atom_debug.c b/arch/x86/platform/atom/punit_atom_debug.c index 5ca8ead..81c769e 100644 --- a/arch/x86/platform/atom/punit_atom_debug.c +++ b/arch/x86/platform/atom/punit_atom_debug.c @@ -25,8 +25,6 @@ #include #include -/* Side band Interface port */ -#define PUNIT_PORT 0x04 /* Power gate status reg */ #define PWRGT_STATUS 0x61 /* Subsystem config/status Video processor */ @@ -85,9 +83,8 @@ static int punit_dev_state_show(struct seq_file *seq_file, void *unused) seq_puts(seq_file, "\n\nPUNIT NORTH COMPLEX DEVICES :\n"); while (punit_devp->name) { - status = iosf_mbi_read(PUNIT_PORT, BT_MBI_PMC_READ, - punit_devp->reg, - &punit_pwr_status); + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, + punit_devp->reg, &punit_pwr_status); if (status) { seq_printf(seq_file, "%9s : Read Failed\n", punit_devp->name); diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c index 0ee619f..c1bdafa 100644 --- a/arch/x86/platform/intel-quark/imr.c +++ b/arch/x86/platform/intel-quark/imr.c @@ -111,23 +111,19 @@ static int imr_read(struct imr_device *idev, u32 imr_id, struct imr_regs *imr) u32 reg = imr_id * IMR_NUM_REGS + idev->reg_base; int ret; - ret = iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ, - reg++, &imr->addr_lo); + ret = iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->addr_lo); if (ret) return ret; - ret = iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ, - reg++, &imr->addr_hi); + ret = iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->addr_hi); if (ret) return ret; - ret = iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ, - reg++, &imr->rmask); + ret = iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->rmask); if (ret) return ret; - return iosf_mbi_read(QRK_MBI_UNIT_MM, QRK_MBI_MM_READ, - reg++, &imr->wmask); + return iosf_mbi_read(QRK_MBI_UNIT_MM, MBI_REG_READ, reg++, &imr->wmask); } /** @@ -151,31 +147,27 @@ static int imr_write(struct imr_device *idev, u32 imr_id, local_irq_save(flags); - ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE, reg++, - imr->addr_lo); + ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->addr_lo); if (ret) goto failed; - ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE, - reg++, imr->addr_hi); + ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->addr_hi); if (ret) goto failed; - ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE, - reg++, imr->rmask); + ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->rmask); if (ret) goto failed; - ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE, - reg++, imr->wmask); + ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, reg++, imr->wmask); if (ret) goto failed; /* Lock bit must be set separately to addr_lo address bits. */ if (lock) { imr->addr_lo |= IMR_LOCK; - ret = iosf_mbi_write(QRK_MBI_UNIT_MM, QRK_MBI_MM_WRITE, - reg - IMR_NUM_REGS, imr->addr_lo); + ret = iosf_mbi_write(QRK_MBI_UNIT_MM, MBI_REG_WRITE, + reg - IMR_NUM_REGS, imr->addr_lo); if (ret) goto failed; } diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index 7d7ae97..e38c2bb 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -34,8 +34,7 @@ static int get_sem(struct device *dev, u32 *sem) u32 data; int ret; - ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE, - &data); + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, PUNIT_SEMAPHORE, &data); if (ret) { dev_err(dev, "iosf failed to read punit semaphore\n"); return ret; @@ -50,21 +49,19 @@ static void reset_semaphore(struct device *dev) { u32 data; - if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - PUNIT_SEMAPHORE, &data)) { + if (iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, PUNIT_SEMAPHORE, &data)) { dev_err(dev, "iosf failed to reset punit semaphore during read\n"); return; } data &= ~PUNIT_SEMAPHORE_BIT; - if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - PUNIT_SEMAPHORE, data)) + if (iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, PUNIT_SEMAPHORE, data)) dev_err(dev, "iosf failed to reset punit semaphore during write\n"); } static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) { - u32 sem; + u32 sem = PUNIT_SEMAPHORE_ACQUIRE; int ret; unsigned long start, end; @@ -77,8 +74,7 @@ static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) return 0; /* host driver writes to side band semaphore register */ - ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, - PUNIT_SEMAPHORE, PUNIT_SEMAPHORE_ACQUIRE); + ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, PUNIT_SEMAPHORE, sem); if (ret) { dev_err(dev->dev, "iosf punit semaphore request failed\n"); return ret; @@ -102,8 +98,7 @@ static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) dev_err(dev->dev, "punit semaphore timed out, resetting\n"); reset_semaphore(dev->dev); - ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - PUNIT_SEMAPHORE, &sem); + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, PUNIT_SEMAPHORE, &sem); if (ret) dev_err(dev->dev, "iosf failed to read punit semaphore\n"); else diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index cc97f08..fa07809 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -988,16 +988,16 @@ static void set_floor_freq_atom(struct rapl_domain *rd, bool enable) } if (!power_ctrl_orig_val) - iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_PMC_READ, - rapl_defaults->floor_freq_reg_addr, - &power_ctrl_orig_val); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_CR_READ, + rapl_defaults->floor_freq_reg_addr, + &power_ctrl_orig_val); mdata = power_ctrl_orig_val; if (enable) { mdata &= ~(0x7f << 8); mdata |= 1 << 8; } - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_PMC_WRITE, - rapl_defaults->floor_freq_reg_addr, mdata); + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_CR_WRITE, + rapl_defaults->floor_freq_reg_addr, mdata); } static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value, diff --git a/drivers/thermal/intel_quark_dts_thermal.c b/drivers/thermal/intel_quark_dts_thermal.c index 5ed90e6..5d33b35 100644 --- a/drivers/thermal/intel_quark_dts_thermal.c +++ b/drivers/thermal/intel_quark_dts_thermal.c @@ -125,8 +125,8 @@ static int soc_dts_enable(struct thermal_zone_device *tzd) struct soc_sensor_entry *aux_entry = tzd->devdata; int ret; - ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_ENABLE, &out); + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_ENABLE, &out); if (ret) return ret; @@ -137,8 +137,8 @@ static int soc_dts_enable(struct thermal_zone_device *tzd) if (!aux_entry->locked) { out |= QRK_DTS_ENABLE_BIT; - ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, - QRK_DTS_REG_OFFSET_ENABLE, out); + ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, + QRK_DTS_REG_OFFSET_ENABLE, out); if (ret) return ret; @@ -158,8 +158,8 @@ static int soc_dts_disable(struct thermal_zone_device *tzd) struct soc_sensor_entry *aux_entry = tzd->devdata; int ret; - ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_ENABLE, &out); + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_ENABLE, &out); if (ret) return ret; @@ -170,8 +170,8 @@ static int soc_dts_disable(struct thermal_zone_device *tzd) if (!aux_entry->locked) { out &= ~QRK_DTS_ENABLE_BIT; - ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, - QRK_DTS_REG_OFFSET_ENABLE, out); + ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, + QRK_DTS_REG_OFFSET_ENABLE, out); if (ret) return ret; @@ -192,8 +192,8 @@ static int _get_trip_temp(int trip, int *temp) u32 out; mutex_lock(&dts_update_mutex); - status = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_PTPS, &out); + status = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_PTPS, &out); mutex_unlock(&dts_update_mutex); if (status) @@ -236,8 +236,8 @@ static int update_trip_temp(struct soc_sensor_entry *aux_entry, goto failed; } - ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_PTPS, &store_ptps); + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_PTPS, &store_ptps); if (ret) goto failed; @@ -262,8 +262,8 @@ static int update_trip_temp(struct soc_sensor_entry *aux_entry, out |= (temp_out & QRK_DTS_MASK_TP_THRES) << (trip * QRK_DTS_SHIFT_TP); - ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, - QRK_DTS_REG_OFFSET_PTPS, out); + ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, + QRK_DTS_REG_OFFSET_PTPS, out); failed: mutex_unlock(&dts_update_mutex); @@ -294,8 +294,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int ret; mutex_lock(&dts_update_mutex); - ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_TEMP, &out); + ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_TEMP, &out); mutex_unlock(&dts_update_mutex); if (ret) @@ -350,13 +350,13 @@ static void free_soc_dts(struct soc_sensor_entry *aux_entry) if (aux_entry) { if (!aux_entry->locked) { mutex_lock(&dts_update_mutex); - iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, - QRK_DTS_REG_OFFSET_ENABLE, - aux_entry->store_dts_enable); + iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, + QRK_DTS_REG_OFFSET_ENABLE, + aux_entry->store_dts_enable); - iosf_mbi_write(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_WRITE, - QRK_DTS_REG_OFFSET_PTPS, - aux_entry->store_ptps); + iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, + QRK_DTS_REG_OFFSET_PTPS, + aux_entry->store_ptps); mutex_unlock(&dts_update_mutex); } thermal_zone_device_unregister(aux_entry->tzone); @@ -378,9 +378,8 @@ static struct soc_sensor_entry *alloc_soc_dts(void) } /* Check if DTS register is locked */ - err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_LOCK, - &out); + err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_LOCK, &out); if (err) goto err_ret; @@ -395,16 +394,16 @@ static struct soc_sensor_entry *alloc_soc_dts(void) /* Store DTS default state if DTS registers are not locked */ if (!aux_entry->locked) { /* Store DTS default enable for restore on exit */ - err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_ENABLE, - &aux_entry->store_dts_enable); + err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_ENABLE, + &aux_entry->store_dts_enable); if (err) goto err_ret; /* Store DTS default PTPS register for restore on exit */ - err = iosf_mbi_read(QRK_MBI_UNIT_RMU, QRK_MBI_RMU_READ, - QRK_DTS_REG_OFFSET_PTPS, - &aux_entry->store_ptps); + err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, + QRK_DTS_REG_OFFSET_PTPS, + &aux_entry->store_ptps); if (err) goto err_ret; } diff --git a/drivers/thermal/intel_soc_dts_iosf.c b/drivers/thermal/intel_soc_dts_iosf.c index 5841d1d..f72e1db 100644 --- a/drivers/thermal/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel_soc_dts_iosf.c @@ -90,7 +90,7 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, dts = tzd->devdata; sensors = dts->sensors; mutex_lock(&sensors->dts_update_lock); - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_PTPS, &out); mutex_unlock(&sensors->dts_update_lock); if (status) @@ -124,27 +124,27 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, temp_out = (sensors->tj_max - temp) / 1000; - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_PTPS, &store_ptps); if (status) return status; out = (store_ptps & ~(0xFF << (thres_index * 8))); out |= (temp_out & 0xFF) << (thres_index * 8); - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTPS, out); if (status) return status; pr_debug("update_trip_temp PTPS = %x\n", out); - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_PTMC, &out); if (status) goto err_restore_ptps; store_ptmc = out; - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_TE_AUX0 + thres_index, &te_out); if (status) @@ -167,12 +167,12 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, out &= ~SOC_DTS_AUX0_ENABLE_BIT; te_out &= ~int_enable_bit; } - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTMC, out); if (status) goto err_restore_te_out; - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_TE_AUX0 + thres_index, te_out); if (status) @@ -182,13 +182,13 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, return 0; err_restore_te_out: - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTMC, store_te_out); err_restore_ptmc: - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTMC, store_ptmc); err_restore_ptps: - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTPS, store_ptps); /* Nothing we can do if restore fails */ @@ -235,7 +235,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, dts = tzd->devdata; sensors = dts->sensors; - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_TEMP, &out); if (status) return status; @@ -259,14 +259,14 @@ static int soc_dts_enable(int id) u32 out; int ret; - ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_ENABLE, &out); if (ret) return ret; if (!(out & BIT(id))) { out |= BIT(id); - ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_ENABLE, out); if (ret) return ret; @@ -278,7 +278,7 @@ static int soc_dts_enable(int id) static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts) { if (dts) { - iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_ENABLE, dts->store_status); thermal_zone_device_unregister(dts->tzone); } @@ -296,9 +296,8 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, int i; /* Store status to restor on exit */ - ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, - SOC_DTS_OFFSET_ENABLE, - &dts->store_status); + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, + SOC_DTS_OFFSET_ENABLE, &dts->store_status); if (ret) goto err_ret; @@ -311,7 +310,7 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, } /* Check if the writable trip we provide is not used by BIOS */ - ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_PTPS, &store_ptps); if (ret) trip_mask = 0; @@ -374,19 +373,19 @@ void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) spin_lock_irqsave(&sensors->intr_notify_lock, flags); - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_PTMC, &ptmc_out); ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTMC, ptmc_out); - status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, SOC_DTS_OFFSET_PTTSS, &sticky_out); pr_debug("status %d PTTSS %x\n", status, sticky_out); if (sticky_out & SOC_DTS_TRIP_MASK) { int i; /* reset sticky bit */ - status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, SOC_DTS_OFFSET_PTTSS, sticky_out); spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); -- cgit v0.10.2 From 14b6257a5f3dca3817b0826cb32967e3c2b935c8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:17 +0200 Subject: device core: add BUS_NOTIFY_DRIVER_NOT_BOUND notification The users of BUS_NOTIFY_BIND_DRIVER have no chance to do any cleanup in case of a probe failure. In the result there might be problems, such as some resources that had been allocated will continue to be allocated and therefore lead to a resource leak. Introduce a new notification to inform the subscriber that ->probe() failed. Do the same in case of failed device_bind_driver() call. Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a641cf3..0369704 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -268,6 +268,9 @@ int device_bind_driver(struct device *dev) ret = driver_sysfs_add(dev); if (!ret) driver_bound(dev); + else if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DRIVER_NOT_BOUND, dev); return ret; } EXPORT_SYMBOL_GPL(device_bind_driver); @@ -290,7 +293,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) /* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) - goto probe_failed; + goto pinctrl_bind_failed; if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", @@ -334,6 +337,10 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto done; probe_failed: + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DRIVER_NOT_BOUND, dev); +pinctrl_bind_failed: devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; @@ -701,7 +708,6 @@ static void __device_release_driver(struct device *dev) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBOUND_DRIVER, dev); - } } diff --git a/include/linux/device.h b/include/linux/device.h index b8f411b..f627ba2 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -191,6 +191,7 @@ extern int bus_unregister_notifier(struct bus_type *bus, unbound */ #define BUS_NOTIFY_UNBOUND_DRIVER 0x00000007 /* driver is unbound from the device */ +#define BUS_NOTIFY_DRIVER_NOT_BOUND 0x00000008 /* driver fails to be bound */ extern struct kset *bus_get_kset(struct bus_type *bus); extern struct klist *bus_get_device_klist(struct bus_type *bus); -- cgit v0.10.2 From b5f88dd1d6efc472e35ca1b21a44e662c5422088 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:18 +0200 Subject: Revert "ACPI / LPSS: allow to use specific PM domain during ->probe()" The specific power domain can't be used in a way provided by the commit 01ac170ba29a, i.e. pointer to platform device is a subject to change during unbound / bind cycle. This reverts commit 01ac170ba29a9903ee590e1ef2d8e6b27b49a16c. Fixes: 3df2da968744 (Revert "ACPI / LPSS: introduce a 'proxy' device to power on LPSS for DMA") Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index f9e0d09..da0e276 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -705,8 +705,13 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, } switch (action) { - case BUS_NOTIFY_ADD_DEVICE: + case BUS_NOTIFY_BOUND_DRIVER: pdev->dev.pm_domain = &acpi_lpss_pm_domain; + break; + case BUS_NOTIFY_UNBOUND_DRIVER: + pdev->dev.pm_domain = NULL; + break; + case BUS_NOTIFY_ADD_DEVICE: if (pdata->dev_desc->flags & LPSS_LTR) return sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); @@ -714,7 +719,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, case BUS_NOTIFY_DEL_DEVICE: if (pdata->dev_desc->flags & LPSS_LTR) sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); - pdev->dev.pm_domain = NULL; break; default: break; -- cgit v0.10.2 From de16d55206c5ce82ad44590b01718fbe2323853c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:19 +0200 Subject: ACPI / LPSS: allow to use specific PM domain during ->probe() This is an amendment to previously pushed commit 01ac170ba29a (ACPI / LPSS: allow to use specific PM domain during ->probe()). We can't assign anything to the platform device on ADD_DEVICE stage since it might be changed during unbound / bind cycle. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index da0e276..6263939 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -705,9 +705,10 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, } switch (action) { - case BUS_NOTIFY_BOUND_DRIVER: + case BUS_NOTIFY_BIND_DRIVER: pdev->dev.pm_domain = &acpi_lpss_pm_domain; break; + case BUS_NOTIFY_DRIVER_NOT_BOUND: case BUS_NOTIFY_UNBOUND_DRIVER: pdev->dev.pm_domain = NULL; break; -- cgit v0.10.2 From 02b98540433e6018806df539071c495a63cc0da4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:21 +0200 Subject: ACPI / LPSS: do delay for all LPSS devices when D3->D0 The LPSS DMA device has no context to save, though it requires the same delay like the rest of LPSS devices when power state is changed from D3 to D0. Do delay for the DMA device as well. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 6263939..bd3e84a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -574,6 +574,17 @@ static void acpi_lpss_restore_ctx(struct device *dev, { unsigned int i; + for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { + unsigned long offset = i * sizeof(u32); + + __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset); + dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n", + pdata->prv_reg_ctx[i], offset); + } +} + +static void acpi_lpss_d3_to_d0_delay(struct lpss_private_data *pdata) +{ /* * The following delay is needed or the subsequent write operations may * fail. The LPSS devices are actually PCI devices and the PCI spec @@ -586,14 +597,6 @@ static void acpi_lpss_restore_ctx(struct device *dev, delay = 0; msleep(delay); - - for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { - unsigned long offset = i * sizeof(u32); - - __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset); - dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n", - pdata->prv_reg_ctx[i], offset); - } } #ifdef CONFIG_PM_SLEEP @@ -621,6 +624,8 @@ static int acpi_lpss_resume_early(struct device *dev) if (ret) return ret; + acpi_lpss_d3_to_d0_delay(pdata); + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) acpi_lpss_restore_ctx(dev, pdata); @@ -652,6 +657,8 @@ static int acpi_lpss_runtime_resume(struct device *dev) if (ret) return ret; + acpi_lpss_d3_to_d0_delay(pdata); + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) acpi_lpss_restore_ctx(dev, pdata); -- cgit v0.10.2 From c3a49cf35ead83829e54fc771a3acc1b1aa6dfd8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:20 +0200 Subject: ACPI / LPSS: power on when probe() and otherwise when remove() When LPSS drivers are compiled as a module, which is usually the case, the second probe of that driver may fail because the driver is written in an assumption that device is powered on. That is not the case for all drivers. Moreover we would like not drain power in vain. Implement ->activate() and ->dismiss() callbacks in the ACPI LPSS custom power domain. -------- 8< -------- 8< -------- 8< -------- 8< -------- 8< -------- Case 1: The I2C probe() repeat. /sys/bus/platform/devices/808622C1:00 \_SB_.PCI0.I2C1 [D3hot] /sys/bus/platform/devices/808622C1:01 \_SB_.PCI0.I2C2 [D3hot] /sys/bus/platform/devices/808622C1:02 \_SB_.PCI0.I2C3 [D3hot] /sys/bus/platform/devices/808622C1:03 \_SB_.PCI0.I2C4 [D3hot] /sys/bus/platform/devices/808622C1:05 \_SB_.PCI0.I2C6 [D3hot] /sys/bus/platform/devices/808622C1:06 \_SB_.PCI0.I2C7 [D3hot] % modprobe i2c-designware-platform i2c_designware 808622C1:00: Unknown Synopsys component type: 0xffffffff i2c_designware 808622C1:01: Unknown Synopsys component type: 0xffffffff i2c_designware 808622C1:02: Unknown Synopsys component type: 0xffffffff i2c_designware 808622C1:03: Unknown Synopsys component type: 0xffffffff i2c_designware 808622C1:05: Unknown Synopsys component type: 0xffffffff i2c_designware 808622C1:06: Unknown Synopsys component type: 0xffffffff Case 2: The power drain in case of SDHCI. /sys/bus/platform/devices/80860F14:00 \_SB_.PCI0.SDHA [D3hot] /sys/bus/platform/devices/80860F14:01 \_SB_.PCI0.SDHC [D3hot] % modprobe -r sdhci-acpi mmc0: card 0001 removed /sys/bus/platform/devices/80860F14:00 \_SB_.PCI0.SDHA [D0] /sys/bus/platform/devices/80860F14:01 \_SB_.PCI0.SDHC [D0] -------- 8< -------- 8< -------- 8< -------- 8< -------- 8< -------- Patch fixes above problems. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index bd3e84a..a10c2d6 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -599,6 +599,34 @@ static void acpi_lpss_d3_to_d0_delay(struct lpss_private_data *pdata) msleep(delay); } +static int acpi_lpss_activate(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + + ret = acpi_dev_runtime_resume(dev); + if (ret) + return ret; + + acpi_lpss_d3_to_d0_delay(pdata); + + /* + * This is called only on ->probe() stage where a device is either in + * known state defined by BIOS or most likely powered off. Due to this + * we have to deassert reset line to be sure that ->probe() will + * recognize the device. + */ + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) + lpss_deassert_reset(pdata); + + return 0; +} + +static void acpi_lpss_dismiss(struct device *dev) +{ + acpi_dev_runtime_suspend(dev); +} + #ifdef CONFIG_PM_SLEEP static int acpi_lpss_suspend_late(struct device *dev) { @@ -667,6 +695,10 @@ static int acpi_lpss_runtime_resume(struct device *dev) #endif /* CONFIG_PM */ static struct dev_pm_domain acpi_lpss_pm_domain = { +#ifdef CONFIG_PM + .activate = acpi_lpss_activate, + .dismiss = acpi_lpss_dismiss, +#endif .ops = { #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP -- cgit v0.10.2 From ca9dc8d42b30e2d766b471fe5ecf0c71fd309c8f Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 25 Nov 2015 21:19:55 +0100 Subject: ACPI / scan: Fix acpi_bus_id_list bookkeeping acpi_device_add() allocates and adds an element to acpi_bus_id_list (or increments the instance count if the device's HID is already present in the list), but the element is never deleted from the list nor freed. Fix it. Signed-off-by: Lukas Wunner Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ddfed0d..be1fc12 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -471,10 +471,24 @@ static void acpi_device_release(struct device *dev) static void acpi_device_del(struct acpi_device *device) { + struct acpi_device_bus_id *acpi_device_bus_id; + mutex_lock(&acpi_device_lock); if (device->parent) list_del(&device->node); + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) + if (!strcmp(acpi_device_bus_id->bus_id, + acpi_device_hid(device))) { + if (acpi_device_bus_id->instance_no > 0) + acpi_device_bus_id->instance_no--; + else { + list_del(&acpi_device_bus_id->node); + kfree(acpi_device_bus_id); + } + break; + } + list_del(&device->wakeup_list); mutex_unlock(&acpi_device_lock); -- cgit v0.10.2 From 2d12b6b381ba059d5f92798f5ea739672a2f5fcf Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 25 Nov 2015 21:19:55 +0100 Subject: ACPI / utils: Add acpi_dev_present() There's an idiom in use by 7 Linux drivers to detect the presence of a particular ACPI HID by walking the namespace with acpi_get_devices(). The callback passed to acpi_get_devices() is mostly identical across the drivers, leading to lots of duplicate code. Add acpi_dev_present(), the ACPI equivalent to pci_dev_present(), allowing us to deduplicate all that boilerplate in the drivers. Signed-off-by: Lukas Wunner Reviewed-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 11d87bf..60bda0d 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -86,6 +86,14 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) +extern struct list_head acpi_bus_id_list; + +struct acpi_device_bus_id{ + char bus_id[15]; + unsigned int instance_no; + struct list_head node; +}; + int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index be1fc12..407a376 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -39,7 +39,7 @@ static const char *dummy_hid = "device"; static LIST_HEAD(acpi_dep_list); static DEFINE_MUTEX(acpi_dep_list_lock); -static LIST_HEAD(acpi_bus_id_list); +LIST_HEAD(acpi_bus_id_list); static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); DEFINE_MUTEX(acpi_device_lock); @@ -52,12 +52,6 @@ struct acpi_dep_data { acpi_handle slave; }; -struct acpi_device_bus_id{ - char bus_id[15]; - unsigned int instance_no; - struct list_head node; -}; - void acpi_scan_lock_acquire(void) { mutex_lock(&acpi_scan_lock); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 475c907..f2f9873 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -29,6 +29,7 @@ #include #include "internal.h" +#include "sleep.h" #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("utils"); @@ -709,6 +710,36 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) } EXPORT_SYMBOL(acpi_check_dsm); +/** + * acpi_dev_present - Detect presence of a given ACPI device in the system. + * @hid: Hardware ID of the device. + * + * Return %true if the device was present at the moment of invocation. + * Note that if the device is pluggable, it may since have disappeared. + * + * For this function to work, acpi_bus_scan() must have been executed + * which happens in the subsys_initcall() subsection. Hence, do not + * call from a subsys_initcall() or earlier (use acpi_get_devices() + * instead). Calling from module_init() is fine (which is synonymous + * with device_initcall()). + */ +bool acpi_dev_present(const char *hid) +{ + struct acpi_device_bus_id *acpi_device_bus_id; + bool found = false; + + mutex_lock(&acpi_device_lock); + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) + if (!strcmp(acpi_device_bus_id->bus_id, hid)) { + found = true; + break; + } + mutex_unlock(&acpi_device_lock); + + return found; +} +EXPORT_SYMBOL(acpi_dev_present); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ad0a5ff..0fe7bab 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -87,6 +87,8 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, int rev, int func, .package.elements = (eles) \ } +bool acpi_dev_present(const char *hid); + #ifdef CONFIG_ACPI #include -- cgit v0.10.2 From 299f2ffed329c1a2ea8d6e90f0df26b885d16e08 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 6 Dec 2015 17:33:45 +0100 Subject: PCI / PM: constify pci_platform_pm_ops structure The pci_platform_pm_ops structure is never modified, so declare it as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a32ba75..8400f80 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -529,7 +529,7 @@ static bool acpi_pci_need_resume(struct pci_dev *dev) return !!adev->power.flags.dsw_present; } -static struct pci_platform_pm_ops acpi_pci_platform_pm = { +static const struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 314db8c..d1a7105 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -527,9 +527,9 @@ static void pci_restore_bars(struct pci_dev *dev) pci_update_resource(dev, i); } -static struct pci_platform_pm_ops *pci_platform_pm; +static const struct pci_platform_pm_ops *pci_platform_pm; -int pci_set_platform_pm(struct pci_platform_pm_ops *ops) +int pci_set_platform_pm(const struct pci_platform_pm_ops *ops) { if (!ops->is_manageable || !ops->set_state || !ops->choose_state || !ops->sleep_wake) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d390fc1..f6f151a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -68,7 +68,7 @@ struct pci_platform_pm_ops { bool (*need_resume)(struct pci_dev *dev); }; -int pci_set_platform_pm(struct pci_platform_pm_ops *ops); +int pci_set_platform_pm(const struct pci_platform_pm_ops *ops); void pci_update_current_state(struct pci_dev *dev, pci_power_t state); void pci_power_up(struct pci_dev *dev); void pci_disable_enabled_device(struct pci_dev *dev); -- cgit v0.10.2 From 76fc35ddf8c075aa0e3f52384591d613b906ebb6 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 8 Dec 2015 16:17:25 +0200 Subject: PCI / PM: Fix small typo in documentation cuased -> caused Signed-off-by: Jarkko Nikula Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt index b0e911e..4455888 100644 --- a/Documentation/power/pci.txt +++ b/Documentation/power/pci.txt @@ -999,7 +999,7 @@ from its probe routine to make runtime PM work for the device. It is important to remember that the driver's runtime_suspend() callback may be executed right after the usage counter has been decremented, because -user space may already have cuased the pm_runtime_allow() helper function +user space may already have caused the pm_runtime_allow() helper function unblocking the runtime PM of the device to run via sysfs, so the driver must be prepared to cope with that. -- cgit v0.10.2 From 70f43e5e798c8818d97d8d6a9bd4cd3235af9686 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 9 Dec 2015 07:34:42 +0530 Subject: cpufreq: governor: replace per-CPU delayed work with timers cpufreq governors evaluate load at sampling rate and based on that they update frequency for a group of CPUs belonging to the same cpufreq policy. This is required to be done in a single thread for all policy->cpus, but because we don't want to wakeup idle CPUs to do just that, we use deferrable work for this. If we would have used a single delayed deferrable work for the entire policy, there were chances that the CPU required to run the handler can be in idle and we might end up not changing the frequency for the entire group with load variations. And so we were forced to keep per-cpu works, and only the one that expires first need to do the real work and others are rescheduled for next sampling time. We have been using the more complex solution until now, where we used a delayed deferrable work for this, which is a combination of a timer and a work. This could be made lightweight by keeping per-cpu deferred timers with a single work item, which is scheduled by the first timer that expires. This patch does just that and here are important changes: - The timer handler will run in irq context and so we need to use a spin_lock instead of the timer_mutex. And so a separate timer_lock is created. This also makes the use of the mutex and lock quite clear, as we know what exactly they are protecting. - A new field 'skip_work' is added to track when the timer handlers can queue a work. More comments present in code. Suggested-by: Rafael J. Wysocki Signed-off-by: Viresh Kumar Reviewed-by: Ashwin Chaugule Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 999e1f6..2d61eae 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -158,47 +158,53 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) } EXPORT_SYMBOL_GPL(dbs_check_cpu); -static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data, - unsigned int delay) +void gov_add_timers(struct cpufreq_policy *policy, unsigned int delay) { - struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); - - mod_delayed_work_on(cpu, system_wq, &cdbs->dwork, delay); -} - -void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, - unsigned int delay, bool all_cpus) -{ - int i; + struct dbs_data *dbs_data = policy->governor_data; + struct cpu_dbs_info *cdbs; + int cpu; - if (!all_cpus) { - /* - * Use raw_smp_processor_id() to avoid preemptible warnings. - * We know that this is only called with all_cpus == false from - * works that have been queued with *_work_on() functions and - * those works are canceled during CPU_DOWN_PREPARE so they - * can't possibly run on any other CPU. - */ - __gov_queue_work(raw_smp_processor_id(), dbs_data, delay); - } else { - for_each_cpu(i, policy->cpus) - __gov_queue_work(i, dbs_data, delay); + for_each_cpu(cpu, policy->cpus) { + cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); + cdbs->timer.expires = jiffies + delay; + add_timer_on(&cdbs->timer, cpu); } } -EXPORT_SYMBOL_GPL(gov_queue_work); +EXPORT_SYMBOL_GPL(gov_add_timers); -static inline void gov_cancel_work(struct dbs_data *dbs_data, - struct cpufreq_policy *policy) +static inline void gov_cancel_timers(struct cpufreq_policy *policy) { + struct dbs_data *dbs_data = policy->governor_data; struct cpu_dbs_info *cdbs; int i; for_each_cpu(i, policy->cpus) { cdbs = dbs_data->cdata->get_cpu_cdbs(i); - cancel_delayed_work_sync(&cdbs->dwork); + del_timer_sync(&cdbs->timer); } } +void gov_cancel_work(struct cpu_common_dbs_info *shared) +{ + unsigned long flags; + + /* + * No work will be queued from timer handlers after skip_work is + * updated. And so we can safely cancel the work first and then the + * timers. + */ + spin_lock_irqsave(&shared->timer_lock, flags); + shared->skip_work++; + spin_unlock_irqrestore(&shared->timer_lock, flags); + + cancel_work_sync(&shared->work); + + gov_cancel_timers(shared->policy); + + shared->skip_work = 0; +} +EXPORT_SYMBOL_GPL(gov_cancel_work); + /* Will return if we need to evaluate cpu load again or not */ static bool need_load_eval(struct cpu_common_dbs_info *shared, unsigned int sampling_rate) @@ -217,29 +223,22 @@ static bool need_load_eval(struct cpu_common_dbs_info *shared, return true; } -static void dbs_timer(struct work_struct *work) +static void dbs_work_handler(struct work_struct *work) { - struct cpu_dbs_info *cdbs = container_of(work, struct cpu_dbs_info, - dwork.work); - struct cpu_common_dbs_info *shared = cdbs->shared; + struct cpu_common_dbs_info *shared = container_of(work, struct + cpu_common_dbs_info, work); struct cpufreq_policy *policy; struct dbs_data *dbs_data; unsigned int sampling_rate, delay; - bool modify_all = true; - - mutex_lock(&shared->timer_mutex); + unsigned long flags; + bool eval_load; policy = shared->policy; - - /* - * Governor might already be disabled and there is no point continuing - * with the work-handler. - */ - if (!policy) - goto unlock; - dbs_data = policy->governor_data; + /* Kill all timers */ + gov_cancel_timers(policy); + if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -250,14 +249,43 @@ static void dbs_timer(struct work_struct *work) sampling_rate = od_tuners->sampling_rate; } - if (!need_load_eval(cdbs->shared, sampling_rate)) - modify_all = false; + eval_load = need_load_eval(shared, sampling_rate); - delay = dbs_data->cdata->gov_dbs_timer(policy, modify_all); - gov_queue_work(dbs_data, policy, delay, modify_all); - -unlock: + /* + * Make sure cpufreq_governor_limits() isn't evaluating load in + * parallel. + */ + mutex_lock(&shared->timer_mutex); + delay = dbs_data->cdata->gov_dbs_timer(policy, eval_load); mutex_unlock(&shared->timer_mutex); + + spin_lock_irqsave(&shared->timer_lock, flags); + shared->skip_work--; + spin_unlock_irqrestore(&shared->timer_lock, flags); + + gov_add_timers(policy, delay); +} + +static void dbs_timer_handler(unsigned long data) +{ + struct cpu_dbs_info *cdbs = (struct cpu_dbs_info *)data; + struct cpu_common_dbs_info *shared = cdbs->shared; + unsigned long flags; + + spin_lock_irqsave(&shared->timer_lock, flags); + + /* + * Timer handler isn't allowed to queue work at the moment, because: + * - Another timer handler has done that + * - We are stopping the governor + * - Or we are updating the sampling rate of ondemand governor + */ + if (!shared->skip_work) { + shared->skip_work++; + queue_work(system_wq, &shared->work); + } + + spin_unlock_irqrestore(&shared->timer_lock, flags); } static void set_sampling_rate(struct dbs_data *dbs_data, @@ -288,6 +316,8 @@ static int alloc_common_dbs_info(struct cpufreq_policy *policy, cdata->get_cpu_cdbs(j)->shared = shared; mutex_init(&shared->timer_mutex); + spin_lock_init(&shared->timer_lock); + INIT_WORK(&shared->work, dbs_work_handler); return 0; } @@ -452,7 +482,9 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - INIT_DEFERRABLE_WORK(&j_cdbs->dwork, dbs_timer); + __setup_timer(&j_cdbs->timer, dbs_timer_handler, + (unsigned long)j_cdbs, + TIMER_DEFERRABLE | TIMER_IRQSAFE); } if (cdata->governor == GOV_CONSERVATIVE) { @@ -470,8 +502,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, od_ops->powersave_bias_init_cpu(cpu); } - gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate), - true); + gov_add_timers(policy, delay_for_sampling_rate(sampling_rate)); return 0; } @@ -485,16 +516,9 @@ static int cpufreq_governor_stop(struct cpufreq_policy *policy, if (!shared || !shared->policy) return -EBUSY; - /* - * Work-handler must see this updated, as it should not proceed any - * further after governor is disabled. And so timer_mutex is taken while - * updating this value. - */ - mutex_lock(&shared->timer_mutex); + gov_cancel_work(shared); shared->policy = NULL; - mutex_unlock(&shared->timer_mutex); - gov_cancel_work(dbs_data, policy); return 0; } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 0c75890..7674290 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -132,12 +132,20 @@ static void *get_cpu_dbs_info_s(int cpu) \ struct cpu_common_dbs_info { struct cpufreq_policy *policy; /* - * percpu mutex that serializes governor limit change with dbs_timer - * invocation. We do not want dbs_timer to run when user is changing - * the governor or limits. + * Per policy mutex that serializes load evaluation from limit-change + * and work-handler. */ struct mutex timer_mutex; + + /* + * Per policy lock that serializes access to queuing work from timer + * handlers. + */ + spinlock_t timer_lock; + ktime_t time_stamp; + unsigned int skip_work; + struct work_struct work; }; /* Per cpu structures */ @@ -152,7 +160,7 @@ struct cpu_dbs_info { * wake-up from idle. */ unsigned int prev_load; - struct delayed_work dwork; + struct timer_list timer; struct cpu_common_dbs_info *shared; }; @@ -268,11 +276,11 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; +void gov_add_timers(struct cpufreq_policy *policy, unsigned int delay); +void gov_cancel_work(struct cpu_common_dbs_info *shared); void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); -void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, - unsigned int delay, bool all_cpus); void od_register_powersave_bias_handler(unsigned int (*f) (struct cpufreq_policy *, unsigned int, unsigned int), unsigned int powersave_bias); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index fc0384b..f879012 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -286,13 +286,11 @@ static void update_sampling_rate(struct dbs_data *dbs_data, continue; next_sampling = jiffies + usecs_to_jiffies(new_rate); - appointed_at = dbs_info->cdbs.dwork.timer.expires; + appointed_at = dbs_info->cdbs.timer.expires; if (time_before(next_sampling, appointed_at)) { - cancel_delayed_work_sync(&dbs_info->cdbs.dwork); - - gov_queue_work(dbs_data, policy, - usecs_to_jiffies(new_rate), true); + gov_cancel_work(shared); + gov_add_timers(policy, usecs_to_jiffies(new_rate)); } } -- cgit v0.10.2 From f08f638b9c7f1bf3cb9006d3d26bf568d807ede0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Dec 2015 09:37:54 +0530 Subject: cpufreq: ondemand: update update_sampling_rate() to make it more efficient Currently update_sampling_rate() runs over each online CPU and cancels/queues timers on all policy->cpus every time. This should be done just once for any cpu belonging to a policy. Create a cpumask and keep on clearing it as and when we process policies, so that we don't have to traverse through all CPUs of the same policy. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index f879012..eae5107 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -246,6 +246,7 @@ static void update_sampling_rate(struct dbs_data *dbs_data, unsigned int new_rate) { struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct cpumask cpumask; int cpu; od_tuners->sampling_rate = new_rate = max(new_rate, @@ -256,7 +257,9 @@ static void update_sampling_rate(struct dbs_data *dbs_data, */ mutex_lock(&od_dbs_cdata.mutex); - for_each_online_cpu(cpu) { + cpumask_copy(&cpumask, cpu_online_mask); + + for_each_cpu(cpu, &cpumask) { struct cpufreq_policy *policy; struct od_cpu_dbs_info_s *dbs_info; struct cpu_dbs_info *cdbs; @@ -276,6 +279,9 @@ static void update_sampling_rate(struct dbs_data *dbs_data, policy = shared->policy; + /* clear all CPUs of this policy */ + cpumask_andnot(&cpumask, &cpumask, policy->cpus); + /* * Update sampling rate for CPUs whose policy is governed by * dbs_data. In case of governor_per_policy, only a single @@ -285,6 +291,10 @@ static void update_sampling_rate(struct dbs_data *dbs_data, if (dbs_data != policy->governor_data) continue; + /* + * Checking this for any CPU should be fine, timers for all of + * them are scheduled together. + */ next_sampling = jiffies + usecs_to_jiffies(new_rate); appointed_at = dbs_info->cdbs.timer.expires; -- cgit v0.10.2 From 2dd3e724b4e2237cfaaf155cab72af02c1c420cc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Dec 2015 21:44:05 +0100 Subject: cpufreq: governor: Use lockless timer function It is possible to get rid of the timer_lock spinlock used by the governor timer function for synchronization, but a couple of races need to be avoided. The first race is between multiple dbs_timer_handler() instances that may be running in parallel with each other on different CPUs. Namely, one of them has to queue up the work item, but it cannot be queued up more than once. To achieve that, atomic_inc_return() can be used on the skip_work field of struct cpu_common_dbs_info. The second race is between an already running dbs_timer_handler() and gov_cancel_work(). In that case the dbs_timer_handler() might not notice the skip_work incrementation in gov_cancel_work() and it might queue up its work item after gov_cancel_work() had returned (and that work item would corrupt skip_work going forward). To prevent that from happening, gov_cancel_work() can be made wait for the timer function to complete (on all CPUs) right after skip_work has been incremented. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 2d61eae..4de12fd 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -186,22 +186,24 @@ static inline void gov_cancel_timers(struct cpufreq_policy *policy) void gov_cancel_work(struct cpu_common_dbs_info *shared) { - unsigned long flags; - + /* Tell dbs_timer_handler() to skip queuing up work items. */ + atomic_inc(&shared->skip_work); /* - * No work will be queued from timer handlers after skip_work is - * updated. And so we can safely cancel the work first and then the - * timers. + * If dbs_timer_handler() is already running, it may not notice the + * incremented skip_work, so wait for it to complete to prevent its work + * item from being queued up after the cancel_work_sync() below. + */ + gov_cancel_timers(shared->policy); + /* + * In case dbs_timer_handler() managed to run and spawn a work item + * before the timers have been canceled, wait for that work item to + * complete and then cancel all of the timers set up by it. If + * dbs_timer_handler() runs again at that point, it will see the + * positive value of skip_work and won't spawn any more work items. */ - spin_lock_irqsave(&shared->timer_lock, flags); - shared->skip_work++; - spin_unlock_irqrestore(&shared->timer_lock, flags); - cancel_work_sync(&shared->work); - gov_cancel_timers(shared->policy); - - shared->skip_work = 0; + atomic_set(&shared->skip_work, 0); } EXPORT_SYMBOL_GPL(gov_cancel_work); @@ -230,7 +232,6 @@ static void dbs_work_handler(struct work_struct *work) struct cpufreq_policy *policy; struct dbs_data *dbs_data; unsigned int sampling_rate, delay; - unsigned long flags; bool eval_load; policy = shared->policy; @@ -259,9 +260,7 @@ static void dbs_work_handler(struct work_struct *work) delay = dbs_data->cdata->gov_dbs_timer(policy, eval_load); mutex_unlock(&shared->timer_mutex); - spin_lock_irqsave(&shared->timer_lock, flags); - shared->skip_work--; - spin_unlock_irqrestore(&shared->timer_lock, flags); + atomic_dec(&shared->skip_work); gov_add_timers(policy, delay); } @@ -270,22 +269,18 @@ static void dbs_timer_handler(unsigned long data) { struct cpu_dbs_info *cdbs = (struct cpu_dbs_info *)data; struct cpu_common_dbs_info *shared = cdbs->shared; - unsigned long flags; - - spin_lock_irqsave(&shared->timer_lock, flags); /* - * Timer handler isn't allowed to queue work at the moment, because: + * Timer handler may not be allowed to queue the work at the moment, + * because: * - Another timer handler has done that * - We are stopping the governor - * - Or we are updating the sampling rate of ondemand governor + * - Or we are updating the sampling rate of the ondemand governor */ - if (!shared->skip_work) { - shared->skip_work++; + if (atomic_inc_return(&shared->skip_work) > 1) + atomic_dec(&shared->skip_work); + else queue_work(system_wq, &shared->work); - } - - spin_unlock_irqrestore(&shared->timer_lock, flags); } static void set_sampling_rate(struct dbs_data *dbs_data, @@ -316,7 +311,7 @@ static int alloc_common_dbs_info(struct cpufreq_policy *policy, cdata->get_cpu_cdbs(j)->shared = shared; mutex_init(&shared->timer_mutex); - spin_lock_init(&shared->timer_lock); + atomic_set(&shared->skip_work, 0); INIT_WORK(&shared->work, dbs_work_handler); return 0; } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 7674290..91e767a 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -17,6 +17,7 @@ #ifndef _CPUFREQ_GOVERNOR_H #define _CPUFREQ_GOVERNOR_H +#include #include #include #include @@ -137,14 +138,8 @@ struct cpu_common_dbs_info { */ struct mutex timer_mutex; - /* - * Per policy lock that serializes access to queuing work from timer - * handlers. - */ - spinlock_t timer_lock; - ktime_t time_stamp; - unsigned int skip_work; + atomic_t skip_work; struct work_struct work; }; -- cgit v0.10.2 From cd7f84c02825cfca6cc86826395167479bdc1a05 Mon Sep 17 00:00:00 2001 From: Ken Xue Date: Wed, 9 Dec 2015 16:17:30 +0800 Subject: ACPI / PM: Support D3 COLD device in old BIOS for ZPODD D3cold is only regarded as valid if the "_PR3" object is present for the given device after the commit 20dacb71ad28 ("ACPI/PM: Rework device power management to follow ACPI 6"). But some old BIOS only defined "_PS3" for the D3COLD device, such as ZPODD device. And old kernel also believes the device with "_PS3" is a D3COLD device. So, add some logics for supporting D3 COLD device with old BIOS which is compatible with earlier ACPI spec and kernel behavior. Link: http://marc.info/?l=linux-acpi&m=144946938709759&w=2 Signed-off-by: Ken Xue Reported-and-tested-by: Gang Long Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ad0a5ff..9894b75 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -631,7 +631,9 @@ static inline bool acpi_device_can_wakeup(struct acpi_device *adev) static inline bool acpi_device_can_poweroff(struct acpi_device *adev) { - return adev->power.states[ACPI_STATE_D3_COLD].flags.valid; + return adev->power.states[ACPI_STATE_D3_COLD].flags.valid || + ((acpi_gbl_FADT.header.revision < 6) && + adev->power.states[ACPI_STATE_D3_HOT].flags.explicit_set); } #else /* CONFIG_ACPI */ -- cgit v0.10.2 From 08dc7c7e407fed00a89bd6f4fc13c7ea20320de1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 20 Nov 2015 14:35:02 -0300 Subject: ACPI: Fix build errors due objects compiled unconditionally If the CONFIG_ACPI Kconfig symbol is not enabled and a partial build is attempted, compile errors will happen due missing types and identifiers. This can be easily reproduced with the following commands: $ export CROSS_COMPILE="arm-linux-gnueabihf-" ARCH=arm $ make allmodconfig $ make M=drivers/acpi/ CC drivers/acpi//tables.o drivers/acpi//tables.c:235:3: warning: 'struct acpi_subtable_proc' declared inside parameter list unsigned int max_entries) ^ drivers/acpi//tables.c:235:3: warning: its scope is only this definition or declaration, which is probably not what you want drivers/acpi//tables.c: In function 'acpi_parse_entries_array': drivers/acpi//tables.c:269:4: error: invalid use of undefined type 'struct acpi_subtable_proc' ... scripts/Makefile.build:258: recipe for target 'drivers/acpi//tables.o' failed make[1]: *** [drivers/acpi//tables.o] Error 1 Makefile:1401: recipe for target '_module_drivers/acpi/' failed make: *** [_module_drivers/acpi/] Error 2 This is because objects are tried to be built unconditionally even when CONFIG_ACPI is not enabled. This is usually not a problem since arches' Kconfig sources drivers/acpi/Kconfig directly and also selects ACPI but the Makefile should conditionally build the objects as well to prevent these build errors. Signed-off-by: Javier Martinez Canillas Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 675eaf3..73ec23c 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -8,13 +8,13 @@ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # # ACPI Boot-Time Table Parsing # -obj-y += tables.o +obj-$(CONFIG_ACPI) += tables.o obj-$(CONFIG_X86) += blacklist.o # # ACPI Core Subsystem (Interpreter) # -obj-y += acpi.o \ +obj-$(CONFIG_ACPI) += acpi.o \ acpica/ # All the builtin files are in the "acpi." module_param namespace. @@ -66,10 +66,10 @@ obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o -obj-y += container.o +obj-$(CONFIG_ACPI) += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_NFIT) += nfit.o -obj-y += acpi_memhotplug.o +obj-$(CONFIG_ACPI) += acpi_memhotplug.o obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o -- cgit v0.10.2 From 3be3f8f36e7349006f19c8c8f0d686e98462a993 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 17 Nov 2015 12:06:21 +0000 Subject: devicetree: bindings: Add optional dynamic-power-coefficient property The dynamic power consumption of a device is proportional to the square of voltage (V) and the clock frequency (f). It can be expressed as Pdyn = dynamic-power-coefficient * V^2 * f. The coefficient represents the running time dynamic power consumption in units of mw/MHz/uVolt^2 and can be used in the above formula to calculate the dynamic power in mW. Signed-off-by: Punit Agrawal Acked-by: Rob Herring Reviewed-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 3a07a87..6aca64f 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -242,6 +242,23 @@ nodes to be present and contain the properties described below. Definition: Specifies the syscon node controlling the cpu core power domains. + - dynamic-power-coefficient + Usage: optional + Value type: + Definition: A u32 value that represents the running time dynamic + power coefficient in units of mW/MHz/uVolt^2. The + coefficient can either be calculated from power + measurements or derived by analysis. + + The dynamic power consumption of the CPU is + proportional to the square of the Voltage (V) and + the clock frequency (f). The coefficient is used to + calculate the dynamic power as below - + + Pdyn = dynamic-power-coefficient * V^2 * f + + where voltage is in uV, frequency is in MHz. + Example 1 (dual-cluster big.LITTLE system 32-bit): cpus { -- cgit v0.10.2 From f8fa8ae06b8c2c25d81c99766f9226adc5c3e073 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 17 Nov 2015 12:06:22 +0000 Subject: cpufreq-dt: Supply power coefficient when registering cooling devices Support registering cooling devices with dynamic power coefficient where provided by the device tree. This allows OF registered cooling devices driver to be used with the power_allocator thermal governor. Signed-off-by: Punit Agrawal Acked-by: Viresh Kumar Reviewed-by: Javi Merino Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 90d6408..1ceece9 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -407,8 +407,13 @@ static void cpufreq_ready(struct cpufreq_policy *policy) * thermal DT code takes care of matching them. */ if (of_find_property(np, "#cooling-cells", NULL)) { - priv->cdev = of_cpufreq_cooling_register(np, - policy->related_cpus); + u32 power_coefficient = 0; + + of_property_read_u32(np, "dynamic-power-coefficient", + &power_coefficient); + + priv->cdev = of_cpufreq_power_cooling_register(np, + policy->related_cpus, power_coefficient, NULL); if (IS_ERR(priv->cdev)) { dev_err(priv->cpu_dev, "running cpufreq without cooling device: %ld\n", -- cgit v0.10.2 From 2f7e8a175db72bdaf377235962fd85796edb3fbc Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 17 Nov 2015 12:06:23 +0000 Subject: cpufreq: arm_big_little: Add support to register a cpufreq cooling device Register passive cooling devices when initialising cpufreq on big.LITTLE systems. If the device tree provides a dynamic power coefficient for the CPUs then the bound cooling device will support the extensions that allow it to be used with all the existing thermal governors including the power allocator governor. A cooling device will be created per individual frequency domain and can be bound to thermal zones via the thermal DT bindings. Signed-off-by: Punit Agrawal Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 235a1ba..80fbfb3 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -6,6 +6,8 @@ config ARM_BIG_LITTLE_CPUFREQ tristate "Generic ARM big LITTLE CPUfreq driver" depends on (ARM_CPU_TOPOLOGY || ARM64) && HAVE_CLK + # if CPU_THERMAL is on and THERMAL=m, ARM_BIT_LITTLE_CPUFREQ cannot be =y + depends on !CPU_THERMAL || THERMAL select PM_OPP help This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index c5d256c..c251247 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ static bool bL_switching_enabled; #define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq) #define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) +static struct thermal_cooling_device *cdev[MAX_CLUSTERS]; static struct cpufreq_arm_bL_ops *arm_bL_ops; static struct clk *clk[MAX_CLUSTERS]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; @@ -493,6 +495,12 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) static int bL_cpufreq_exit(struct cpufreq_policy *policy) { struct device *cpu_dev; + int cur_cluster = cpu_to_cluster(policy->cpu); + + if (cur_cluster < MAX_CLUSTERS) { + cpufreq_cooling_unregister(cdev[cur_cluster]); + cdev[cur_cluster] = NULL; + } cpu_dev = get_cpu_device(policy->cpu); if (!cpu_dev) { @@ -507,6 +515,38 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy) return 0; } +static void bL_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct device *cpu_dev = get_cpu_device(policy->cpu); + int cur_cluster = cpu_to_cluster(policy->cpu); + struct device_node *np; + + /* Do not register a cpu_cooling device if we are in IKS mode */ + if (cur_cluster >= MAX_CLUSTERS) + return; + + np = of_node_get(cpu_dev->of_node); + if (WARN_ON(!np)) + return; + + if (of_find_property(np, "#cooling-cells", NULL)) { + u32 power_coefficient = 0; + + of_property_read_u32(np, "dynamic-power-coefficient", + &power_coefficient); + + cdev[cur_cluster] = of_cpufreq_power_cooling_register(np, + policy->related_cpus, power_coefficient, NULL); + if (IS_ERR(cdev[cur_cluster])) { + dev_err(cpu_dev, + "running cpufreq without cooling device: %ld\n", + PTR_ERR(cdev[cur_cluster])); + cdev[cur_cluster] = NULL; + } + } + of_node_put(np); +} + static struct cpufreq_driver bL_cpufreq_driver = { .name = "arm-big-little", .flags = CPUFREQ_STICKY | @@ -517,6 +557,7 @@ static struct cpufreq_driver bL_cpufreq_driver = { .get = bL_cpufreq_get_rate, .init = bL_cpufreq_init, .exit = bL_cpufreq_exit, + .ready = bL_cpufreq_ready, .attr = cpufreq_generic_attr, }; -- cgit v0.10.2 From 790d849bf811a8ab5d4cd2cce0f6fda92f6aebf2 Mon Sep 17 00:00:00 2001 From: Jacob Tanenbaum Date: Thu, 19 Nov 2015 10:29:01 -0500 Subject: cpufreq: pcc-cpufreq: update default value of cpuinfo_transition_latency The cpufreq documentation specifies policy->cpuinfo.transition_latency the time it takes on this CPU to switch between two frequencies in nanoseconds (if appropriate, else specify CPUFREQ_ETERNAL) currently pcc-cpufreq does not expose the value and sets it to zero. I changed the pcc-cpufreq driver and it's documentation to conform to the default value specified in Documentation/cpu-freq/cpu-drivers.txt Signed-off-by: Jacob Tanenbaum Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/cpu-freq/pcc-cpufreq.txt b/Documentation/cpu-freq/pcc-cpufreq.txt index 9e3c3b3..0a94224 100644 --- a/Documentation/cpu-freq/pcc-cpufreq.txt +++ b/Documentation/cpu-freq/pcc-cpufreq.txt @@ -159,8 +159,8 @@ to be strictly associated with a P-state. 2.2 cpuinfo_transition_latency: ------------------------------- -The cpuinfo_transition_latency field is 0. The PCC specification does -not include a field to expose this value currently. +The cpuinfo_transition_latency field is CPUFREQ_ETERNAL. The PCC specification +does not include a field to expose this value currently. 2.3 cpuinfo_cur_freq: --------------------- diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 2a0d589..808a320 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -555,6 +555,8 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->min = policy->cpuinfo.min_freq = ioread32(&pcch_hdr->minimum_frequency) * 1000; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + pr_debug("init: policy->max is %d, policy->min is %d\n", policy->max, policy->min); out: -- cgit v0.10.2 From 8ae1702a0df5e0730607b97fd9fd1f8066870832 Mon Sep 17 00:00:00 2001 From: Hongtao Jia Date: Thu, 26 Nov 2015 17:21:11 +0800 Subject: cpufreq: qoriq: Register cooling device based on device tree Register the qoriq cpufreq driver as a cooling device, based on the thermal device tree framework. When temperature crosses the passive trip point cpufreq is used to throttle CPUs. Signed-off-by: Jia Hongtao Reviewed-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 358f075..b23e525 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ struct cpu_data { struct clk **pclk; struct cpufreq_frequency_table *table; + struct thermal_cooling_device *cdev; }; /** @@ -321,6 +323,27 @@ static int qoriq_cpufreq_target(struct cpufreq_policy *policy, return clk_set_parent(policy->clk, parent); } + +static void qoriq_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct cpu_data *cpud = policy->driver_data; + struct device_node *np = of_get_cpu_node(policy->cpu, NULL); + + if (of_find_property(np, "#cooling-cells", NULL)) { + cpud->cdev = of_cpufreq_cooling_register(np, + policy->related_cpus); + + if (IS_ERR(cpud->cdev)) { + pr_err("Failed to register cooling device cpu%d: %ld\n", + policy->cpu, PTR_ERR(cpud->cdev)); + + cpud->cdev = NULL; + } + } + + of_node_put(np); +} + static struct cpufreq_driver qoriq_cpufreq_driver = { .name = "qoriq_cpufreq", .flags = CPUFREQ_CONST_LOOPS, @@ -329,6 +352,7 @@ static struct cpufreq_driver qoriq_cpufreq_driver = { .verify = cpufreq_generic_frequency_table_verify, .target_index = qoriq_cpufreq_target, .get = cpufreq_generic_get, + .ready = qoriq_cpufreq_ready, .attr = cpufreq_generic_attr, }; -- cgit v0.10.2 From 9bb46b87d662ab704bd852db9916f0e51db3e94b Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Sun, 29 Nov 2015 16:31:35 +0800 Subject: cpufreq: mt8173: add CPUFREQ_HAVE_GOVERNOR_PER_POLICY flag Add CPUFREQ_HAVE_GOVERNOR_PER_POLICY to have individual set of tunables for each cluster of MT8173. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 83001dc..c438109 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -469,7 +469,8 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy) } static struct cpufreq_driver mt8173_cpufreq_driver = { - .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | + CPUFREQ_HAVE_GOVERNOR_PER_POLICY, .verify = cpufreq_generic_frequency_table_verify, .target_index = mtk_cpufreq_set_target, .get = cpufreq_generic_get, -- cgit v0.10.2 From 93625d52e7a74492416f77fed945ba34e0ae0c18 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Sun, 29 Nov 2015 16:31:36 +0800 Subject: cpufreq: mt8173: remove redundant regulator_get_voltage() call Remove redundant regulator_get_voltage() call to get Vsram value since it will be obtained later at the beginning of voltage tracking loop. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index c438109..750cda7 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -59,7 +59,6 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, int old_vproc, old_vsram, new_vsram, vsram, vproc, ret; old_vproc = regulator_get_voltage(proc_reg); - old_vsram = regulator_get_voltage(sram_reg); /* Vsram should not exceed the maximum allowed voltage of SoC. */ new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT); -- cgit v0.10.2 From 40be4c3ccbf4078e2f8426a7962879b7a447cde4 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Sun, 29 Nov 2015 16:31:37 +0800 Subject: cpufreq: mt8173: check return value of regulator_get_voltage() call Sometimes regulator_get_voltage() call returns negative values for reasons(e.g. underlying I2C bus timeout). Add check for the return values and fail out early. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 750cda7..9d0fe37 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -59,6 +59,10 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, int old_vproc, old_vsram, new_vsram, vsram, vproc, ret; old_vproc = regulator_get_voltage(proc_reg); + if (old_vproc < 0) { + pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc); + return old_vproc; + } /* Vsram should not exceed the maximum allowed voltage of SoC. */ new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT); @@ -71,7 +75,17 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, */ do { old_vsram = regulator_get_voltage(sram_reg); + if (old_vsram < 0) { + pr_err("%s: invalid Vsram value: %d\n", + __func__, old_vsram); + return old_vsram; + } old_vproc = regulator_get_voltage(proc_reg); + if (old_vproc < 0) { + pr_err("%s: invalid Vproc value: %d\n", + __func__, old_vproc); + return old_vproc; + } vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT); @@ -116,7 +130,17 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, */ do { old_vproc = regulator_get_voltage(proc_reg); + if (old_vproc < 0) { + pr_err("%s: invalid Vproc value: %d\n", + __func__, old_vproc); + return old_vproc; + } old_vsram = regulator_get_voltage(sram_reg); + if (old_vsram < 0) { + pr_err("%s: invalid Vsram value: %d\n", + __func__, old_vsram); + return old_vsram; + } vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT); ret = regulator_set_voltage(proc_reg, vproc, @@ -184,6 +208,10 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, old_freq_hz = clk_get_rate(cpu_clk); old_vproc = regulator_get_voltage(info->proc_reg); + if (old_vproc < 0) { + pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc); + return old_vproc; + } freq_hz = freq_table[index].frequency * 1000; -- cgit v0.10.2 From 157386b6fc1465f292b66c4133409033650ad335 Mon Sep 17 00:00:00 2001 From: Philippe Longepe Date: Fri, 4 Dec 2015 17:40:30 +0100 Subject: cpufreq: intel_pstate: Configurable algorithm to get target pstate Target systems using different cpus have different power and performance requirements. They may use different algorithms to get the next P-state based on their power or performance preference. For example, power-constrained systems may not want to use high-performance P-states as aggressively as a full-size desktop or a server platform. A server platform may want to run close to the max to achieve better performance, while laptop-like systems may prefer sacrificing performance for longer battery lifes. For the above reasons, modify intel_pstate to allow the target P-state selection algorithm to be depend on the CPU ID. Signed-off-by: Srinivas Pandruvada Signed-off-by: Philippe Longepe Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 4d07cbd..ff58029 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -66,6 +66,7 @@ static inline int ceiling_fp(int32_t x) struct sample { int32_t core_pct_busy; + int32_t busy_scaled; u64 aperf; u64 mperf; u64 tsc; @@ -133,6 +134,7 @@ struct pstate_funcs { int (*get_scaling)(void); void (*set)(struct cpudata*, int pstate); void (*get_vid)(struct cpudata *); + int32_t (*get_target_pstate)(struct cpudata *); }; struct cpu_defaults { @@ -140,6 +142,8 @@ struct cpu_defaults { struct pstate_funcs funcs; }; +static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu); + static struct pstate_adjust_policy pid_params; static struct pstate_funcs pstate_funcs; static int hwp_active; @@ -738,6 +742,7 @@ static struct cpu_defaults core_params = { .get_turbo = core_get_turbo_pstate, .get_scaling = core_get_scaling, .set = core_set_pstate, + .get_target_pstate = get_target_pstate_use_performance, }, }; @@ -758,6 +763,7 @@ static struct cpu_defaults silvermont_params = { .set = atom_set_pstate, .get_scaling = silvermont_get_scaling, .get_vid = atom_get_vid, + .get_target_pstate = get_target_pstate_use_performance, }, }; @@ -778,6 +784,7 @@ static struct cpu_defaults airmont_params = { .set = atom_set_pstate, .get_scaling = airmont_get_scaling, .get_vid = atom_get_vid, + .get_target_pstate = get_target_pstate_use_performance, }, }; @@ -797,6 +804,7 @@ static struct cpu_defaults knl_params = { .get_turbo = knl_get_turbo_pstate, .get_scaling = core_get_scaling, .set = core_set_pstate, + .get_target_pstate = get_target_pstate_use_performance, }, }; @@ -922,7 +930,7 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) mod_timer_pinned(&cpu->timer, jiffies + delay); } -static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) +static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) { int32_t core_busy, max_pstate, current_pstate, sample_ratio; s64 duration_us; @@ -960,30 +968,24 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) core_busy = mul_fp(core_busy, sample_ratio); } - return core_busy; + cpu->sample.busy_scaled = core_busy; + return cpu->pstate.current_pstate - pid_calc(&cpu->pid, core_busy); } static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) { - int32_t busy_scaled; - struct _pid *pid; - signed int ctl; - int from; + int from, target_pstate; struct sample *sample; from = cpu->pstate.current_pstate; - pid = &cpu->pid; - busy_scaled = intel_pstate_get_scaled_busy(cpu); + target_pstate = pstate_funcs.get_target_pstate(cpu); - ctl = pid_calc(pid, busy_scaled); - - /* Negative values of ctl increase the pstate and vice versa */ - intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl, true); + intel_pstate_set_pstate(cpu, target_pstate, true); sample = &cpu->sample; trace_pstate_sample(fp_toint(sample->core_pct_busy), - fp_toint(busy_scaled), + fp_toint(sample->busy_scaled), from, cpu->pstate.current_pstate, sample->mperf, @@ -1237,6 +1239,8 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) pstate_funcs.get_scaling = funcs->get_scaling; pstate_funcs.set = funcs->set; pstate_funcs.get_vid = funcs->get_vid; + pstate_funcs.get_target_pstate = funcs->get_target_pstate; + } #if IS_ENABLED(CONFIG_ACPI) -- cgit v0.10.2 From e70eed2b64545ab5c9d2f4d43372d79762f1b985 Mon Sep 17 00:00:00 2001 From: Philippe Longepe Date: Fri, 4 Dec 2015 17:40:32 +0100 Subject: cpufreq: intel_pstate: Account for non C0 time The current function to calculate cpu utilization uses the average P-state ratio (APerf/Mperf) scaled by the ratio of the current P-state to the max available non-turbo one. This leads to an overestimation of utilization which causes higher-performance P-states to be selected more often and that leads to increased energy consumption. This is a problem for low-power systems, so it is better to use a different utilization calculation algorithm for them. Namely, the Percent Busy value (or load) can be estimated as the ratio of the MPERF counter that runs at a constant rate only during active periods (C0) to the time stamp counter (TSC) that also runs (at the same rate) during idle. That is: Percent Busy = 100 * (delta_mperf / delta_tsc) Use this algorithm for platforms with SoCs based on the Airmont and Silvermont Atom cores. Signed-off-by: Philippe Longepe Signed-off-by: Stephane Gasparini Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index ff58029..8bfebae 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -143,6 +143,7 @@ struct cpu_defaults { }; static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu); +static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu); static struct pstate_adjust_policy pid_params; static struct pstate_funcs pstate_funcs; @@ -763,7 +764,7 @@ static struct cpu_defaults silvermont_params = { .set = atom_set_pstate, .get_scaling = silvermont_get_scaling, .get_vid = atom_get_vid, - .get_target_pstate = get_target_pstate_use_performance, + .get_target_pstate = get_target_pstate_use_cpu_load, }, }; @@ -784,7 +785,7 @@ static struct cpu_defaults airmont_params = { .set = atom_set_pstate, .get_scaling = airmont_get_scaling, .get_vid = atom_get_vid, - .get_target_pstate = get_target_pstate_use_performance, + .get_target_pstate = get_target_pstate_use_cpu_load, }, }; @@ -890,12 +891,11 @@ static inline void intel_pstate_sample(struct cpudata *cpu) local_irq_save(flags); rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); - if (cpu->prev_mperf == mperf) { + tsc = rdtsc(); + if ((cpu->prev_mperf == mperf) || (cpu->prev_tsc == tsc)) { local_irq_restore(flags); return; } - - tsc = rdtsc(); local_irq_restore(flags); cpu->last_sample_time = cpu->sample.time; @@ -930,6 +930,25 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) mod_timer_pinned(&cpu->timer, jiffies + delay); } +static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) +{ + struct sample *sample = &cpu->sample; + int32_t cpu_load; + + /* + * The load can be estimated as the ratio of the mperf counter + * running at a constant frequency during active periods + * (C0) and the time stamp counter running at the same frequency + * also during C-states. + */ + cpu_load = div64_u64(int_tofp(100) * sample->mperf, sample->tsc); + + cpu->sample.busy_scaled = cpu_load; + + return cpu->pstate.current_pstate - pid_calc(&cpu->pid, cpu_load); +} + + static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) { int32_t core_busy, max_pstate, current_pstate, sample_ratio; -- cgit v0.10.2 From 63d1d656a5232f2f189b217b50542eadcf9d74ae Mon Sep 17 00:00:00 2001 From: Philippe Longepe Date: Fri, 4 Dec 2015 17:40:35 +0100 Subject: cpufreq: intel_pstate: Account for IO wait time In cases where we have many IOs, the global load becomes low and the load algorithm will decrease the requested P-State. Because of that, the IOs overheads will increase and impact the IO performances. To improve IO bound work, we can count the io-wait time as busy time in calculating CPU busy. This change uses get_cpu_iowait_time_us() to obtain the IO wait time value and converts time into number of cycles spent waiting on IO at the TSC rate. At the moment, this trick is only used for Atom. Signed-off-by: Philippe Longepe Signed-off-by: Stephane Gasparini Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 8bfebae..efc5813 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -113,6 +113,7 @@ struct cpudata { u64 prev_aperf; u64 prev_mperf; u64 prev_tsc; + u64 prev_cummulative_iowait; struct sample sample; }; @@ -933,22 +934,39 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) { struct sample *sample = &cpu->sample; + u64 cummulative_iowait, delta_iowait_us; + u64 delta_iowait_mperf; + u64 mperf, now; int32_t cpu_load; + cummulative_iowait = get_cpu_iowait_time_us(cpu->cpu, &now); + + /* + * Convert iowait time into number of IO cycles spent at max_freq. + * IO is considered as busy only for the cpu_load algorithm. For + * performance this is not needed since we always try to reach the + * maximum P-State, so we are already boosting the IOs. + */ + delta_iowait_us = cummulative_iowait - cpu->prev_cummulative_iowait; + delta_iowait_mperf = div64_u64(delta_iowait_us * cpu->pstate.scaling * + cpu->pstate.max_pstate, MSEC_PER_SEC); + + mperf = cpu->sample.mperf + delta_iowait_mperf; + cpu->prev_cummulative_iowait = cummulative_iowait; + + /* * The load can be estimated as the ratio of the mperf counter * running at a constant frequency during active periods * (C0) and the time stamp counter running at the same frequency * also during C-states. */ - cpu_load = div64_u64(int_tofp(100) * sample->mperf, sample->tsc); - + cpu_load = div64_u64(int_tofp(100) * mperf, sample->tsc); cpu->sample.busy_scaled = cpu_load; return cpu->pstate.current_pstate - pid_calc(&cpu->pid, cpu_load); } - static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu) { int32_t core_busy, max_pstate, current_pstate, sample_ratio; -- cgit v0.10.2 From 24c96dc79c5e76d3cff7a33f955a4d3244644766 Mon Sep 17 00:00:00 2001 From: Maruthi Bayyavarapu Date: Wed, 18 Nov 2015 01:12:00 +0530 Subject: PM / Domains: export symbols to add/remove devices from genpd Drivers which can be built as loadable module needs symbols - pm_genpd_add_device/pm_genpd_remove_device to add/remove devices to/from genpd. Those drivers create platform devices, which comes under a powerdomain. Signed-off-by: Maruthi Bayyavarapu Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 167418e..e0dc12e 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1252,6 +1252,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, return ret; } +EXPORT_SYMBOL_GPL(__pm_genpd_add_device); /** * pm_genpd_remove_device - Remove a device from an I/O PM domain. @@ -1302,6 +1303,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, return ret; } +EXPORT_SYMBOL_GPL(pm_genpd_remove_device); /** * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. -- cgit v0.10.2 From 7de36b0aa51a5a59e28fb2da768fa3ab07de0674 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 9 Dec 2015 08:01:46 +0530 Subject: PM / OPP: Parse 'opp-supported-hw' binding OPP bindings allow a platform to enable OPPs based on the version of the hardware they are used for. Add support to the OPP-core to parse these bindings, by introducing dev_pm_opp_{set|put}_supported_hw() APIs. Signed-off-by: Viresh Kumar Tested-by: Lee Jones Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 6aa172b..55cf1a9 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -559,6 +559,9 @@ static void _remove_device_opp(struct device_opp *dev_opp) if (!list_empty(&dev_opp->opp_list)) return; + if (dev_opp->supported_hw) + return; + list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp, node); @@ -834,6 +837,145 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev) } /** + * dev_pm_opp_set_supported_hw() - Set supported platforms + * @dev: Device for which supported-hw has to be set. + * @versions: Array of hierarchy of versions to match. + * @count: Number of elements in the array. + * + * This is required only for the V2 bindings, and it enables a platform to + * specify the hierarchy of versions it supports. OPP layer will then enable + * OPPs, which are available for those versions, based on its 'opp-supported-hw' + * property. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, + unsigned int count) +{ + struct device_opp *dev_opp; + int ret = 0; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + dev_opp = _add_device_opp(dev); + if (!dev_opp) { + ret = -ENOMEM; + goto unlock; + } + + /* Make sure there are no concurrent readers while updating dev_opp */ + WARN_ON(!list_empty(&dev_opp->opp_list)); + + /* Do we already have a version hierarchy associated with dev_opp? */ + if (dev_opp->supported_hw) { + dev_err(dev, "%s: Already have supported hardware list\n", + __func__); + ret = -EBUSY; + goto err; + } + + dev_opp->supported_hw = kmemdup(versions, count * sizeof(*versions), + GFP_KERNEL); + if (!dev_opp->supported_hw) { + ret = -ENOMEM; + goto err; + } + + dev_opp->supported_hw_count = count; + mutex_unlock(&dev_opp_list_lock); + return 0; + +err: + _remove_device_opp(dev_opp); +unlock: + mutex_unlock(&dev_opp_list_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); + +/** + * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw + * @dev: Device for which supported-hw has to be set. + * + * This is required only for the V2 bindings, and is called for a matching + * dev_pm_opp_set_supported_hw(). Until this is called, the device_opp structure + * will not be freed. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +void dev_pm_opp_put_supported_hw(struct device *dev) +{ + struct device_opp *dev_opp; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + /* Check for existing list for 'dev' first */ + dev_opp = _find_device_opp(dev); + if (IS_ERR(dev_opp)) { + dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp)); + goto unlock; + } + + /* Make sure there are no concurrent readers while updating dev_opp */ + WARN_ON(!list_empty(&dev_opp->opp_list)); + + if (!dev_opp->supported_hw) { + dev_err(dev, "%s: Doesn't have supported hardware list\n", + __func__); + goto unlock; + } + + kfree(dev_opp->supported_hw); + dev_opp->supported_hw = NULL; + dev_opp->supported_hw_count = 0; + + /* Try freeing device_opp if this was the last blocking resource */ + _remove_device_opp(dev_opp); + +unlock: + mutex_unlock(&dev_opp_list_lock); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); + +static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp, + struct device_node *np) +{ + unsigned int count = dev_opp->supported_hw_count; + u32 version; + int ret; + + if (!dev_opp->supported_hw) + return true; + + while (count--) { + ret = of_property_read_u32_index(np, "opp-supported-hw", count, + &version); + if (ret) { + dev_warn(dev, "%s: failed to read opp-supported-hw property at index %d: %d\n", + __func__, count, ret); + return false; + } + + /* Both of these are bitwise masks of the versions */ + if (!(version & dev_opp->supported_hw[count])) + return false; + } + + return true; +} + +/** * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) * @dev: device for which we do this operation * @np: device node @@ -879,6 +1021,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) goto free_opp; } + /* Check if the OPP supports hardware's hierarchy of versions or not */ + if (!_opp_is_supported(dev, dev_opp, np)) { + dev_dbg(dev, "OPP not supported by hardware: %llu\n", rate); + goto free_opp; + } + /* * Rate is defined as an unsigned long in clk API, and so casting * explicitly to its type. Must be fixed once rate is 64 bit diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index b8880c7..70f4564 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -129,6 +129,8 @@ struct device_list_opp { * @clock_latency_ns_max: Max clock latency in nanoseconds. * @shared_opp: OPP is shared between multiple devices. * @suspend_opp: Pointer to OPP to be used during device suspend. + * @supported_hw: Array of version number to support. + * @supported_hw_count: Number of elements in supported_hw array. * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. * @@ -153,6 +155,9 @@ struct device_opp { bool shared_opp; struct dev_pm_opp *suspend_opp; + unsigned int *supported_hw; + unsigned int supported_hw_count; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; char dentry_name[NAME_MAX]; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 9a2e503..3a85110 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -55,6 +55,9 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq); int dev_pm_opp_disable(struct device *dev, unsigned long freq); struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev); +int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, + unsigned int count); +void dev_pm_opp_put_supported_hw(struct device *dev); #else static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) { @@ -129,6 +132,16 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( { return ERR_PTR(-EINVAL); } + +static inline int dev_pm_opp_set_supported_hw(struct device *dev, + const u32 *versions, + unsigned int count) +{ + return -EINVAL; +} + +static inline void dev_pm_opp_put_supported_hw(struct device *dev) {} + #endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) -- cgit v0.10.2 From 01fb4d3c39d35b725441e8a9a26b3f3ad67793ed Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 9 Dec 2015 08:01:47 +0530 Subject: PM / OPP: Parse 'opp--' bindings OPP bindings (for few properties) allow a platform to choose a value/range among a set of available options. The options are present as opp--, where the platform needs to supply the string. The OPP properties which allow such an option are: opp-microvolt and opp-microamp. Add support to the OPP-core to parse these bindings, by introducing dev_pm_opp_{set|put}_prop_name() APIs. Signed-off-by: Viresh Kumar Tested-by: Lee Jones Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 55cf1a9..5c01fec 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -562,6 +562,9 @@ static void _remove_device_opp(struct device_opp *dev_opp) if (dev_opp->supported_hw) return; + if (dev_opp->prop_name) + return; + list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp, node); @@ -794,35 +797,48 @@ unlock: } /* TODO: Support multiple regulators */ -static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev) +static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, + struct device_opp *dev_opp) { u32 microvolt[3] = {0}; u32 val; int count, ret; + struct property *prop = NULL; + char name[NAME_MAX]; + + /* Search for "opp-microvolt-" */ + if (dev_opp->prop_name) { + sprintf(name, "opp-microvolt-%s", dev_opp->prop_name); + prop = of_find_property(opp->np, name, NULL); + } + + if (!prop) { + /* Search for "opp-microvolt" */ + name[13] = '\0'; + prop = of_find_property(opp->np, name, NULL); - /* Missing property isn't a problem, but an invalid entry is */ - if (!of_find_property(opp->np, "opp-microvolt", NULL)) - return 0; + /* Missing property isn't a problem, but an invalid entry is */ + if (!prop) + return 0; + } - count = of_property_count_u32_elems(opp->np, "opp-microvolt"); + count = of_property_count_u32_elems(opp->np, name); if (count < 0) { - dev_err(dev, "%s: Invalid opp-microvolt property (%d)\n", - __func__, count); + dev_err(dev, "%s: Invalid %s property (%d)\n", + __func__, name, count); return count; } /* There can be one or three elements here */ if (count != 1 && count != 3) { - dev_err(dev, "%s: Invalid number of elements in opp-microvolt property (%d)\n", - __func__, count); + dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n", + __func__, name, count); return -EINVAL; } - ret = of_property_read_u32_array(opp->np, "opp-microvolt", microvolt, - count); + ret = of_property_read_u32_array(opp->np, name, microvolt, count); if (ret) { - dev_err(dev, "%s: error parsing opp-microvolt: %d\n", __func__, - ret); + dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret); return -EINVAL; } @@ -830,7 +846,20 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev) opp->u_volt_min = microvolt[1]; opp->u_volt_max = microvolt[2]; - if (!of_property_read_u32(opp->np, "opp-microamp", &val)) + /* Search for "opp-microamp-" */ + prop = NULL; + if (dev_opp->prop_name) { + sprintf(name, "opp-microamp-%s", dev_opp->prop_name); + prop = of_find_property(opp->np, name, NULL); + } + + if (!prop) { + /* Search for "opp-microamp" */ + name[12] = '\0'; + prop = of_find_property(opp->np, name, NULL); + } + + if (prop && !of_property_read_u32(opp->np, name, &val)) opp->u_amp = val; return 0; @@ -948,6 +977,112 @@ unlock: } EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); +/** + * dev_pm_opp_set_prop_name() - Set prop-extn name + * @dev: Device for which the regulator has to be set. + * @name: name to postfix to properties. + * + * This is required only for the V2 bindings, and it enables a platform to + * specify the extn to be used for certain property names. The properties to + * which the extension will apply are opp-microvolt and opp-microamp. OPP core + * should postfix the property name with - while looking for them. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +int dev_pm_opp_set_prop_name(struct device *dev, const char *name) +{ + struct device_opp *dev_opp; + int ret = 0; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + dev_opp = _add_device_opp(dev); + if (!dev_opp) { + ret = -ENOMEM; + goto unlock; + } + + /* Make sure there are no concurrent readers while updating dev_opp */ + WARN_ON(!list_empty(&dev_opp->opp_list)); + + /* Do we already have a prop-name associated with dev_opp? */ + if (dev_opp->prop_name) { + dev_err(dev, "%s: Already have prop-name %s\n", __func__, + dev_opp->prop_name); + ret = -EBUSY; + goto err; + } + + dev_opp->prop_name = kstrdup(name, GFP_KERNEL); + if (!dev_opp->prop_name) { + ret = -ENOMEM; + goto err; + } + + mutex_unlock(&dev_opp_list_lock); + return 0; + +err: + _remove_device_opp(dev_opp); +unlock: + mutex_unlock(&dev_opp_list_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name); + +/** + * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name + * @dev: Device for which the regulator has to be set. + * + * This is required only for the V2 bindings, and is called for a matching + * dev_pm_opp_set_prop_name(). Until this is called, the device_opp structure + * will not be freed. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +void dev_pm_opp_put_prop_name(struct device *dev) +{ + struct device_opp *dev_opp; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + /* Check for existing list for 'dev' first */ + dev_opp = _find_device_opp(dev); + if (IS_ERR(dev_opp)) { + dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp)); + goto unlock; + } + + /* Make sure there are no concurrent readers while updating dev_opp */ + WARN_ON(!list_empty(&dev_opp->opp_list)); + + if (!dev_opp->prop_name) { + dev_err(dev, "%s: Doesn't have a prop-name\n", __func__); + goto unlock; + } + + kfree(dev_opp->prop_name); + dev_opp->prop_name = NULL; + + /* Try freeing device_opp if this was the last blocking resource */ + _remove_device_opp(dev_opp); + +unlock: + mutex_unlock(&dev_opp_list_lock); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name); + static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp, struct device_node *np) { @@ -1042,7 +1177,7 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) if (!of_property_read_u32(np, "clock-latency-ns", &val)) new_opp->clock_latency_ns = val; - ret = opp_parse_supplies(new_opp, dev); + ret = opp_parse_supplies(new_opp, dev, dev_opp); if (ret) goto free_opp; diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 70f4564..690638e 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -131,6 +131,7 @@ struct device_list_opp { * @suspend_opp: Pointer to OPP to be used during device suspend. * @supported_hw: Array of version number to support. * @supported_hw_count: Number of elements in supported_hw array. + * @prop_name: A name to postfix to many DT properties, while parsing them. * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. * @@ -157,6 +158,7 @@ struct device_opp { unsigned int *supported_hw; unsigned int supported_hw_count; + const char *prop_name; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 3a85110..95403d2 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -58,6 +58,8 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev); int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count); void dev_pm_opp_put_supported_hw(struct device *dev); +int dev_pm_opp_set_prop_name(struct device *dev, const char *name); +void dev_pm_opp_put_prop_name(struct device *dev); #else static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) { @@ -142,6 +144,13 @@ static inline int dev_pm_opp_set_supported_hw(struct device *dev, static inline void dev_pm_opp_put_supported_hw(struct device *dev) {} +static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name) +{ + return -EINVAL; +} + +static inline void dev_pm_opp_put_prop_name(struct device *dev) {} + #endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) -- cgit v0.10.2 From 89b56047f6f9b15fa3e9df3e34fa391835972ab7 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Thu, 10 Dec 2015 11:48:13 +0800 Subject: cpufreq: mt8173: Move resources allocation into ->probe() Since the return value of ->init() of cpufreq driver is not propagated to the device driver model now, move resources allocation into ->probe() to handle -EPROBE_DEFER properly. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 9d0fe37..fd601b9 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -41,16 +41,35 @@ * the original PLL becomes stable at target frequency. */ struct mtk_cpu_dvfs_info { + struct cpumask cpus; struct device *cpu_dev; struct regulator *proc_reg; struct regulator *sram_reg; struct clk *cpu_clk; struct clk *inter_clk; struct thermal_cooling_device *cdev; + struct list_head list_head; int intermediate_voltage; bool need_voltage_tracking; }; +static LIST_HEAD(dvfs_info_list); + +static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu) +{ + struct mtk_cpu_dvfs_info *info; + struct list_head *list; + + list_for_each(list, &dvfs_info_list) { + info = list_entry(list, struct mtk_cpu_dvfs_info, list_head); + + if (cpumask_test_cpu(cpu, &info->cpus)) + return info; + } + + return NULL; +} + static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, int new_vproc) { @@ -402,6 +421,9 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) */ info->need_voltage_tracking = !IS_ERR(sram_reg); + /* CPUs in the same cluster share a clock and power domain. */ + cpumask_copy(&info->cpus, &cpu_topology[cpu].core_sibling); + return 0; out_free_opp_table: @@ -440,22 +462,18 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) struct cpufreq_frequency_table *freq_table; int ret; - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - ret = mtk_cpu_dvfs_info_init(info, policy->cpu); - if (ret) { - pr_err("%s failed to initialize dvfs info for cpu%d\n", - __func__, policy->cpu); - goto out_free_dvfs_info; + info = mtk_cpu_dvfs_info_lookup(policy->cpu); + if (!info) { + pr_err("dvfs info for cpu%d is not initialized.\n", + policy->cpu); + return -EINVAL; } ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); if (ret) { pr_err("failed to init cpufreq table for cpu%d: %d\n", policy->cpu, ret); - goto out_release_dvfs_info; + return ret; } ret = cpufreq_table_validate_and_show(policy, freq_table); @@ -464,8 +482,7 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) goto out_free_cpufreq_table; } - /* CPUs in the same cluster share a clock and power domain. */ - cpumask_copy(policy->cpus, &cpu_topology[policy->cpu].core_sibling); + cpumask_copy(policy->cpus, &info->cpus); policy->driver_data = info; policy->clk = info->cpu_clk; @@ -473,13 +490,6 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) out_free_cpufreq_table: dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); - -out_release_dvfs_info: - mtk_cpu_dvfs_info_release(info); - -out_free_dvfs_info: - kfree(info); - return ret; } @@ -489,8 +499,6 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy) cpufreq_cooling_unregister(info->cdev); dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); - mtk_cpu_dvfs_info_release(info); - kfree(info); return 0; } @@ -510,11 +518,47 @@ static struct cpufreq_driver mt8173_cpufreq_driver = { static int mt8173_cpufreq_probe(struct platform_device *pdev) { - int ret; + struct mtk_cpu_dvfs_info *info; + struct list_head *list, *tmp; + int cpu, ret; + + for_each_possible_cpu(cpu) { + info = mtk_cpu_dvfs_info_lookup(cpu); + if (info) + continue; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto release_dvfs_info_list; + } + + ret = mtk_cpu_dvfs_info_init(info, cpu); + if (ret) { + dev_err(&pdev->dev, + "failed to initialize dvfs info for cpu%d\n", + cpu); + goto release_dvfs_info_list; + } + + list_add(&info->list_head, &dvfs_info_list); + } ret = cpufreq_register_driver(&mt8173_cpufreq_driver); - if (ret) - pr_err("failed to register mtk cpufreq driver\n"); + if (ret) { + dev_err(&pdev->dev, "failed to register mtk cpufreq driver\n"); + goto release_dvfs_info_list; + } + + return 0; + +release_dvfs_info_list: + list_for_each_safe(list, tmp, &dvfs_info_list) { + info = list_entry(list, struct mtk_cpu_dvfs_info, list_head); + + mtk_cpu_dvfs_info_release(info); + list_del(list); + } return ret; } -- cgit v0.10.2 From ab0ea257fc58d8742f73f50fba3797dfe001aa3c Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 10 Dec 2015 09:42:16 +0000 Subject: cpufreq: st: Provide runtime initialised driver for ST's platforms The bootloader is charged with the responsibility to provide platform specific Dynamic Voltage and Frequency Scaling (DVFS) information via Device Tree. This driver takes the supplied configuration and registers it with the new generic OPP framework, to then be used with CPUFreq. Acked-by: Viresh Kumar Signed-off-by: Lee Jones Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 80fbfb3..ff9be36 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -219,6 +219,16 @@ config ARM_SPEAR_CPUFREQ help This adds the CPUFreq driver support for SPEAr SOCs. +config ARM_STI_CPUFREQ + tristate "STi CPUFreq support" + depends on SOC_STIH407 + help + This driver uses the generic OPP framework to match the running + platform with a predefined set of suitable values. If not provided + we will fall-back so safe-values contained in Device Tree. Enable + this config option if you wish to add CPUFreq support for STi based + SoCs. + config ARM_TEGRA20_CPUFREQ bool "Tegra20 CPUFreq support" depends on ARCH_TEGRA diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index c0af1a1..9e63fb1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o +obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o diff --git a/drivers/cpufreq/sti-cpufreq.c b/drivers/cpufreq/sti-cpufreq.c new file mode 100644 index 0000000..a9c659f --- /dev/null +++ b/drivers/cpufreq/sti-cpufreq.c @@ -0,0 +1,294 @@ +/* + * Match running platform with pre-defined OPP values for CPUFreq + * + * Author: Ajit Pal Singh + * Lee Jones + * + * Copyright (C) 2015 STMicroelectronics (R&D) Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License as + * published by the Free Software Foundation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION_ELEMENTS 3 +#define MAX_PCODE_NAME_LEN 7 + +#define VERSION_SHIFT 28 +#define HW_INFO_INDEX 1 +#define MAJOR_ID_INDEX 1 +#define MINOR_ID_INDEX 2 + +/* + * Only match on "suitable for ALL versions" entries + * + * This will be used with the BIT() macro. It sets the + * top bit of a 32bit value and is equal to 0x80000000. + */ +#define DEFAULT_VERSION 31 + +enum { + PCODE = 0, + SUBSTRATE, + DVFS_MAX_REGFIELDS, +}; + +/** + * ST CPUFreq Driver Data + * + * @cpu_node CPU's OF node + * @syscfg_eng Engineering Syscon register map + * @regmap Syscon register map + */ +static struct sti_cpufreq_ddata { + struct device *cpu; + struct regmap *syscfg_eng; + struct regmap *syscfg; +} ddata; + +static int sti_cpufreq_fetch_major(void) { + struct device_node *np = ddata.cpu->of_node; + struct device *dev = ddata.cpu; + unsigned int major_offset; + unsigned int socid; + int ret; + + ret = of_property_read_u32_index(np, "st,syscfg", + MAJOR_ID_INDEX, &major_offset); + if (ret) { + dev_err(dev, "No major number offset provided in %s [%d]\n", + np->full_name, ret); + return ret; + } + + ret = regmap_read(ddata.syscfg, major_offset, &socid); + if (ret) { + dev_err(dev, "Failed to read major number from syscon [%d]\n", + ret); + return ret; + } + + return ((socid >> VERSION_SHIFT) & 0xf) + 1; +} + +static int sti_cpufreq_fetch_minor(void) +{ + struct device *dev = ddata.cpu; + struct device_node *np = dev->of_node; + unsigned int minor_offset; + unsigned int minid; + int ret; + + ret = of_property_read_u32_index(np, "st,syscfg-eng", + MINOR_ID_INDEX, &minor_offset); + if (ret) { + dev_err(dev, + "No minor number offset provided %s [%d]\n", + np->full_name, ret); + return ret; + } + + ret = regmap_read(ddata.syscfg_eng, minor_offset, &minid); + if (ret) { + dev_err(dev, + "Failed to read the minor number from syscon [%d]\n", + ret); + return ret; + } + + return minid & 0xf; +} + +static int sti_cpufreq_fetch_regmap_field(const struct reg_field *reg_fields, + int hw_info_offset, int field) +{ + struct regmap_field *regmap_field; + struct reg_field reg_field = reg_fields[field]; + struct device *dev = ddata.cpu; + unsigned int value; + int ret; + + reg_field.reg = hw_info_offset; + regmap_field = devm_regmap_field_alloc(dev, + ddata.syscfg_eng, + reg_field); + if (IS_ERR(regmap_field)) { + dev_err(dev, "Failed to allocate reg field\n"); + return PTR_ERR(regmap_field); + } + + ret = regmap_field_read(regmap_field, &value); + if (ret) { + dev_err(dev, "Failed to read %s code\n", + field ? "SUBSTRATE" : "PCODE"); + return ret; + } + + return value; +} + +static const struct reg_field sti_stih407_dvfs_regfields[DVFS_MAX_REGFIELDS] = { + [PCODE] = REG_FIELD(0, 16, 19), + [SUBSTRATE] = REG_FIELD(0, 0, 2), +}; + +static const struct reg_field *sti_cpufreq_match(void) +{ + if (of_machine_is_compatible("st,stih407") || + of_machine_is_compatible("st,stih410")) + return sti_stih407_dvfs_regfields; + + return NULL; +} + +static int sti_cpufreq_set_opp_info(void) +{ + struct device *dev = ddata.cpu; + struct device_node *np = dev->of_node; + const struct reg_field *reg_fields; + unsigned int hw_info_offset; + unsigned int version[VERSION_ELEMENTS]; + int pcode, substrate, major, minor; + int ret; + char name[MAX_PCODE_NAME_LEN]; + + reg_fields = sti_cpufreq_match(); + if (!reg_fields) { + dev_err(dev, "This SoC doesn't support voltage scaling"); + return -ENODEV; + } + + ret = of_property_read_u32_index(np, "st,syscfg-eng", + HW_INFO_INDEX, &hw_info_offset); + if (ret) { + dev_warn(dev, "Failed to read HW info offset from DT\n"); + substrate = DEFAULT_VERSION; + pcode = 0; + goto use_defaults; + } + + pcode = sti_cpufreq_fetch_regmap_field(reg_fields, + hw_info_offset, + PCODE); + if (pcode < 0) { + dev_warn(dev, "Failed to obtain process code\n"); + /* Use default pcode */ + pcode = 0; + } + + substrate = sti_cpufreq_fetch_regmap_field(reg_fields, + hw_info_offset, + SUBSTRATE); + if (substrate) { + dev_warn(dev, "Failed to obtain substrate code\n"); + /* Use default substrate */ + substrate = DEFAULT_VERSION; + } + +use_defaults: + major = sti_cpufreq_fetch_major(); + if (major < 0) { + dev_err(dev, "Failed to obtain major version\n"); + /* Use default major number */ + major = DEFAULT_VERSION; + } + + minor = sti_cpufreq_fetch_minor(); + if (minor < 0) { + dev_err(dev, "Failed to obtain minor version\n"); + /* Use default minor number */ + minor = DEFAULT_VERSION; + } + + snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode); + + ret = dev_pm_opp_set_prop_name(dev, name); + if (ret) { + dev_err(dev, "Failed to set prop name\n"); + return ret; + } + + version[0] = BIT(major); + version[1] = BIT(minor); + version[2] = BIT(substrate); + + ret = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS); + if (ret) { + dev_err(dev, "Failed to set supported hardware\n"); + return ret; + } + + dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n", + pcode, major, minor, substrate); + dev_dbg(dev, "version[0]: %x version[1]: %x version[2]: %x\n", + version[0], version[1], version[2]); + + return 0; +} + +static int sti_cpufreq_fetch_syscon_regsiters(void) +{ + struct device *dev = ddata.cpu; + struct device_node *np = dev->of_node; + + ddata.syscfg = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(ddata.syscfg)) { + dev_err(dev, "\"st,syscfg\" not supplied\n"); + return PTR_ERR(ddata.syscfg); + } + + ddata.syscfg_eng = syscon_regmap_lookup_by_phandle(np, "st,syscfg-eng"); + if (IS_ERR(ddata.syscfg_eng)) { + dev_err(dev, "\"st,syscfg-eng\" not supplied\n"); + return PTR_ERR(ddata.syscfg_eng); + } + + return 0; +} + +static int sti_cpufreq_init(void) +{ + int ret; + + ddata.cpu = get_cpu_device(0); + if (!ddata.cpu) { + dev_err(ddata.cpu, "Failed to get device for CPU0\n"); + goto skip_voltage_scaling; + } + + if (!of_get_property(ddata.cpu->of_node, "operating-points-v2", NULL)) { + dev_err(ddata.cpu, "OPP-v2 not supported\n"); + goto skip_voltage_scaling; + } + + ret = sti_cpufreq_fetch_syscon_regsiters(); + if (ret) + goto skip_voltage_scaling; + + ret = sti_cpufreq_set_opp_info(); + if (!ret) + goto register_cpufreq_dt; + +skip_voltage_scaling: + dev_err(ddata.cpu, "Not doing voltage scaling\n"); + +register_cpufreq_dt: + platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + + return 0; +} +module_init(sti_cpufreq_init); + +MODULE_DESCRIPTION("STMicroelectronics CPUFreq/OPP driver"); +MODULE_AUTHOR("Ajitpal Singh "); +MODULE_AUTHOR("Lee Jones "); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From b122bcd94743239cc26a5732fef87b28d7f5c22a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 10 Dec 2015 09:42:17 +0000 Subject: dt: cpufreq: st: Provide bindings for ST's CPUFreq implementation Acked-by: Rob Herring Acked-by: Viresh Kumar Signed-off-by: Lee Jones Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt new file mode 100644 index 0000000..d91a02a --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt @@ -0,0 +1,91 @@ +Binding for ST's CPUFreq driver +=============================== + +ST's CPUFreq driver attempts to read 'process' and 'version' attributes +from the SoC, then supplies the OPP framework with 'prop' and 'supported +hardware' information respectively. The framework is then able to read +the DT and operate in the usual way. + +For more information about the expected DT format [See: ../opp/opp.txt]. + +Frequency Scaling only +---------------------- + +No vendor specific driver required for this. + +Located in CPU's node: + +- operating-points : [See: ../power/opp.txt] + +Example [safe] +-------------- + +cpus { + cpu@0 { + /* kHz uV */ + operating-points = <1500000 0 + 1200000 0 + 800000 0 + 500000 0>; + }; +}; + +Dynamic Voltage and Frequency Scaling (DVFS) +-------------------------------------------- + +This requires the ST CPUFreq driver to supply 'process' and 'version' info. + +Located in CPU's node: + +- operating-points-v2 : [See ../power/opp.txt] + +Example [unsafe] +---------------- + +cpus { + cpu@0 { + operating-points-v2 = <&cpu0_opp_table>; + }; +}; + +cpu0_opp_table: opp_table { + compatible = "operating-points-v2"; + + /* ############################################################### */ + /* # WARNING: Do not attempt to copy/replicate these nodes, # */ + /* # they are only to be supplied by the bootloader !!! # */ + /* ############################################################### */ + opp0 { + /* Major Minor Substrate */ + /* 2 all all */ + opp-supported-hw = <0x00000004 0xffffffff 0xffffffff>; + opp-hz = /bits/ 64 <1500000000>; + clock-latency-ns = <10000000>; + + opp-microvolt-pcode0 = <1200000>; + opp-microvolt-pcode1 = <1200000>; + opp-microvolt-pcode2 = <1200000>; + opp-microvolt-pcode3 = <1200000>; + opp-microvolt-pcode4 = <1170000>; + opp-microvolt-pcode5 = <1140000>; + opp-microvolt-pcode6 = <1100000>; + opp-microvolt-pcode7 = <1070000>; + }; + + opp1 { + /* Major Minor Substrate */ + /* all all all */ + opp-supported-hw = <0xffffffff 0xffffffff 0xffffffff>; + opp-hz = /bits/ 64 <1200000000>; + clock-latency-ns = <10000000>; + + opp-microvolt-pcode0 = <1110000>; + opp-microvolt-pcode1 = <1150000>; + opp-microvolt-pcode2 = <1100000>; + opp-microvolt-pcode3 = <1080000>; + opp-microvolt-pcode4 = <1040000>; + opp-microvolt-pcode5 = <1020000>; + opp-microvolt-pcode6 = <980000>; + opp-microvolt-pcode7 = <930000>; + }; +}; -- cgit v0.10.2 From 96889231fbc047be91a49d953f50c9f747bc9f89 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 3 Dec 2015 10:42:38 +0800 Subject: ACPICA: Debugger: Remove unnecessary status check ACPICA commit f9d5c6c9a25e9f5ac05458bfcd8b381e21bb2ba5 ACPICA BZ 1205. Colin Ian King. Link: https://bugs.acpica.org/show_bug.cgi?id=1205 Link: https://github.com/acpica/acpica/commit/f9d5c6c9 Signed-off-by: Colin Ian King Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 0480254..fe93f67 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -1246,9 +1246,6 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) * and wait for the command to complete. */ acpi_os_release_mutex(acpi_gbl_db_command_ready); - if (ACPI_FAILURE(status)) { - return (status); - } status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete, -- cgit v0.10.2 From f8d31489629c125806ce4bf587c0c5c284d6d113 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Dec 2015 10:42:46 +0800 Subject: ACPICA: Debugger: Convert some mechanisms to OSPM specific The following mechanisms are OSPM specific: 1. Redirect output destination to console: no file redirection will be needed by an in-kernel debugger, there is even no file can be accessed when the debugger is running in the kernel mode. 2. Output command prompts: programs other than acpiexec can have different prompt characters and the prompt characters may be implemented as a special character sequence to form a char device IO protocol. 3. Command ready/complete handshake: OSPM debugger may wait more conditions to implement OSPM specific semantics (for example, FIFO full/empty conditions for O_NONBLOCK or IO open/close conditions). Leaving such OSPM specific stuffs in the ACPICA debugger core blocks Linux debugger IO driver implementation. Several new OSL APIs are provided by this patch: 1. acpi_os_initialize_command_signals: initialize command handshake mechanism or any other OSPM specific stuffs. 2. acpi_os_terminate_command_signals: reversal of acpi_os_initialize_command_signals. 3. acpi_os_wait_command_ready: putting debugger task into wait state when a command is not ready. OSPMs can terminate command loop by returning AE_CTRL_TERMINATE from this API. Normally, wait_event() or wait_for_multiple_object() may be used to implement this API. 4. acpi_os_notify_command_complete: putting user task into running state when a command has been completed. OSPMs can terminate command loop by returning AE_CTRL_TERMINATE from this API. Normally, wake_up() or set_event() may be used to implement this API. This patch also converts current command signaling implementation into a generic debugger layer (osgendbg.c) to be used by the existing OSPMs or acpiexec, in return, Linux can have chance to implement its own command handshake mechanism. This patch also implements acpiexec batch mode in a multi-threading mode comaptible style as a demo (this can be confirmed by configuring acpiexec into DEBUGGER_MULTI_THREADED mode where the batch mode is still working). Lv Zheng. Note that the OSPM specific command handshake mechanism is required by Linux kernel because: 1. Linux kernel trends to use wait queue to synchronize two threads, using mutexes to achieve that will cause false "dead lock" warnings. 2. The command handshake mechanism implemented by ACPICA is implemented in this way because of a design issue in debugger IO streaming. Debugger IO outputs are simply cached using a giant buffer, this should be tuned by Linux in the future. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index c928ba4..86474d8 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -257,7 +257,7 @@ acpi_db_command_dispatch(char *input_buffer, void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); -acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); +acpi_status acpi_db_user_commands(void); char *acpi_db_get_next_token(char *string, char **next, acpi_object_type * return_type); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index faa9760..3977134 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -326,7 +326,6 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list); #ifdef ACPI_DEBUGGER ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); -ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE); ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID); ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods); @@ -345,7 +344,6 @@ ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]); /* These buffers should all be the same size */ -ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]); ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]); ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]); ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); @@ -360,9 +358,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); ACPI_GLOBAL(u32, acpi_gbl_num_nodes); ACPI_GLOBAL(u32, acpi_gbl_num_objects); -ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_ready); -ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_complete); - #endif /* ACPI_DEBUGGER */ /***************************************************************************** diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index fe93f67..2bf8e6b 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -53,8 +53,6 @@ static u32 acpi_db_get_line(char *input_buffer); static u32 acpi_db_match_command(char *user_command); -static void acpi_db_single_thread(void); - static void acpi_db_display_command_info(char *command, u8 display_all); static void acpi_db_display_help(char *command); @@ -1149,55 +1147,16 @@ acpi_db_command_dispatch(char *input_buffer, void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) { - acpi_status status = AE_OK; - acpi_status Mstatus; - - while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) { - acpi_gbl_method_executing = FALSE; - acpi_gbl_step_to_next_call = FALSE; - - Mstatus = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, - ACPI_WAIT_FOREVER); - if (ACPI_FAILURE(Mstatus)) { - return; - } - - status = - acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); - acpi_os_release_mutex(acpi_gbl_db_command_complete); - } + (void)acpi_db_user_commands(); acpi_gbl_db_threads_terminated = TRUE; } /******************************************************************************* * - * FUNCTION: acpi_db_single_thread - * - * PARAMETERS: None - * - * RETURN: None - * - * DESCRIPTION: Debugger execute thread. Waits for a command line, then - * simply dispatches it. - * - ******************************************************************************/ - -static void acpi_db_single_thread(void) -{ - - acpi_gbl_method_executing = FALSE; - acpi_gbl_step_to_next_call = FALSE; - - (void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); -} - -/******************************************************************************* - * * FUNCTION: acpi_db_user_commands * - * PARAMETERS: prompt - User prompt (depends on mode) - * op - Current executing parse op + * PARAMETERS: None * * RETURN: None * @@ -1206,7 +1165,7 @@ static void acpi_db_single_thread(void) * ******************************************************************************/ -acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) +acpi_status acpi_db_user_commands(void) { acpi_status status = AE_OK; @@ -1216,49 +1175,31 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) while (!acpi_gbl_db_terminate_loop) { - /* Force output to console until a command is entered */ - - acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); - - /* Different prompt if method is executing */ - - if (!acpi_gbl_method_executing) { - acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); - } else { - acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); - } - - /* Get the user input line */ + /* Wait the readiness of the command */ - status = acpi_os_get_line(acpi_gbl_db_line_buf, - ACPI_DB_LINE_BUFFER_SIZE, NULL); + status = acpi_os_wait_command_ready(); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "While parsing command line")); - return (status); + break; } - /* Check for single or multithreaded debug */ + /* Just call to the command line interpreter */ - if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { - /* - * Signal the debug thread that we have a command to execute, - * and wait for the command to complete. - */ - acpi_os_release_mutex(acpi_gbl_db_command_ready); + acpi_gbl_method_executing = FALSE; + acpi_gbl_step_to_next_call = FALSE; - status = - acpi_os_acquire_mutex(acpi_gbl_db_command_complete, - ACPI_WAIT_FOREVER); - if (ACPI_FAILURE(status)) { - return (status); - } - } else { - /* Just call to the command line interpreter */ + (void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, + NULL); + + /* Notify the completion of the command */ - acpi_db_single_thread(); + status = acpi_os_notify_command_complete(); + if (ACPI_FAILURE(status)) { + break; } } + if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) { + ACPI_EXCEPTION((AE_INFO, status, "While parsing command line")); + } return (status); } diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 342298a..d95e91f 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -85,46 +85,21 @@ acpi_db_start_command(struct acpi_walk_state *walk_state, acpi_gbl_method_executing = TRUE; status = AE_CTRL_TRUE; - while (status == AE_CTRL_TRUE) { - if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) { - - /* Handshake with the front-end that gets user command lines */ - - acpi_os_release_mutex(acpi_gbl_db_command_complete); - - status = - acpi_os_acquire_mutex(acpi_gbl_db_command_ready, - ACPI_WAIT_FOREVER); - if (ACPI_FAILURE(status)) { - return (status); - } - } else { - /* Single threaded, we must get a command line ourselves */ - /* Force output to console until a command is entered */ - - acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); + while (status == AE_CTRL_TRUE) { - /* Different prompt if method is executing */ + /* Notify the completion of the command */ - if (!acpi_gbl_method_executing) { - acpi_os_printf("%1c ", - ACPI_DEBUGGER_COMMAND_PROMPT); - } else { - acpi_os_printf("%1c ", - ACPI_DEBUGGER_EXECUTE_PROMPT); - } + status = acpi_os_notify_command_complete(); + if (ACPI_FAILURE(status)) { + goto error_exit; + } - /* Get the user input line */ + /* Wait the readiness of the command */ - status = acpi_os_get_line(acpi_gbl_db_line_buf, - ACPI_DB_LINE_BUFFER_SIZE, - NULL); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "While parsing command line")); - return (status); - } + status = acpi_os_wait_command_ready(); + if (ACPI_FAILURE(status)) { + goto error_exit; } status = @@ -134,6 +109,11 @@ acpi_db_start_command(struct acpi_walk_state *walk_state, /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */ +error_exit: + if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) { + ACPI_EXCEPTION((AE_INFO, status, + "While parsing/handling command line")); + } return (status); } @@ -420,15 +400,7 @@ acpi_status acpi_initialize_debugger(void) /* These were created with one unit, grab it */ - status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete, - ACPI_WAIT_FOREVER); - if (ACPI_FAILURE(status)) { - acpi_os_printf("Could not get debugger mutex\n"); - return_ACPI_STATUS(status); - } - - status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, - ACPI_WAIT_FOREVER); + status = acpi_os_initialize_command_signals(); if (ACPI_FAILURE(status)) { acpi_os_printf("Could not get debugger mutex\n"); return_ACPI_STATUS(status); @@ -473,13 +445,14 @@ void acpi_terminate_debugger(void) acpi_gbl_db_terminate_loop = TRUE; if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { - acpi_os_release_mutex(acpi_gbl_db_command_ready); /* Wait the AML Debugger threads */ while (!acpi_gbl_db_threads_terminated) { acpi_os_sleep(100); } + + acpi_os_terminate_command_signals(); } if (acpi_gbl_db_buffer) { diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index ce406e3..ea0c207 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -111,17 +111,6 @@ acpi_status acpi_ut_mutex_initialize(void) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } -#ifdef ACPI_DEBUGGER - - /* Debugger Support */ - - status = acpi_os_create_mutex(&acpi_gbl_db_command_ready); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - status = acpi_os_create_mutex(&acpi_gbl_db_command_complete); -#endif return_ACPI_STATUS(status); } @@ -162,12 +151,6 @@ void acpi_ut_mutex_terminate(void) /* Delete the reader/writer lock */ acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock); - -#ifdef ACPI_DEBUGGER - acpi_os_delete_mutex(acpi_gbl_db_command_ready); - acpi_os_delete_mutex(acpi_gbl_db_command_complete); -#endif - return_VOID; } diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index fbc2baf..0d824a2 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -349,12 +349,28 @@ void acpi_os_redirect_output(void *destination); #endif /* - * Debug input + * Debug IO */ #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read); #endif +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals +acpi_status acpi_os_initialize_command_signals(void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals +void acpi_os_terminate_command_signals(void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready +acpi_status acpi_os_wait_command_ready(void); +#endif + +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete +acpi_status acpi_os_notify_command_complete(void); +#endif + /* * Obtain ACPI table(s) */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 3aaaa86..95ebae3 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -264,6 +264,15 @@ ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); /* + * Debugger command handshake globals. Host OSes need to access these + * variables to implement their own command handshake mechanism. + */ +#ifdef ACPI_DEBUGGER +ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE); +ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]); +#endif + +/* * Other miscellaneous globals */ ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); @@ -929,6 +938,8 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status void **data, void (*callback)(void *))) +void acpi_run_debugger(char *batch_buffer); + void acpi_set_debugger_thread_id(acpi_thread_id thread_id); #endif /* __ACXFACE_H__ */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 323e5da..69dbae6 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -150,6 +150,10 @@ */ #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete /* * OSL interfaces used by utilities diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index fd6d70f..673fdf4 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -129,6 +129,25 @@ static inline u8 acpi_os_readable(void *pointer, acpi_size length) return TRUE; } +static inline acpi_status acpi_os_initialize_command_signals(void) +{ + return AE_OK; +} + +static inline void acpi_os_terminate_command_signals(void) +{ +} + +static inline acpi_status acpi_os_wait_command_ready(void) +{ + return AE_ERROR; +} + +static inline acpi_status acpi_os_notify_command_complete(void) +{ + return AE_ERROR; +} + /* * OSL interfaces added by Linux */ -- cgit v0.10.2 From 8a2a2501a893bfce65af7098a1b0a61f14f95626 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Dec 2015 10:42:53 +0800 Subject: ACPICA: Debugger: Fix runtime stub issues of ACPI_DEBUGGER_EXEC using different stub mechanism ACPICA commit 11522d6b894054fc4d62dd4f9863ec151296b386 The ACPI_DEBUGGER_EXEC is a problem now when the debugger code is compiled but runtime disabled. They actually will get executed in this situation. Although such executions are harmless if we can correctly make acpi_db_single_step() a runtime stub, users may still do not want to see the debugger print messages logged into OSPMs' kernel logs when a debugger driver is not loaded to enable the debugger during runtime. This patch fixes this issue by introducing new stub mechanism instead of ACPI_DEBUGGER_EXEC. Lv Zheng. Link: https://github.com/acpica/acpica/commit/11522d6b Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 86474d8..dcaa15d 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -80,9 +80,15 @@ struct acpi_db_execute_walk { /* * dbxface - external debugger interfaces */ -acpi_status -acpi_db_single_step(struct acpi_walk_state *walk_state, - union acpi_parse_object *op, u32 op_type); +ACPI_DBR_DEPENDENT_RETURN_OK(acpi_status + acpi_db_single_step(struct acpi_walk_state + *walk_state, + union acpi_parse_object *op, + u32 op_type)) + ACPI_DBR_DEPENDENT_RETURN_VOID(void + acpi_db_signal_break_point(struct + acpi_walk_state + *walk_state)) /* * dbcmds - debug commands and output routines @@ -182,11 +188,15 @@ void acpi_db_display_method_info(union acpi_parse_object *op); void acpi_db_decode_and_display_object(char *target, char *output_type); -void -acpi_db_display_result_object(union acpi_operand_object *obj_desc, - struct acpi_walk_state *walk_state); +ACPI_DBR_DEPENDENT_RETURN_VOID(void + acpi_db_display_result_object(union + acpi_operand_object + *obj_desc, + struct + acpi_walk_state + *walk_state)) -acpi_status acpi_db_display_all_methods(char *display_count_arg); + acpi_status acpi_db_display_all_methods(char *display_count_arg); void acpi_db_display_arguments(void); @@ -198,9 +208,13 @@ void acpi_db_display_calling_tree(void); void acpi_db_display_object_type(char *object_arg); -void -acpi_db_display_argument_object(union acpi_operand_object *obj_desc, - struct acpi_walk_state *walk_state); +ACPI_DBR_DEPENDENT_RETURN_VOID(void + acpi_db_display_argument_object(union + acpi_operand_object + *obj_desc, + struct + acpi_walk_state + *walk_state)) /* * dbexec - debugger control method execution diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index e85366c..bad5bca 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -401,17 +401,6 @@ #endif /* - * Some code only gets executed when the debugger is built in. - * Note that this is entirely independent of whether the - * DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not. - */ -#ifdef ACPI_DEBUGGER -#define ACPI_DEBUGGER_EXEC(a) a -#else -#define ACPI_DEBUGGER_EXEC(a) -#endif - -/* * Macros used for ACPICA utilities only */ diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index 672977e..c42ce8a 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -679,6 +679,12 @@ acpi_db_display_result_object(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { +#ifndef ACPI_APPLICATION + if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { + return; + } +#endif + /* Only display if single stepping */ if (!acpi_gbl_cm_single_step) { @@ -708,6 +714,12 @@ acpi_db_display_argument_object(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { +#ifndef ACPI_APPLICATION + if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { + return; + } +#endif + if (!acpi_gbl_cm_single_step) { return; } diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index d95e91f..d7ff58e 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -119,6 +119,36 @@ error_exit: /******************************************************************************* * + * FUNCTION: acpi_db_signal_break_point + * + * PARAMETERS: walk_state - Current walk + * + * RETURN: Status + * + * DESCRIPTION: Called for AML_BREAK_POINT_OP + * + ******************************************************************************/ + +void acpi_db_signal_break_point(struct acpi_walk_state *walk_state) +{ + +#ifndef ACPI_APPLICATION + if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { + return; + } +#endif + + /* + * Set the single-step flag. This will cause the debugger (if present) + * to break to the console within the AML debugger at the start of the + * next AML instruction. + */ + acpi_gbl_cm_single_step = TRUE; + acpi_os_printf("**break** Executed AML BreakPoint opcode\n"); +} + +/******************************************************************************* + * * FUNCTION: acpi_db_single_step * * PARAMETERS: walk_state - Current walk diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 435fc16..06a6f7f 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -47,6 +47,7 @@ #include "amlcode.h" #include "acdispat.h" #include "acinterp.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dscontrol") @@ -348,14 +349,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, case AML_BREAK_POINT_OP: - /* - * Set the single-step flag. This will cause the debugger (if present) - * to break to the console within the AML debugger at the start of the - * next AML instruction. - */ - ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); - ACPI_DEBUGGER_EXEC(acpi_os_printf - ("**break** Executed AML BreakPoint opcode\n")); + acpi_db_signal_break_point(walk_state); /* Call to the OSL in case OS wants a piece of the action */ diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index ebc577b..e4293a8 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -605,8 +605,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object - (obj_desc, walk_state)); + + acpi_db_display_argument_object(obj_desc, walk_state); } else { /* Check for null name case */ @@ -638,10 +638,11 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Argument previously created, already stacked\n")); - ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object - (walk_state-> - operands[walk_state->num_operands - - 1], walk_state)); + acpi_db_display_argument_object(walk_state-> + operands[walk_state-> + num_operands - + 1], + walk_state); /* * Use value that was already previously returned @@ -685,8 +686,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, return_ACPI_STATUS(status); } - ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object - (obj_desc, walk_state)); + acpi_db_display_argument_object(obj_desc, walk_state); } return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index df54d46..9cc5761 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -178,8 +178,7 @@ cleanup: /* Break to debugger to display result */ - ACPI_DEBUGGER_EXEC(acpi_db_display_result_object - (local_obj_desc, walk_state)); + acpi_db_display_result_object(local_obj_desc, walk_state); /* * Delete the predicate result object (we know that @@ -386,11 +385,10 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) /* Call debugger for single step support (DEBUG build only) */ - ACPI_DEBUGGER_EXEC(status = - acpi_db_single_step(walk_state, op, op_class)); - ACPI_DEBUGGER_EXEC(if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status);} - ) ; + status = acpi_db_single_step(walk_state, op, op_class); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Decode the Opcode Class */ @@ -728,8 +726,8 @@ cleanup: /* Break to debugger to display result */ - ACPI_DEBUGGER_EXEC(acpi_db_display_result_object - (walk_state->result_obj, walk_state)); + acpi_db_display_result_object(walk_state->result_obj, + walk_state); /* * Delete the result op if and only if: diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 95ebae3..5dfab9c 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -375,6 +375,29 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); #endif /* ACPI_APPLICATION */ +/* + * Debugger prototypes + * + * All interfaces used by debugger will be configured + * out of the ACPICA build unless the ACPI_DEBUGGER + * flag is defined. + */ +#ifdef ACPI_DEBUGGER +#define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \ + ACPI_EXTERNAL_RETURN_OK(prototype) + +#define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \ + ACPI_EXTERNAL_RETURN_VOID(prototype) + +#else +#define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \ + static ACPI_INLINE prototype {return(AE_OK);} + +#define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} + +#endif /* ACPI_DEBUGGER */ + /***************************************************************************** * * ACPICA public interface prototypes -- cgit v0.10.2 From 8cfb0cdf07e2c260c4d1a102bfec35183907834f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Dec 2015 10:43:00 +0800 Subject: ACPI / debugger: Add IO interface to access debugger functionalities This patch adds /sys/kernel/debug/acpi/acpidbg, which can be used by userspace programs to access ACPICA debugger functionalities. Known issue: 1. IO flush support acpi_os_notify_command_complete() and acpi_os_wait_command_ready() can be used by acpi_dbg module to implement .flush() filesystem operation. While this patch doesn't go that far. It then becomes userspace tool's duty now to flush old commands before executing new batch mode commands. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5eef4cb..2a7e6d4 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -58,8 +58,9 @@ config ACPI_CCA_REQUIRED bool config ACPI_DEBUGGER - bool "AML debugger interface (EXPERIMENTAL)" + bool "AML debugger interface" select ACPI_DEBUG + depends on DEBUG_FS help Enable in-kernel debugging of AML facilities: statistics, internal object dump, single step control method execution. diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 675eaf3..102b5e6 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -50,6 +50,7 @@ acpi-y += sysfs.o acpi-y += property.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o +acpi-$(CONFIG_ACPI_DEBUGGER) += acpi_dbg.o acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o acpi-y += acpi_lpat.o diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c new file mode 100644 index 0000000..abc23b2 --- /dev/null +++ b/drivers/acpi/acpi_dbg.c @@ -0,0 +1,779 @@ +/* + * ACPI AML interfacing support + * + * Copyright (C) 2015, Intel Corporation + * Authors: Lv Zheng + * + * 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. + */ + +/* #define DEBUG */ +#define pr_fmt(fmt) "ACPI : AML: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +#define ACPI_AML_BUF_ALIGN (sizeof (acpi_size)) +#define ACPI_AML_BUF_SIZE PAGE_SIZE + +#define circ_count(circ) \ + (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) +#define circ_count_to_end(circ) \ + (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) +#define circ_space(circ) \ + (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) +#define circ_space_to_end(circ) \ + (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) + +#define ACPI_AML_OPENED 0x0001 +#define ACPI_AML_CLOSED 0x0002 +#define ACPI_AML_IN_USER 0x0004 /* user space is writing cmd */ +#define ACPI_AML_IN_KERN 0x0008 /* kernel space is reading cmd */ +#define ACPI_AML_OUT_USER 0x0010 /* user space is reading log */ +#define ACPI_AML_OUT_KERN 0x0020 /* kernel space is writing log */ +#define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER) +#define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN) +#define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN) +#define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED) + +struct acpi_aml_io { + wait_queue_head_t wait; + unsigned long flags; + unsigned long users; + struct mutex lock; + struct task_struct *thread; + char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); + struct circ_buf out_crc; + char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); + struct circ_buf in_crc; + acpi_osd_exec_callback function; + void *context; + unsigned long usages; +}; + +static struct acpi_aml_io acpi_aml_io; +static bool acpi_aml_initialized; +static struct file *acpi_aml_active_reader; +static struct dentry *acpi_aml_dentry; + +static inline bool __acpi_aml_running(void) +{ + return acpi_aml_io.thread ? true : false; +} + +static inline bool __acpi_aml_access_ok(unsigned long flag) +{ + /* + * The debugger interface is in opened state (OPENED && !CLOSED), + * then it is allowed to access the debugger buffers from either + * user space or the kernel space. + * In addition, for the kernel space, only the debugger thread + * (thread ID matched) is allowed to access. + */ + if (!(acpi_aml_io.flags & ACPI_AML_OPENED) || + (acpi_aml_io.flags & ACPI_AML_CLOSED) || + !__acpi_aml_running()) + return false; + if ((flag & ACPI_AML_KERN) && + current != acpi_aml_io.thread) + return false; + return true; +} + +static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag) +{ + /* + * Another read is not in progress and there is data in buffer + * available for read. + */ + if (!(acpi_aml_io.flags & flag) && circ_count(circ)) + return true; + return false; +} + +static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag) +{ + /* + * Another write is not in progress and there is buffer space + * available for write. + */ + if (!(acpi_aml_io.flags & flag) && circ_space(circ)) + return true; + return false; +} + +static inline bool __acpi_aml_busy(void) +{ + if (acpi_aml_io.flags & ACPI_AML_BUSY) + return true; + return false; +} + +static inline bool __acpi_aml_opened(void) +{ + if (acpi_aml_io.flags & ACPI_AML_OPEN) + return true; + return false; +} + +static inline bool __acpi_aml_used(void) +{ + return acpi_aml_io.usages ? true : false; +} + +static inline bool acpi_aml_running(void) +{ + bool ret; + + mutex_lock(&acpi_aml_io.lock); + ret = __acpi_aml_running(); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static bool acpi_aml_busy(void) +{ + bool ret; + + mutex_lock(&acpi_aml_io.lock); + ret = __acpi_aml_busy(); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static bool acpi_aml_used(void) +{ + bool ret; + + /* + * The usage count is prepared to avoid race conditions between the + * starts and the stops of the debugger thread. + */ + mutex_lock(&acpi_aml_io.lock); + ret = __acpi_aml_used(); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static bool acpi_aml_kern_readable(void) +{ + bool ret; + + mutex_lock(&acpi_aml_io.lock); + ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) || + __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static bool acpi_aml_kern_writable(void) +{ + bool ret; + + mutex_lock(&acpi_aml_io.lock); + ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) || + __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static bool acpi_aml_user_readable(void) +{ + bool ret; + + mutex_lock(&acpi_aml_io.lock); + ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) || + __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static bool acpi_aml_user_writable(void) +{ + bool ret; + + mutex_lock(&acpi_aml_io.lock); + ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) || + __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER); + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag) +{ + int ret = 0; + + mutex_lock(&acpi_aml_io.lock); + if (!__acpi_aml_access_ok(flag)) { + ret = -EFAULT; + goto out; + } + if (!__acpi_aml_writable(circ, flag)) { + ret = -EAGAIN; + goto out; + } + acpi_aml_io.flags |= flag; +out: + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag) +{ + int ret = 0; + + mutex_lock(&acpi_aml_io.lock); + if (!__acpi_aml_access_ok(flag)) { + ret = -EFAULT; + goto out; + } + if (!__acpi_aml_readable(circ, flag)) { + ret = -EAGAIN; + goto out; + } + acpi_aml_io.flags |= flag; +out: + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup) +{ + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.flags &= ~flag; + if (wakeup) + wake_up_interruptible(&acpi_aml_io.wait); + mutex_unlock(&acpi_aml_io.lock); +} + +static int acpi_aml_write_kern(const char *buf, int len) +{ + int ret; + struct circ_buf *crc = &acpi_aml_io.out_crc; + int n; + char *p; + + ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN); + if (IS_ERR_VALUE(ret)) + return ret; + /* sync tail before inserting logs */ + smp_mb(); + p = &crc->buf[crc->head]; + n = min(len, circ_space_to_end(crc)); + memcpy(p, buf, n); + /* sync head after inserting logs */ + smp_wmb(); + crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); + acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true); + return n; +} + +static int acpi_aml_readb_kern(void) +{ + int ret; + struct circ_buf *crc = &acpi_aml_io.in_crc; + char *p; + + ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN); + if (IS_ERR_VALUE(ret)) + return ret; + /* sync head before removing cmds */ + smp_rmb(); + p = &crc->buf[crc->tail]; + ret = (int)*p; + /* sync tail before inserting cmds */ + smp_mb(); + crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1); + acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true); + return ret; +} + +/* + * acpi_aml_write_log() - Capture debugger output + * @msg: the debugger output + * + * This function should be used to implement acpi_os_printf() to filter out + * the debugger output and store the output into the debugger interface + * buffer. Return the size of stored logs or errno. + */ +ssize_t acpi_aml_write_log(const char *msg) +{ + int ret = 0; + int count = 0, size = 0; + + if (!acpi_aml_initialized) + return -ENODEV; + if (msg) + count = strlen(msg); + while (count > 0) { +again: + ret = acpi_aml_write_kern(msg + size, count); + if (ret == -EAGAIN) { + ret = wait_event_interruptible(acpi_aml_io.wait, + acpi_aml_kern_writable()); + /* + * We need to retry when the condition + * becomes true. + */ + if (ret == 0) + goto again; + break; + } + if (IS_ERR_VALUE(ret)) + break; + size += ret; + count -= ret; + } + return size > 0 ? size : ret; +} +EXPORT_SYMBOL(acpi_aml_write_log); + +/* + * acpi_aml_read_cmd() - Capture debugger input + * @msg: the debugger input + * @size: the size of the debugger input + * + * This function should be used to implement acpi_os_get_line() to capture + * the debugger input commands and store the input commands into the + * debugger interface buffer. Return the size of stored commands or errno. + */ +ssize_t acpi_aml_read_cmd(char *msg, size_t count) +{ + int ret = 0; + int size = 0; + + /* + * This is ensured by the running fact of the debugger thread + * unless a bug is introduced. + */ + BUG_ON(!acpi_aml_initialized); + while (count > 0) { +again: + /* + * Check each input byte to find the end of the command. + */ + ret = acpi_aml_readb_kern(); + if (ret == -EAGAIN) { + ret = wait_event_interruptible(acpi_aml_io.wait, + acpi_aml_kern_readable()); + /* + * We need to retry when the condition becomes + * true. + */ + if (ret == 0) + goto again; + } + if (IS_ERR_VALUE(ret)) + break; + *(msg + size) = (char)ret; + size++; + count--; + if (ret == '\n') { + /* + * acpi_os_get_line() requires a zero terminated command + * string. + */ + *(msg + size - 1) = '\0'; + break; + } + } + return size > 0 ? size : ret; +} +EXPORT_SYMBOL(acpi_aml_read_cmd); + +static int acpi_aml_thread(void *unsed) +{ + acpi_osd_exec_callback function = NULL; + void *context; + + mutex_lock(&acpi_aml_io.lock); + if (acpi_aml_io.function) { + acpi_aml_io.usages++; + function = acpi_aml_io.function; + context = acpi_aml_io.context; + } + mutex_unlock(&acpi_aml_io.lock); + + if (function) + function(context); + + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.usages--; + if (!__acpi_aml_used()) { + acpi_aml_io.thread = NULL; + wake_up(&acpi_aml_io.wait); + } + mutex_unlock(&acpi_aml_io.lock); + + return 0; +} + +/* + * acpi_aml_create_thread() - Create AML debugger thread + * @function: the debugger thread callback + * @context: the context to be passed to the debugger thread + * + * This function should be used to implement acpi_os_execute() which is + * used by the ACPICA debugger to create the debugger thread. + */ +int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) +{ + struct task_struct *t; + + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.function = function; + acpi_aml_io.context = context; + mutex_unlock(&acpi_aml_io.lock); + + t = kthread_create(acpi_aml_thread, NULL, "aml"); + if (IS_ERR(t)) { + pr_err("Failed to create AML debugger thread.\n"); + return PTR_ERR(t); + } + + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.thread = t; + acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t); + wake_up_process(t); + mutex_unlock(&acpi_aml_io.lock); + return 0; +} +EXPORT_SYMBOL(acpi_aml_create_thread); + +int acpi_aml_wait_command_ready(void) +{ + acpi_status status; + + if (!acpi_gbl_method_executing) + acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); + else + acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); + + status = acpi_os_get_line(acpi_gbl_db_line_buf, + ACPI_DB_LINE_BUFFER_SIZE, NULL); + if (ACPI_FAILURE(status)) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(acpi_aml_wait_command_ready); + +int acpi_aml_notify_command_complete(void) +{ + return 0; +} +EXPORT_SYMBOL(acpi_aml_notify_command_complete); + +static int acpi_aml_open(struct inode *inode, struct file *file) +{ + int ret = 0; + acpi_status status; + + mutex_lock(&acpi_aml_io.lock); + /* + * The debugger interface is being closed, no new user is allowed + * during this period. + */ + if (acpi_aml_io.flags & ACPI_AML_CLOSED) { + ret = -EBUSY; + goto err_lock; + } + if ((file->f_flags & O_ACCMODE) != O_WRONLY) { + /* + * Only one reader is allowed to initiate the debugger + * thread. + */ + if (acpi_aml_active_reader) { + ret = -EBUSY; + goto err_lock; + } else { + pr_debug("Opening debugger reader.\n"); + acpi_aml_active_reader = file; + } + } else { + /* + * No writer is allowed unless the debugger thread is + * ready. + */ + if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) { + ret = -ENODEV; + goto err_lock; + } + } + if (acpi_aml_active_reader == file) { + pr_debug("Opening debugger interface.\n"); + mutex_unlock(&acpi_aml_io.lock); + + pr_debug("Initializing debugger thread.\n"); + status = acpi_initialize_debugger(); + if (ACPI_FAILURE(status)) { + pr_err("Failed to initialize debugger.\n"); + ret = -EINVAL; + goto err_lock; + } + acpi_aml_io.flags |= ACPI_AML_OPENED; + pr_debug("Debugger thread initialized.\n"); + + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0; + acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0; + pr_debug("Debugger interface opened.\n"); + } + acpi_aml_io.users++; +err_lock: + if (IS_ERR_VALUE(ret)) { + if (acpi_aml_active_reader == file) + acpi_aml_active_reader = NULL; + } + mutex_unlock(&acpi_aml_io.lock); + return ret; +} + +static int acpi_aml_release(struct inode *inode, struct file *file) +{ + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.users--; + if (file == acpi_aml_active_reader) { + pr_debug("Closing debugger reader.\n"); + acpi_aml_active_reader = NULL; + + pr_debug("Closing debugger interface.\n"); + acpi_aml_io.flags |= ACPI_AML_CLOSED; + + /* + * Wake up all user space/kernel space blocked + * readers/writers. + */ + wake_up_interruptible(&acpi_aml_io.wait); + mutex_unlock(&acpi_aml_io.lock); + /* + * Wait all user space/kernel space readers/writers to + * stop so that ACPICA command loop of the debugger thread + * should fail all its command line reads after this point. + */ + wait_event(acpi_aml_io.wait, !acpi_aml_busy()); + + /* + * Then we try to terminate the debugger thread if it is + * not terminated. + */ + pr_debug("Terminating debugger thread.\n"); + acpi_terminate_debugger(); + wait_event(acpi_aml_io.wait, !acpi_aml_used()); + pr_debug("Debugger thread terminated.\n"); + + mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.flags &= ~ACPI_AML_OPENED; + } + if (acpi_aml_io.users == 0) { + pr_debug("Debugger interface closed.\n"); + acpi_aml_io.flags &= ~ACPI_AML_CLOSED; + } + mutex_unlock(&acpi_aml_io.lock); + return 0; +} + +static int acpi_aml_read_user(char __user *buf, int len) +{ + int ret; + struct circ_buf *crc = &acpi_aml_io.out_crc; + int n; + char *p; + + ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER); + if (IS_ERR_VALUE(ret)) + return ret; + /* sync head before removing logs */ + smp_rmb(); + p = &crc->buf[crc->tail]; + n = min(len, circ_count_to_end(crc)); + ret = copy_to_user(buf, p, n); + if (IS_ERR_VALUE(ret)) + goto out; + /* sync tail after removing logs */ + smp_mb(); + crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); + ret = n; +out: + acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !IS_ERR_VALUE(ret)); + return ret; +} + +static ssize_t acpi_aml_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + int size = 0; + + if (!buf || count < 0) + return -EINVAL; + if (!count) + return 0; + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; + + while (count > 0) { +again: + ret = acpi_aml_read_user(buf + size, count); + if (ret == -EAGAIN) { + if (file->f_flags & O_NONBLOCK) + break; + else { + ret = wait_event_interruptible(acpi_aml_io.wait, + acpi_aml_user_readable()); + /* + * We need to retry when the condition + * becomes true. + */ + if (ret == 0) + goto again; + } + } + if (IS_ERR_VALUE(ret)) { + if (!acpi_aml_running()) + ret = 0; + break; + } + if (ret) { + size += ret; + count -= ret; + *ppos += ret; + break; + } + } + return size > 0 ? size : ret; +} + +static int acpi_aml_write_user(const char __user *buf, int len) +{ + int ret; + struct circ_buf *crc = &acpi_aml_io.in_crc; + int n; + char *p; + + ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER); + if (IS_ERR_VALUE(ret)) + return ret; + /* sync tail before inserting cmds */ + smp_mb(); + p = &crc->buf[crc->head]; + n = min(len, circ_space_to_end(crc)); + ret = copy_from_user(p, buf, n); + if (IS_ERR_VALUE(ret)) + goto out; + /* sync head after inserting cmds */ + smp_wmb(); + crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); + ret = n; +out: + acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !IS_ERR_VALUE(ret)); + return n; +} + +static ssize_t acpi_aml_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + int size = 0; + + if (!buf || count < 0) + return -EINVAL; + if (!count) + return 0; + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + while (count > 0) { +again: + ret = acpi_aml_write_user(buf + size, count); + if (ret == -EAGAIN) { + if (file->f_flags & O_NONBLOCK) + break; + else { + ret = wait_event_interruptible(acpi_aml_io.wait, + acpi_aml_user_writable()); + /* + * We need to retry when the condition + * becomes true. + */ + if (ret == 0) + goto again; + } + } + if (IS_ERR_VALUE(ret)) { + if (!acpi_aml_running()) + ret = 0; + break; + } + if (ret) { + size += ret; + count -= ret; + *ppos += ret; + } + } + return size > 0 ? size : ret; +} + +static unsigned int acpi_aml_poll(struct file *file, poll_table *wait) +{ + int masks = 0; + + poll_wait(file, &acpi_aml_io.wait, wait); + if (acpi_aml_user_readable()) + masks |= POLLIN | POLLRDNORM; + if (acpi_aml_user_writable()) + masks |= POLLOUT | POLLWRNORM; + + return masks; +} + +static const struct file_operations acpi_aml_operations = { + .read = acpi_aml_read, + .write = acpi_aml_write, + .poll = acpi_aml_poll, + .open = acpi_aml_open, + .release = acpi_aml_release, + .llseek = generic_file_llseek, +}; + +int __init acpi_aml_init(void) +{ + if (!acpi_debugfs_dir) + return -ENOENT; + /* Initialize AML IO interface */ + mutex_init(&acpi_aml_io.lock); + init_waitqueue_head(&acpi_aml_io.wait); + acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf; + acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf; + acpi_aml_dentry = debugfs_create_file("acpidbg", + S_IFREG | S_IRUGO | S_IWUSR, + acpi_debugfs_dir, NULL, + &acpi_aml_operations); + if (acpi_aml_dentry == NULL) + return -ENODEV; + acpi_aml_initialized = true; + return 0; +} + +#if 0 +void __exit acpi_aml_exit(void) +{ + /* TODO: Stop the in kernel debugger */ + if (acpi_aml_dentry) + debugfs_remove(acpi_aml_dentry); + acpi_aml_initialized = false; +} + +module_init(acpi_aml_init); +module_exit(acpi_aml_exit); +#endif diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a212cef..06fbba9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "internal.h" @@ -1094,6 +1095,7 @@ static int __init acpi_init(void) acpi_debugfs_init(); acpi_sleep_proc_init(); acpi_wakeup_device_init(); + acpi_aml_init(); return 0; } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 32d684a..4c13398 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -234,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args) printk(KERN_CONT "%s", buffer); } #else - printk(KERN_CONT "%s", buffer); + if (acpi_aml_write_log(buffer) < 0) + printk(KERN_CONT "%s", buffer); #endif } @@ -1127,6 +1129,15 @@ acpi_status acpi_os_execute(acpi_execute_type type, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); + if (type == OSL_DEBUGGER_MAIN_THREAD) { + ret = acpi_aml_create_thread(function, context); + if (ret) { + pr_err("Call to kthread_create() failed.\n"); + status = AE_ERROR; + } + goto out_thread; + } + /* * Allocate/initialize DPC structure. Note that this memory will be * freed by the callee. The kernel handles the work_struct list in a @@ -1151,11 +1162,17 @@ acpi_status acpi_os_execute(acpi_execute_type type, if (type == OSL_NOTIFY_HANDLER) { queue = kacpi_notify_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); - } else { + } else if (type == OSL_GPE_HANDLER) { queue = kacpid_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); + } else { + pr_err("Unsupported os_execute type %d.\n", type); + status = AE_ERROR; } + if (ACPI_FAILURE(status)) + goto err_workqueue; + /* * On some machines, a software-initiated SMI causes corruption unless * the SMI runs on CPU 0. An SMI can be initiated by any AML, but @@ -1164,13 +1181,15 @@ acpi_status acpi_os_execute(acpi_execute_type type, * queueing on CPU 0. */ ret = queue_work_on(0, queue, &dpc->work); - if (!ret) { printk(KERN_ERR PREFIX "Call to queue_work() failed.\n"); status = AE_ERROR; - kfree(dpc); } +err_workqueue: + if (ACPI_FAILURE(status)) + kfree(dpc); +out_thread: return status; } EXPORT_SYMBOL(acpi_os_execute); @@ -1358,11 +1377,39 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) chars = strlen(buffer) - 1; buffer[chars] = '\0'; } +#else + int ret; + + ret = acpi_aml_read_cmd(buffer, buffer_length); + if (ret < 0) + return AE_ERROR; + if (bytes_read) + *bytes_read = ret; #endif return AE_OK; } +acpi_status acpi_os_wait_command_ready(void) +{ + int ret; + + ret = acpi_aml_wait_command_ready(); + if (ret < 0) + return AE_ERROR; + return AE_OK; +} + +acpi_status acpi_os_notify_command_complete(void) +{ + int ret; + + ret = acpi_aml_notify_command_complete(); + if (ret < 0) + return AE_ERROR; + return AE_OK; +} + acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 69dbae6..e21857d 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -152,8 +152,6 @@ #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete /* * OSL interfaces used by utilities diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index 673fdf4..ceea026 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -138,16 +138,6 @@ static inline void acpi_os_terminate_command_signals(void) { } -static inline acpi_status acpi_os_wait_command_ready(void) -{ - return AE_ERROR; -} - -static inline acpi_status acpi_os_notify_command_complete(void) -{ - return AE_ERROR; -} - /* * OSL interfaces added by Linux */ diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h new file mode 100644 index 0000000..60f3887 --- /dev/null +++ b/include/linux/acpi_dbg.h @@ -0,0 +1,52 @@ +/* + * ACPI AML interfacing support + * + * Copyright (C) 2015, Intel Corporation + * Authors: Lv Zheng + * + * 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. + */ + +#ifndef _LINUX_ACPI_DBG_H +#define _LINUX_ACPI_DBG_H + +#include + +#ifdef CONFIG_ACPI_DEBUGGER +int __init acpi_aml_init(void); +int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context); +ssize_t acpi_aml_write_log(const char *msg); +ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length); +int acpi_aml_wait_command_ready(void); +int acpi_aml_notify_command_complete(void); +#else +static int inline acpi_aml_init(void) +{ + return 0; +} +static inline int acpi_aml_create_thread(acpi_osd_exec_callback function, + void *context) +{ + return -ENODEV; +} +static inline int acpi_aml_write_log(const char *msg) +{ + return -ENODEV; +} +static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length) +{ + return -ENODEV; +} +static inline int acpi_aml_wait_command_ready(void) +{ + return -ENODEV; +} +static inline int acpi_aml_notify_command_complete(void) +{ + return -ENODEV; +} +#endif + +#endif /* _LINUX_ACPI_DBG_H */ -- cgit v0.10.2 From 37645d6590a49d3009eecdf093599795da2b5b41 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Dec 2015 10:43:07 +0800 Subject: tools/power/acpi: Add userspace AML interface support This patch adds a userspace tool to access Linux kernel AML debugger interface. Tow modes are supported by this tool: 1. Interactive: Users are able to launch a debugging shell to talk with in-kernel AML debugger. Note that it's user duty to ensure kernel runtime integrity by using this debugging tool: A. Some control methods evaluated by the users may result in kernel panics if those control methods shouldn't be evaluated by the OSPMs according to the current BIOS/OS configurations. B. Currently if a single stepping evaluation couldn't run to an end, then the synchronization primitives acquired by the evaluation may block normal OSPM control method evaluations. 2. Batch: Users are able to execute debugger commands in a script. Note that in addition to the above duties, it's user duty to ensure script runtime integrity by using this debugging tool in this mode: C. Currently only those commands that are not used for single stepping are suitable to be used in this mode. D. If the execution of the command may cause a failure that could result in an endless kernel execution, the execution of the script may also get blocked. To exit the utility, currently "exit/quit" commands are recommended, but ctrl-C" can also be used. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile index e882c83..a8bf908 100644 --- a/tools/power/acpi/Makefile +++ b/tools/power/acpi/Makefile @@ -10,18 +10,18 @@ include ../../scripts/Makefile.include -all: acpidump ec -clean: acpidump_clean ec_clean -install: acpidump_install ec_install -uninstall: acpidump_uninstall ec_uninstall +all: acpidbg acpidump ec +clean: acpidbg_clean acpidump_clean ec_clean +install: acpidbg_install acpidump_install ec_install +uninstall: acpidbg_uninstall acpidump_uninstall ec_uninstall -acpidump ec: FORCE +acpidbg acpidump ec: FORCE $(call descend,tools/$@,all) -acpidump_clean ec_clean: +acpidbg_clean acpidump_clean ec_clean: $(call descend,tools/$(@:_clean=),clean) -acpidump_install ec_install: +acpidbg_install acpidump_install ec_install: $(call descend,tools/$(@:_install=),install) -acpidump_uninstall ec_uninstall: +acpidbg_uninstall acpidump_uninstall ec_uninstall: $(call descend,tools/$(@:_uninstall=),uninstall) .PHONY: FORCE diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile new file mode 100644 index 0000000..352df4b --- /dev/null +++ b/tools/power/acpi/tools/acpidbg/Makefile @@ -0,0 +1,27 @@ +# tools/power/acpi/tools/acpidbg/Makefile - ACPI tool Makefile +# +# Copyright (c) 2015, Intel Corporation +# Author: Lv Zheng +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. + +include ../../Makefile.config + +TOOL = acpidbg +vpath %.c \ + ../../../../../drivers/acpi/acpica\ + ../../common\ + ../../os_specific/service_layers\ + . +CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\ + -I.\ + -I../../../../../drivers/acpi/acpica\ + -I../../../../../include +LDFLAGS += -lpthread +TOOL_OBJS = \ + acpidbg.o + +include ../../Makefile.rules diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c new file mode 100644 index 0000000..d070fcc --- /dev/null +++ b/tools/power/acpi/tools/acpidbg/acpidbg.c @@ -0,0 +1,438 @@ +/* + * ACPI AML interfacing userspace utility + * + * Copyright (C) 2015, Intel Corporation + * Authors: Lv Zheng + * + * 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 + +/* Headers not included by include/acpi/platform/aclinux.h */ +#include +#include +#include +#include + +#define ACPI_AML_FILE "/sys/kernel/debug/acpi/acpidbg" +#define ACPI_AML_SEC_TICK 1 +#define ACPI_AML_USEC_PEEK 200 +#define ACPI_AML_BUF_SIZE 4096 + +#define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */ +#define ACPI_AML_BATCH_READ_LOG 0x01 /* Read log from kernel */ +#define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */ + +#define ACPI_AML_LOG_START 0x00 +#define ACPI_AML_PROMPT_START 0x01 +#define ACPI_AML_PROMPT_STOP 0x02 +#define ACPI_AML_LOG_STOP 0x03 +#define ACPI_AML_PROMPT_ROLL 0x04 + +#define ACPI_AML_INTERACTIVE 0x00 +#define ACPI_AML_BATCH 0x01 + +#define circ_count(circ) \ + (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) +#define circ_count_to_end(circ) \ + (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) +#define circ_space(circ) \ + (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) +#define circ_space_to_end(circ) \ + (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) + +#define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc) +#define acpi_aml_log_count() circ_count(&acpi_aml_log_crc) +#define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc) +#define acpi_aml_log_space() circ_space(&acpi_aml_log_crc) + +#define ACPI_AML_DO(_fd, _op, _buf, _ret) \ + do { \ + _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \ + if (_ret == 0) { \ + fprintf(stderr, \ + "%s %s pipe closed.\n", #_buf, #_op); \ + return; \ + } \ + } while (0) +#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \ + do { \ + _ret = acpi_aml_##_op##_batch_##_buf(_fd, \ + &acpi_aml_##_buf##_crc); \ + if (_ret == 0) \ + return; \ + } while (0) + + +static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE]; +static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE]; +static struct circ_buf acpi_aml_cmd_crc = { + .buf = acpi_aml_cmd_buf, + .head = 0, + .tail = 0, +}; +static struct circ_buf acpi_aml_log_crc = { + .buf = acpi_aml_log_buf, + .head = 0, + .tail = 0, +}; +static const char *acpi_aml_file_path = ACPI_AML_FILE; +static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE; +static bool acpi_aml_exit; + +static bool acpi_aml_batch_drain; +static unsigned long acpi_aml_batch_state; +static char acpi_aml_batch_prompt; +static char acpi_aml_batch_roll; +static unsigned long acpi_aml_log_state; +static char *acpi_aml_batch_cmd = NULL; +static char *acpi_aml_batch_pos = NULL; + +static int acpi_aml_set_fl(int fd, int flags) +{ + int ret; + + ret = fcntl(fd, F_GETFL, 0); + if (ret < 0) { + perror("fcntl(F_GETFL)"); + return ret; + } + flags |= ret; + ret = fcntl(fd, F_SETFL, flags); + if (ret < 0) { + perror("fcntl(F_SETFL)"); + return ret; + } + return ret; +} + +static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set) +{ + if (fd > maxfd) + maxfd = fd; + FD_SET(fd, set); + return maxfd; +} + +static int acpi_aml_read(int fd, struct circ_buf *crc) +{ + char *p; + int len; + + p = &crc->buf[crc->head]; + len = circ_space_to_end(crc); + len = read(fd, p, len); + if (len < 0) + perror("read"); + else if (len > 0) + crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1); + return len; +} + +static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc) +{ + char *p; + int len; + int remained = strlen(acpi_aml_batch_pos); + + p = &crc->buf[crc->head]; + len = circ_space_to_end(crc); + if (len > remained) { + memcpy(p, acpi_aml_batch_pos, remained); + acpi_aml_batch_pos += remained; + len = remained; + } else { + memcpy(p, acpi_aml_batch_pos, len); + acpi_aml_batch_pos += len; + } + if (len > 0) + crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1); + return len; +} + +static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc) +{ + char *p; + int len; + int ret = 0; + + p = &crc->buf[crc->head]; + len = circ_space_to_end(crc); + while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) { + if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) { + *p = acpi_aml_batch_roll; + len = 1; + crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); + ret += 1; + acpi_aml_log_state = ACPI_AML_LOG_START; + } else { + len = read(fd, p, 1); + if (len <= 0) { + if (len < 0) + perror("read"); + ret = len; + break; + } + } + switch (acpi_aml_log_state) { + case ACPI_AML_LOG_START: + if (*p == '\n') + acpi_aml_log_state = ACPI_AML_PROMPT_START; + crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); + ret += 1; + break; + case ACPI_AML_PROMPT_START: + if (*p == ACPI_DEBUGGER_COMMAND_PROMPT || + *p == ACPI_DEBUGGER_EXECUTE_PROMPT) { + acpi_aml_batch_prompt = *p; + acpi_aml_log_state = ACPI_AML_PROMPT_STOP; + } else { + if (*p != '\n') + acpi_aml_log_state = ACPI_AML_LOG_START; + crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); + ret += 1; + } + break; + case ACPI_AML_PROMPT_STOP: + if (*p == ' ') { + acpi_aml_log_state = ACPI_AML_LOG_STOP; + acpi_aml_exit = true; + } else { + /* Roll back */ + acpi_aml_log_state = ACPI_AML_PROMPT_ROLL; + acpi_aml_batch_roll = *p; + *p = acpi_aml_batch_prompt; + crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); + ret += 1; + } + break; + default: + assert(0); + break; + } + } + return ret; +} + +static int acpi_aml_write(int fd, struct circ_buf *crc) +{ + char *p; + int len; + + p = &crc->buf[crc->tail]; + len = circ_count_to_end(crc); + len = write(fd, p, len); + if (len < 0) + perror("write"); + else if (len > 0) + crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1); + return len; +} + +static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc) +{ + char *p; + int len; + + p = &crc->buf[crc->tail]; + len = circ_count_to_end(crc); + if (!acpi_aml_batch_drain) { + len = write(fd, p, len); + if (len < 0) + perror("write"); + } + if (len > 0) + crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1); + return len; +} + +static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc) +{ + int len; + + len = acpi_aml_write(fd, crc); + if (circ_count_to_end(crc) == 0) + acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG; + return len; +} + +static void acpi_aml_loop(int fd) +{ + fd_set rfds; + fd_set wfds; + struct timeval tv; + int ret; + int maxfd = 0; + + if (acpi_aml_mode == ACPI_AML_BATCH) { + acpi_aml_log_state = ACPI_AML_LOG_START; + acpi_aml_batch_pos = acpi_aml_batch_cmd; + if (acpi_aml_batch_drain) + acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG; + else + acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD; + } + acpi_aml_exit = false; + while (!acpi_aml_exit) { + tv.tv_sec = ACPI_AML_SEC_TICK; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + if (acpi_aml_cmd_space()) { + if (acpi_aml_mode == ACPI_AML_INTERACTIVE) + maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds); + else if (strlen(acpi_aml_batch_pos) && + acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD) + ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret); + } + if (acpi_aml_cmd_count() && + (acpi_aml_mode == ACPI_AML_INTERACTIVE || + acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)) + maxfd = acpi_aml_set_fd(fd, maxfd, &wfds); + if (acpi_aml_log_space() && + (acpi_aml_mode == ACPI_AML_INTERACTIVE || + acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG)) + maxfd = acpi_aml_set_fd(fd, maxfd, &rfds); + if (acpi_aml_log_count()) + maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds); + + ret = select(maxfd+1, &rfds, &wfds, NULL, &tv); + if (ret < 0) { + perror("select"); + break; + } + if (ret > 0) { + if (FD_ISSET(STDIN_FILENO, &rfds)) + ACPI_AML_DO(STDIN_FILENO, read, cmd, ret); + if (FD_ISSET(fd, &wfds)) { + if (acpi_aml_mode == ACPI_AML_BATCH) + ACPI_AML_BATCH_DO(fd, write, cmd, ret); + else + ACPI_AML_DO(fd, write, cmd, ret); + } + if (FD_ISSET(fd, &rfds)) { + if (acpi_aml_mode == ACPI_AML_BATCH) + ACPI_AML_BATCH_DO(fd, read, log, ret); + else + ACPI_AML_DO(fd, read, log, ret); + } + if (FD_ISSET(STDOUT_FILENO, &wfds)) { + if (acpi_aml_mode == ACPI_AML_BATCH) + ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret); + else + ACPI_AML_DO(STDOUT_FILENO, write, log, ret); + } + } + } +} + +static bool acpi_aml_readable(int fd) +{ + fd_set rfds; + struct timeval tv; + int ret; + int maxfd = 0; + + tv.tv_sec = 0; + tv.tv_usec = ACPI_AML_USEC_PEEK; + FD_ZERO(&rfds); + maxfd = acpi_aml_set_fd(fd, maxfd, &rfds); + ret = select(maxfd+1, &rfds, NULL, NULL, &tv); + if (ret < 0) + perror("select"); + if (ret > 0 && FD_ISSET(fd, &rfds)) + return true; + return false; +} + +/* + * This is a userspace IO flush implementation, replying on the prompt + * characters and can be turned into a flush() call after kernel implements + * .flush() filesystem operation. + */ +static void acpi_aml_flush(int fd) +{ + while (acpi_aml_readable(fd)) { + acpi_aml_batch_drain = true; + acpi_aml_loop(fd); + acpi_aml_batch_drain = false; + } +} + +void usage(FILE *file, char *progname) +{ + fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname); + fprintf(file, "\nOptions:\n"); + fprintf(file, " -b Specify command to be executed in batch mode\n"); + fprintf(file, " -f Specify interface file other than"); + fprintf(file, " /sys/kernel/debug/acpi/acpidbg\n"); + fprintf(file, " -h Print this help message\n"); +} + +int main(int argc, char **argv) +{ + int fd = 0; + int ch; + int len; + int ret = EXIT_SUCCESS; + + while ((ch = getopt(argc, argv, "b:f:h")) != -1) { + switch (ch) { + case 'b': + if (acpi_aml_batch_cmd) { + fprintf(stderr, "Already specify %s\n", + acpi_aml_batch_cmd); + ret = EXIT_FAILURE; + goto exit; + } + len = strlen(optarg); + acpi_aml_batch_cmd = calloc(len + 2, 1); + if (!acpi_aml_batch_cmd) { + perror("calloc"); + ret = EXIT_FAILURE; + goto exit; + } + memcpy(acpi_aml_batch_cmd, optarg, len); + acpi_aml_batch_cmd[len] = '\n'; + acpi_aml_mode = ACPI_AML_BATCH; + break; + case 'f': + acpi_aml_file_path = optarg; + break; + case 'h': + usage(stdout, argv[0]); + goto exit; + break; + case '?': + default: + usage(stderr, argv[0]); + ret = EXIT_FAILURE; + goto exit; + break; + } + } + + fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK); + if (fd < 0) { + perror("open"); + ret = EXIT_FAILURE; + goto exit; + } + acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK); + acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK); + + if (acpi_aml_mode == ACPI_AML_BATCH) + acpi_aml_flush(fd); + acpi_aml_loop(fd); + +exit: + if (fd < 0) + close(fd); + if (acpi_aml_batch_cmd) + free(acpi_aml_batch_cmd); + return ret; +} -- cgit v0.10.2 From 836d0830188a97d5c73e8eb514f346a857c086b9 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Dec 2015 10:43:14 +0800 Subject: ACPI / debugger: Add module support for ACPI debugger This patch converts AML debugger into a loadable module. Note that, it implements driver unloading at the level dependent on the module reference count. Which means if ACPI debugger is being used by a userspace program, "rmmod acpi_dbg" should result in failure. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 2a7e6d4..82b96ee 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -60,13 +60,23 @@ config ACPI_CCA_REQUIRED config ACPI_DEBUGGER bool "AML debugger interface" select ACPI_DEBUG - depends on DEBUG_FS help - Enable in-kernel debugging of AML facilities: statistics, internal - object dump, single step control method execution. + Enable in-kernel debugging of AML facilities: statistics, + internal object dump, single step control method execution. This is still under development, currently enabling this only results in the compilation of the ACPICA debugger files. +if ACPI_DEBUGGER + +config ACPI_DEBUGGER_USER + tristate "Userspace debugger accessiblity" + depends on DEBUG_FS + help + Export /sys/kernel/debug/acpi/acpidbg for userspace utilities + to access the debugger functionalities. + +endif + config ACPI_SLEEP bool depends on SUSPEND || HIBERNATION diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 102b5e6..c6f236f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -50,7 +50,6 @@ acpi-y += sysfs.o acpi-y += property.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o -acpi-$(CONFIG_ACPI_DEBUGGER) += acpi_dbg.o acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o acpi-y += acpi_lpat.o @@ -80,6 +79,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o +obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o # processor has its own "processor." module_param namespace processor-y := processor_driver.o diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index abc23b2..381beb2 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "internal.h" #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size)) @@ -307,7 +307,7 @@ static int acpi_aml_readb_kern(void) * the debugger output and store the output into the debugger interface * buffer. Return the size of stored logs or errno. */ -ssize_t acpi_aml_write_log(const char *msg) +static ssize_t acpi_aml_write_log(const char *msg) { int ret = 0; int count = 0, size = 0; @@ -337,7 +337,6 @@ again: } return size > 0 ? size : ret; } -EXPORT_SYMBOL(acpi_aml_write_log); /* * acpi_aml_read_cmd() - Capture debugger input @@ -348,7 +347,7 @@ EXPORT_SYMBOL(acpi_aml_write_log); * the debugger input commands and store the input commands into the * debugger interface buffer. Return the size of stored commands or errno. */ -ssize_t acpi_aml_read_cmd(char *msg, size_t count) +static ssize_t acpi_aml_read_cmd(char *msg, size_t count) { int ret = 0; int size = 0; @@ -390,7 +389,6 @@ again: } return size > 0 ? size : ret; } -EXPORT_SYMBOL(acpi_aml_read_cmd); static int acpi_aml_thread(void *unsed) { @@ -427,7 +425,7 @@ static int acpi_aml_thread(void *unsed) * This function should be used to implement acpi_os_execute() which is * used by the ACPICA debugger to create the debugger thread. */ -int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) +static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) { struct task_struct *t; @@ -449,30 +447,27 @@ int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) mutex_unlock(&acpi_aml_io.lock); return 0; } -EXPORT_SYMBOL(acpi_aml_create_thread); -int acpi_aml_wait_command_ready(void) +static int acpi_aml_wait_command_ready(bool single_step, + char *buffer, size_t length) { acpi_status status; - if (!acpi_gbl_method_executing) - acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); - else + if (single_step) acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); + else + acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); - status = acpi_os_get_line(acpi_gbl_db_line_buf, - ACPI_DB_LINE_BUFFER_SIZE, NULL); + status = acpi_os_get_line(buffer, length, NULL); if (ACPI_FAILURE(status)) return -EINVAL; return 0; } -EXPORT_SYMBOL(acpi_aml_wait_command_ready); -int acpi_aml_notify_command_complete(void) +static int acpi_aml_notify_command_complete(void) { return 0; } -EXPORT_SYMBOL(acpi_aml_notify_command_complete); static int acpi_aml_open(struct inode *inode, struct file *file) { @@ -746,10 +741,23 @@ static const struct file_operations acpi_aml_operations = { .llseek = generic_file_llseek, }; +static const struct acpi_debugger_ops acpi_aml_debugger = { + .create_thread = acpi_aml_create_thread, + .read_cmd = acpi_aml_read_cmd, + .write_log = acpi_aml_write_log, + .wait_command_ready = acpi_aml_wait_command_ready, + .notify_command_complete = acpi_aml_notify_command_complete, +}; + int __init acpi_aml_init(void) { - if (!acpi_debugfs_dir) - return -ENOENT; + int ret = 0; + + if (!acpi_debugfs_dir) { + ret = -ENOENT; + goto err_exit; + } + /* Initialize AML IO interface */ mutex_init(&acpi_aml_io.lock); init_waitqueue_head(&acpi_aml_io.wait); @@ -759,21 +767,39 @@ int __init acpi_aml_init(void) S_IFREG | S_IRUGO | S_IWUSR, acpi_debugfs_dir, NULL, &acpi_aml_operations); - if (acpi_aml_dentry == NULL) - return -ENODEV; + if (acpi_aml_dentry == NULL) { + ret = -ENODEV; + goto err_exit; + } + ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); + if (ret) + goto err_fs; acpi_aml_initialized = true; - return 0; + +err_fs: + if (ret) { + debugfs_remove(acpi_aml_dentry); + acpi_aml_dentry = NULL; + } +err_exit: + return ret; } -#if 0 void __exit acpi_aml_exit(void) { - /* TODO: Stop the in kernel debugger */ - if (acpi_aml_dentry) - debugfs_remove(acpi_aml_dentry); - acpi_aml_initialized = false; + if (acpi_aml_initialized) { + acpi_unregister_debugger(&acpi_aml_debugger); + if (acpi_aml_dentry) { + debugfs_remove(acpi_aml_dentry); + acpi_aml_dentry = NULL; + } + acpi_aml_initialized = false; + } } module_init(acpi_aml_init); module_exit(acpi_aml_exit); -#endif + +MODULE_AUTHOR("Lv Zheng"); +MODULE_DESCRIPTION("ACPI debugger userspace IO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 06fbba9..1a40111 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "internal.h" @@ -1095,7 +1094,7 @@ static int __init acpi_init(void) acpi_debugfs_init(); acpi_sleep_proc_init(); acpi_wakeup_device_init(); - acpi_aml_init(); + acpi_debugger_init(); return 0; } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 4c13398..bb66093 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -221,6 +220,7 @@ void acpi_os_printf(const char *fmt, ...) acpi_os_vprintf(fmt, args); va_end(args); } +EXPORT_SYMBOL(acpi_os_printf); void acpi_os_vprintf(const char *fmt, va_list args) { @@ -235,7 +235,7 @@ void acpi_os_vprintf(const char *fmt, va_list args) printk(KERN_CONT "%s", buffer); } #else - if (acpi_aml_write_log(buffer) < 0) + if (acpi_debugger_write_log(buffer) < 0) printk(KERN_CONT "%s", buffer); #endif } @@ -1103,6 +1103,200 @@ static void acpi_os_execute_deferred(struct work_struct *work) kfree(dpc); } +#ifdef CONFIG_ACPI_DEBUGGER +static struct acpi_debugger acpi_debugger; +static bool acpi_debugger_initialized; + +int acpi_register_debugger(struct module *owner, + const struct acpi_debugger_ops *ops) +{ + int ret = 0; + + mutex_lock(&acpi_debugger.lock); + if (acpi_debugger.ops) { + ret = -EBUSY; + goto err_lock; + } + + acpi_debugger.owner = owner; + acpi_debugger.ops = ops; + +err_lock: + mutex_unlock(&acpi_debugger.lock); + return ret; +} +EXPORT_SYMBOL(acpi_register_debugger); + +void acpi_unregister_debugger(const struct acpi_debugger_ops *ops) +{ + mutex_lock(&acpi_debugger.lock); + if (ops == acpi_debugger.ops) { + acpi_debugger.ops = NULL; + acpi_debugger.owner = NULL; + } + mutex_unlock(&acpi_debugger.lock); +} +EXPORT_SYMBOL(acpi_unregister_debugger); + +int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context) +{ + int ret; + int (*func)(acpi_osd_exec_callback, void *); + struct module *owner; + + if (!acpi_debugger_initialized) + return -ENODEV; + mutex_lock(&acpi_debugger.lock); + if (!acpi_debugger.ops) { + ret = -ENODEV; + goto err_lock; + } + if (!try_module_get(acpi_debugger.owner)) { + ret = -ENODEV; + goto err_lock; + } + func = acpi_debugger.ops->create_thread; + owner = acpi_debugger.owner; + mutex_unlock(&acpi_debugger.lock); + + ret = func(function, context); + + mutex_lock(&acpi_debugger.lock); + module_put(owner); +err_lock: + mutex_unlock(&acpi_debugger.lock); + return ret; +} + +ssize_t acpi_debugger_write_log(const char *msg) +{ + ssize_t ret; + ssize_t (*func)(const char *); + struct module *owner; + + if (!acpi_debugger_initialized) + return -ENODEV; + mutex_lock(&acpi_debugger.lock); + if (!acpi_debugger.ops) { + ret = -ENODEV; + goto err_lock; + } + if (!try_module_get(acpi_debugger.owner)) { + ret = -ENODEV; + goto err_lock; + } + func = acpi_debugger.ops->write_log; + owner = acpi_debugger.owner; + mutex_unlock(&acpi_debugger.lock); + + ret = func(msg); + + mutex_lock(&acpi_debugger.lock); + module_put(owner); +err_lock: + mutex_unlock(&acpi_debugger.lock); + return ret; +} + +ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length) +{ + ssize_t ret; + ssize_t (*func)(char *, size_t); + struct module *owner; + + if (!acpi_debugger_initialized) + return -ENODEV; + mutex_lock(&acpi_debugger.lock); + if (!acpi_debugger.ops) { + ret = -ENODEV; + goto err_lock; + } + if (!try_module_get(acpi_debugger.owner)) { + ret = -ENODEV; + goto err_lock; + } + func = acpi_debugger.ops->read_cmd; + owner = acpi_debugger.owner; + mutex_unlock(&acpi_debugger.lock); + + ret = func(buffer, buffer_length); + + mutex_lock(&acpi_debugger.lock); + module_put(owner); +err_lock: + mutex_unlock(&acpi_debugger.lock); + return ret; +} + +int acpi_debugger_wait_command_ready(void) +{ + int ret; + int (*func)(bool, char *, size_t); + struct module *owner; + + if (!acpi_debugger_initialized) + return -ENODEV; + mutex_lock(&acpi_debugger.lock); + if (!acpi_debugger.ops) { + ret = -ENODEV; + goto err_lock; + } + if (!try_module_get(acpi_debugger.owner)) { + ret = -ENODEV; + goto err_lock; + } + func = acpi_debugger.ops->wait_command_ready; + owner = acpi_debugger.owner; + mutex_unlock(&acpi_debugger.lock); + + ret = func(acpi_gbl_method_executing, + acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE); + + mutex_lock(&acpi_debugger.lock); + module_put(owner); +err_lock: + mutex_unlock(&acpi_debugger.lock); + return ret; +} + +int acpi_debugger_notify_command_complete(void) +{ + int ret; + int (*func)(void); + struct module *owner; + + if (!acpi_debugger_initialized) + return -ENODEV; + mutex_lock(&acpi_debugger.lock); + if (!acpi_debugger.ops) { + ret = -ENODEV; + goto err_lock; + } + if (!try_module_get(acpi_debugger.owner)) { + ret = -ENODEV; + goto err_lock; + } + func = acpi_debugger.ops->notify_command_complete; + owner = acpi_debugger.owner; + mutex_unlock(&acpi_debugger.lock); + + ret = func(); + + mutex_lock(&acpi_debugger.lock); + module_put(owner); +err_lock: + mutex_unlock(&acpi_debugger.lock); + return ret; +} + +int __init acpi_debugger_init(void) +{ + mutex_init(&acpi_debugger.lock); + acpi_debugger_initialized = true; + return 0; +} +#endif + /******************************************************************************* * * FUNCTION: acpi_os_execute @@ -1130,7 +1324,7 @@ acpi_status acpi_os_execute(acpi_execute_type type, function, context)); if (type == OSL_DEBUGGER_MAIN_THREAD) { - ret = acpi_aml_create_thread(function, context); + ret = acpi_debugger_create_thread(function, context); if (ret) { pr_err("Call to kthread_create() failed.\n"); status = AE_ERROR; @@ -1380,7 +1574,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) #else int ret; - ret = acpi_aml_read_cmd(buffer, buffer_length); + ret = acpi_debugger_read_cmd(buffer, buffer_length); if (ret < 0) return AE_ERROR; if (bytes_read) @@ -1389,12 +1583,13 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) return AE_OK; } +EXPORT_SYMBOL(acpi_os_get_line); acpi_status acpi_os_wait_command_ready(void) { int ret; - ret = acpi_aml_wait_command_ready(); + ret = acpi_debugger_wait_command_ready(); if (ret < 0) return AE_ERROR; return AE_OK; @@ -1404,7 +1599,7 @@ acpi_status acpi_os_notify_command_complete(void) { int ret; - ret = acpi_aml_notify_command_complete(); + ret = acpi_debugger_notify_command_complete(); if (ret < 0) return AE_ERROR; return AE_OK; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 1991aea..a03a054 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -119,6 +121,75 @@ typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table); typedef int (*acpi_tbl_entry_handler)(struct acpi_subtable_header *header, const unsigned long end); +/* Debugger support */ + +struct acpi_debugger_ops { + int (*create_thread)(acpi_osd_exec_callback function, void *context); + ssize_t (*write_log)(const char *msg); + ssize_t (*read_cmd)(char *buffer, size_t length); + int (*wait_command_ready)(bool single_step, char *buffer, size_t length); + int (*notify_command_complete)(void); +}; + +struct acpi_debugger { + const struct acpi_debugger_ops *ops; + struct module *owner; + struct mutex lock; +}; + +#ifdef CONFIG_ACPI_DEBUGGER +int __init acpi_debugger_init(void); +int acpi_register_debugger(struct module *owner, + const struct acpi_debugger_ops *ops); +void acpi_unregister_debugger(const struct acpi_debugger_ops *ops); +int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context); +ssize_t acpi_debugger_write_log(const char *msg); +ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length); +int acpi_debugger_wait_command_ready(void); +int acpi_debugger_notify_command_complete(void); +#else +static inline int acpi_debugger_init(void) +{ + return -ENODEV; +} + +static inline int acpi_register_debugger(struct module *owner, + const struct acpi_debugger_ops *ops) +{ + return -ENODEV; +} + +static inline void acpi_unregister_debugger(const struct acpi_debugger_ops *ops) +{ +} + +static inline int acpi_debugger_create_thread(acpi_osd_exec_callback function, + void *context) +{ + return -ENODEV; +} + +static inline int acpi_debugger_write_log(const char *msg) +{ + return -ENODEV; +} + +static inline int acpi_debugger_read_cmd(char *buffer, u32 buffer_length) +{ + return -ENODEV; +} + +static inline int acpi_debugger_wait_command_ready(void) +{ + return -ENODEV; +} + +static inline int acpi_debugger_notify_command_complete(void) +{ + return -ENODEV; +} +#endif + #ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE void acpi_initrd_override(void *data, size_t size); #else diff --git a/include/linux/acpi_dbg.h b/include/linux/acpi_dbg.h deleted file mode 100644 index 60f3887..0000000 --- a/include/linux/acpi_dbg.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ACPI AML interfacing support - * - * Copyright (C) 2015, Intel Corporation - * Authors: Lv Zheng - * - * 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. - */ - -#ifndef _LINUX_ACPI_DBG_H -#define _LINUX_ACPI_DBG_H - -#include - -#ifdef CONFIG_ACPI_DEBUGGER -int __init acpi_aml_init(void); -int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context); -ssize_t acpi_aml_write_log(const char *msg); -ssize_t acpi_aml_read_cmd(char *buffer, size_t buffer_length); -int acpi_aml_wait_command_ready(void); -int acpi_aml_notify_command_complete(void); -#else -static int inline acpi_aml_init(void) -{ - return 0; -} -static inline int acpi_aml_create_thread(acpi_osd_exec_callback function, - void *context) -{ - return -ENODEV; -} -static inline int acpi_aml_write_log(const char *msg) -{ - return -ENODEV; -} -static inline int acpi_aml_read_cmd(char *buffer, u32 buffer_length) -{ - return -ENODEV; -} -static inline int acpi_aml_wait_command_ready(void) -{ - return -ENODEV; -} -static inline int acpi_aml_notify_command_complete(void) -{ - return -ENODEV; -} -#endif - -#endif /* _LINUX_ACPI_DBG_H */ -- cgit v0.10.2 From 94e8057b8420ca6eea90df76f8598639d0df26ec Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 13 Dec 2015 18:57:10 -0500 Subject: drivers/cpuidle: make cpuidle-clps711x.c explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/cpuidle/Kconfig.arm:config ARM_CLPS711X_CPUIDLE drivers/cpuidle/Kconfig.arm: bool "CPU Idle Driver for CLPS711X processors" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Acked-by: Daniel Lezcano Signed-off-by: Paul Gortmaker Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-clps711x.c b/drivers/cpuidle/cpuidle-clps711x.c index 18a7f73..66a9f23 100644 --- a/drivers/cpuidle/cpuidle-clps711x.c +++ b/drivers/cpuidle/cpuidle-clps711x.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #define CLPS711X_CPUIDLE_NAME "clps711x-cpuidle" @@ -56,8 +56,4 @@ static struct platform_driver clps711x_cpuidle_driver = { .name = CLPS711X_CPUIDLE_NAME, }, }; -module_platform_driver_probe(clps711x_cpuidle_driver, clps711x_cpuidle_probe); - -MODULE_AUTHOR("Alexander Shiyan "); -MODULE_DESCRIPTION("CLPS711X CPU idle driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver_probe(clps711x_cpuidle_driver, clps711x_cpuidle_probe); -- cgit v0.10.2 From fdc7d515adc302030f7e4113959130bd8d123546 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 13 Dec 2015 18:57:11 -0500 Subject: drivers/cpuidle: make cpuidle-ux500.c explicitly non-modular The Kconfig currently controlling compilation of this code is: cpuidle/Kconfig.arm:config ARM_U8500_CPUIDLE cpuidle/Kconfig.arm: bool "Cpu Idle Driver for the ST-E u8500 processors" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modularity so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Acked-by: Daniel Lezcano Signed-off-by: Paul Gortmaker Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c index 8bf895c..7941a09 100644 --- a/drivers/cpuidle/cpuidle-ux500.c +++ b/drivers/cpuidle/cpuidle-ux500.c @@ -9,7 +9,7 @@ * published by the Free Software Foundation. */ -#include +#include #include #include #include @@ -124,5 +124,4 @@ static struct platform_driver dbx500_cpuidle_plat_driver = { }, .probe = dbx500_cpuidle_probe, }; - -module_platform_driver(dbx500_cpuidle_plat_driver); +builtin_platform_driver(dbx500_cpuidle_plat_driver); -- cgit v0.10.2 From 84599238ea78d98136fc6f6239a14083128ecf8b Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 13 Dec 2015 18:57:12 -0500 Subject: drivers/cpuidle: make cpuidle-exynos.c explicitly non-modular The Kconfig currently controlling compilation of this code is: cpuidle/Kconfig.arm:config ARM_EXYNOS_CPUIDLE cpuidle/Kconfig.arm: bool "Cpu Idle Driver for the Exynos processors" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modularity so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Acked-by: Daniel Lezcano Signed-off-by: Paul Gortmaker Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c index b5f0a9c..00cd129 100644 --- a/drivers/cpuidle/cpuidle-exynos.c +++ b/drivers/cpuidle/cpuidle-exynos.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -142,5 +142,4 @@ static struct platform_driver exynos_cpuidle_driver = { .name = "exynos_cpuidle", }, }; - -module_platform_driver(exynos_cpuidle_driver); +builtin_platform_driver(exynos_cpuidle_driver); -- cgit v0.10.2 From a436b6a19f57656a6557439523923d89eb4a880d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Dec 2015 02:54:26 +0100 Subject: PM / runtime: Add new helper for conditional usage count incrementation Introduce a new runtime PM function, pm_runtime_get_if_in_use(), that will increment the device's runtime PM usage counter and return 1 if its status is RPM_ACTIVE and its usage counter is greater than 0 at the same time (0 will be returned otherwise). This is useful for things that should only be done if the device is active (from the runtime PM perspective) and used by somebody (as indicated by the usage counter) already and they are not worth bothering otherwise. Requested-by: Imre Deak Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 0784bc3..7328cf8 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -371,6 +371,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: - increment the device's usage counter, run pm_runtime_resume(dev) and return its result + int pm_runtime_get_if_in_use(struct device *dev); + - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the + runtime PM status is RPM_ACTIVE and the runtime PM usage counter is + nonzero, increment the counter and return 1; otherwise return 0 without + changing the counter + void pm_runtime_put_noidle(struct device *dev); - decrement the device's usage counter diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index ab3fcd9..4c70550 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -966,6 +966,30 @@ int __pm_runtime_resume(struct device *dev, int rpmflags) EXPORT_SYMBOL_GPL(__pm_runtime_resume); /** + * pm_runtime_get_if_in_use - Conditionally bump up the device's usage counter. + * @dev: Device to handle. + * + * Return -EINVAL if runtime PM is disabled for the device. + * + * If that's not the case and if the device's runtime PM status is RPM_ACTIVE + * and the runtime PM usage counter is nonzero, increment the counter and + * return 1. Otherwise return 0 without changing the counter. + */ +int pm_runtime_get_if_in_use(struct device *dev) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&dev->power.lock, flags); + retval = dev->power.disable_depth > 0 ? -EINVAL : + dev->power.runtime_status == RPM_ACTIVE + && atomic_inc_not_zero(&dev->power.usage_count); + spin_unlock_irqrestore(&dev->power.lock, flags); + return retval; +} +EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use); + +/** * __pm_runtime_set_status - Set runtime PM status of a device. * @dev: Device to handle. * @status: New runtime PM status of the device. diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 3bdbb41..7af093d 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -39,6 +39,7 @@ extern int pm_runtime_force_resume(struct device *dev); extern int __pm_runtime_idle(struct device *dev, int rpmflags); extern int __pm_runtime_suspend(struct device *dev, int rpmflags); extern int __pm_runtime_resume(struct device *dev, int rpmflags); +extern int pm_runtime_get_if_in_use(struct device *dev); extern int pm_schedule_suspend(struct device *dev, unsigned int delay); extern int __pm_runtime_set_status(struct device *dev, unsigned int status); extern int pm_runtime_barrier(struct device *dev); @@ -143,6 +144,10 @@ static inline int pm_schedule_suspend(struct device *dev, unsigned int delay) { return -ENOSYS; } +static inline int pm_runtime_get_if_in_use(struct device *dev) +{ + return -EINVAL; +} static inline int __pm_runtime_set_status(struct device *dev, unsigned int status) { return 0; } static inline int pm_runtime_barrier(struct device *dev) { return 0; } -- cgit v0.10.2 From 50fe763cc8fa00bef9ff78e58645dbfdcaa998da Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 15 Dec 2015 08:37:39 -0800 Subject: ACPI / bus: Tidy up _OSC error spacing The whitespace in _OSC error reports is weird. Improve it. Acked-by: Bjorn Helgaas Signed-off-by: Andy Lutomirski Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a212cef..2177ef0 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -182,12 +182,12 @@ static void acpi_print_osc_error(acpi_handle handle, if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) printk(KERN_DEBUG "%s\n", error); else { - printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); + printk(KERN_DEBUG "%s: %s\n", (char *)buffer.pointer, error); kfree(buffer.pointer); } - printk(KERN_DEBUG"_OSC request data:"); + printk(KERN_DEBUG "_OSC request data:"); for (i = 0; i < context->cap.length; i += sizeof(u32)) - printk("%x ", *((u32 *)(context->cap.pointer + i))); + printk(" %x", *((u32 *)(context->cap.pointer + i))); printk("\n"); } -- cgit v0.10.2 From 76c599bcab26795b0669694e1e32a78274cb901b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 15 Dec 2015 08:37:40 -0800 Subject: ACPI / bus: Show _OSC UUID when _OSC fails When _OSC fails and especially when it fails due to an invalid UUID, it's helpful to show the UUID that we tried. Acked-by: Bjorn Helgaas Signed-off-by: Andy Lutomirski Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2177ef0..fcfdf6c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -180,9 +180,10 @@ static void acpi_print_osc_error(acpi_handle handle, int i; if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) - printk(KERN_DEBUG "%s\n", error); + printk(KERN_DEBUG "%s: %s\n", context->uuid_str, error); else { - printk(KERN_DEBUG "%s: %s\n", (char *)buffer.pointer, error); + printk(KERN_DEBUG "%s (%s): %s\n", + (char *)buffer.pointer, context->uuid_str, error); kfree(buffer.pointer); } printk(KERN_DEBUG "_OSC request data:"); -- cgit v0.10.2 From 73af2d590ab1b7bc7c3fc3e6933d5dcd379c9c2e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 24 Dec 2015 14:16:26 +0800 Subject: ACPI / debugger: Fix an issue a flag is modified without locking There is one line of code, executed out of locking due to rebase mistakes. This patch fixes this issue. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index 381beb2..fa18bd0 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -516,10 +516,10 @@ static int acpi_aml_open(struct inode *inode, struct file *file) ret = -EINVAL; goto err_lock; } - acpi_aml_io.flags |= ACPI_AML_OPENED; pr_debug("Debugger thread initialized.\n"); mutex_lock(&acpi_aml_io.lock); + acpi_aml_io.flags |= ACPI_AML_OPENED; acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0; acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0; pr_debug("Debugger interface opened.\n"); -- cgit v0.10.2 From 436db5ce0d0e892d2f7327dd7ffd573c5fb9e6cb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Dec 2015 10:23:03 +0300 Subject: ACPI / debugger: remove some unneeded conditions "count" is unsigned so checking for less than zero here causes a static checker warning. And really it's better to let the access_ok() check fail if the user passes in a NULL "buf" pointer because -EFAULT is the correct error code. Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index fa18bd0..975ccec 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -610,8 +610,6 @@ static ssize_t acpi_aml_read(struct file *file, char __user *buf, int ret = 0; int size = 0; - if (!buf || count < 0) - return -EINVAL; if (!count) return 0; if (!access_ok(VERIFY_WRITE, buf, count)) @@ -681,8 +679,6 @@ static ssize_t acpi_aml_write(struct file *file, const char __user *buf, int ret = 0; int size = 0; - if (!buf || count < 0) - return -EINVAL; if (!count) return 0; if (!access_ok(VERIFY_READ, buf, count)) -- cgit v0.10.2 From ec74765d9f592715292b8b33689a6af6db4cf5c5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Dec 2015 10:24:37 +0300 Subject: ACPI / debugger: copy_to_user doesn't return errors The copy_to/from_user() functions don't return error codes, they return the number of bytes remaining. We had intended to return -EFUALT here. We actually have already checked access_ok() in an earlier function so I don't think these functions will fail but let's fix it anyway. Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index 975ccec..e8d1698 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -592,9 +592,10 @@ static int acpi_aml_read_user(char __user *buf, int len) smp_rmb(); p = &crc->buf[crc->tail]; n = min(len, circ_count_to_end(crc)); - ret = copy_to_user(buf, p, n); - if (IS_ERR_VALUE(ret)) + if (copy_to_user(buf, p, n)) { + ret = -EFAULT; goto out; + } /* sync tail after removing logs */ smp_mb(); crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); @@ -661,9 +662,10 @@ static int acpi_aml_write_user(const char __user *buf, int len) smp_mb(); p = &crc->buf[crc->head]; n = min(len, circ_space_to_end(crc)); - ret = copy_from_user(p, buf, n); - if (IS_ERR_VALUE(ret)) + if (copy_from_user(p, buf, n)) { + ret = -EFAULT; goto out; + } /* sync head after inserting cmds */ smp_wmb(); crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); -- cgit v0.10.2 From 59adb3988ebeec012343317ac783d6a7935e0c83 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 25 Dec 2015 11:22:32 +0800 Subject: ACPI / debugger: Fix a redundant mutex unlock issue in acpi_aml_open() Fix a double mutex_unlock() issue where acpi_initialize_debugger() is called with the mutex already unlocked. Reported-by: Dan Carpenter Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index e8d1698..15e4604 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -514,7 +514,7 @@ static int acpi_aml_open(struct inode *inode, struct file *file) if (ACPI_FAILURE(status)) { pr_err("Failed to initialize debugger.\n"); ret = -EINVAL; - goto err_lock; + goto err_exit; } pr_debug("Debugger thread initialized.\n"); @@ -531,6 +531,7 @@ err_lock: acpi_aml_active_reader = NULL; } mutex_unlock(&acpi_aml_io.lock); +err_exit: return ret; } -- cgit v0.10.2 From fd8d8e63467c922be9ae4452cca2980d473477d9 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 17 Dec 2015 19:04:38 +0100 Subject: PM / OPP: Fix parsing of opp-microvolt and opp-microamp properties Commit 01fb4d3c39d3 ("PM / OPP: Parse 'opp--' bindings") broke support for parsing standard opp-microvolt and opp-microamp properties. Fix it by setting 'name' string to proper value for !prop cases. Fixes: 01fb4d3c39d3 ("PM / OPP: Parse 'opp-- 'bindings") Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 5c01fec..cd230c6 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -814,7 +814,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, if (!prop) { /* Search for "opp-microvolt" */ - name[13] = '\0'; + sprintf(name, "opp-microvolt"); prop = of_find_property(opp->np, name, NULL); /* Missing property isn't a problem, but an invalid entry is */ @@ -855,7 +855,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, if (!prop) { /* Search for "opp-microamp" */ - name[12] = '\0'; + sprintf(name, "opp-microamp"); prop = of_find_property(opp->np, name, NULL); } -- cgit v0.10.2 From a5810b4f078f4a41ff47668d7e3351b903ab959f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 21 Dec 2015 21:56:27 +0100 Subject: blackfin-cpufreq: Change return type of cpu_set_cclk() to that of clk_set_rate() The return type "unsigned long" was used by the cpu_set_cclk() function while the type "int" is provided by the clk_set_rate() function. Let us make this usage consistent. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c index a9f8e5b..2a6f3ac 100644 --- a/drivers/cpufreq/blackfin-cpufreq.c +++ b/drivers/cpufreq/blackfin-cpufreq.c @@ -112,7 +112,7 @@ static unsigned int bfin_getfreq_khz(unsigned int cpu) } #ifdef CONFIG_BF60x -unsigned long cpu_set_cclk(int cpu, unsigned long new) +int cpu_set_cclk(int cpu, unsigned long new) { struct clk *clk; int ret; -- cgit v0.10.2 From d23f8cadf99b553eaa78544c53e96f3aec456530 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 21 Dec 2015 22:12:26 +0100 Subject: blackfin-cpufreq: Mark cpu_set_cclk() as static The cpu_set_cclk() function was only used in a single source file so far. Indicate this setting also by the corresponding linkage specifier. Signed-off-by: Markus Elfring Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c index 2a6f3ac..12e97d8 100644 --- a/drivers/cpufreq/blackfin-cpufreq.c +++ b/drivers/cpufreq/blackfin-cpufreq.c @@ -112,7 +112,7 @@ static unsigned int bfin_getfreq_khz(unsigned int cpu) } #ifdef CONFIG_BF60x -int cpu_set_cclk(int cpu, unsigned long new) +static int cpu_set_cclk(int cpu, unsigned long new) { struct clk *clk; int ret; -- cgit v0.10.2 From d76eebfa175e86383324ad2bbaf472866950398b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 1 Jan 2016 02:07:09 +0100 Subject: include/linux/property.h: fix build issues with gcc-4.4.4 gcc-4.4.4 has problems with initialization of anonymous unions: drivers/mfd/intel-lpss-acpi.c:30: error: unknown field 'value' specified in initializer work around this by crafting the initializers in a manner which the compiler can handle. Signed-off-by: Andrew Morton Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/property.h b/include/linux/property.h index 3a8c7d7..b8c4e42 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -175,12 +175,19 @@ struct property_entry { }; }; +/* + * Note: the below four initializers for the anonymous union are carefully + * crafted to avoid gcc-4.4.4's problems with initialization of anon unions + * and structs. + */ + #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ { \ .name = _name_, \ .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ .is_array = true, \ - .pointer._type_##_data = _val_, \ + .is_string = false, \ + { .pointer = { _type_##_data = _val_ } }, \ } #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ @@ -198,14 +205,15 @@ struct property_entry { .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ .is_array = true, \ .is_string = true, \ - .pointer.str = _val_, \ + { .pointer = { .str = _val_ } }, \ } #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ { \ .name = _name_, \ .length = sizeof(_type_), \ - .value._type_##_data = _val_, \ + .is_string = false, \ + { .value = { ._type_##_data = _val_ } }, \ } #define PROPERTY_ENTRY_U8(_name_, _val_) \ @@ -222,7 +230,7 @@ struct property_entry { .name = _name_, \ .length = sizeof(_val_), \ .is_string = true, \ - .value.str = _val_, \ + { .value = {.str = _val_} }, \ } #define PROPERTY_ENTRY_BOOL(_name_) \ -- cgit v0.10.2 From aace7367bf83aef7baa021c7bcc9d2e331b040aa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 29 Dec 2015 13:07:48 +0200 Subject: device property: add spaces to PROPERTY_ENTRY_STRING macro Just a style fix, no functional changes. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/property.h b/include/linux/property.h index b8c4e42..b51fcd3 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -230,7 +230,7 @@ struct property_entry { .name = _name_, \ .length = sizeof(_val_), \ .is_string = true, \ - { .value = {.str = _val_} }, \ + { .value = { .str = _val_ } }, \ } #define PROPERTY_ENTRY_BOOL(_name_) \ -- cgit v0.10.2 From 0fb5902f2f9ec7996a0846087f3e69165ea9ce1e Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Tue, 29 Dec 2015 13:07:49 +0200 Subject: device property: the secondary fwnode needs to depend on the primary This fixes NULL pointer dereference when the primary fwnode handle does not exist, for example with PCI devices that do not have ACPI companion. Signed-off-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index 0b22c8a..b3429cc 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -218,7 +218,7 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) bool ret; ret = __fwnode_property_present(fwnode, propname); - if (ret == false && fwnode->secondary) + if (ret == false && fwnode && fwnode->secondary) ret = __fwnode_property_present(fwnode->secondary, propname); return ret; } @@ -423,7 +423,7 @@ EXPORT_SYMBOL_GPL(device_property_match_string); int _ret_; \ _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \ _val_, _nval_); \ - if (_ret_ == -EINVAL && _fwnode_->secondary) \ + if (_ret_ == -EINVAL && _fwnode_ && _fwnode_->secondary) \ _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \ _proptype_, _val_, _nval_); \ _ret_; \ @@ -593,7 +593,7 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, int ret; ret = __fwnode_property_read_string_array(fwnode, propname, val, nval); - if (ret == -EINVAL && fwnode->secondary) + if (ret == -EINVAL && fwnode && fwnode->secondary) ret = __fwnode_property_read_string_array(fwnode->secondary, propname, val, nval); return ret; @@ -621,7 +621,7 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, int ret; ret = __fwnode_property_read_string(fwnode, propname, val); - if (ret == -EINVAL && fwnode->secondary) + if (ret == -EINVAL && fwnode && fwnode->secondary) ret = __fwnode_property_read_string(fwnode->secondary, propname, val); return ret; -- cgit v0.10.2 From f6740c1899d2ee2c4c9ec5301d4b712d4e706a79 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 29 Dec 2015 13:07:50 +0200 Subject: device property: avoid allocations of 0 length Arrays can not have zero elements by definition of the unified device properties. If such property comes from outside we should not allow it to pass. Otherwise memory allocation on 0 length will return non-NULL value, which we currently don't check. Prevent memory allocations of 0 length. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/property.c b/drivers/base/property.c index b3429cc..c359351 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -653,6 +653,9 @@ int fwnode_property_match_string(struct fwnode_handle *fwnode, if (nval < 0) return nval; + if (nval == 0) + return -ENODATA; + values = kcalloc(nval, sizeof(*values), GFP_KERNEL); if (!values) return -ENOMEM; @@ -718,6 +721,9 @@ static int pset_copy_entry(struct property_entry *dst, return -ENOMEM; if (src->is_array) { + if (!src->length) + return -ENODATA; + if (src->is_string) { nval = src->length / sizeof(const char *); dst->pointer.str = kcalloc(nval, sizeof(const char *), -- cgit v0.10.2 From b5bd0269547105046f2236d9895bd5e3038cc8bc Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 9 Dec 2015 11:18:27 -0500 Subject: ACPI, PCI, irq: remove interrupt count restriction Code currently supports 256 maximum interrupts at this moment. The patch is reconfiguring the penalty array as a dynamic list to remove this limitation. A new penalty linklist has been added for all other interrupts greater than 16. If an IRQ is not found in the link list, an IRQ info structure will be dynamically allocated on the first access and will be placed on the list for further reuse. The list will grow by the number of supported interrupts in the ACPI table rather than having a 256 hard limitation. Acked-by: Bjorn Helgaas Signed-off-by: Sinan Kaya Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 7c8408b..0286f17 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -4,6 +4,7 @@ * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh * Copyright (C) 2002 Dominik Brodowski + * Copyright (c) 2015, The Linux Foundation. All rights reserved. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -437,7 +438,6 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) * enabled system. */ -#define ACPI_MAX_IRQS 256 #define ACPI_MAX_ISA_IRQ 16 #define PIRQ_PENALTY_PCI_AVAILABLE (0) @@ -447,7 +447,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) -static int acpi_irq_penalty[ACPI_MAX_IRQS] = { +static int acpi_irq_isa_penalty[ACPI_MAX_ISA_IRQ] = { PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ @@ -464,9 +464,68 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = { PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ - /* >IRQ15 */ }; +struct irq_penalty_info { + int irq; + int penalty; + struct list_head node; +}; + +static LIST_HEAD(acpi_irq_penalty_list); + +static int acpi_irq_get_penalty(int irq) +{ + struct irq_penalty_info *irq_info; + + if (irq < ACPI_MAX_ISA_IRQ) + return acpi_irq_isa_penalty[irq]; + + list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) { + if (irq_info->irq == irq) + return irq_info->penalty; + } + + return 0; +} + +static int acpi_irq_set_penalty(int irq, int new_penalty) +{ + struct irq_penalty_info *irq_info; + + /* see if this is a ISA IRQ */ + if (irq < ACPI_MAX_ISA_IRQ) { + acpi_irq_isa_penalty[irq] = new_penalty; + return 0; + } + + /* next, try to locate from the dynamic list */ + list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) { + if (irq_info->irq == irq) { + irq_info->penalty = new_penalty; + return 0; + } + } + + /* nope, let's allocate a slot for this IRQ */ + irq_info = kzalloc(sizeof(*irq_info), GFP_KERNEL); + if (!irq_info) + return -ENOMEM; + + irq_info->irq = irq; + irq_info->penalty = new_penalty; + list_add_tail(&irq_info->node, &acpi_irq_penalty_list); + + return 0; +} + +static void acpi_irq_add_penalty(int irq, int penalty) +{ + int curpen = acpi_irq_get_penalty(irq); + + acpi_irq_set_penalty(irq, curpen + penalty); +} + int __init acpi_irq_penalty_init(void) { struct acpi_pci_link *link; @@ -487,15 +546,16 @@ int __init acpi_irq_penalty_init(void) link->irq.possible_count; for (i = 0; i < link->irq.possible_count; i++) { - if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) - acpi_irq_penalty[link->irq. - possible[i]] += - penalty; + if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) { + int irqpos = link->irq.possible[i]; + + acpi_irq_add_penalty(irqpos, penalty); + } } } else if (link->irq.active) { - acpi_irq_penalty[link->irq.active] += - PIRQ_PENALTY_PCI_POSSIBLE; + acpi_irq_add_penalty(link->irq.active, + PIRQ_PENALTY_PCI_POSSIBLE); } } @@ -547,12 +607,12 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) * the use of IRQs 9, 10, 11, and >15. */ for (i = (link->irq.possible_count - 1); i >= 0; i--) { - if (acpi_irq_penalty[irq] > - acpi_irq_penalty[link->irq.possible[i]]) + if (acpi_irq_get_penalty(irq) > + acpi_irq_get_penalty(link->irq.possible[i])) irq = link->irq.possible[i]; } } - if (acpi_irq_penalty[irq] >= PIRQ_PENALTY_ISA_ALWAYS) { + if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) { printk(KERN_ERR PREFIX "No IRQ available for %s [%s]. " "Try pci=noacpi or acpi=off\n", acpi_device_name(link->device), @@ -568,7 +628,8 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) acpi_device_bid(link->device)); return -ENODEV; } else { - acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; + acpi_irq_add_penalty(link->irq.active, PIRQ_PENALTY_PCI_USING); + printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", acpi_device_name(link->device), acpi_device_bid(link->device), link->irq.active); @@ -778,7 +839,7 @@ static void acpi_pci_link_remove(struct acpi_device *device) } /* - * modify acpi_irq_penalty[] from cmdline + * modify penalty from cmdline */ static int __init acpi_irq_penalty_update(char *str, int used) { @@ -796,13 +857,10 @@ static int __init acpi_irq_penalty_update(char *str, int used) if (irq < 0) continue; - if (irq >= ARRAY_SIZE(acpi_irq_penalty)) - continue; - if (used) - acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; + acpi_irq_add_penalty(irq, PIRQ_PENALTY_ISA_USED); else - acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE; + acpi_irq_set_penalty(irq, PIRQ_PENALTY_PCI_AVAILABLE); if (retval != 2) /* no next number */ break; @@ -819,18 +877,23 @@ static int __init acpi_irq_penalty_update(char *str, int used) */ void acpi_penalize_isa_irq(int irq, int active) { - if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) { - if (active) - acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; - else - acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; - } + int penalty; + + if (irq < 0) + return; + + if (active) + penalty = PIRQ_PENALTY_ISA_USED; + else + penalty = PIRQ_PENALTY_PCI_USING; + + acpi_irq_add_penalty(irq, penalty); } bool acpi_isa_irq_available(int irq) { - return irq >= 0 && (irq >= ARRAY_SIZE(acpi_irq_penalty) || - acpi_irq_penalty[irq] < PIRQ_PENALTY_ISA_ALWAYS); + return irq >= 0 && + (acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS); } /* @@ -840,13 +903,18 @@ bool acpi_isa_irq_available(int irq) */ void acpi_penalize_sci_irq(int irq, int trigger, int polarity) { - if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) { - if (trigger != ACPI_MADT_TRIGGER_LEVEL || - polarity != ACPI_MADT_POLARITY_ACTIVE_LOW) - acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_ALWAYS; - else - acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; - } + int penalty; + + if (irq < 0) + return; + + if (trigger != ACPI_MADT_TRIGGER_LEVEL || + polarity != ACPI_MADT_POLARITY_ACTIVE_LOW) + penalty = PIRQ_PENALTY_ISA_ALWAYS; + else + penalty = PIRQ_PENALTY_PCI_USING; + + acpi_irq_add_penalty(irq, penalty); } /* -- cgit v0.10.2 From 37c5939136d7ce42b36c5d5b46f5272903a68433 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 9 Dec 2015 11:18:28 -0500 Subject: ACPI, PCI, irq: remove interrupt number restriction The ACPI compiler uses the extended format when used interrupt numbers are greater than 15. The extended IRQ syntax is 32 bits according to the ACPI spec. The code supports parsing the extended interrupt numbers. However, due to used data structure type; the code silently truncates interrupt numbers greater than 256. Acked-by: Bjorn Helgaas Signed-off-by: Sinan Kaya Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 0286f17..5114d80 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -68,12 +68,12 @@ static struct acpi_scan_handler pci_link_handler = { * later even the link is disable. Instead, we just repick the active irq */ struct acpi_pci_link_irq { - u8 active; /* Current IRQ */ + u32 active; /* Current IRQ */ u8 triggering; /* All IRQs */ u8 polarity; /* All IRQs */ u8 resource_type; u8 possible_count; - u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; + u32 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; u8 initialized:1; u8 reserved:7; }; -- cgit v0.10.2 From 90b066b15eda028ed44299f01236f8576dd8551d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Dec 2015 19:09:48 +0100 Subject: ACPI / video: Add a acpi_video_handles_brightness_key_presses() helper Several drivers want to know if the acpi-video is generating key-presses for brightness change hotkeys to avoid sending double key-events to userspace for these. Currently these driver use this construct for this: if (acpi_video_get_backlight_type() == acpi_backlight_vendor) report_brightness_key_event(); This indirect way of detecting if acpi-video is active does not make the code easier to understand, and in some cases it is wrong because just because the preferred type != vendor does not mean that acpi-video is actually listening for brightness events, e.g. there may be no acpi-video bus on the system at all. This commit adds a acpi_video_handles_brightness_key_presses() helper function, making the code needing this functionality both easier to read and more correct. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 3405f7a..2a649f3e 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2072,6 +2072,18 @@ void acpi_video_unregister_backlight(void) mutex_unlock(®ister_count_mutex); } +bool acpi_video_handles_brightness_key_presses(void) +{ + bool have_video_busses; + + mutex_lock(&video_list_lock); + have_video_busses = !list_empty(&video_bus_head); + mutex_unlock(&video_list_lock); + + return have_video_busses; +} +EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); + /* * This is kind of nasty. Hardware using Intel chipsets may require * the video opregion code to be run first in order to initialise diff --git a/include/acpi/video.h b/include/acpi/video.h index c62392d..f11d342 100644 --- a/include/acpi/video.h +++ b/include/acpi/video.h @@ -2,6 +2,7 @@ #define __ACPI_VIDEO_H #include /* for ENODEV */ +#include /* for bool */ struct acpi_device; @@ -31,6 +32,7 @@ extern int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, void **edid); extern enum acpi_backlight_type acpi_video_get_backlight_type(void); extern void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type); +extern bool acpi_video_handles_brightness_key_presses(void); #else static inline int acpi_video_register(void) { return 0; } static inline void acpi_video_unregister(void) { return; } @@ -46,6 +48,10 @@ static inline enum acpi_backlight_type acpi_video_get_backlight_type(void) static inline void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type) { } +static inline bool acpi_video_handles_brightness_key_presses(void) +{ + return false; +} #endif #endif -- cgit v0.10.2 From 61679c725553ccffd8b281955186410550bd1eaf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Dec 2015 19:09:49 +0100 Subject: dell-wmi: Use acpi_video_handles_brightness_key_presses() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new acpi_video_handles_brightness_key_presses function to check if we should report brightness key-presses. This makes the code both easier to read and makes it properly report key-presses when acpi-video is not reporting them for reasons other then the backlight type being vendor. Signed-off-by: Hans de Goede Acked-by: Pali Rohár Signed-off-by: Rafael J. Wysocki diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index f2d77fe..cb8a9c2 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -43,8 +43,6 @@ MODULE_LICENSE("GPL"); #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" -static int acpi_video; - MODULE_ALIAS("wmi:"DELL_EVENT_GUID); /* @@ -159,7 +157,8 @@ static void dell_wmi_process_key(int reported_key) /* Don't report brightness notifications that will also come via ACPI */ if ((key->keycode == KEY_BRIGHTNESSUP || - key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) + key->keycode == KEY_BRIGHTNESSDOWN) && + acpi_video_handles_brightness_key_presses()) return; sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); @@ -398,7 +397,6 @@ static int __init dell_wmi_init(void) } dmi_walk(find_hk_type, NULL); - acpi_video = acpi_video_get_backlight_type() != acpi_backlight_vendor; err = dell_wmi_input_setup(); if (err) -- cgit v0.10.2 From 7714687a2b2d4afcfac8c3bcc99ace16efa98882 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Dec 2015 19:09:50 +0100 Subject: thinkpad_acpi: Use acpi_video_handles_brightness_key_presses() Use the new acpi_video_handles_brightness_key_presses function to check if we should report brightness key-presses. This makes the code both easier to read and makes it properly report key-presses when acpi-video is not reporting them for reasons other then the backlight type being vendor. Signed-off-by: Hans de Goede Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 0bed473..f453d5d 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3488,7 +3488,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* Do not issue duplicate brightness change events to * userspace. tpacpi_detect_brightness_capabilities() must have * been called before this point */ - if (acpi_video_get_backlight_type() != acpi_backlight_vendor) { + if (acpi_video_handles_brightness_key_presses()) { pr_info("This ThinkPad has standard ACPI backlight " "brightness control, supported by the ACPI " "video driver\n"); -- cgit v0.10.2 From 05bc59a079eaa6c38b049473fe62fab84d934802 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Dec 2015 19:09:51 +0100 Subject: ACPI / video: Add a module option to disable the reporting of keypresses Add a module option to disable the reporting of keypresses, in some buggy firmware implementatinon, the reported events are wrong. E.g. they lag reality by one event in the case triggering the writing of this patch. In this case it is better to not forward these wrong events to userspace (esp.) when there is another source of the same events which is not buggy. Note this is only intended to work around implementations which send events which are plain wrong. In some cases we get double events, e.g. from both acpi-video and the atkbd driver, in this case acpi-video is considered the canonical source, and the events from the other source should be filtered (using e.g. /lib/udev/hwdb.d/60-keyboard.hwdb). Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 2a649f3e..2971154 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -77,6 +77,13 @@ module_param(allow_duplicates, bool, 0644); static int disable_backlight_sysfs_if = -1; module_param(disable_backlight_sysfs_if, int, 0444); +#define REPORT_OUTPUT_KEY_EVENTS 0x01 +#define REPORT_BRIGHTNESS_KEY_EVENTS 0x02 +static int report_key_events = -1; +module_param(report_key_events, int, 0644); +MODULE_PARM_DESC(report_key_events, + "0: none, 1: output changes, 2: brightness changes, 3: all"); + static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); @@ -1480,7 +1487,7 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) /* Something vetoed the keypress. */ keycode = 0; - if (keycode) { + if (keycode && (report_key_events & REPORT_OUTPUT_KEY_EVENTS)) { input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); @@ -1544,7 +1551,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) acpi_notifier_call_chain(device, event, 0); - if (keycode) { + if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) { input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); @@ -2080,7 +2087,8 @@ bool acpi_video_handles_brightness_key_presses(void) have_video_busses = !list_empty(&video_bus_head); mutex_unlock(&video_list_lock); - return have_video_busses; + return have_video_busses && + (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS); } EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); -- cgit v0.10.2 From 4b4b3b20e8e645be103cf737827372f86479867a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Dec 2015 19:09:52 +0100 Subject: ACPI / video: Add quirks for the Dell Vostro V131 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Dell Vostro V131 has an especially broken acpi-video implementation. The backlight control bits work, but when the brightness is changed via the acpi-video interface the backlight flickers annoyingly before settling at the new brightness, switching to using the native interface fixes the flickering so add a quirk for this (the vendor interface has the same problem). Brightness keypresses reported through the acpi-video-bus are also broken, they get reported one event delayed, so if you press the brightness-up hotkey on the keyboard nothing happens, then if you press brightness-down, the previous brightness-up event gets reported. Since the keypresses are also reported via wmi (if active) and via atkbd (when wmi is not active) add a quirk to simply filter out the delayed (broken) events. Reported-and-tested-by: Michał Kępień Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 2971154..80b13d4 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -419,6 +419,13 @@ static int video_enable_only_lcd(const struct dmi_system_id *d) return 0; } +static int video_set_report_key_events(const struct dmi_system_id *id) +{ + if (report_key_events == -1) + report_key_events = (uintptr_t)id->driver_data; + return 0; +} + static struct dmi_system_id video_dmi_table[] = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -507,6 +514,24 @@ static struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"), }, }, + /* + * Some machines report wrong key events on the acpi-bus, suppress + * key event reporting on these. Note this is only intended to work + * around events which are plain wrong. In some cases we get double + * events, in this case acpi-video is considered the canonical source + * and the events from the other source should be filtered. E.g. + * by calling acpi_video_handles_brightness_key_presses() from the + * vendor acpi/wmi driver or by using /lib/udev/hwdb.d/60-keyboard.hwdb + */ + { + .callback = video_set_report_key_events, + .driver_data = (void *)((uintptr_t)REPORT_OUTPUT_KEY_EVENTS), + .ident = "Dell Vostro V131", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), + }, + }, {} }; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index daaf1c4..8fe2682 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -279,6 +279,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"), }, }, + { + .callback = video_detect_force_native, + .ident = "Dell Vostro V131", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), + }, + }, { }, }; -- cgit v0.10.2 From 49eb5208220a9eef7529decbdefd95e4b94a928b Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Wed, 30 Dec 2015 13:11:24 +0800 Subject: ACPI / video: Add a quirk to force acpi-video backlight on SAMSUNG 530U4E/540U4E The native interface on SAMSUNG 530U4E/540U4E doesn't work even though the firmware claims Win8 compatible while the acpi_video interface works, add a quirk for this. Link: https://bugzilla.kernel.org/show_bug.cgi?id=108971 Reported-and-tested-by: adam bk Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 8fe2682..90e2d54 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -250,6 +250,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"), }, }, + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=108971 */ + .callback = video_detect_force_video, + .ident = "SAMSUNG 530U4E/540U4E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"), + }, + }, /* Non win8 machines which need native backlight nevertheless */ { -- cgit v0.10.2 From 55a93417c27c6ad1022d5f1121004c494735e8fa Mon Sep 17 00:00:00 2001 From: Christophe RICARD Date: Wed, 23 Dec 2015 23:25:33 +0100 Subject: ACPI: Rename acpi_gsi_get_irq_type to acpi_dev_get_irq_type and export symbol acpi_gsi_get_irq_type could be use out of GSI purpose. Rename and make it available as a resource function. Acked-by: Mika Westerberg Signed-off-by: Christophe Ricard Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index fa4585a..ee9e0f2 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -17,25 +17,6 @@ enum acpi_irq_model_id acpi_irq_model; static struct fwnode_handle *acpi_gsi_domain_id; -static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity) -{ - switch (polarity) { - case ACPI_ACTIVE_LOW: - return trigger == ACPI_EDGE_SENSITIVE ? - IRQ_TYPE_EDGE_FALLING : - IRQ_TYPE_LEVEL_LOW; - case ACPI_ACTIVE_HIGH: - return trigger == ACPI_EDGE_SENSITIVE ? - IRQ_TYPE_EDGE_RISING : - IRQ_TYPE_LEVEL_HIGH; - case ACPI_ACTIVE_BOTH: - if (trigger == ACPI_EDGE_SENSITIVE) - return IRQ_TYPE_EDGE_BOTH; - default: - return IRQ_TYPE_NONE; - } -} - /** * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI * @gsi: GSI IRQ number to map @@ -82,7 +63,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, fwspec.fwnode = acpi_gsi_domain_id; fwspec.param[0] = gsi; - fwspec.param[1] = acpi_gsi_get_irq_type(trigger, polarity); + fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); fwspec.param_count = 2; return irq_create_fwspec_mapping(&fwspec); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index cdc5c25..d02fd53 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) @@ -336,6 +337,31 @@ unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable) } EXPORT_SYMBOL_GPL(acpi_dev_irq_flags); +/** + * acpi_dev_get_irq_type - Determine irq type. + * @triggering: Triggering type as provided by ACPI. + * @polarity: Interrupt polarity as provided by ACPI. + */ +unsigned int acpi_dev_get_irq_type(int triggering, int polarity) +{ + switch (polarity) { + case ACPI_ACTIVE_LOW: + return triggering == ACPI_EDGE_SENSITIVE ? + IRQ_TYPE_EDGE_FALLING : + IRQ_TYPE_LEVEL_LOW; + case ACPI_ACTIVE_HIGH: + return triggering == ACPI_EDGE_SENSITIVE ? + IRQ_TYPE_EDGE_RISING : + IRQ_TYPE_LEVEL_HIGH; + case ACPI_ACTIVE_BOTH: + if (triggering == ACPI_EDGE_SENSITIVE) + return IRQ_TYPE_EDGE_BOTH; + default: + return IRQ_TYPE_NONE; + } +} +EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type); + static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) { res->start = gsi; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 1991aea..42adb80 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -318,6 +318,7 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, struct resource_win *win); unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); +unsigned int acpi_dev_get_irq_type(int triggering, int polarity); bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res); -- cgit v0.10.2 From 52044723cd27aed6dad655a3bdf6142a8239ce74 Mon Sep 17 00:00:00 2001 From: Christophe RICARD Date: Wed, 23 Dec 2015 23:25:34 +0100 Subject: ACPI / gpio: Add irq_type when a GPIO is used as an interrupt When a GPIO is used as an interrupt in ACPI, the irq_type was not available for device driver. Make available polarity and triggering information in acpi_find_gpio by renaming acpi_gpio_info field active_low to polarity and adding triggering field (edge/level). For sanity, in gpiolib.c replace info.active_low by "info.polarity == GPIO_ACTIVE_LOW". Set the irq_type if necessary in acpi_dev_gpio_irq_get. Signed-off-by: Christophe Ricard Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 16a7b68..cbbb67a 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -417,10 +417,15 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) * ActiveLow is only specified for GpioInt resource. If * GpioIo is used then the only way to set the flag is * to use _DSD "gpios" property. + * Note: we expect here: + * - ACPI_ACTIVE_LOW == GPIO_ACTIVE_LOW + * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH */ - if (lookup->info.gpioint) - lookup->info.active_low = - agpio->polarity == ACPI_ACTIVE_LOW; + if (lookup->info.gpioint) { + lookup->info.polarity = agpio->polarity; + lookup->info.triggering = agpio->triggering; + } + } return 1; @@ -447,7 +452,7 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, if (info) { *info = lookup->info; if (lookup->active_low) - info->active_low = lookup->active_low; + info->polarity = lookup->active_low; } return 0; } @@ -595,6 +600,7 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { int idx, i; + unsigned int irq_flags; for (i = 0, idx = 0; idx <= index; i++) { struct acpi_gpio_info info; @@ -603,8 +609,23 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) desc = acpi_get_gpiod_by_index(adev, NULL, i, &info); if (IS_ERR(desc)) break; - if (info.gpioint && idx++ == index) - return gpiod_to_irq(desc); + if (info.gpioint && idx++ == index) { + int irq = gpiod_to_irq(desc); + + if (irq < 0) + return irq; + + irq_flags = acpi_dev_get_irq_type(info.triggering, + info.polarity); + + /* Set type if specified and different than the current one */ + if (irq_flags != IRQ_TYPE_NONE && + irq_flags != irq_get_trigger_type(irq)) + irq_set_irq_type(irq, irq_flags); + + return irq; + } + } return -ENOENT; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4e4c308..5d8d7ab 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1879,7 +1879,7 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, return desc; } - if (info.active_low) + if (info.polarity == GPIO_ACTIVE_LOW) *flags |= GPIO_ACTIVE_LOW; return desc; @@ -2217,7 +2217,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, desc = acpi_node_get_gpiod(fwnode, propname, 0, &info); if (!IS_ERR(desc)) - active_low = info.active_low; + active_low = info.polarity == GPIO_ACTIVE_LOW; } if (IS_ERR(desc)) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 98ab08c..5ac3b88 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -26,7 +26,8 @@ struct acpi_device; */ struct acpi_gpio_info { bool gpioint; - bool active_low; + int polarity; + int triggering; }; /* gpio suffixes used for ACPI and device tree lookup */ -- cgit v0.10.2 From 33ada67da352e138b6dbb372dccad6c3f13b15b2 Mon Sep 17 00:00:00 2001 From: Christophe RICARD Date: Wed, 23 Dec 2015 23:25:35 +0100 Subject: ACPI / spi: attach GPIO IRQ from ACPI description to SPI device spi->irq was ignoring GpioInt property setting it to -1. acpi_dev_gpio_irq_get returns and configure the slave IRQ according to the ACPI slave node description. It is now inline with devicetree behavior. Acked-by: Mark Brown Signed-off-by: Christophe Ricard Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index dee1cb8..151b01c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1623,6 +1623,9 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, return AE_OK; } + if (spi->irq < 0) + spi->irq = acpi_dev_gpio_irq_get(adev, 0); + adev->power.flags.ignore_parent = true; strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); if (spi_add_device(spi)) { -- cgit v0.10.2 From 5431b6543fb45f6c61dbb1394c918f3bc5acefae Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 13:52:32 +0800 Subject: ACPICA: Linuxize: reduce divergences for 20151218 release The patch reduces source code differences between the Linux kernel and the ACPICA upstream so that the linuxized ACPICA 20151218 release can be applied with reduced human intervention. The pscode.c has already been out of sync for months, and it becomes more and more difficult to merge pscode.c changes, so instead of update the affected lines of pscode.c, this patch synchronizes entire pscode.c file. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 20de148..37e11a3 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -310,8 +310,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, switch (arg->common.aml_opcode) { case AML_INT_RESERVEDFIELD_OP: - position = (u64) info->field_bit_position - + (u64) arg->common.value.size; + position = (u64)info->field_bit_position + + (u64)arg->common.value.size; if (position > ACPI_UINT32_MAX) { ACPI_ERROR((AE_INFO, @@ -425,8 +425,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, /* Keep track of bit position for the next field */ - position = (u64) info->field_bit_position - + (u64) arg->common.value.size; + position = (u64)info->field_bit_position + + (u64)arg->common.value.size; if (position > ACPI_UINT32_MAX) { ACPI_ERROR((AE_INFO, diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index e4293a8..cecba39 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -504,8 +504,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, if ((walk_state->deferred_node) && (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) && (arg_index == - (u32) ((walk_state->opcode == - AML_CREATE_FIELD_OP) ? 3 : 2))) { + (u32)((walk_state->opcode == + AML_CREATE_FIELD_OP) ? 3 : 2))) { obj_desc = ACPI_CAST_PTR(union acpi_operand_object, walk_state->deferred_node); diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 1e4c5b6..145de28 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -355,8 +355,8 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width) /* Get one hex digit, most significant digits first */ string[k] = - (u8) acpi_ut_hex_to_ascii_char(integer, - ACPI_MUL_4(j)); + (u8)acpi_ut_hex_to_ascii_char(integer, + ACPI_MUL_4(j)); k++; } break; diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index ccb7219..95fe464 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -492,10 +492,9 @@ acpi_ex_create_method(u8 * aml_start, * Disassemble the method flags. Split off the arg_count, Serialized * flag, and sync_level for efficiency. */ - method_flags = (u8) operand[1]->integer.value; - + method_flags = (u8)operand[1]->integer.value; obj_desc->method.param_count = - (u8) (method_flags & AML_METHOD_ARG_COUNT); + (u8)(method_flags & AML_METHOD_ARG_COUNT); /* * Get the sync_level. If method is serialized, a mutex will be diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 61fd9c7..c95fd18 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -439,7 +439,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, * same buffer) */ status = acpi_ex_access_region(obj_desc, 0, - (u64 *) buffer, function); + (u64 *)buffer, function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 472030f..a97f520 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -254,7 +254,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } - status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value, + status = acpi_ex_acquire_mutex_object((u16)time_desc->integer.value, obj_desc, walk_state->thread->thread_id); if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index fa100b3..351b82a 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -96,9 +96,9 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "FatalOp: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", - (u32) operand[0]->integer.value, - (u32) operand[1]->integer.value, - (u32) operand[2]->integer.value)); + (u32)operand[0]->integer.value, + (u32)operand[1]->integer.value, + (u32)operand[2]->integer.value)); fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info)); if (fatal) { diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 73cfa59..da4a923 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -298,6 +298,7 @@ acpi_hw_gpe_enable_write(u8 enable_mask, gpe_register_info->enable_mask = enable_mask; status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); + return (status); } diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 0515a70..7ca8f2b 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -710,7 +710,7 @@ acpi_ns_repair_PSS(struct acpi_evaluate_info *info, elements = (*outer_elements)->package.elements; obj_desc = elements[1]; /* Index1 = power_dissipation */ - if ((u32) obj_desc->integer.value > previous_value) { + if ((u32)obj_desc->integer.value > previous_value) { ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags, "SubPackage[%u,%u] - suspicious power dissipation values", diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index ed90fdd..c3005bd 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -185,458 +185,458 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */ /* 00 */ ACPI_OP("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER, - AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* 01 */ ACPI_OP("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER, - AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* 02 */ ACPI_OP("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, - ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 03 */ ACPI_OP("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 04 */ ACPI_OP("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 05 */ ACPI_OP("WordConst", ARGP_WORD_OP, ARGI_WORD_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 06 */ ACPI_OP("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 07 */ ACPI_OP("String", ARGP_STRING_OP, ARGI_STRING_OP, - ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 08 */ ACPI_OP("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, - ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 09 */ ACPI_OP("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, - ACPI_TYPE_BUFFER, AML_CLASS_CREATE, - AML_TYPE_CREATE_OBJECT, - AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), + ACPI_TYPE_BUFFER, AML_CLASS_CREATE, + AML_TYPE_CREATE_OBJECT, + AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), /* 0A */ ACPI_OP("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, - ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, - AML_TYPE_CREATE_OBJECT, - AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), + ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, + AML_TYPE_CREATE_OBJECT, + AML_HAS_ARGS | AML_DEFER | AML_CONSTANT), /* 0B */ ACPI_OP("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, - ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED | AML_DEFER), + ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED | AML_DEFER), /* 0C */ ACPI_OP("Local0", ARGP_LOCAL0, ARGI_LOCAL0, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 0D */ ACPI_OP("Local1", ARGP_LOCAL1, ARGI_LOCAL1, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 0E */ ACPI_OP("Local2", ARGP_LOCAL2, ARGI_LOCAL2, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 0F */ ACPI_OP("Local3", ARGP_LOCAL3, ARGI_LOCAL3, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 10 */ ACPI_OP("Local4", ARGP_LOCAL4, ARGI_LOCAL4, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 11 */ ACPI_OP("Local5", ARGP_LOCAL5, ARGI_LOCAL5, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 12 */ ACPI_OP("Local6", ARGP_LOCAL6, ARGI_LOCAL6, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 13 */ ACPI_OP("Local7", ARGP_LOCAL7, ARGI_LOCAL7, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LOCAL_VARIABLE, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LOCAL_VARIABLE, 0), /* 14 */ ACPI_OP("Arg0", ARGP_ARG0, ARGI_ARG0, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 15 */ ACPI_OP("Arg1", ARGP_ARG1, ARGI_ARG1, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 16 */ ACPI_OP("Arg2", ARGP_ARG2, ARGI_ARG2, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 17 */ ACPI_OP("Arg3", ARGP_ARG3, ARGI_ARG3, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 18 */ ACPI_OP("Arg4", ARGP_ARG4, ARGI_ARG4, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 19 */ ACPI_OP("Arg5", ARGP_ARG5, ARGI_ARG5, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 1A */ ACPI_OP("Arg6", ARGP_ARG6, ARGI_ARG6, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_METHOD_ARGUMENT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_METHOD_ARGUMENT, 0), /* 1B */ ACPI_OP("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R), /* 1C */ ACPI_OP("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R), /* 1D */ ACPI_OP("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 1E */ ACPI_OP("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 1F */ ACPI_OP("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 20 */ ACPI_OP("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), /* 21 */ ACPI_OP("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), /* 22 */ ACPI_OP("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 23 */ ACPI_OP("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_2T_1R, - AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_2T_1R, + AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT), /* 24 */ ACPI_OP("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 25 */ ACPI_OP("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 26 */ ACPI_OP("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 27 */ ACPI_OP("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 28 */ ACPI_OP("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 29 */ ACPI_OP("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 2A */ ACPI_OP("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT), /* 2B */ ACPI_OP("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 2C */ ACPI_OP("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP, - ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 2D */ ACPI_OP("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP, - ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 2E */ ACPI_OP("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R), /* 2F */ ACPI_OP("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R), /* 30 */ ACPI_OP("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), /* 31 */ ACPI_OP("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R), /* 32 */ ACPI_OP("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, - AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, + AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT), /* 33 */ ACPI_OP("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP, - ARGI_CREATE_DWORD_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_DWORD_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 34 */ ACPI_OP("CreateWordField", ARGP_CREATE_WORD_FIELD_OP, - ARGI_CREATE_WORD_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_WORD_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 35 */ ACPI_OP("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP, - ARGI_CREATE_BYTE_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_BYTE_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 36 */ ACPI_OP("CreateBitField", ARGP_CREATE_BIT_FIELD_OP, - ARGI_CREATE_BIT_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_BIT_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 37 */ ACPI_OP("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), /* 38 */ ACPI_OP("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), /* 39 */ ACPI_OP("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), /* 3A */ ACPI_OP("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, - AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, + AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), /* 3B */ ACPI_OP("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), /* 3C */ ACPI_OP("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), /* 3D */ ACPI_OP("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT), /* 3E */ ACPI_OP("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), /* 3F */ ACPI_OP("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), /* 40 */ ACPI_OP("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS), /* 41 */ ACPI_OP("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 42 */ ACPI_OP("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, - ACPI_TYPE_ANY, AML_CLASS_CONTROL, - AML_TYPE_CONTROL, AML_HAS_ARGS), + ACPI_TYPE_ANY, AML_CLASS_CONTROL, + AML_TYPE_CONTROL, AML_HAS_ARGS), /* 43 */ ACPI_OP("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY, - AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 44 */ ACPI_OP("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, - ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 45 */ ACPI_OP("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER, - AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), + AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT), /* Prefixed opcodes (Two-byte opcodes with a prefix op) */ /* 46 */ ACPI_OP("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 47 */ ACPI_OP("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, - AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, + AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), /* 48 */ ACPI_OP("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), /* 49 */ ACPI_OP("CreateField", ARGP_CREATE_FIELD_OP, - ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, - AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_FIELD | AML_CREATE), + ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, + AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_FIELD | AML_CREATE), /* 4A */ ACPI_OP("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, - AML_FLAGS_EXEC_1A_1T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, + AML_FLAGS_EXEC_1A_1T_0R), /* 4B */ ACPI_OP("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, - AML_FLAGS_EXEC_1A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, + AML_FLAGS_EXEC_1A_0T_0R), /* 4C */ ACPI_OP("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, - AML_FLAGS_EXEC_1A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, + AML_FLAGS_EXEC_1A_0T_0R), /* 4D */ ACPI_OP("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R), /* 4E */ ACPI_OP("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), /* 4F */ ACPI_OP("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, + AML_FLAGS_EXEC_2A_0T_1R), /* 50 */ ACPI_OP("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, - AML_FLAGS_EXEC_1A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, + AML_FLAGS_EXEC_1A_0T_0R), /* 51 */ ACPI_OP("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), /* 52 */ ACPI_OP("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 53 */ ACPI_OP("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 54 */ ACPI_OP("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R), /* 55 */ ACPI_OP("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_CONSTANT, 0), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_CONSTANT, 0), /* 56 */ ACPI_OP("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_CONSTANT, 0), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_CONSTANT, 0), /* 57 */ ACPI_OP("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, - AML_FLAGS_EXEC_3A_0T_0R), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, + AML_FLAGS_EXEC_3A_0T_0R), /* 58 */ ACPI_OP("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP, - ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED | AML_DEFER), + ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED | AML_DEFER), /* 59 */ ACPI_OP("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* 5A */ ACPI_OP("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, - ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5B */ ACPI_OP("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, - ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5C */ ACPI_OP("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, - ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_SIMPLE, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5D */ ACPI_OP("ThermalZone", ARGP_THERMAL_ZONE_OP, - ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED), + ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 5E */ ACPI_OP("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, - ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), /* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, - ACPI_TYPE_LOCAL_BANK_FIELD, + ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD | AML_DEFER), /* Internal opcodes that map to invalid AML opcodes */ /* 60 */ ACPI_OP("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, - ACPI_TYPE_ANY, AML_CLASS_INTERNAL, - AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_INTERNAL, + AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), /* 61 */ ACPI_OP("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, - ACPI_TYPE_ANY, AML_CLASS_INTERNAL, - AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_INTERNAL, + AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT), /* 62 */ ACPI_OP("LGreaterEqual", ARGP_LGREATEREQUAL_OP, - ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, - AML_HAS_ARGS | AML_CONSTANT), + ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, + AML_HAS_ARGS | AML_CONSTANT), /* 63 */ ACPI_OP("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, - ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE), + ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE), /* 64 */ ACPI_OP("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, - ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, - AML_TYPE_METHOD_CALL, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), + ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, + AML_TYPE_METHOD_CALL, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE), /* 65 */ ACPI_OP("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, - ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, 0), + ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, 0), /* 66 */ ACPI_OP("-ReservedField-", ARGP_RESERVEDFIELD_OP, - ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), /* 67 */ ACPI_OP("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, - ACPI_TYPE_ANY, AML_CLASS_INTERNAL, - AML_TYPE_BOGUS, - AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), + ACPI_TYPE_ANY, AML_CLASS_INTERNAL, + AML_TYPE_BOGUS, + AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED), /* 68 */ ACPI_OP("-AccessField-", ARGP_ACCESSFIELD_OP, - ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), /* 69 */ ACPI_OP("-StaticString", ARGP_STATICSTRING_OP, - ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, - AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), + ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0), /* 6A */ ACPI_OP("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, - AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, - AML_HAS_ARGS | AML_HAS_RETVAL), + AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, + AML_HAS_ARGS | AML_HAS_RETVAL), /* 6B */ ACPI_OP("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID, - AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), + AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS), /* 6C */ ACPI_OP("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, - AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), + AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS), /* 6D */ ACPI_OP("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, - AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), + AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS), /* ACPI 2.0 opcodes */ /* 6E */ ACPI_OP("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP, - ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, - AML_TYPE_LITERAL, AML_CONSTANT), + ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, + AML_TYPE_LITERAL, AML_CONSTANT), /* 6F */ ACPI_OP("Package", /* Var */ ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER), /* 70 */ ACPI_OP("ConcatenateResTemplate", ARGP_CONCAT_RES_OP, - ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 71 */ ACPI_OP("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 72 */ ACPI_OP("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP, - ARGI_CREATE_QWORD_FIELD_OP, - ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, - AML_TYPE_CREATE_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | - AML_DEFER | AML_CREATE), + ARGI_CREATE_QWORD_FIELD_OP, + ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, + AML_TYPE_CREATE_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | + AML_DEFER | AML_CREATE), /* 73 */ ACPI_OP("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 74 */ ACPI_OP("ToDecimalString", ARGP_TO_DEC_STR_OP, - ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 75 */ ACPI_OP("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 76 */ ACPI_OP("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, - AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, + AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT), /* 77 */ ACPI_OP("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_2A_1T_1R, - AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_2A_1T_1R, + AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT), /* 78 */ ACPI_OP("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R), /* 79 */ ACPI_OP("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, - AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), + AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, + AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT), /* 7A */ ACPI_OP("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, - ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), + ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0), /* 7B */ ACPI_OP("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, - AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), + ACPI_TYPE_ANY, AML_CLASS_EXECUTE, + AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R), /* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP, - ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, - AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | - AML_NSNODE | AML_NAMED | AML_DEFER), + ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED | AML_DEFER), /* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, - ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_NO_OBJ, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE), /* ACPI 3.0 opcodes */ /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, - AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, + AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, AML_FLAGS_EXEC_0A_0T_1R), /* ACPI 5.0 opcodes */ diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index ac37852..b528ed90 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -446,7 +446,7 @@ exit: /* Round the resource struct length up to the next boundary (32 or 64) */ resource->length = - (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); + (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); } return_ACPI_STATUS(AE_OK); } @@ -551,8 +551,8 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, ACPI_SET8(destination, item_count); aml_length = - (u16) (aml_length + - (info->value * (item_count - 1))); + (u16)(aml_length + + (info->value * (item_count - 1))); break; case ACPI_RSC_COUNT16: diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 7d83efe..c7e11cc 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -253,7 +253,7 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size) buffer = ACPI_ALLOCATE_ZEROED(buffer_size); if (!buffer) { ACPI_ERROR((AE_INFO, "Could not allocate size %u", - (u32) buffer_size)); + (u32)buffer_size)); acpi_ut_remove_reference(buffer_desc); return_PTR(NULL); } @@ -305,7 +305,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size) string = ACPI_ALLOCATE_ZEROED(string_size + 1); if (!string) { ACPI_ERROR((AE_INFO, "Could not allocate size %u", - (u32) string_size)); + (u32)string_size)); acpi_ut_remove_reference(string_desc); return_PTR(NULL); } diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index ceea026..f903fe6 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -136,6 +136,7 @@ static inline acpi_status acpi_os_initialize_command_signals(void) static inline void acpi_os_terminate_command_signals(void) { + return; } /* -- cgit v0.10.2 From a59b679ab85635737947310323f2f2bcfa0664a7 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Tue, 29 Dec 2015 13:52:41 +0800 Subject: ACPICA: acpi_get_sleep_type_data: Reduce warnings ACPICA commit 7bb77313091e52a846df4c9c2bea90be31bfb9d8 Eliminate warnings for "not found" _Sx errors, since these are optional. Original NOT_FOUND status is still returned. Original changes by Prarit Bhargava. ACPICA BZ 1208. Link: https://github.com/acpica/acpica/commit/7bb77313 Link: https://bugs.acpica.org/show_bug.cgi?id=1208 Signed-off-by: Prarit Bhargava Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 5f97468..b2e50d8 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -504,11 +504,20 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) * Evaluate the \_Sx namespace object containing the register values * for this state */ - info->relative_pathname = - ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); + info->relative_pathname = ACPI_CAST_PTR(char, + acpi_gbl_sleep_state_names + [sleep_state]); + status = acpi_ns_evaluate(info); if (ACPI_FAILURE(status)) { - goto cleanup; + if (status == AE_NOT_FOUND) { + + /* The _Sx states are optional, ignore NOT_FOUND */ + + goto final_cleanup; + } + + goto warning_cleanup; } /* Must have a return object */ @@ -517,7 +526,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", info->relative_pathname)); status = AE_AML_NO_RETURN_VALUE; - goto cleanup; + goto warning_cleanup; } /* Return object must be of type Package */ @@ -526,7 +535,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) ACPI_ERROR((AE_INFO, "Sleep State return object is not a Package")); status = AE_AML_OPERAND_TYPE; - goto cleanup1; + goto return_value_cleanup; } /* @@ -570,16 +579,17 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) break; } -cleanup1: +return_value_cleanup: acpi_ut_remove_reference(info->return_object); -cleanup: +warning_cleanup: if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While evaluating Sleep State [%s]", info->relative_pathname)); } +final_cleanup: ACPI_FREE(info); return_ACPI_STATUS(status); } -- cgit v0.10.2 From ac9b64a046b6ee6a80d5985770432c2735085578 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 13:52:51 +0800 Subject: ACPICA: Namespace: Fix wrong error log ACPICA commit 20228e39e125d92f9d80c6e07d3767b225d0536e The Info->Node in acpi_ns_init_one_device() may not be initialized. Even it is initialized, the redundant "._INI" can be seen for this log entry. This patch fixes this issue by using device_node instead. Lv Zheng. Link: https://github.com/acpica/acpica/commit/20228e39 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index b744a53..656eacf 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -582,7 +582,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, /* Ignore error and move on to next device */ - char *scope_name = acpi_ns_get_external_pathname(info->node); + char *scope_name = acpi_ns_get_external_pathname(device_node); ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", scope_name)); -- cgit v0.10.2 From 0e166e4f67f544370328bf879694f7ed116c2563 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 13:53:50 +0800 Subject: ACPICA: Debugger: reduce old external path format ACPICA commit 75c0da9e796bdf9bdd46d75f028a3e1779903214 In the error logs and debugger outputs, use new external path format that does not contain a trailing underscore. This patch takes care of acpi_ns_get_external_pathname() invocations, chaning them into acpi_ns_get_normalized_pathname(TRUE) where possible. Along with some error log fixes, the following debugger commands are fixed: resources, handlers, paths. Lv Zheng. Link: https://github.com/acpica/acpica/commit/75c0da9e Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c index 30414b3..84ab1c2 100644 --- a/drivers/acpi/acpica/dbcmds.c +++ b/drivers/acpi/acpica/dbcmds.c @@ -798,7 +798,7 @@ acpi_db_device_resources(acpi_handle obj_handle, acpi_status status; node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); - parent_path = acpi_ns_get_external_pathname(node); + parent_path = acpi_ns_get_normalized_pathname(node, TRUE); if (!parent_path) { return (AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index c42ce8a..3acc3a5 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -1091,7 +1091,7 @@ acpi_db_display_non_root_handlers(acpi_handle obj_handle, return (AE_OK); } - pathname = acpi_ns_get_external_pathname(node); + pathname = acpi_ns_get_normalized_pathname(node, TRUE); if (!pathname) { return (AE_OK); } diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index 04ff1eb..4f68dfc 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -438,7 +438,7 @@ acpi_db_walk_for_predefined_names(acpi_handle obj_handle, return (AE_OK); } - pathname = acpi_ns_get_external_pathname(node); + pathname = acpi_ns_get_normalized_pathname(node, TRUE); if (!pathname) { return (AE_OK); } diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c index 10ea8bf..68b4e8d 100644 --- a/drivers/acpi/acpica/dbtest.c +++ b/drivers/acpi/acpica/dbtest.c @@ -953,7 +953,7 @@ acpi_db_evaluate_one_predefined_name(acpi_handle obj_handle, return (AE_OK); } - pathname = acpi_ns_get_external_pathname(node); + pathname = acpi_ns_get_normalized_pathname(node, TRUE); if (!pathname) { return (AE_OK); } diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 37aa5c4..e071956 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -717,7 +717,7 @@ acpi_ns_dump_one_object_path(acpi_handle obj_handle, return (AE_OK); } - pathname = acpi_ns_get_external_pathname(node); + pathname = acpi_ns_get_normalized_pathname(node, TRUE); path_indent = 1; if (level <= max_level) { diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 7eba578..15e0b2e 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -135,7 +135,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) /* Get the full pathname to the object, for use in warning messages */ - info->full_pathname = acpi_ns_get_external_pathname(info->node); + info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE); if (!info->full_pathname) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 656eacf..ac59929 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -582,7 +582,8 @@ acpi_ns_init_one_device(acpi_handle obj_handle, /* Ignore error and move on to next device */ - char *scope_name = acpi_ns_get_external_pathname(device_node); + char *scope_name = + acpi_ns_get_normalized_pathname(device_node, TRUE); ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", scope_name)); diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index d739040..9cc3564d 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -105,7 +105,7 @@ acpi_ns_search_one_scope(u32 target_name, if (ACPI_LV_NAMES & acpi_dbg_level) { char *scope_name; - scope_name = acpi_ns_get_external_pathname(parent_node); + scope_name = acpi_ns_get_normalized_pathname(parent_node, TRUE); if (scope_name) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Searching %s (%p) For [%4.4s] (%s)\n", diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index 911ea8e..38a29e2 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -239,8 +239,9 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id, overlap_count++; if (warn) { /* Optional warning message */ pathname = - acpi_ns_get_external_pathname(range_info-> - region_node); + acpi_ns_get_normalized_pathname(range_info-> + region_node, + TRUE); ACPI_WARNING((AE_INFO, "%s range 0x%8.8X%8.8X-0x%8.8X%8.8X conflicts with OpRegion 0x%8.8X%8.8X-0x%8.8X%8.8X (%s)", -- cgit v0.10.2 From 33d3a2abbd7afd51d8dcf1e35756e13e6b89f2cb Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Tue, 29 Dec 2015 13:53:57 +0800 Subject: ACPICA: Fix SyncLevel support interaction with method auto-serialization ACPICA commit 253e3c03efc1a495d2aa61eee09ab1d0842a3dce The control method auto-serialization can interfere with existing ASL code that makes use of Mutex/Method SyncLevel support. This change makes the auto-serialization transparent to the SyncLevel support and management. David Box. Link: https://github.com/acpica/acpica/commit/253e3c03 Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index bc32f31..49ba082 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -411,8 +411,19 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, obj_desc->method.mutex->mutex.thread_id = walk_state->thread->thread_id; - walk_state->thread->current_sync_level = - obj_desc->method.sync_level; + + /* + * Update the current sync_level only if this is not an auto- + * serialized method. In the auto case, we have to ignore + * the sync level for the method mutex (created for the + * auto-serialization) because we have no idea of what the + * sync level should be. Therefore, just ignore it. + */ + if (!(obj_desc->method.info_flags & + ACPI_METHOD_IGNORE_SYNC_LEVEL)) { + walk_state->thread->current_sync_level = + obj_desc->method.sync_level; + } } else { obj_desc->method.mutex->mutex. original_sync_level = -- cgit v0.10.2 From c118abc55464fee761be3ea32b4d90db3a9d1bbe Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Tue, 29 Dec 2015 13:54:04 +0800 Subject: ACPICA: Add "const" to some functions that return fixed strings ACPICA commit 28645f8a113f346c8db103a4f7565fcba88c746f Most of the "get_name" - style functions can return "const char *" with no ill side-effects. Original linux patch from LABBE Corentin and backported to ACPICA. Link: https://github.com/acpica/acpica/commit/28645f8a Signed-off-by: LABBE Corentin Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 8b8fef6..7495421 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -184,24 +184,24 @@ acpi_status acpi_ut_init_globals(void); #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -char *acpi_ut_get_mutex_name(u32 mutex_id); +const char *acpi_ut_get_mutex_name(u32 mutex_id); const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type); #endif -char *acpi_ut_get_type_name(acpi_object_type type); +const char *acpi_ut_get_type_name(acpi_object_type type); -char *acpi_ut_get_node_name(void *object); +const char *acpi_ut_get_node_name(void *object); -char *acpi_ut_get_descriptor_name(void *object); +const char *acpi_ut_get_descriptor_name(void *object); const char *acpi_ut_get_reference_name(union acpi_operand_object *object); -char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc); +const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc); -char *acpi_ut_get_region_name(u8 space_id); +const char *acpi_ut_get_region_name(u8 space_id); -char *acpi_ut_get_event_name(u32 event_id); +const char *acpi_ut_get_event_name(u32 event_id); char acpi_ut_hex_to_ascii_char(u64 integer, u32 position); diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 4b4d2f4..138cf5e 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -159,7 +159,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; - char *node_name; + const char *node_name; /* Parameter validation */ diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index ecaaaff..7e14400 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -114,7 +114,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "PCC" /* 0x0A */ }; -char *acpi_ut_get_region_name(u8 space_id) +const char *acpi_ut_get_region_name(u8 space_id) { if (space_id >= ACPI_USER_REGION_BEGIN) { @@ -127,7 +127,7 @@ char *acpi_ut_get_region_name(u8 space_id) return ("InvalidSpaceId"); } - return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id])); + return (acpi_gbl_region_types[space_id]); } /******************************************************************************* @@ -152,14 +152,14 @@ static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = { "RealTimeClock", }; -char *acpi_ut_get_event_name(u32 event_id) +const char *acpi_ut_get_event_name(u32 event_id) { if (event_id > ACPI_EVENT_MAX) { return ("InvalidEventID"); } - return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id])); + return (acpi_gbl_event_types[event_id]); } /******************************************************************************* @@ -220,17 +220,17 @@ static const char *acpi_gbl_ns_type_names[] = { /* 30 */ "Invalid" }; -char *acpi_ut_get_type_name(acpi_object_type type) +const char *acpi_ut_get_type_name(acpi_object_type type) { if (type > ACPI_TYPE_INVALID) { - return (ACPI_CAST_PTR(char, acpi_gbl_bad_type)); + return (acpi_gbl_bad_type); } - return (ACPI_CAST_PTR(char, acpi_gbl_ns_type_names[type])); + return (acpi_gbl_ns_type_names[type]); } -char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) +const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) { ACPI_FUNCTION_TRACE(ut_get_object_type_name); @@ -267,7 +267,7 @@ char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) * ******************************************************************************/ -char *acpi_ut_get_node_name(void *object) +const char *acpi_ut_get_node_name(void *object) { struct acpi_namespace_node *node = (struct acpi_namespace_node *)object; @@ -333,7 +333,7 @@ static const char *acpi_gbl_desc_type_names[] = { /* 15 */ "Node" }; -char *acpi_ut_get_descriptor_name(void *object) +const char *acpi_ut_get_descriptor_name(void *object) { if (!object) { @@ -344,10 +344,7 @@ char *acpi_ut_get_descriptor_name(void *object) return ("Not a Descriptor"); } - return (ACPI_CAST_PTR(char, - acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE - (object)])); - + return (acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE(object)]); } /******************************************************************************* @@ -415,7 +412,7 @@ const char *acpi_ut_get_reference_name(union acpi_operand_object *object) /* Names for internal mutex objects, used for debug output */ -static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { +static const char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { "ACPI_MTX_Interpreter", "ACPI_MTX_Namespace", "ACPI_MTX_Tables", @@ -424,7 +421,7 @@ static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { "ACPI_MTX_Memory", }; -char *acpi_ut_get_mutex_name(u32 mutex_id) +const char *acpi_ut_get_mutex_name(u32 mutex_id) { if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index fda8b3d..8ad086e 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -48,7 +48,7 @@ ACPI_MODULE_NAME("uthex") /* Hex to ASCII conversion table */ -static char acpi_gbl_hex_to_ascii[] = { +static const char acpi_gbl_hex_to_ascii[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; -- cgit v0.10.2 From cd162b35a29900b7e7a595c5ea70066cd5d47aee Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:54:28 +0800 Subject: ACPICA: exmutex: General cleanup, restructured some code ACPICA commit c2a7d000b6be34313b1c50c8a718df16113f0f32 Should be no functional change. Link: https://github.com/acpica/acpica/commit/c2a7d000 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index a97f520..843c60a 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -185,8 +185,9 @@ acpi_ex_acquire_mutex_object(u16 timeout, if (obj_desc == acpi_gbl_global_lock_mutex) { status = acpi_ev_acquire_global_lock(timeout); } else { - status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, - timeout); + status = + acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, + timeout); } if (ACPI_FAILURE(status)) { @@ -243,20 +244,30 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, } /* - * Current sync level must be less than or equal to the sync level of the - * mutex. This mechanism provides some deadlock prevention + * Current sync level must be less than or equal to the sync level + * of the mutex. This mechanism provides some deadlock prevention. */ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { ACPI_ERROR((AE_INFO, - "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)", + "Cannot acquire Mutex [%4.4s], " + "current SyncLevel is too large (%u)", acpi_ut_get_node_name(obj_desc->mutex.node), walk_state->thread->current_sync_level)); return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, " + "Depth %u TID %p\n", + obj_desc->mutex.sync_level, + walk_state->thread->current_sync_level, + obj_desc->mutex.acquisition_depth, + walk_state->thread)); + status = acpi_ex_acquire_mutex_object((u16)time_desc->integer.value, obj_desc, walk_state->thread->thread_id); + if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { /* Save Thread object, original/current sync levels */ @@ -272,6 +283,12 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, acpi_ex_link_mutex(obj_desc, walk_state->thread); } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n", + obj_desc->mutex.sync_level, + walk_state->thread->current_sync_level, + obj_desc->mutex.acquisition_depth)); + return_ACPI_STATUS(status); } @@ -356,9 +373,9 @@ acpi_status acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { - acpi_status status = AE_OK; u8 previous_sync_level; struct acpi_thread_state *owner_thread; + acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_release_mutex); @@ -409,7 +426,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, */ if (obj_desc->mutex.sync_level != owner_thread->current_sync_level) { ACPI_ERROR((AE_INFO, - "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u", + "Cannot release Mutex [%4.4s], SyncLevel mismatch: " + "mutex %u current %u", acpi_ut_get_node_name(obj_desc->mutex.node), obj_desc->mutex.sync_level, walk_state->thread->current_sync_level)); @@ -424,6 +442,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, previous_sync_level = owner_thread->acquired_mutex_list->mutex.original_sync_level; + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Releasing: Object SyncLevel %u, Thread SyncLevel %u, " + "Prev SyncLevel %u, Depth %u TID %p\n", + obj_desc->mutex.sync_level, + walk_state->thread->current_sync_level, + previous_sync_level, + obj_desc->mutex.acquisition_depth, + walk_state->thread)); + status = acpi_ex_release_mutex_object(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -436,6 +463,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, owner_thread->current_sync_level = previous_sync_level; } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Released: Object SyncLevel %u, Thread SyncLevel, %u, " + "Prev SyncLevel %u, Depth %u\n", + obj_desc->mutex.sync_level, + walk_state->thread->current_sync_level, + previous_sync_level, + obj_desc->mutex.acquisition_depth)); + return_ACPI_STATUS(status); } @@ -462,21 +497,17 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) union acpi_operand_object *next = thread->acquired_mutex_list; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_NAME(ex_release_all_mutexes); + ACPI_FUNCTION_TRACE(ex_release_all_mutexes); /* Traverse the list of owned mutexes, releasing each one */ while (next) { obj_desc = next; - next = obj_desc->mutex.next; - - obj_desc->mutex.prev = NULL; - obj_desc->mutex.next = NULL; - obj_desc->mutex.acquisition_depth = 0; - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Force-releasing held mutex: %p\n", - obj_desc)); + "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n", + obj_desc->mutex.node->name.ascii, + obj_desc->mutex.sync_level, + obj_desc->mutex.acquisition_depth)); /* Release the mutex, special case for Global Lock */ @@ -489,14 +520,21 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) acpi_os_release_mutex(obj_desc->mutex.os_mutex); } - /* Mark mutex unowned */ - - obj_desc->mutex.owner_thread = NULL; - obj_desc->mutex.thread_id = 0; - /* Update Thread sync_level (Last mutex is the important one) */ thread->current_sync_level = obj_desc->mutex.original_sync_level; + + /* Mark mutex unowned */ + + next = obj_desc->mutex.next; + + obj_desc->mutex.prev = NULL; + obj_desc->mutex.next = NULL; + obj_desc->mutex.acquisition_depth = 0; + obj_desc->mutex.owner_thread = NULL; + obj_desc->mutex.thread_id = 0; } + + return_VOID; } -- cgit v0.10.2 From 1fad87385e7e82f656fb661aef0f841e42991974 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:54:36 +0800 Subject: ACPICA: Core: Major update for code formatting, no functional changes ACPICA commit dfa394471f6c01b2ee9433dbc143ec70cb9bca72 Mostly indentation inconsistencies across the code. Split some long lines, etc. Link: https://github.com/acpica/acpica/commit/dfa39447 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c index 4ba0a20..de255d9 100644 --- a/drivers/acpi/acpica/dbstats.c +++ b/drivers/acpi/acpica/dbstats.c @@ -382,6 +382,7 @@ acpi_status acpi_db_display_statistics(char *type_arg) acpi_gbl_node_type_count[i], acpi_gbl_obj_type_count[i]); } + acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown", acpi_gbl_node_type_count_misc, acpi_gbl_obj_type_count_misc); diff --git a/drivers/acpi/acpica/dbutils.c b/drivers/acpi/acpica/dbutils.c index 86790e0..8c85d85 100644 --- a/drivers/acpi/acpica/dbutils.c +++ b/drivers/acpi/acpica/dbutils.c @@ -173,6 +173,7 @@ void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level) if (obj_desc->buffer.length > 16) { acpi_os_printf("\n"); } + acpi_ut_debug_dump_buffer(ACPI_CAST_PTR (u8, obj_desc->buffer.pointer), diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index e2ab59e..76cfced 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -194,8 +194,8 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) extra_desc = acpi_ns_get_secondary_object(obj_desc); node = obj_desc->buffer_field.node; - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_BUFFER_FIELD, - node, NULL)); + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname + (ACPI_TYPE_BUFFER_FIELD, node, NULL)); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", acpi_ut_get_node_name(node))); @@ -385,7 +385,8 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL)); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "[%4.4s] OpRegion Arg Init at AML %p\n", acpi_ut_get_node_name(node), extra_desc->extra.aml_start)); diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 309556e..1eb82bd 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -161,6 +161,7 @@ acpi_ds_dump_method_stack(acpi_status status, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "\n**** Exception %s during execution of method ", acpi_format_exception(status))); + acpi_ds_print_node_pathname(walk_state->method_node, NULL); /* Display stack of executing methods */ @@ -203,8 +204,8 @@ acpi_ds_dump_method_stack(acpi_status status, } else { /* * This method has called another method - * NOTE: the method call parse subtree is already deleted at this - * point, so we cannot disassemble the method invocation. + * NOTE: the method call parse subtree is already deleted at + * this point, so we cannot disassemble the method invocation. */ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "Call to method ")); diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 37e11a3..6bca0ec 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -106,6 +106,7 @@ acpi_ds_create_external_region(acpi_status lookup_status, * insert the name into the namespace. */ 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); @@ -202,11 +203,10 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, /* Enter the name_string into the namespace */ - status = - acpi_ns_lookup(walk_state->scope_info, - arg->common.value.string, ACPI_TYPE_ANY, - ACPI_IMODE_LOAD_PASS1, flags, walk_state, - &node); + status = acpi_ns_lookup(walk_state->scope_info, + arg->common.value.string, ACPI_TYPE_ANY, + ACPI_IMODE_LOAD_PASS1, flags, + walk_state, &node); if (ACPI_FAILURE(status)) { ACPI_ERROR_NAMESPACE(arg->common.value.string, status); return_ACPI_STATUS(status); @@ -244,8 +244,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, } /* - * Remember location in AML stream of the field unit opcode and operands -- - * since the buffer and index operands must be evaluated. + * Remember location in AML stream of the field unit opcode and operands + * -- since the buffer and index operands must be evaluated. */ second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = op->named.data; @@ -310,8 +310,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, switch (arg->common.aml_opcode) { case AML_INT_RESERVEDFIELD_OP: - position = (u64)info->field_bit_position - + (u64)arg->common.value.size; + position = (u64)info->field_bit_position + + (u64)arg->common.value.size; if (position > ACPI_UINT32_MAX) { ACPI_ERROR((AE_INFO, @@ -344,13 +344,13 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, /* access_attribute (attrib_quick, attrib_byte, etc.) */ - info->attribute = - (u8)((arg->common.value.integer >> 8) & 0xFF); + info->attribute = (u8) + ((arg->common.value.integer >> 8) & 0xFF); /* access_length (for serial/buffer protocols) */ - info->access_length = - (u8)((arg->common.value.integer >> 16) & 0xFF); + info->access_length = (u8) + ((arg->common.value.integer >> 16) & 0xFF); break; case AML_INT_CONNECTION_OP: @@ -425,8 +425,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, /* Keep track of bit position for the next field */ - position = (u64)info->field_bit_position - + (u64)arg->common.value.size; + position = (u64)info->field_bit_position + + (u64)arg->common.value.size; if (position > ACPI_UINT32_MAX) { ACPI_ERROR((AE_INFO, @@ -716,11 +716,12 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, /* * Use Info.data_register_node to store bank_field Op - * It's safe because data_register_node will never be used when create bank field - * We store aml_start and aml_length in the bank_field Op for late evaluation - * Used in acpi_ex_prep_field_value(Info) + * It's safe because data_register_node will never be used when create + * bank field \we store aml_start and aml_length in the bank_field Op for + * late evaluation. Used in acpi_ex_prep_field_value(Info) * - * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"? + * TBD: Or, should we add a field in struct acpi_create_field_info, like + * "void *ParentOp"? */ info.data_register_node = (struct acpi_namespace_node *)op; diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 920f1b1..c1d8af8 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -247,7 +247,7 @@ acpi_ds_initialize_objects(u32 table_index, /* Summary of objects initialized */ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "Table [%4.4s:%8.8s] (id %.2X) - %4u Objects with %3u Devices, " + "Table [%4.4s: %-8.8s] (id %.2X) - %4u Objects with %3u Devices, " "%3u Regions, %4u Methods (%u/%u/%u Serial/Non/Cvt)\n", table->signature, table->oem_table_id, owner_id, info.object_count, info.device_count, diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 49ba082..6585e8e 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -118,10 +118,9 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, return_ACPI_STATUS(AE_NO_MEMORY); } - status = - acpi_ds_init_aml_walk(walk_state, op, node, - obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, 0); + status = acpi_ds_init_aml_walk(walk_state, op, node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 0); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); acpi_ps_free_op(op); @@ -375,7 +374,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, && (walk_state->thread->current_sync_level > obj_desc->method.mutex->mutex.sync_level)) { ACPI_ERROR((AE_INFO, - "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", + "Cannot acquire Mutex for method [%4.4s]" + ", current SyncLevel is too large (%u)", acpi_ut_get_node_name(method_node), walk_state->thread->current_sync_level)); @@ -512,16 +512,18 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, /* Init for new method, possibly wait on method mutex */ - status = acpi_ds_begin_method_execution(method_node, obj_desc, - this_walk_state); + status = + acpi_ds_begin_method_execution(method_node, obj_desc, + this_walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Begin method parse/execution. Create a new walk state */ - next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, - NULL, obj_desc, thread); + next_walk_state = + acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, + thread); if (!next_walk_state) { status = AE_NO_MEMORY; goto cleanup; @@ -808,7 +810,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, info_flags & ACPI_METHOD_SERIALIZED_PENDING) { if (walk_state) { ACPI_INFO((AE_INFO, - "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", + "Marking method %4.4s as Serialized " + "because of AE_ALREADY_EXISTS error", walk_state->method_node->name. ascii)); } @@ -826,6 +829,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, */ method_desc->method.info_flags &= ~ACPI_METHOD_SERIALIZED_PENDING; + method_desc->method.info_flags |= (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 2e4c42b..03c44f2 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -99,6 +99,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name, NAMEOF_ARG_NTE); + walk_state->arguments[i].name.integer |= (i << 24); walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED; walk_state->arguments[i].type = ACPI_TYPE_ANY; @@ -201,7 +202,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params, if (!params) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "No param list passed to method\n")); + "No parameter list passed to method\n")); return_ACPI_STATUS(AE_OK); } @@ -214,9 +215,9 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params, * Store the argument in the method/walk descriptor. * Do not copy the arg in order to implement call by reference */ - status = acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index, - params[index], - walk_state); + status = + acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index, + params[index], walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -610,11 +611,11 @@ acpi_ds_store_object_to_local(u8 type, * do the indirect store */ if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) == - ACPI_DESC_TYPE_OPERAND) - && (current_obj_desc->common.type == - ACPI_TYPE_LOCAL_REFERENCE) - && (current_obj_desc->reference.class == - ACPI_REFCLASS_REFOF)) { + ACPI_DESC_TYPE_OPERAND) && + (current_obj_desc->common.type == + ACPI_TYPE_LOCAL_REFERENCE) && + (current_obj_desc->reference.class == + ACPI_REFCLASS_REFOF)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Arg (%p) is an ObjRef(Node), storing in node %p\n", new_obj_desc, @@ -638,6 +639,7 @@ acpi_ds_store_object_to_local(u8 type, if (new_obj_desc != obj_desc) { acpi_ut_remove_reference(new_obj_desc); } + return_ACPI_STATUS(status); } } diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 2beb7fd..302c91f 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -463,10 +463,10 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, arg->common.node); } } else { - status = acpi_ds_build_internal_object(walk_state, arg, - &obj_desc-> - package. - elements[i]); + status = + acpi_ds_build_internal_object(walk_state, arg, + &obj_desc->package. + elements[i]); } if (*obj_desc_ptr) { @@ -525,7 +525,8 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, } ACPI_INFO((AE_INFO, - "Actual Package length (%u) is larger than NumElements field (%u), truncated", + "Actual Package length (%u) is larger than " + "NumElements field (%u), truncated", i, element_count)); } else if (i < element_count) { /* @@ -533,7 +534,8 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, * Note: this is not an error, the package is padded out with NULLs. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Package List length (%u) smaller than NumElements count (%u), padded with null elements\n", + "Package List length (%u) smaller than NumElements " + "count (%u), padded with null elements\n", i, element_count)); } @@ -584,8 +586,9 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, /* Build an internal object for the argument(s) */ - status = acpi_ds_build_internal_object(walk_state, op->common.value.arg, - &obj_desc); + status = + acpi_ds_build_internal_object(walk_state, op->common.value.arg, + &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 81d7b986..1edd66f 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -243,8 +243,9 @@ acpi_ds_init_buffer_field(u16 aml_opcode, * For field_flags, use LOCK_RULE = 0 (NO_LOCK), * UPDATE_RULE = 0 (UPDATE_PRESERVE) */ - status = acpi_ex_prep_common_field_object(obj_desc, field_flags, 0, - bit_offset, bit_count); + status = + acpi_ex_prep_common_field_object(obj_desc, field_flags, 0, + bit_offset, bit_count); if (ACPI_FAILURE(status)) { goto cleanup; } @@ -330,8 +331,9 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, /* Resolve the operands */ - status = acpi_ex_resolve_operands(op->common.aml_opcode, - ACPI_WALK_OPERANDS, walk_state); + status = + acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, + walk_state); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "(%s) bad operand(s), status 0x%X", acpi_ps_get_opcode_name(op->common.aml_opcode), @@ -414,8 +416,9 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, /* Resolve the length and address operands to numbers */ - status = acpi_ex_resolve_operands(op->common.aml_opcode, - ACPI_WALK_OPERANDS, walk_state); + status = + acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, + walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -452,7 +455,6 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, /* Now the address and length are valid for this opregion */ obj_desc->region.flags |= AOPOBJ_DATA_VALID; - return_ACPI_STATUS(status); } @@ -510,8 +512,9 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, * Resolve the Signature string, oem_id string, * and oem_table_id string operands */ - status = acpi_ex_resolve_operands(op->common.aml_opcode, - ACPI_WALK_OPERANDS, walk_state); + status = + acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, + walk_state); if (ACPI_FAILURE(status)) { goto cleanup; } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index cecba39..fa8e292 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -245,9 +245,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op, * we will use the return value */ if ((walk_state->control_state->common.state == - ACPI_CONTROL_PREDICATE_EXECUTING) - && (walk_state->control_state->control. - predicate_op == op)) { + ACPI_CONTROL_PREDICATE_EXECUTING) && + (walk_state->control_state->control.predicate_op == + op)) { goto result_used; } break; @@ -481,10 +481,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* Get the entire name string from the AML stream */ - status = - acpi_ex_get_name_string(ACPI_TYPE_ANY, - arg->common.value.buffer, - &name_string, &name_length); + status = acpi_ex_get_name_string(ACPI_TYPE_ANY, + arg->common.value.buffer, + &name_string, &name_length); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -503,9 +502,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, */ if ((walk_state->deferred_node) && (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) - && (arg_index == - (u32)((walk_state->opcode == - AML_CREATE_FIELD_OP) ? 3 : 2))) { + && (arg_index == (u32) + ((walk_state->opcode == AML_CREATE_FIELD_OP) ? 3 : 2))) { obj_desc = ACPI_CAST_PTR(union acpi_operand_object, walk_state->deferred_node); @@ -522,9 +520,10 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, op_info = acpi_ps_get_opcode_info(parent_op->common. aml_opcode); - if ((op_info->flags & AML_NSNODE) - && (parent_op->common.aml_opcode != - AML_INT_METHODCALL_OP) + + if ((op_info->flags & AML_NSNODE) && + (parent_op->common.aml_opcode != + AML_INT_METHODCALL_OP) && (parent_op->common.aml_opcode != AML_REGION_OP) && (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) { @@ -633,8 +632,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NOT_IMPLEMENTED); } - if ((op_info->flags & AML_HAS_RETVAL) - || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { + if ((op_info->flags & AML_HAS_RETVAL) || + (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Argument previously created, already stacked\n")); diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 9cc5761..ed2f1d3 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -172,7 +172,8 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, cleanup: - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Completed a predicate eval=%X Op=%p\n", walk_state->control_state->common.value, walk_state->op)); @@ -263,8 +264,8 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, (walk_state->control_state->common.state == ACPI_CONTROL_CONDITIONAL_EXECUTING)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Exec predicate Op=%p State=%p\n", op, - walk_state)); + "Exec predicate Op=%p State=%p\n", + op, walk_state)); walk_state->control_state->common.state = ACPI_CONTROL_PREDICATE_EXECUTING; @@ -500,9 +501,8 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) "Method Reference in a Package, Op=%p\n", op)); - op->common.node = - (struct acpi_namespace_node *)op->asl.value. - arg->asl.node; + op->common.node = (struct acpi_namespace_node *) + op->asl.value.arg->asl.node; acpi_ut_add_reference(op->asl.value.arg->asl. node->object); return_ACPI_STATUS(AE_OK); @@ -584,8 +584,8 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) * Put the Node on the object stack (Contains the ACPI Name * of this object) */ - walk_state->operands[0] = - (void *)op->common.parent->common.node; + walk_state->operands[0] = (void *) + op->common.parent->common.node; walk_state->num_operands = 1; status = acpi_ds_create_node(walk_state, @@ -690,7 +690,8 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) default: ACPI_ERROR((AE_INFO, - "Unimplemented opcode, class=0x%X type=0x%X Opcode=0x%X Op=%p", + "Unimplemented opcode, class=0x%X " + "type=0x%X Opcode=0x%X Op=%p", op_class, op_type, op->common.aml_opcode, op)); diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 097188a..b325474 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -476,13 +476,9 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) status = acpi_ex_create_region(op->named.data, op->named.length, - (acpi_adr_space_type) ((op-> - common. - value. - arg)-> - common. - value. - integer), + (acpi_adr_space_type) + ((op->common.value.arg)-> + common.value.integer), walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index e2c08cd..8a32153 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -598,11 +598,10 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) * Executing a method: initialize the region and unlock * the interpreter */ - status = - acpi_ex_create_region(op->named.data, - op->named.length, - region_space, - walk_state); + status = acpi_ex_create_region(op->named.data, + op->named.length, + region_space, + walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -664,6 +663,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) length, walk_state); } + walk_state->operands[0] = NULL; walk_state->num_operands = 0; diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 43b3ea4..2d7a044 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -77,6 +77,7 @@ void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state) "Popped object type (%s)\n", acpi_ut_get_type_name(scope_info->common. value))); + acpi_ut_delete_generic_state(scope_info); } } diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index ccf7932..112e821 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -92,8 +92,8 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) ACPI_SET_BIT(gpe_register_info->enable_for_run, (u8)register_bit); } - gpe_register_info->enable_mask = gpe_register_info->enable_for_run; + gpe_register_info->enable_mask = gpe_register_info->enable_for_run; return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index e0f24c5..c00a9f2 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -167,6 +167,7 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) if (gpe_block->next) { gpe_block->next->previous = gpe_block->previous; } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); } diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 3a958f3..fd5ab90 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -346,6 +346,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ACPI_FREE(notify); notify = next; } + gpe_event_info->dispatch.notify_list = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index f7c9dfe..8866f50 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -68,6 +68,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node) { + switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_PROCESSOR: @@ -170,8 +171,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY), node)); - status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, - info); + status = acpi_os_execute(OSL_NOTIFY_HANDLER, + acpi_ev_notify_dispatch, info); if (ACPI_FAILURE(status)) { acpi_ut_delete_generic_state(info); } diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 07d22bf..012b9de 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -879,9 +879,8 @@ acpi_install_gpe_handler(acpi_handle gpe_device, ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); - status = - acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, FALSE, - address, context); + status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, + FALSE, address, context); return_ACPI_STATUS(status); } @@ -914,8 +913,8 @@ acpi_install_gpe_raw_handler(acpi_handle gpe_device, ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler); - status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, TRUE, - address, context); + status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, + TRUE, address, context); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index f21afba..dbd9f16 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -135,6 +135,7 @@ acpi_install_address_space_handler(acpi_handle device, if (!acpi_gbl_reg_methods_executed) { /* We will defer execution of the _REG methods for this space */ + goto unlock_and_exit; } break; diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index b540913..adcb9c7 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -358,8 +358,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } /* - * If the Region Address and Length have not been previously evaluated, - * evaluate them now and save the results. + * If the Region Address and Length have not been previously + * evaluated, evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_region_arguments(obj_desc); @@ -454,8 +454,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } /* - * Copy the table from the buffer because the buffer could be modified - * or even deleted in the future + * Copy the table from the buffer because the buffer could be + * modified or even deleted in the future */ table = ACPI_ALLOCATE(length); if (!table) { diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 145de28..73c2e82 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -227,8 +227,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, /* Copy the integer to the buffer, LSB first */ new_buf = return_desc->buffer.pointer; - memcpy(new_buf, - &obj_desc->integer.value, acpi_gbl_integer_byte_width); + memcpy(new_buf, &obj_desc->integer.value, + acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: @@ -354,9 +354,8 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width) /* Get one hex digit, most significant digits first */ - string[k] = - (u8)acpi_ut_hex_to_ascii_char(integer, - ACPI_MUL_4(j)); + string[k] = (u8) + acpi_ut_hex_to_ascii_char(integer, ACPI_MUL_4(j)); k++; } break; diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 95fe464..0f34446 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -189,9 +189,9 @@ acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state) /* Attach object to the Node */ - status = - acpi_ns_attach_object((struct acpi_namespace_node *)walk_state-> - operands[0], obj_desc, ACPI_TYPE_EVENT); + status = acpi_ns_attach_object((struct acpi_namespace_node *) + walk_state->operands[0], obj_desc, + ACPI_TYPE_EVENT); cleanup: /* @@ -493,8 +493,8 @@ acpi_ex_create_method(u8 * aml_start, * flag, and sync_level for efficiency. */ method_flags = (u8)operand[1]->integer.value; - obj_desc->method.param_count = - (u8)(method_flags & AML_METHOD_ARG_COUNT); + obj_desc->method.param_count = (u8) + (method_flags & AML_METHOD_ARG_COUNT); /* * Get the sync_level. If method is serialized, a mutex will be diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index de92458..665a4b9 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -491,6 +491,7 @@ acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, acpi_dbg_layer = acpi_gbl_trace_dbg_layer; } } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); exit: diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index c95fd18..ad7080b 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -167,10 +167,11 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold - * the data and then directly access the region handler. + * This is an SMBus, GSBus or IPMI read. We must create a buffer to + * hold the data and then directly access the region handler. * - * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function + * Note: SMBus and GSBus protocol value is passed in upper 16-bits + * of Function */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { @@ -180,17 +181,17 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { accessor_type = obj_desc->field.attribute; - length = acpi_ex_get_serial_access_length(accessor_type, - obj_desc-> - field. - access_length); + length = + acpi_ex_get_serial_access_length(accessor_type, + obj_desc->field. + access_length); /* * Add additional 2 bytes for the generic_serial_bus data buffer: * - * Status; (Byte 0 of the data buffer) - * Length; (Byte 1 of the data buffer) - * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) + * Status; (Byte 0 of the data buffer) + * Length; (Byte 1 of the data buffer) + * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) */ length += 2; function = ACPI_READ | (accessor_type << 16); @@ -216,6 +217,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, buffer_desc-> buffer.pointer), function); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } @@ -232,6 +234,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, */ length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); + if (length > acpi_gbl_integer_byte_width) { /* Field is too large for an Integer, create a Buffer instead */ @@ -273,8 +276,10 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, /* Perform the write */ - status = acpi_ex_access_region(obj_desc, 0, - (u64 *)buffer, ACPI_READ); + status = + acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, + ACPI_READ); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); @@ -366,19 +371,22 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus, GSBus or IPMI write. We will bypass the entire field - * mechanism and handoff the buffer directly to the handler. For - * these address spaces, the buffer is bi-directional; on a write, - * return data is returned in the same buffer. + * This is an SMBus, GSBus or IPMI write. We will bypass the entire + * field mechanism and handoff the buffer directly to the handler. + * For these address spaces, the buffer is bi-directional; on a + * write, return data is returned in the same buffer. * * Source must be a buffer of sufficient size: - * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. + * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or + * ACPI_IPMI_BUFFER_SIZE. * - * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function + * Note: SMBus and GSBus protocol type is passed in upper 16-bits + * of Function */ if (source_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, - "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", + "SMBus/IPMI/GenericSerialBus write requires " + "Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); @@ -392,17 +400,17 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { accessor_type = obj_desc->field.attribute; - length = acpi_ex_get_serial_access_length(accessor_type, - obj_desc-> - field. - access_length); + length = + acpi_ex_get_serial_access_length(accessor_type, + obj_desc->field. + access_length); /* * Add additional 2 bytes for the generic_serial_bus data buffer: * - * Status; (Byte 0 of the data buffer) - * Length; (Byte 1 of the data buffer) - * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) + * Status; (Byte 0 of the data buffer) + * Length; (Byte 1 of the data buffer) + * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) */ length += 2; function = ACPI_WRITE | (accessor_type << 16); @@ -414,7 +422,8 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, if (source_desc->buffer.length < length) { ACPI_ERROR((AE_INFO, - "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", + "SMBus/IPMI/GenericSerialBus write requires " + "Buffer of length %u, found length %u", length, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); @@ -438,8 +447,8 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, * Perform the write (returns status and perhaps data in the * same buffer) */ - status = acpi_ex_access_region(obj_desc, 0, - (u64 *)buffer, function); + status = + acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); *result_desc = buffer_desc; @@ -460,7 +469,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", + "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", acpi_ut_get_type_name(source_desc->common. type), source_desc->common.type, @@ -476,8 +485,9 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* Perform the write */ - status = acpi_ex_access_region(obj_desc, 0, - (u64 *)buffer, ACPI_WRITE); + status = + acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, + ACPI_WRITE); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 70b7bbb..0337191 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -180,7 +180,8 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, * byte, and a field with Dword access specified. */ ACPI_ERROR((AE_INFO, - "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", + "Field [%4.4s] access width (%u bytes) " + "too large for region [%4.4s] (length %u)", acpi_ut_get_node_name(obj_desc-> common_field.node), obj_desc->common_field.access_byte_width, @@ -194,7 +195,8 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, * exceeds region length, indicate an error */ ACPI_ERROR((AE_INFO, - "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", + "Field [%4.4s] Base+Offset+Width %u+%u+%u " + "is beyond end of region [%4.4s] (length %u)", acpi_ut_get_node_name(obj_desc->common_field.node), obj_desc->common_field.base_byte_offset, field_datum_byte_offset, @@ -638,15 +640,15 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, ACPI_ERROR((AE_INFO, "Unknown UpdateRule value: 0x%X", - (obj_desc->common_field. - field_flags & + (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK))); return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", + "Mask %8.8X%8.8X, DatumOffset %X, Width %X, " + "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", ACPI_FORMAT_UINT64(mask), field_datum_byte_offset, obj_desc->common_field.access_byte_width, @@ -655,8 +657,9 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, /* Write the merged value */ - status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset, - &merged_value, ACPI_WRITE); + status = + acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset, + &merged_value, ACPI_WRITE); return_ACPI_STATUS(status); } @@ -764,8 +767,9 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, /* Get next input datum from the field */ field_offset += obj_desc->common_field.access_byte_width; - status = acpi_ex_field_datum_io(obj_desc, field_offset, - &raw_datum, ACPI_READ); + status = + acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum, + ACPI_READ); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -858,6 +862,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, new_buffer = NULL; required_length = ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); + /* * We must have a buffer that is at least as long as the field * we are writing to. This is because individual fields are @@ -932,9 +937,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Write merged datum to the target field */ merged_datum &= mask; - status = acpi_ex_write_with_update_rule(obj_desc, mask, - merged_datum, - field_offset); + status = + acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum, + field_offset); if (ACPI_FAILURE(status)) { goto exit; } @@ -990,9 +995,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Write the last datum to the field */ merged_datum &= mask; - status = acpi_ex_write_with_update_rule(obj_desc, - mask, merged_datum, - field_offset); + status = + acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum, + field_offset); exit: /* Free temporary buffer if we used one */ diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index d02afec..b5413bb 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -267,8 +267,9 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, case ACPI_TYPE_STRING: - status = acpi_ex_convert_to_string(operand1, &local_operand1, - ACPI_IMPLICIT_CONVERT_HEX); + status = + acpi_ex_convert_to_string(operand1, &local_operand1, + ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: @@ -591,8 +592,9 @@ acpi_ex_do_logical_op(u16 opcode, case ACPI_TYPE_STRING: - status = acpi_ex_convert_to_string(operand1, &local_operand1, - ACPI_IMPLICIT_CONVERT_HEX); + status = + acpi_ex_convert_to_string(operand1, &local_operand1, + ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 20e8781..b2e911a 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -164,8 +164,8 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) ACPI_FUNCTION_TRACE(ex_name_segment); /* - * If first character is a digit, then we know that we aren't looking at a - * valid name segment + * If first character is a digit, then we know that we aren't looking + * at a valid name segment */ char_buf[0] = *aml_address; diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 7793068..bcdf43c 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -484,22 +484,26 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */ - status = acpi_ex_convert_to_string(operand[0], &return_desc, - ACPI_EXPLICIT_CONVERT_DECIMAL); + status = + acpi_ex_convert_to_string(operand[0], &return_desc, + ACPI_EXPLICIT_CONVERT_DECIMAL); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference(return_desc); } break; case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */ - status = acpi_ex_convert_to_string(operand[0], &return_desc, - ACPI_EXPLICIT_CONVERT_HEX); + status = + acpi_ex_convert_to_string(operand[0], &return_desc, + ACPI_EXPLICIT_CONVERT_HEX); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference(return_desc); } break; @@ -510,17 +514,20 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference(return_desc); } break; case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */ - status = acpi_ex_convert_to_integer(operand[0], &return_desc, - ACPI_ANY_BASE); + status = + acpi_ex_convert_to_integer(operand[0], &return_desc, + ACPI_ANY_BASE); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference(return_desc); } break; @@ -713,9 +720,9 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* Get the base object */ - status = acpi_ex_resolve_multiple(walk_state, - operand[0], &type, - &temp_desc); + status = + acpi_ex_resolve_multiple(walk_state, operand[0], &type, + &temp_desc); if (ACPI_FAILURE(status)) { goto cleanup; } @@ -759,8 +766,10 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) default: ACPI_ERROR((AE_INFO, - "Operand must be Buffer/Integer/String/Package - found type %s", + "Operand must be Buffer/Integer/String/Package" + " - found type %s", acpi_ut_get_type_name(type))); + status = AE_AML_OPERAND_TYPE; goto cleanup; } @@ -981,6 +990,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) "Unknown Index TargetType 0x%X in reference object %p", operand[0]->reference. target_type, operand[0])); + status = AE_AML_OPERAND_TYPE; goto cleanup; } @@ -1050,6 +1060,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); + status = AE_AML_BAD_OPCODE; goto cleanup; } diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index b8944eb..6dad2ca 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -199,6 +199,7 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); + status = AE_AML_BAD_OPCODE; goto cleanup; } @@ -299,8 +300,9 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ - status = acpi_ex_do_concatenate(operand[0], operand[1], - &return_desc, walk_state); + status = + acpi_ex_do_concatenate(operand[0], operand[1], &return_desc, + walk_state); break; case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ @@ -345,8 +347,9 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ - status = acpi_ex_concat_template(operand[0], operand[1], - &return_desc, walk_state); + status = + acpi_ex_concat_template(operand[0], operand[1], + &return_desc, walk_state); break; case AML_INDEX_OP: /* Index (Source Index Result) */ @@ -553,6 +556,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); + status = AE_AML_BAD_OPCODE; goto cleanup; } diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 351b82a..27fb017 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -95,7 +95,8 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "FatalOp: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + "FatalOp: Type %X Code %X Arg %X " + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", (u32)operand[0]->integer.value, (u32)operand[1]->integer.value, (u32)operand[2]->integer.value)); @@ -131,6 +132,7 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); + status = AE_AML_BAD_OPCODE; goto cleanup; } @@ -193,7 +195,8 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* Truncate request if larger than the actual String/Buffer */ else if ((index + length) > operand[0]->string.length) { - length = (acpi_size) operand[0]->string.length - + length = + (acpi_size) operand[0]->string.length - (acpi_size) index; } @@ -237,8 +240,8 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* We have a buffer, copy the portion requested */ - memcpy(buffer, operand[0]->string.pointer + index, - length); + memcpy(buffer, + operand[0]->string.pointer + index, length); } /* Set the length of the new String/Buffer */ @@ -255,6 +258,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); + status = AE_AML_BAD_OPCODE; goto cleanup; } @@ -270,12 +274,11 @@ cleanup: if (ACPI_FAILURE(status) || walk_state->result_obj) { acpi_ut_remove_reference(return_desc); walk_state->result_obj = NULL; - } + } else { + /* Set the return object and exit */ - /* Set the return object and exit */ - - else { walk_state->result_obj = return_desc; } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index c930edd..7efc9f4 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -310,6 +310,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); + status = AE_AML_BAD_OPCODE; goto cleanup; } diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 4c2836d..1f111cc 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities + * Module Name: exprep - ACPI AML field prep utilities * *****************************************************************************/ @@ -103,8 +103,10 @@ acpi_ex_generate_access(u32 field_bit_offset, /* Round Field start offset and length to "minimal" byte boundaries */ field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8)); - field_byte_end_offset = ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + - field_bit_offset, 8)); + + field_byte_end_offset = + ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8)); + field_byte_length = field_byte_end_offset - field_byte_offset; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, @@ -159,7 +161,8 @@ acpi_ex_generate_access(u32 field_bit_offset, if (accesses <= 1) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "Entire field can be accessed with one operation of size %u\n", + "Entire field can be accessed " + "with one operation of size %u\n", access_byte_width)); return_VALUE(access_byte_width); } @@ -202,6 +205,7 @@ acpi_ex_generate_access(u32 field_bit_offset, */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Cannot access field in one operation, using width 8\n")); + return_VALUE(8); } #endif /* ACPI_UNDER_DEVELOPMENT */ @@ -281,6 +285,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, /* Invalid field access type */ ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access)); + return_UINT32(0); } @@ -354,8 +359,8 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is * the same (equivalent) as the byte_alignment. */ - access_bit_width = acpi_ex_decode_field_access(obj_desc, field_flags, - &byte_alignment); + access_bit_width = + acpi_ex_decode_field_access(obj_desc, field_flags, &byte_alignment); if (!access_bit_width) { return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } @@ -595,7 +600,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", + "IndexField: BitOff %X, Off %X, Value %X, " + "Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, @@ -615,8 +621,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) * Store the constructed descriptor (obj_desc) into the parent Node, * preserving the current type of that named_obj. */ - status = acpi_ns_attach_object(info->field_node, obj_desc, - acpi_ns_get_type(info->field_node)); + status = + acpi_ns_attach_object(info->field_node, obj_desc, + acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index b4a5e44..1851a30 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -392,7 +392,8 @@ acpi_ex_pci_config_space_handler(u32 function, pci_register = (u16) (u32) address; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Pci-Config %u (%u) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n", + "Pci-Config %u (%u) Seg(%04x) Bus(%04x) " + "Dev(%04x) Func(%04x) Reg(%04x)\n", function, bit_width, pci_id->segment, pci_id->bus, pci_id->device, pci_id->function, pci_register)); @@ -400,14 +401,16 @@ acpi_ex_pci_config_space_handler(u32 function, case ACPI_READ: *value = 0; - status = acpi_os_read_pci_configuration(pci_id, pci_register, - value, bit_width); + status = + acpi_os_read_pci_configuration(pci_id, pci_register, value, + bit_width); break; case ACPI_WRITE: - status = acpi_os_write_pci_configuration(pci_id, pci_register, - *value, bit_width); + status = + acpi_os_write_pci_configuration(pci_id, pci_register, + *value, bit_width); break; default: diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 1b372ef..6793dcc 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -112,7 +112,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, /* * Several object types require no further processing: - * 1) Device/Thermal objects don't have a "real" subobject, return the Node + * 1) Device/Thermal objects don't have a "real" subobject, return Node * 2) Method locals and arguments have a pseudo-Node * 3) 10/2007: Added method type to assist with Package construction. */ diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index a1afe1a..7f9260b 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -217,7 +217,8 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, * the package, can't dereference it */ ACPI_ERROR((AE_INFO, - "Attempt to dereference an Index to NULL package element Idx=%p", + "Attempt to dereference an Index to " + "NULL package element Idx=%p", stack_desc)); status = AE_AML_UNINITIALIZED_ELEMENT; } @@ -361,10 +362,9 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, if (type == ACPI_TYPE_LOCAL_ALIAS) { type = ((struct acpi_namespace_node *)obj_desc)->type; - obj_desc = - acpi_ns_get_attached_object((struct - acpi_namespace_node *) - obj_desc); + obj_desc = acpi_ns_get_attached_object((struct + acpi_namespace_node + *)obj_desc); } if (!obj_desc) { diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 424442d..861453e 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -90,8 +90,8 @@ acpi_ex_check_object_type(acpi_object_type type_needed, * specification, a store to a constant is a noop.) */ if ((this_type == ACPI_TYPE_INTEGER) && - (((union acpi_operand_object *)object)->common. - flags & AOPOBJ_AML_CONSTANT)) { + (((union acpi_operand_object *)object)->common.flags & + AOPOBJ_AML_CONSTANT)) { return (AE_OK); } } @@ -196,10 +196,10 @@ acpi_ex_resolve_operands(u16 opcode, * thus, the attached object is always the aliased namespace node */ if (object_type == ACPI_TYPE_LOCAL_ALIAS) { - obj_desc = - acpi_ns_get_attached_object((struct - acpi_namespace_node - *)obj_desc); + obj_desc = acpi_ns_get_attached_object((struct + acpi_namespace_node + *) + obj_desc); *stack_ptr = obj_desc; object_type = ((struct acpi_namespace_node *)obj_desc)-> @@ -285,8 +285,8 @@ acpi_ex_resolve_operands(u16 opcode, case ARGI_REF_OR_STRING: /* Can be a String or Reference */ if ((ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == - ACPI_DESC_TYPE_OPERAND) - && (obj_desc->common.type == ACPI_TYPE_STRING)) { + ACPI_DESC_TYPE_OPERAND) && + (obj_desc->common.type == ACPI_TYPE_STRING)) { /* * String found - the string references a named object and * must be resolved to a node @@ -465,8 +465,9 @@ acpi_ex_resolve_operands(u16 opcode, * But we can implicitly convert from a BUFFER or INTEGER * aka - "Implicit Source Operand Conversion" */ - status = acpi_ex_convert_to_string(obj_desc, stack_ptr, - ACPI_IMPLICIT_CONVERT_HEX); + status = + acpi_ex_convert_to_string(obj_desc, stack_ptr, + ACPI_IMPLICIT_CONVERT_HEX); if (ACPI_FAILURE(status)) { if (status == AE_TYPE) { ACPI_ERROR((AE_INFO, @@ -597,8 +598,10 @@ acpi_ex_resolve_operands(u16 opcode, case ARGI_REGION_OR_BUFFER: /* Used by Load() only */ - /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */ - + /* + * Need an operand of type REGION or a BUFFER + * (which could be a resolved region field) + */ switch (obj_desc->common.type) { case ACPI_TYPE_BUFFER: case ACPI_TYPE_REGION: @@ -640,9 +643,9 @@ acpi_ex_resolve_operands(u16 opcode, if (acpi_gbl_enable_interpreter_slack) { /* - * Enable original behavior of Store(), allowing any and all - * objects as the source operand. The ACPI spec does not - * allow this, however. + * Enable original behavior of Store(), allowing any + * and all objects as the source operand. The ACPI + * spec does not allow this, however. */ break; } @@ -655,7 +658,8 @@ acpi_ex_resolve_operands(u16 opcode, } ACPI_ERROR((AE_INFO, - "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p", + "Needed Integer/Buffer/String/Package/Ref/Ddb]" + ", found [%s] %p", acpi_ut_get_object_type_name (obj_desc), obj_desc)); @@ -678,9 +682,10 @@ acpi_ex_resolve_operands(u16 opcode, * Make sure that the original object was resolved to the * required object type (Simple cases only). */ - status = acpi_ex_check_object_type(type_needed, - (*stack_ptr)->common.type, - *stack_ptr); + status = + acpi_ex_check_object_type(type_needed, + (*stack_ptr)->common.type, + *stack_ptr); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index c076e91..d3afbcb 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -467,7 +467,8 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, case ACPI_TYPE_THERMAL: ACPI_ERROR((AE_INFO, - "Target must be [Buffer/Integer/String/Reference], found [%s] (%4.4s)", + "Target must be [Buffer/Integer/String/Reference]" + ", found [%s] (%4.4s)", acpi_ut_get_type_name(node->type), node->name.ascii)); @@ -504,8 +505,9 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, * an implicit conversion, as per the ACPI specification. * A direct store is performed instead. */ - status = acpi_ex_store_direct_to_node(source_desc, node, - walk_state); + status = + acpi_ex_store_direct_to_node(source_desc, node, + walk_state); break; } @@ -528,8 +530,9 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, * store has been performed such that the node/object type * has been changed. */ - status = acpi_ns_attach_object(node, new_desc, - new_desc->common.type); + status = + acpi_ns_attach_object(node, new_desc, + new_desc->common.type); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Store type [%s] into [%s] via Convert/Attach\n", @@ -563,8 +566,8 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, * operator. (Note, for this default case, all normal * Store/Target operations exited above with an error). */ - status = acpi_ex_store_direct_to_node(source_desc, node, - walk_state); + status = + acpi_ex_store_direct_to_node(source_desc, node, walk_state); break; } diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index e1d4f4d..ad3bc92 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Module Name: exstorob - AML Interpreter object store support, store to object + * Module Name: exstorob - AML object store support, store to object * *****************************************************************************/ @@ -203,8 +203,9 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, ACPI_FREE(target_desc->string.pointer); } - target_desc->string.pointer = ACPI_ALLOCATE_ZEROED((acpi_size) - length + 1); + target_desc->string.pointer = + ACPI_ALLOCATE_ZEROED((acpi_size) length + 1); + if (!target_desc->string.pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index 0545065..7c91c1f 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -78,7 +78,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* We must wait, so unlock the interpreter */ acpi_ex_exit_interpreter(); - status = acpi_os_wait_semaphore(semaphore, 1, timeout); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, @@ -124,7 +123,6 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* We must wait, so unlock the interpreter */ acpi_ex_exit_interpreter(); - status = acpi_os_acquire_mutex(mutex, timeout); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, @@ -169,8 +167,8 @@ acpi_status acpi_ex_system_do_stall(u32 how_long) * (ACPI specifies 100 usec as max, but this gives some slack in * order to support existing BIOSs) */ - ACPI_ERROR((AE_INFO, "Time parameter is too large (%u)", - how_long)); + ACPI_ERROR((AE_INFO, + "Time parameter is too large (%u)", how_long)); status = AE_AML_OPERAND_VALUE; } else { acpi_os_stall(how_long); diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 30c3f46..8ae7634 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -167,8 +167,8 @@ u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc) if ((acpi_gbl_integer_byte_width == 4) && (obj_desc->integer.value > (u64)ACPI_UINT32_MAX)) { /* - * We are executing in a 32-bit ACPI table. - * Truncate the value to 32 bits by zeroing out the upper 32-bit field + * We are executing in a 32-bit ACPI table. Truncate + * the value to 32 bits by zeroing out the upper 32-bit field */ obj_desc->integer.value &= (u64)ACPI_UINT32_MAX; return (TRUE); @@ -323,7 +323,8 @@ void acpi_ex_eisa_id_to_string(char *out_string, u64 compressed_id) if (compressed_id > ACPI_UINT32_MAX) { ACPI_WARNING((AE_INFO, - "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating", + "Expected EISAID is larger than 32 bits: " + "0x%8.8X%8.8X, truncating", ACPI_FORMAT_UINT64(compressed_id))); } diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index e5599f6..d0319a2 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -117,8 +117,8 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) /* Clear wake status (WAK_STS) */ - status = - acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status); + status = acpi_write((u64)ACPI_X_WAKE_STATUS, + &acpi_gbl_FADT.sleep_status); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index da4a923..8272f96 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -187,9 +187,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) */ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info); - status = acpi_hw_write(register_bit, - &gpe_register_info->status_address); - + status = + acpi_hw_write(register_bit, &gpe_register_info->status_address); return (status); } @@ -297,8 +296,8 @@ acpi_hw_gpe_enable_write(u8 enable_mask, acpi_status status; gpe_register_info->enable_mask = enable_mask; - status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); + status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); return (status); } diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 7d21cae..ac5b7f7 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -80,8 +80,8 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) /* Clear wake status */ - status = - acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); + status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, + ACPI_CLEAR_STATUS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index d62a616..f8af1ab 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -286,6 +286,7 @@ acpi_status acpi_enter_sleep_state_s4bios(void) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } + } while (!in_value); return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index da55a1c..749a189 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -96,9 +96,9 @@ acpi_ns_convert_to_integer(union acpi_operand_object *original_object, /* Extract each buffer byte to create the integer */ for (i = 0; i < original_object->buffer.length; i++) { - value |= - ((u64)original_object->buffer. - pointer[i] << (i * 8)); + value |= ((u64) + original_object->buffer.pointer[i] << (i * + 8)); } break; @@ -153,10 +153,9 @@ acpi_ns_convert_to_string(union acpi_operand_object *original_object, return (AE_NO_MEMORY); } } else { - status = - acpi_ex_convert_to_string(original_object, - &new_object, - ACPI_IMPLICIT_CONVERT_HEX); + status = acpi_ex_convert_to_string(original_object, + &new_object, + ACPI_IMPLICIT_CONVERT_HEX); if (ACPI_FAILURE(status)) { return (status); } @@ -244,9 +243,8 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, /* String-to-Buffer conversion. Simple data copy */ - new_object = - acpi_ut_create_buffer_object(original_object->string. - length); + new_object = acpi_ut_create_buffer_object + (original_object->string.length); if (!new_object) { return (AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index e071956..bc5ff35 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -539,11 +539,13 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, acpi_os_printf ("(Pointer to ACPI Object type %.2X [UNKNOWN])\n", obj_type); + bytes_to_dump = 32; } else { acpi_os_printf ("(Pointer to ACPI Object type %.2X [%s])\n", obj_type, acpi_ut_get_type_name(obj_type)); + bytes_to_dump = sizeof(union acpi_operand_object); } @@ -573,6 +575,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, */ bytes_to_dump = obj_desc->string.length; obj_desc = (void *)obj_desc->string.pointer; + acpi_os_printf("(Buffer/String pointer %p length %X)\n", obj_desc, bytes_to_dump); ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 14ab836..c106916 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -321,7 +321,6 @@ acpi_status acpi_ns_unload_namespace(acpi_handle handle) /* This function does the real work */ status = acpi_ns_delete_subtree(handle); - return_ACPI_STATUS(status); } #endif diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 8934b4e..521031f 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -70,7 +70,6 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node); name_buffer = acpi_ns_get_normalized_pathname(node, FALSE); - return_PTR(name_buffer); } @@ -93,7 +92,6 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) ACPI_FUNCTION_ENTRY(); size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE); - return (size); } @@ -217,6 +215,7 @@ acpi_ns_build_normalized_path(struct acpi_namespace_node *node, ACPI_PATH_PUT8(full_path, path_size, AML_DUAL_NAME_PREFIX, length); } + ACPI_MOVE_32_TO_32(name, &next_node->name); do_no_trailing = no_trailing; for (i = 0; i < 4; i++) { @@ -228,8 +227,10 @@ acpi_ns_build_normalized_path(struct acpi_namespace_node *node, ACPI_PATH_PUT8(full_path, path_size, c, length); } } + next_node = next_node->parent; } + ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length); /* Reverse the path string */ @@ -237,6 +238,7 @@ acpi_ns_build_normalized_path(struct acpi_namespace_node *node, if (length <= path_size) { left = full_path; right = full_path + length - 1; + while (left < right) { c = *left; *left++ = *right; diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 3736d43b..43b45a8 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -141,8 +141,8 @@ acpi_ns_one_complete_parse(u32 pass_number, /* Parse the AML */ - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %u parse\n", - pass_number)); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "*PARSE* pass %u parse\n", pass_number)); status = acpi_ps_parse_aml(walk_state); cleanup: @@ -181,6 +181,7 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) * performs another complete parse of the AML. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); + status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index, start_node); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index 9bb2519..c05a83b 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -233,8 +233,9 @@ acpi_ns_check_package(struct acpi_evaluate_info *info, /* First element is the (Integer) revision */ - status = acpi_ns_check_object_type(info, elements, - ACPI_RTYPE_INTEGER, 0); + status = + acpi_ns_check_object_type(info, elements, + ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { return (status); } @@ -252,8 +253,9 @@ acpi_ns_check_package(struct acpi_evaluate_info *info, /* First element is the (Integer) count of subpackages to follow */ - status = acpi_ns_check_object_type(info, elements, - ACPI_RTYPE_INTEGER, 0); + status = + acpi_ns_check_object_type(info, elements, + ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { return (status); } diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 77d8103..360e3ab 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -366,6 +366,7 @@ static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct return (NULL); } + this_name++; } @@ -521,6 +522,7 @@ acpi_ns_remove_null_elements(struct acpi_evaluate_info *info, *dest = *source; dest++; } + source++; } @@ -572,8 +574,8 @@ acpi_ns_wrap_with_package(struct acpi_evaluate_info *info, ACPI_FUNCTION_NAME(ns_wrap_with_package); /* - * Create the new outer package and populate it. The new package will - * have a single element, the lone sub-object. + * Create the new outer package and populate it. The new + * package will have a single element, the lone sub-object. */ pkg_obj_desc = acpi_ut_create_package_object(1); if (!pkg_obj_desc) { diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 7ca8f2b..f6dd2a8 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -225,6 +225,7 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) { return (this_name); } + this_name++; } @@ -301,7 +302,8 @@ acpi_ns_repair_FDE(struct acpi_evaluate_info *info, /* We can only repair if we have exactly 5 BYTEs */ if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) { - ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, + ACPI_WARN_PREDEFINED((AE_INFO, + info->full_pathname, info->node_flags, "Incorrect return buffer length %u, expected %u", return_object->buffer.length, @@ -321,8 +323,8 @@ acpi_ns_repair_FDE(struct acpi_evaluate_info *info, /* Expand each byte to a DWORD */ byte_buffer = return_object->buffer.pointer; - dword_buffer = - ACPI_CAST_PTR(u32, buffer_object->buffer.pointer); + dword_buffer = ACPI_CAST_PTR(u32, + buffer_object->buffer.pointer); for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) { *dword_buffer = (u32) *byte_buffer; @@ -461,7 +463,8 @@ acpi_ns_repair_CST(struct acpi_evaluate_info *info, removing = FALSE; if ((*outer_elements)->package.count == 0) { - ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, + ACPI_WARN_PREDEFINED((AE_INFO, + info->full_pathname, info->node_flags, "SubPackage[%u] - removing entry due to zero count", i)); @@ -471,7 +474,8 @@ acpi_ns_repair_CST(struct acpi_evaluate_info *info, obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */ if ((u32)obj_desc->integer.value == 0) { - ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, + ACPI_WARN_PREDEFINED((AE_INFO, + info->full_pathname, info->node_flags, "SubPackage[%u] - removing entry due to invalid Type(0)", i)); @@ -538,8 +542,8 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info, } if (return_object->string.length == 0) { - ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, - info->node_flags, + ACPI_WARN_PREDEFINED((AE_INFO, + info->full_pathname, info->node_flags, "Invalid zero-length _HID or _CID string")); /* Return AE_OK anyway, let driver handle it */ @@ -711,7 +715,8 @@ acpi_ns_repair_PSS(struct acpi_evaluate_info *info, obj_desc = elements[1]; /* Index1 = power_dissipation */ if ((u32)obj_desc->integer.value > previous_value) { - ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, + ACPI_WARN_PREDEFINED((AE_INFO, + info->full_pathname, info->node_flags, "SubPackage[%u,%u] - suspicious power dissipation values", i - 1, i)); @@ -969,6 +974,7 @@ acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index) *dest = *source; dest++; } + source++; } diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index de325ae..32f1d95 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -173,9 +173,10 @@ void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info) info->fully_qualified = FALSE; /* - * For the internal name, the required length is 4 bytes per segment, plus - * 1 each for root_prefix, multi_name_prefix_op, segment count, trailing null - * (which is not really needed, but no there's harm in putting it there) + * For the internal name, the required length is 4 bytes per segment, + * plus 1 each for root_prefix, multi_name_prefix_op, segment count, + * trailing null (which is not really needed, but no there's harm in + * putting it there) * * strlen() + 1 covers the first name_seg, which has no path separator */ @@ -699,6 +700,7 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node, if (!prefix_node) { *return_node = acpi_gbl_root_node; } + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 6ee1e52..429f0d2 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -750,8 +750,8 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, /* We have a valid device, invoke the user function */ - status = info->user_function(obj_handle, nesting_level, info->context, - return_value); + status = info->user_function(obj_handle, nesting_level, + info->context, return_value); return (status); } diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 138cf5e..c19d86c 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -591,6 +591,7 @@ acpi_status acpi_install_method(u8 *buffer) parser_state.aml += acpi_ps_get_opcode_size(opcode); parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); path = acpi_ps_get_next_namestring(&parser_state); + method_flags = *parser_state.aml++; aml_start = parser_state.aml; aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 7933835..6e1389b 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -74,10 +74,8 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) return (AE_BAD_PARAMETER); } - /* - * Special case for the predefined Root Node - * (return type ANY) - */ + /* Special case for the predefined Root Node (return type ANY) */ + if (handle == ACPI_ROOT_OBJECT) { *ret_type = ACPI_TYPE_ANY; return (AE_OK); diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 29d8b7b..3f0ffee 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -733,6 +733,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } + acpi_ps_get_next_simple_arg(parser_state, arg_type, arg); break; diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 03ac8c9..c660006 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -124,8 +124,8 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, /* * Op is not a constant or string, append each argument to the Op */ - while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) - && !walk_state->arg_count) { + while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && + !walk_state->arg_count) { walk_state->aml = walk_state->parser_state.aml; status = diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 98001d7..b729d9b 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -526,8 +526,8 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) } /* - * If the transfer to the new method method call worked, a new walk - * state was created -- get it + * If the transfer to the new method method call worked + *, a new walk state was created -- get it */ walk_state = acpi_ds_get_current_walk_state(thread); continue; @@ -544,8 +544,8 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) /* Check for possible multi-thread reentrancy problem */ if ((status == AE_ALREADY_EXISTS) && - (!(walk_state->method_desc->method. - info_flags & ACPI_METHOD_SERIALIZED))) { + (!(walk_state->method_desc->method.info_flags & + ACPI_METHOD_SERIALIZED))) { /* * Method is not serialized and tried to create an object * twice. The probable cause is that the method cannot diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 71d2877..6cb02a2 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -175,8 +175,8 @@ void acpi_ps_free_op(union acpi_parse_object *op) ACPI_FUNCTION_NAME(ps_free_op); if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { - ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", - op)); + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, + "Free retval op: %p\n", op)); } if (op->common.flags & ACPI_PARSEOP_GENERIC) { diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index ba5f691..f620d43 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -99,6 +99,7 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) if (op == subtree_root) { return_VOID; } + if (next) { op = next; } else { diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 66d406e..bdb7e73 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -312,8 +312,8 @@ acpi_rs_get_address_common(struct acpi_resource *resource, /* Validate the Resource Type */ - if ((aml->address.resource_type > 2) - && (aml->address.resource_type < 0xC0)) { + if ((aml->address.resource_type > 2) && + (aml->address.resource_type < 0xC0)) { return (FALSE); } diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index cb739a6..88fce58 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -143,16 +143,17 @@ acpi_rs_stream_option_length(u32 resource_length, ACPI_FUNCTION_ENTRY(); /* - * The resource_source_index and resource_source are optional elements of some - * Large-type resource descriptors. + * The resource_source_index and resource_source are optional elements of + * some Large-type resource descriptors. */ /* - * If the length of the actual resource descriptor is greater than the ACPI - * spec-defined minimum length, it means that a resource_source_index exists - * and is followed by a (required) null terminated string. The string length - * (including the null terminator) is the resource length minus the minimum - * length, minus one byte for the resource_source_index itself. + * If the length of the actual resource descriptor is greater than the + * ACPI spec-defined minimum length, it means that a resource_source_index + * exists and is followed by a (required) null terminated string. The + * string length (including the null terminator) is the resource length + * minus the minimum length, minus one byte for the resource_source_index + * itself. */ if (resource_length > minimum_aml_resource_length) { @@ -277,11 +278,11 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, * 16-Bit Address Resource: * Add the size of the optional resource_source info */ - total_size = (acpi_rs_length) - (total_size + - acpi_rs_struct_option_length(&resource->data. - address16. - resource_source)); + total_size = (acpi_rs_length) (total_size + + acpi_rs_struct_option_length + (&resource->data. + address16. + resource_source)); break; case ACPI_RESOURCE_TYPE_ADDRESS32: @@ -289,11 +290,11 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, * 32-Bit Address Resource: * Add the size of the optional resource_source info */ - total_size = (acpi_rs_length) - (total_size + - acpi_rs_struct_option_length(&resource->data. - address32. - resource_source)); + total_size = (acpi_rs_length) (total_size + + acpi_rs_struct_option_length + (&resource->data. + address32. + resource_source)); break; case ACPI_RESOURCE_TYPE_ADDRESS64: @@ -301,11 +302,11 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, * 64-Bit Address Resource: * Add the size of the optional resource_source info */ - total_size = (acpi_rs_length) - (total_size + - acpi_rs_struct_option_length(&resource->data. - address64. - resource_source)); + total_size = (acpi_rs_length) (total_size + + acpi_rs_struct_option_length + (&resource->data. + address64. + resource_source)); break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: @@ -314,26 +315,28 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, * Add the size of each additional optional interrupt beyond the * required 1 (4 bytes for each u32 interrupt number) */ - total_size = (acpi_rs_length) - (total_size + - ((resource->data.extended_irq.interrupt_count - - 1) * 4) + - /* Add the size of the optional resource_source info */ - acpi_rs_struct_option_length(&resource->data. - extended_irq. - resource_source)); + total_size = (acpi_rs_length) (total_size + + ((resource->data. + extended_irq. + interrupt_count - + 1) * 4) + + /* Add the size of the optional resource_source info */ + acpi_rs_struct_option_length + (&resource->data. + extended_irq. + resource_source)); break; case ACPI_RESOURCE_TYPE_GPIO: - total_size = - (acpi_rs_length) (total_size + - (resource->data.gpio. - pin_table_length * 2) + - resource->data.gpio. - resource_source.string_length + - resource->data.gpio. - vendor_length); + total_size = (acpi_rs_length) (total_size + + (resource->data.gpio. + pin_table_length * 2) + + resource->data.gpio. + resource_source. + string_length + + resource->data.gpio. + vendor_length); break; @@ -566,8 +569,8 @@ acpi_rs_get_list_length(u8 * aml_buffer, acpi_gbl_resource_struct_sizes[resource_index] + extra_struct_bytes; } - buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); + buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); *size_needed += buffer_size; ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index a534442..603e544 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -81,8 +81,9 @@ acpi_buffer_to_resource(u8 *aml_buffer, /* Get the required length for the converted resource */ - status = acpi_rs_get_list_length(aml_buffer, aml_buffer_length, - &list_size_needed); + status = + acpi_rs_get_list_length(aml_buffer, aml_buffer_length, + &list_size_needed); if (status == AE_AML_NO_RESOURCE_END_TAG) { status = AE_OK; } @@ -232,8 +233,9 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* Get the required buffer length */ - status = acpi_rs_get_pci_routing_table_length(package_object, - &buffer_size_needed); + status = + acpi_rs_get_pci_routing_table_length(package_object, + &buffer_size_needed); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -270,9 +272,9 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, user_prt = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer); /* - * Fill in the Length field with the information we have at this point. - * The minus four is to subtract the size of the u8 Source[4] member - * because it is added below. + * Fill in the Length field with the information we have at this + * point. The minus four is to subtract the size of the u8 + * Source[4] member because it is added below. */ user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4); @@ -345,11 +347,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, (u8 *) output_buffer->pointer); path_buffer.pointer = user_prt->source; - status = - acpi_ns_handle_to_pathname((acpi_handle) - node, - &path_buffer, - FALSE); + status = acpi_ns_handle_to_pathname((acpi_handle) node, &path_buffer, FALSE); /* +1 to include null terminator */ @@ -371,8 +369,8 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, case ACPI_TYPE_INTEGER: /* - * If this is a number, then the Source Name is NULL, since the - * entire buffer was zeroed out, we can leave this alone. + * If this is a number, then the Source Name is NULL, since + * the entire buffer was zeroed out, we can leave this alone. * * Add to the Length field the length of the u32 NULL */ @@ -451,9 +449,9 @@ acpi_rs_create_aml_resources(struct acpi_buffer *resource_list, /* Get the buffer size needed for the AML byte stream */ - status = acpi_rs_get_aml_length(resource_list->pointer, - resource_list->length, - &aml_size_needed); + status = + acpi_rs_get_aml_length(resource_list->pointer, + resource_list->length, &aml_size_needed); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", (u32)aml_size_needed, acpi_format_exception(status))); diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 2a09288..05cc560 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -483,6 +483,7 @@ static void acpi_rs_dump_address_common(union acpi_resource_data *resource) static void acpi_rs_out_string(char *title, char *value) { + acpi_os_printf("%27s : %s", title, value); if (!*value) { acpi_os_printf("[NULL NAMESTRING]"); @@ -497,21 +498,25 @@ static void acpi_rs_out_integer8(char *title, u8 value) static void acpi_rs_out_integer16(char *title, u16 value) { + acpi_os_printf("%27s : %4.4X\n", title, value); } static void acpi_rs_out_integer32(char *title, u32 value) { + acpi_os_printf("%27s : %8.8X\n", title, value); } static void acpi_rs_out_integer64(char *title, u64 value) { + acpi_os_printf("%27s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value)); } static void acpi_rs_out_title(char *title) { + acpi_os_printf("%27s : ", title); } @@ -544,6 +549,7 @@ static void acpi_rs_dump_short_byte_list(u8 length, u8 * data) for (i = 0; i < length; i++) { acpi_os_printf("%X ", data[i]); } + acpi_os_printf("\n"); } diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 50d5be2..286ccb461 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -89,6 +89,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, /* Get the appropriate conversion info table */ aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { if (aml_resource->common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE) { @@ -225,10 +226,10 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Perform final sanity check on the new AML resource descriptor */ - status = acpi_ut_validate_resource(NULL, - ACPI_CAST_PTR(union - aml_resource, - aml), NULL); + status = + acpi_ut_validate_resource(NULL, + ACPI_CAST_PTR(union aml_resource, + aml), NULL); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index b528ed90..b112c7b 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -189,8 +189,8 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, item_count = ACPI_GET8(source); ACPI_SET8(destination, item_count); - resource->length = resource->length + - (info->value * item_count); + resource->length = + resource->length + (info->value * item_count); break; case ACPI_RSC_COUNT_GPIO_RES: @@ -445,8 +445,8 @@ exit: /* Round the resource struct length up to the next boundary (32 or 64) */ - resource->length = - (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); + resource->length = (u32) + ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); } return_ACPI_STATUS(AE_OK); } @@ -550,9 +550,8 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, item_count = ACPI_GET8(source); ACPI_SET8(destination, item_count); - aml_length = - (u16)(aml_length + - (info->value * (item_count - 1))); + aml_length = (u16) + (aml_length + (info->value * (item_count - 1))); break; case ACPI_RSC_COUNT16: @@ -723,11 +722,10 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, /* * 16-bit encoded bitmask (IRQ macro) */ - temp16 = acpi_rs_encode_bitmask(source, - *ACPI_ADD_PTR(u8, - resource, - info-> - value)); + temp16 = + acpi_rs_encode_bitmask(source, + *ACPI_ADD_PTR(u8, resource, + info->value)); ACPI_MOVE_16_TO_16(destination, &temp16); break; diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 9486992..33e558c 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -221,14 +221,13 @@ acpi_rs_set_resource_length(acpi_rsdesc_size total_length, ACPI_MOVE_16_TO_16(&aml->large_header.resource_length, &resource_length); } else { - /* Small descriptor -- bits 2:0 of byte 0 contain the length */ - + /* + * Small descriptor -- bits 2:0 of byte 0 contain the length + * Clear any existing length, preserving descriptor type bits + */ aml->small_header.descriptor_type = (u8) - - /* Clear any existing length, preserving descriptor type bits */ - ((aml->small_header. - descriptor_type & ~ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK) - + ((aml->small_header.descriptor_type & + ~ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK) | resource_length); } } @@ -333,8 +332,8 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, aml_resource_source = ACPI_ADD_PTR(u8, aml, minimum_length); /* - * resource_source is present if the length of the descriptor is longer than - * the minimum length. + * resource_source is present if the length of the descriptor is longer + * than the minimum length. * * Note: Some resource descriptors will have an additional null, so * we add 1 to the minimum length. @@ -366,6 +365,7 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, total_length = (u32)strlen(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; + total_length = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); memset(resource_source->string_ptr, 0, total_length); @@ -438,8 +438,8 @@ acpi_rs_set_resource_source(union aml_resource * aml, * Add the length of the string (+ 1 for null terminator) to the * final descriptor length */ - descriptor_length += - ((acpi_rsdesc_size) resource_source->string_length + 1); + descriptor_length += ((acpi_rsdesc_size) + resource_source->string_length + 1); } /* Return the new total length of the AML descriptor */ @@ -478,8 +478,9 @@ acpi_rs_get_prt_method_data(struct acpi_namespace_node * node, /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(node, METHOD_NAME__PRT, - ACPI_BTYPE_PACKAGE, &obj_desc); + status = + acpi_ut_evaluate_object(node, METHOD_NAME__PRT, ACPI_BTYPE_PACKAGE, + &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -527,8 +528,9 @@ acpi_rs_get_crs_method_data(struct acpi_namespace_node *node, /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(node, METHOD_NAME__CRS, - ACPI_BTYPE_BUFFER, &obj_desc); + status = + acpi_ut_evaluate_object(node, METHOD_NAME__CRS, ACPI_BTYPE_BUFFER, + &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -577,8 +579,9 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(node, METHOD_NAME__PRS, - ACPI_BTYPE_BUFFER, &obj_desc); + status = + acpi_ut_evaluate_object(node, METHOD_NAME__PRS, ACPI_BTYPE_BUFFER, + &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -627,8 +630,9 @@ acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(node, METHOD_NAME__AEI, - ACPI_BTYPE_BUFFER, &obj_desc); + status = + acpi_ut_evaluate_object(node, METHOD_NAME__AEI, ACPI_BTYPE_BUFFER, + &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 1e8cd57..308bfd6 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -53,7 +53,7 @@ ACPI_MODULE_NAME("rsxface") /* Local macros for 16,32-bit to 64-bit conversion */ #define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) -#define ACPI_COPY_ADDRESS(out, in) \ +#define ACPI_COPY_ADDRESS(out, in) \ ACPI_COPY_FIELD(out, in, resource_type); \ ACPI_COPY_FIELD(out, in, producer_consumer); \ ACPI_COPY_FIELD(out, in, decode); \ diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 5c9d5ab..4a81527 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -407,6 +407,7 @@ acpi_tb_verify_temp_table(struct acpi_table_desc * table_desc, char *signature) table_desc->signature.ascii : "????", ACPI_FORMAT_UINT64(table_desc-> address))); + goto invalidate_and_exit; } } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 6319b42..bd87801 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -337,8 +337,8 @@ acpi_tb_install_standard_table(acpi_physical_address address, * need to be unregistered when they are unloaded, and slots in the * root table list should be reused when empty. */ - if (acpi_gbl_root_table_list.tables[i]. - flags & ACPI_TABLE_IS_LOADED) { + if (acpi_gbl_root_table_list.tables[i].flags & + ACPI_TABLE_IS_LOADED) { /* Table is still loaded, this is an error */ diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index 709d511..d0d1259 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -76,6 +76,7 @@ static void acpi_tb_fix_string(char *string, acpi_size length) if (!isprint((int)*string)) { *string = '?'; } + string++; length--; } diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index d8ddef3..72bcccf 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -121,6 +121,7 @@ void acpi_tb_check_dsdt_header(void) ACPI_BIOS_ERROR((AE_INFO, "The DSDT has been corrupted or replaced - " "old, new headers below")); + acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header); acpi_tb_print_table_header(0, acpi_gbl_DSDT); @@ -379,7 +380,6 @@ next_table: } acpi_os_unmap_memory(table, length); - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 55ee14c..9a7d72b 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -191,6 +191,7 @@ acpi_status acpi_tb_load_namespace(void) "(%4.4s:%8.8s) while loading table", table->signature.ascii, table->pointer->oem_table_id)); + tables_failed++; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 257221d..ade8acf 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -257,9 +257,9 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type, ACPI_FUNCTION_ENTRY(); this_index = state->pkg.index; - target_object = (union acpi_object *) - &((union acpi_object *)(state->pkg.dest_object))->package. - elements[this_index]; + target_object = (union acpi_object *)&((union acpi_object *) + (state->pkg.dest_object))-> + package.elements[this_index]; switch (object_type) { case ACPI_COPY_TYPE_SIMPLE: @@ -348,15 +348,15 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, * Free space begins right after the first package */ info.length = ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); - info.free_space = - buffer + ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); + info.free_space = buffer + + ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)); info.object_space = 0; info.num_packages = 1; external_object->type = internal_object->common.type; external_object->package.count = internal_object->package.count; - external_object->package.elements = ACPI_CAST_PTR(union acpi_object, - info.free_space); + external_object->package.elements = + ACPI_CAST_PTR(union acpi_object, info.free_space); /* * Leave room for an array of ACPI_OBJECTS in the buffer @@ -593,8 +593,8 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, package_elements = package_object->package.elements; /* - * Recursive implementation. Probably ok, since nested external packages - * as parameters should be very rare. + * Recursive implementation. Probably ok, since nested external + * packages as parameters should be very rare. */ for (i = 0; i < external_object->package.count; i++) { status = @@ -649,9 +649,8 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object, /* * Build a simple object (no nested objects) */ - status = - acpi_ut_copy_esimple_to_isimple(external_object, - internal_object); + status = acpi_ut_copy_esimple_to_isimple(external_object, + internal_object); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 7e14400..3533135 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -180,7 +180,8 @@ const char *acpi_ut_get_event_name(u32 event_id) * * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; * when stored in a table it really means that we have thus far seen no - * evidence to indicate what type is actually going to be stored for this entry. + * evidence to indicate what type is actually going to be stored for this + & entry. */ static const char acpi_gbl_bad_type[] = "UNDEFINED"; diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 1638312..1afd742 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -209,6 +209,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) acpi_ut_delete_object_desc(object->method.mutex); object->method.mutex = NULL; } + if (object->method.node) { object->method.node = NULL; } @@ -515,8 +516,8 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) } /* - * All sub-objects must have their reference count incremented also. - * Different object types have different subobjects. + * All sub-objects must have their reference count incremented + * also. Different object types have different subobjects. */ switch (object->common.type) { case ACPI_TYPE_DEVICE: diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 9ef80f2..f93bb90 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -217,8 +217,9 @@ acpi_ut_namespace_error(const char *module_name, } else { /* Convert path to external format */ - status = acpi_ns_externalize_name(ACPI_UINT32_MAX, - internal_name, NULL, &name); + status = + acpi_ns_externalize_name(ACPI_UINT32_MAX, internal_name, + NULL, &name); /* Print target name */ @@ -271,9 +272,8 @@ acpi_ut_method_error(const char *module_name, acpi_os_printf(ACPI_MSG_ERROR); if (path) { - status = - acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH, - &node); + status = acpi_ns_get_node(prefix_node, path, + ACPI_NS_NO_UPSEARCH, &node); if (ACPI_FAILURE(status)) { acpi_os_printf("[Could not get node by pathname]"); } diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c index d435b7b..be49c71 100644 --- a/drivers/acpi/acpica/utfileio.c +++ b/drivers/acpi/acpica/utfileio.c @@ -106,6 +106,7 @@ acpi_ut_check_text_mode_corruption(u8 *table, u32 table_length, u32 file_length) pairs++; } + i++; } } @@ -125,6 +126,7 @@ acpi_ut_check_text_mode_corruption(u8 *table, u32 table_length, u32 file_length) acpi_os_printf("Table has been corrupted by text mode conversion\n"); acpi_os_printf("All LFs (%u) were changed to CR/LF pairs\n", pairs); acpi_os_printf("Table cannot be repaired!\n"); + return (AE_BAD_VALUE); } diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index f9ff100..58b5d42 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -111,6 +111,7 @@ acpi_ut_short_divide(u64 dividend, */ ACPI_DIV_64_BY_32(0, dividend_ovl.part.hi, divisor, quotient.part.hi, remainder32); + ACPI_DIV_64_BY_32(remainder32, dividend_ovl.part.lo, divisor, quotient.part.lo, remainder32); @@ -179,6 +180,7 @@ acpi_ut_divide(u64 in_dividend, */ ACPI_DIV_64_BY_32(0, dividend.part.hi, divisor.part.lo, quotient.part.hi, partial1); + ACPI_DIV_64_BY_32(partial1, dividend.part.lo, divisor.part.lo, quotient.part.lo, remainder.part.lo); } @@ -206,12 +208,12 @@ acpi_ut_divide(u64 in_dividend, ACPI_DIV_64_BY_32(normalized_dividend.part.hi, normalized_dividend.part.lo, - normalized_divisor.part.lo, - quotient.part.lo, partial1); + normalized_divisor.part.lo, quotient.part.lo, + partial1); /* - * The quotient is always 32 bits, and simply requires adjustment. - * The 64-bit remainder must be generated. + * The quotient is always 32 bits, and simply requires + * adjustment. The 64-bit remainder must be generated. */ partial1 = quotient.part.lo * divisor.part.hi; partial2.full = (u64) quotient.part.lo * divisor.part.lo; diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index bd4443b..eab1cfe 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -264,8 +264,8 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, */ if ((!this_source_obj) || (ACPI_GET_DESCRIPTOR_TYPE(this_source_obj) != - ACPI_DESC_TYPE_OPERAND) - || (this_source_obj->common.type != ACPI_TYPE_PACKAGE)) { + ACPI_DESC_TYPE_OPERAND) || + (this_source_obj->common.type != ACPI_TYPE_PACKAGE)) { status = walk_callback(ACPI_COPY_TYPE_SIMPLE, this_source_obj, state, context); @@ -318,9 +318,10 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, * The callback above returned a new target package object. */ acpi_ut_push_generic_state(&state_list, state); - state = acpi_ut_create_pkg_state(this_source_obj, - state->pkg. - this_target_obj, 0); + state = + acpi_ut_create_pkg_state(this_source_obj, + state->pkg.this_target_obj, + 0); if (!state) { /* Free any stacked Update State objects */ diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index ea0c207..038ff84 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -273,8 +273,9 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) (u32)this_thread_id, acpi_ut_get_mutex_name(mutex_id))); - status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, - ACPI_WAIT_FOREVER); + status = + acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, + ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u acquired Mutex [%s]\n", diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c index 1d5f6b1..9c3cadc 100644 --- a/drivers/acpi/acpica/utnonansi.c +++ b/drivers/acpi/acpica/utnonansi.c @@ -282,8 +282,8 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Divide the digit into the correct position */ - (void)acpi_ut_short_divide((dividend - (u64)this_digit), - base, "ient, NULL); + (void)acpi_ut_short_divide((dividend - (u64)this_digit), base, + "ient, NULL); if (return_value > quotient) { if (to_integer_op) { diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index c7e11cc..787eccf 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -112,9 +112,9 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char /* These types require a secondary object */ - second_object = acpi_ut_allocate_object_desc_dbg(module_name, - line_number, - component_id); + second_object = + acpi_ut_allocate_object_desc_dbg(module_name, line_number, + component_id); if (!second_object) { acpi_ut_delete_object_desc(object); return_PTR(NULL); @@ -254,6 +254,7 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size) if (!buffer) { ACPI_ERROR((AE_INFO, "Could not allocate size %u", (u32)buffer_size)); + acpi_ut_remove_reference(buffer_desc); return_PTR(NULL); } @@ -306,6 +307,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size) if (!string) { ACPI_ERROR((AE_INFO, "Could not allocate size %u", (u32)string_size)); + acpi_ut_remove_reference(string_desc); return_PTR(NULL); } @@ -649,8 +651,9 @@ acpi_ut_get_package_object_size(union acpi_operand_object *internal_object, info.object_space = 0; info.num_packages = 1; - status = acpi_ut_walk_package_tree(internal_object, NULL, - acpi_ut_get_element_length, &info); + status = + acpi_ut_walk_package_tree(internal_object, NULL, + acpi_ut_get_element_length, &info); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -660,7 +663,8 @@ acpi_ut_get_package_object_size(union acpi_operand_object *internal_object, * just add the length of the package objects themselves. * Round up to the next machine word. */ - info.length += ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)) * + info.length += + ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof(union acpi_object)) * (acpi_size) info.num_packages; /* Return the total package length */ @@ -692,8 +696,8 @@ acpi_ut_get_object_size(union acpi_operand_object *internal_object, ACPI_FUNCTION_ENTRY(); if ((ACPI_GET_DESCRIPTOR_TYPE(internal_object) == - ACPI_DESC_TYPE_OPERAND) - && (internal_object->common.type == ACPI_TYPE_PACKAGE)) { + ACPI_DESC_TYPE_OPERAND) && + (internal_object->common.type == ACPI_TYPE_PACKAGE)) { status = acpi_ut_get_package_object_size(internal_object, obj_length); diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 8f3d203a..0809d73 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -269,9 +269,10 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name) previous_interface = next_interface = acpi_gbl_supported_interfaces; while (next_interface) { if (!strcmp(interface_name, next_interface->name)) { - - /* Found: name is in either the static list or was added at runtime */ - + /* + * Found: name is in either the static list + * or was added at runtime + */ if (next_interface->flags & ACPI_OSI_DYNAMIC) { /* Interface was added dynamically, remove and free it */ @@ -288,8 +289,8 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name) ACPI_FREE(next_interface); } else { /* - * Interface is in static list. If marked invalid, then it - * does not actually exist. Else, mark it invalid. + * Interface is in static list. If marked invalid, then + * it does not actually exist. Else, mark it invalid. */ if (next_interface->flags & ACPI_OSI_INVALID) { return (AE_NOT_EXIST); diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index 2959217..ebb811c 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -73,8 +73,8 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) /* Guard against multiple allocations of ID to the same location */ if (*owner_id) { - ACPI_ERROR((AE_INFO, "Owner ID [0x%2.2X] already exists", - *owner_id)); + ACPI_ERROR((AE_INFO, + "Owner ID [0x%2.2X] already exists", *owner_id)); return_ACPI_STATUS(AE_ALREADY_EXISTS); } @@ -87,8 +87,8 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) /* * Find a free owner ID, cycle through all possible IDs on repeated - * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index may have - * to be scanned twice. + * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index + * may have to be scanned twice. */ for (i = 0, j = acpi_gbl_last_owner_id_index; i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) { @@ -141,8 +141,8 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) * they are released when a table is unloaded or a method completes * execution. * - * If this error happens, there may be very deep nesting of invoked control - * methods, or there may be a bug where the IDs are not released. + * If this error happens, there may be very deep nesting of invoked + * control methods, or there may be a bug where the IDs are not released. */ status = AE_OWNER_ID_LIMIT; ACPI_ERROR((AE_INFO, diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index 97898ed..9f8e415 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -225,8 +225,10 @@ const union acpi_predefined_info *acpi_ut_match_resource_name(char *name) { const union acpi_predefined_info *this_name; - /* Quick check for a predefined name, first character must be underscore */ - + /* + * Quick check for a predefined name, first character must + * be underscore + */ if (name[0] != '_') { return (NULL); } diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index b26297c..01f04da 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -314,8 +314,9 @@ static char *acpi_ut_format_number(char *string, if (need_prefix) { string = acpi_ut_bound_string_output(string, end, '0'); if (base == 16) { - string = acpi_ut_bound_string_output(string, end, - upper ? 'X' : 'x'); + string = + acpi_ut_bound_string_output(string, end, + upper ? 'X' : 'x'); } } if (!(type & ACPI_FORMAT_LEFT)) { @@ -400,6 +401,7 @@ acpi_ut_vsnprintf(char *string, } else { break; } + } while (1); /* Process width */ @@ -429,6 +431,7 @@ acpi_ut_vsnprintf(char *string, ++format; precision = va_arg(args, int); } + if (precision < 0) { precision = 0; } @@ -488,10 +491,12 @@ acpi_ut_vsnprintf(char *string, ' '); } } + for (i = 0; i < length; ++i) { pos = acpi_ut_bound_string_output(pos, end, *s); ++s; } + while (length < width--) { pos = acpi_ut_bound_string_output(pos, end, ' '); @@ -529,9 +534,9 @@ acpi_ut_vsnprintf(char *string, } p = va_arg(args, void *); - pos = acpi_ut_format_number(pos, end, - ACPI_TO_INTEGER(p), 16, - width, precision, type); + pos = + acpi_ut_format_number(pos, end, ACPI_TO_INTEGER(p), + 16, width, precision, type); continue; default: diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index b3505db..d50b41c 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -441,8 +441,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, acpi_ut_validate_resource(walk_state, aml, &resource_index); if (ACPI_FAILURE(status)) { /* - * Exit on failure. Cannot continue because the descriptor length - * may be bogus also. + * Exit on failure. Cannot continue because the descriptor + * length may be bogus also. */ return_ACPI_STATUS(status); } @@ -568,8 +568,8 @@ acpi_ut_validate_resource(struct acpi_walk_state *walk_state, } /* - * Check validity of the resource type, via acpi_gbl_resource_types. Zero - * indicates an invalid resource. + * Check validity of the resource type, via acpi_gbl_resource_types. + * Zero indicates an invalid resource. */ if (!acpi_gbl_resource_types[resource_index]) { goto invalid_resource; diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index f201171..0050e00 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -246,6 +246,7 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, state->pkg.dest_object = external_object; state->pkg.index = index; state->pkg.num_packages = 1; + return (state); } @@ -279,6 +280,7 @@ union acpi_generic_state *acpi_ut_create_control_state(void) state->common.descriptor_type = ACPI_DESC_TYPE_STATE_CONTROL; state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING; + return (state); } @@ -304,5 +306,6 @@ void acpi_ut_delete_generic_state(union acpi_generic_state *state) if (state) { (void)acpi_os_release_object(acpi_gbl_state_cache, state); } + return; } diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 4ddd105..0c2e2d2 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -135,6 +135,7 @@ void acpi_ut_print_string(char *string, u16 max_length) break; } } + acpi_os_printf("\""); if (i == max_length && string[i]) { diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 9a7dc81..ea698e9 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -150,9 +150,9 @@ void *acpi_ut_allocate_and_track(acpi_size size, return (NULL); } - status = acpi_ut_track_allocation(allocation, size, - ACPI_MEM_MALLOC, component, module, - line); + status = + acpi_ut_track_allocation(allocation, size, ACPI_MEM_MALLOC, + component, module, line); if (ACPI_FAILURE(status)) { acpi_os_free(allocation); return (NULL); @@ -161,6 +161,7 @@ void *acpi_ut_allocate_and_track(acpi_size size, acpi_gbl_global_list->total_allocated++; acpi_gbl_global_list->total_size += (u32)size; acpi_gbl_global_list->current_total_size += (u32)size; + if (acpi_gbl_global_list->current_total_size > acpi_gbl_global_list->max_occupied) { acpi_gbl_global_list->max_occupied = @@ -223,6 +224,7 @@ void *acpi_ut_allocate_zeroed_and_track(acpi_size size, acpi_gbl_global_list->total_allocated++; acpi_gbl_global_list->total_size += (u32)size; acpi_gbl_global_list->current_total_size += (u32)size; + if (acpi_gbl_global_list->current_total_size > acpi_gbl_global_list->max_occupied) { acpi_gbl_global_list->max_occupied = @@ -269,8 +271,8 @@ acpi_ut_free_and_track(void *allocation, acpi_gbl_global_list->total_freed++; acpi_gbl_global_list->current_total_size -= debug_block->size; - status = acpi_ut_remove_allocation(debug_block, - component, module, line); + status = + acpi_ut_remove_allocation(debug_block, component, module, line); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not free memory")); } @@ -525,35 +527,35 @@ void acpi_ut_dump_allocation_info(void) /* ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Current allocations", - mem_list->current_count, - ROUND_UP_TO_1K (mem_list->current_size))); + ("%30s: %4d (%3d Kb)\n", "Current allocations", + mem_list->current_count, + ROUND_UP_TO_1K (mem_list->current_size))); ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", - mem_list->max_concurrent_count, - ROUND_UP_TO_1K (mem_list->max_concurrent_size))); + ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", + mem_list->max_concurrent_count, + ROUND_UP_TO_1K (mem_list->max_concurrent_size))); ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", - running_object_count, - ROUND_UP_TO_1K (running_object_size))); + ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", + running_object_count, + ROUND_UP_TO_1K (running_object_size))); ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", - running_alloc_count, - ROUND_UP_TO_1K (running_alloc_size))); + ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", + running_alloc_count, + ROUND_UP_TO_1K (running_alloc_size))); ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Current Nodes", - acpi_gbl_current_node_count, - ROUND_UP_TO_1K (acpi_gbl_current_node_size))); + ("%30s: %4d (%3d Kb)\n", "Current Nodes", + acpi_gbl_current_node_count, + ROUND_UP_TO_1K (acpi_gbl_current_node_size))); ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Max Nodes", - acpi_gbl_max_concurrent_node_count, - ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * - sizeof (struct acpi_namespace_node))))); + ("%30s: %4d (%3d Kb)\n", "Max Nodes", + acpi_gbl_max_concurrent_node_count, + ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * + sizeof (struct acpi_namespace_node))))); */ return_VOID; } diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index f9c8f9c..9f3f0a1 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -154,7 +154,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) * Populate the return buffer */ info_ptr = (struct acpi_system_info *)out_buffer->pointer; - info_ptr->acpi_ca_version = ACPI_CA_VERSION; /* System flags (ACPI capabilities) */ @@ -216,7 +215,6 @@ acpi_status acpi_get_statistics(struct acpi_statistics *stats) /* Other counters */ stats->method_count = acpi_method_count; - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 98d5787..f6cbaf4 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -117,6 +117,7 @@ acpi_exception(const char *module_name, acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ", acpi_format_exception(status)); } + va_start(arg_list, format); acpi_os_vprintf(format, arg_list); ACPI_MSG_SUFFIX; diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c index f2606af..95d6123 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -89,9 +89,9 @@ acpi_ut_get_mutex_object(acpi_handle handle, mutex_node = handle; if (pathname != NULL) { - status = acpi_get_handle(handle, pathname, - ACPI_CAST_PTR(acpi_handle, - &mutex_node)); + status = + acpi_get_handle(handle, pathname, + ACPI_CAST_PTR(acpi_handle, &mutex_node)); if (ACPI_FAILURE(status)) { return (status); } diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c index 326e826..2496629 100644 --- a/tools/power/acpi/common/getopt.c +++ b/tools/power/acpi/common/getopt.c @@ -85,6 +85,7 @@ static int current_char_ptr = 1; int acpi_getopt_argument(int argc, char **argv) { + acpi_gbl_optind--; current_char_ptr++; diff --git a/tools/power/acpi/os_specific/service_layers/oslibcfs.c b/tools/power/acpi/os_specific/service_layers/oslibcfs.c index b51e40a..6df7583 100644 --- a/tools/power/acpi/os_specific/service_layers/oslibcfs.c +++ b/tools/power/acpi/os_specific/service_layers/oslibcfs.c @@ -73,6 +73,7 @@ ACPI_FILE acpi_os_open_file(const char *path, u8 modes) if (modes & ACPI_FILE_WRITING) { modes_str[i++] = 'w'; } + if (modes & ACPI_FILE_BINARY) { modes_str[i++] = 'b'; } @@ -101,6 +102,7 @@ ACPI_FILE acpi_os_open_file(const char *path, u8 modes) void acpi_os_close_file(ACPI_FILE file) { + fclose(file); } @@ -202,6 +204,7 @@ acpi_status acpi_os_set_file_offset(ACPI_FILE file, long offset, u8 from) if (from == ACPI_FILE_BEGIN) { ret = fseek(file, offset, SEEK_SET); } + if (from == ACPI_FILE_END) { ret = fseek(file, offset, SEEK_END); } diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c index a1c62de..bbdf9e8 100644 --- a/tools/power/acpi/tools/acpidump/apfiles.c +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -48,6 +48,18 @@ static int ap_is_existing_file(char *pathname); +/****************************************************************************** + * + * FUNCTION: ap_is_existing_file + * + * PARAMETERS: pathname - Output filename + * + * RETURN: 0 on success + * + * DESCRIPTION: Query for file overwrite if it already exists. + * + ******************************************************************************/ + static int ap_is_existing_file(char *pathname) { #ifndef _GNU_EFI @@ -136,6 +148,7 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) } else { ACPI_MOVE_NAME(filename, table->signature); } + filename[0] = (char)tolower((int)filename[0]); filename[1] = (char)tolower((int)filename[1]); filename[2] = (char)tolower((int)filename[2]); -- cgit v0.10.2 From 5df2e3ed04862d9e6465b3b2748ef747d31c4bbc Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:54:44 +0800 Subject: ACPICA: Split interpreter tracing functions to a new file ACPICA commit a3f85a7d26a52ee0d9103feb4fbec8d7b6ba4c11 Split out functions from exdebug.c to extrace.c Link: https://github.com/acpica/acpica/commit/a3f85a7d Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 885936f..e75f401 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -50,6 +50,7 @@ acpi-y += \ exdump.o \ exfield.o \ exfldio.o \ + exmisc.o \ exmutex.o \ exnames.o \ exoparg1.o \ @@ -57,7 +58,6 @@ acpi-y += \ exoparg3.o \ exoparg6.o \ exprep.o \ - exmisc.o \ exregion.o \ exresnte.o \ exresolv.o \ @@ -66,6 +66,7 @@ acpi-y += \ exstoren.o \ exstorob.o \ exsystem.o \ + extrace.o \ exutils.o acpi-y += \ diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 665a4b9..815442b 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -43,21 +43,11 @@ #include #include "accommon.h" -#include "acnamesp.h" #include "acinterp.h" -#include "acparser.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exdebug") -static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; - -/* Local prototypes */ - -#ifdef ACPI_DEBUG_OUTPUT -static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); -#endif - #ifndef ACPI_NO_ERROR_MESSAGES /******************************************************************************* * @@ -80,7 +70,6 @@ static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); * enabled if necessary. * ******************************************************************************/ - void acpi_ex_do_debug_object(union acpi_operand_object *source_desc, u32 level, u32 index) @@ -319,317 +308,3 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, return_VOID; } #endif - -/******************************************************************************* - * - * FUNCTION: acpi_ex_interpreter_trace_enabled - * - * PARAMETERS: name - Whether method name should be matched, - * this should be checked before starting - * the tracer - * - * RETURN: TRUE if interpreter trace is enabled. - * - * DESCRIPTION: Check whether interpreter trace is enabled - * - ******************************************************************************/ - -static u8 acpi_ex_interpreter_trace_enabled(char *name) -{ - - /* Check if tracing is enabled */ - - if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) { - return (FALSE); - } - - /* - * Check if tracing is filtered: - * - * 1. If the tracer is started, acpi_gbl_trace_method_object should have - * been filled by the trace starter - * 2. If the tracer is not started, acpi_gbl_trace_method_name should be - * matched if it is specified - * 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should - * not be cleared by the trace stopper during the first match - */ - if (acpi_gbl_trace_method_object) { - return (TRUE); - } - if (name && - (acpi_gbl_trace_method_name && - strcmp(acpi_gbl_trace_method_name, name))) { - return (FALSE); - } - if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) && - !acpi_gbl_trace_method_name) { - return (FALSE); - } - - return (TRUE); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_get_trace_event_name - * - * PARAMETERS: type - Trace event type - * - * RETURN: Trace event name. - * - * DESCRIPTION: Used to obtain the full trace event name. - * - ******************************************************************************/ - -#ifdef ACPI_DEBUG_OUTPUT - -static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type) -{ - switch (type) { - case ACPI_TRACE_AML_METHOD: - - return "Method"; - - case ACPI_TRACE_AML_OPCODE: - - return "Opcode"; - - case ACPI_TRACE_AML_REGION: - - return "Region"; - - default: - - return ""; - } -} - -#endif - -/******************************************************************************* - * - * FUNCTION: acpi_ex_trace_point - * - * PARAMETERS: type - Trace event type - * begin - TRUE if before execution - * aml - Executed AML address - * pathname - Object path - * - * RETURN: None - * - * DESCRIPTION: Internal interpreter execution trace. - * - ******************************************************************************/ - -void -acpi_ex_trace_point(acpi_trace_event_type type, - u8 begin, u8 *aml, char *pathname) -{ - - ACPI_FUNCTION_NAME(ex_trace_point); - - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "%s %s [0x%p:%s] execution.\n", - acpi_ex_get_trace_event_name(type), - begin ? "Begin" : "End", aml, pathname)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "%s %s [0x%p] execution.\n", - acpi_ex_get_trace_event_name(type), - begin ? "Begin" : "End", aml)); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_start_trace_method - * - * PARAMETERS: method_node - Node of the method - * obj_desc - The method object - * walk_state - current state, NULL if not yet executing - * a method. - * - * RETURN: None - * - * DESCRIPTION: Start control method execution trace - * - ******************************************************************************/ - -void -acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, - union acpi_operand_object *obj_desc, - struct acpi_walk_state *walk_state) -{ - acpi_status status; - char *pathname = NULL; - u8 enabled = FALSE; - - ACPI_FUNCTION_NAME(ex_start_trace_method); - - if (method_node) { - pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit; - } - - enabled = acpi_ex_interpreter_trace_enabled(pathname); - if (enabled && !acpi_gbl_trace_method_object) { - acpi_gbl_trace_method_object = obj_desc; - acpi_gbl_original_dbg_level = acpi_dbg_level; - acpi_gbl_original_dbg_layer = acpi_dbg_layer; - acpi_dbg_level = ACPI_TRACE_LEVEL_ALL; - acpi_dbg_layer = ACPI_TRACE_LAYER_ALL; - - if (acpi_gbl_trace_dbg_level) { - acpi_dbg_level = acpi_gbl_trace_dbg_level; - } - if (acpi_gbl_trace_dbg_layer) { - acpi_dbg_layer = acpi_gbl_trace_dbg_layer; - } - } - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - -exit: - if (enabled) { - ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE, - obj_desc ? obj_desc->method.aml_start : NULL, - pathname); - } - if (pathname) { - ACPI_FREE(pathname); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_stop_trace_method - * - * PARAMETERS: method_node - Node of the method - * obj_desc - The method object - * walk_state - current state, NULL if not yet executing - * a method. - * - * RETURN: None - * - * DESCRIPTION: Stop control method execution trace - * - ******************************************************************************/ - -void -acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, - union acpi_operand_object *obj_desc, - struct acpi_walk_state *walk_state) -{ - acpi_status status; - char *pathname = NULL; - u8 enabled; - - ACPI_FUNCTION_NAME(ex_stop_trace_method); - - if (method_node) { - pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit_path; - } - - enabled = acpi_ex_interpreter_trace_enabled(NULL); - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - - if (enabled) { - ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE, - obj_desc ? obj_desc->method.aml_start : NULL, - pathname); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit_path; - } - - /* Check whether the tracer should be stopped */ - - if (acpi_gbl_trace_method_object == obj_desc) { - - /* Disable further tracing if type is one-shot */ - - if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) { - acpi_gbl_trace_method_name = NULL; - } - - acpi_dbg_level = acpi_gbl_original_dbg_level; - acpi_dbg_layer = acpi_gbl_original_dbg_layer; - acpi_gbl_trace_method_object = NULL; - } - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - -exit_path: - if (pathname) { - ACPI_FREE(pathname); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_start_trace_opcode - * - * PARAMETERS: op - The parser opcode object - * walk_state - current state, NULL if not yet executing - * a method. - * - * RETURN: None - * - * DESCRIPTION: Start opcode execution trace - * - ******************************************************************************/ - -void -acpi_ex_start_trace_opcode(union acpi_parse_object *op, - struct acpi_walk_state *walk_state) -{ - - ACPI_FUNCTION_NAME(ex_start_trace_opcode); - - if (acpi_ex_interpreter_trace_enabled(NULL) && - (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { - ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, - op->common.aml, op->common.aml_op_name); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_stop_trace_opcode - * - * PARAMETERS: op - The parser opcode object - * walk_state - current state, NULL if not yet executing - * a method. - * - * RETURN: None - * - * DESCRIPTION: Stop opcode execution trace - * - ******************************************************************************/ - -void -acpi_ex_stop_trace_opcode(union acpi_parse_object *op, - struct acpi_walk_state *walk_state) -{ - - ACPI_FUNCTION_NAME(ex_stop_trace_opcode); - - if (acpi_ex_interpreter_trace_enabled(NULL) && - (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { - ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, - op->common.aml, op->common.aml_op_name); - } -} diff --git a/drivers/acpi/acpica/extrace.c b/drivers/acpi/acpica/extrace.c new file mode 100644 index 0000000..e4a185e --- /dev/null +++ b/drivers/acpi/acpica/extrace.c @@ -0,0 +1,377 @@ +/****************************************************************************** + * + * Module Name: extrace - Support for interpreter execution tracing + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_EXECUTER +ACPI_MODULE_NAME("extrace") + +static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; + +/* Local prototypes */ + +#ifdef ACPI_DEBUG_OUTPUT +static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ex_interpreter_trace_enabled + * + * PARAMETERS: name - Whether method name should be matched, + * this should be checked before starting + * the tracer + * + * RETURN: TRUE if interpreter trace is enabled. + * + * DESCRIPTION: Check whether interpreter trace is enabled + * + ******************************************************************************/ + +static u8 acpi_ex_interpreter_trace_enabled(char *name) +{ + + /* Check if tracing is enabled */ + + if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) { + return (FALSE); + } + + /* + * Check if tracing is filtered: + * + * 1. If the tracer is started, acpi_gbl_trace_method_object should have + * been filled by the trace starter + * 2. If the tracer is not started, acpi_gbl_trace_method_name should be + * matched if it is specified + * 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should + * not be cleared by the trace stopper during the first match + */ + if (acpi_gbl_trace_method_object) { + return (TRUE); + } + + if (name && + (acpi_gbl_trace_method_name && + strcmp(acpi_gbl_trace_method_name, name))) { + return (FALSE); + } + + if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) && + !acpi_gbl_trace_method_name) { + return (FALSE); + } + + return (TRUE); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_get_trace_event_name + * + * PARAMETERS: type - Trace event type + * + * RETURN: Trace event name. + * + * DESCRIPTION: Used to obtain the full trace event name. + * + ******************************************************************************/ + +#ifdef ACPI_DEBUG_OUTPUT + +static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type) +{ + + switch (type) { + case ACPI_TRACE_AML_METHOD: + + return "Method"; + + case ACPI_TRACE_AML_OPCODE: + + return "Opcode"; + + case ACPI_TRACE_AML_REGION: + + return "Region"; + + default: + + return ""; + } +} + +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ex_trace_point + * + * PARAMETERS: type - Trace event type + * begin - TRUE if before execution + * aml - Executed AML address + * pathname - Object path + * + * RETURN: None + * + * DESCRIPTION: Internal interpreter execution trace. + * + ******************************************************************************/ + +void +acpi_ex_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname) +{ + + ACPI_FUNCTION_NAME(ex_trace_point); + + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "%s %s [0x%p:%s] execution.\n", + acpi_ex_get_trace_event_name(type), + begin ? "Begin" : "End", aml, pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "%s %s [0x%p] execution.\n", + acpi_ex_get_trace_event_name(type), + begin ? "Begin" : "End", aml)); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_start_trace_method + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start control method execution trace + * + ******************************************************************************/ + +void +acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + char *pathname = NULL; + u8 enabled = FALSE; + + ACPI_FUNCTION_NAME(ex_start_trace_method); + + if (method_node) { + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit; + } + + enabled = acpi_ex_interpreter_trace_enabled(pathname); + if (enabled && !acpi_gbl_trace_method_object) { + acpi_gbl_trace_method_object = obj_desc; + acpi_gbl_original_dbg_level = acpi_dbg_level; + acpi_gbl_original_dbg_layer = acpi_dbg_layer; + acpi_dbg_level = ACPI_TRACE_LEVEL_ALL; + acpi_dbg_layer = ACPI_TRACE_LAYER_ALL; + + if (acpi_gbl_trace_dbg_level) { + acpi_dbg_level = acpi_gbl_trace_dbg_level; + } + + if (acpi_gbl_trace_dbg_layer) { + acpi_dbg_layer = acpi_gbl_trace_dbg_layer; + } + } + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + +exit: + if (enabled) { + ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE, + obj_desc ? obj_desc->method.aml_start : NULL, + pathname); + } + + if (pathname) { + ACPI_FREE(pathname); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_stop_trace_method + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop control method execution trace + * + ******************************************************************************/ + +void +acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + char *pathname = NULL; + u8 enabled; + + ACPI_FUNCTION_NAME(ex_stop_trace_method); + + if (method_node) { + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit_path; + } + + enabled = acpi_ex_interpreter_trace_enabled(NULL); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + if (enabled) { + ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE, + obj_desc ? obj_desc->method.aml_start : NULL, + pathname); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit_path; + } + + /* Check whether the tracer should be stopped */ + + if (acpi_gbl_trace_method_object == obj_desc) { + + /* Disable further tracing if type is one-shot */ + + if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) { + acpi_gbl_trace_method_name = NULL; + } + + acpi_dbg_level = acpi_gbl_original_dbg_level; + acpi_dbg_layer = acpi_gbl_original_dbg_layer; + acpi_gbl_trace_method_object = NULL; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + +exit_path: + if (pathname) { + ACPI_FREE(pathname); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_start_trace_opcode + * + * PARAMETERS: op - The parser opcode object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start opcode execution trace + * + ******************************************************************************/ + +void +acpi_ex_start_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_NAME(ex_start_trace_opcode); + + if (acpi_ex_interpreter_trace_enabled(NULL) && + (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { + ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, + op->common.aml, op->common.aml_op_name); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_stop_trace_opcode + * + * PARAMETERS: op - The parser opcode object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop opcode execution trace + * + ******************************************************************************/ + +void +acpi_ex_stop_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_NAME(ex_stop_trace_opcode); + + if (acpi_ex_interpreter_trace_enabled(NULL) && + (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { + ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, + op->common.aml, op->common.aml_op_name); + } +} -- cgit v0.10.2 From 675dfa0af8414958a11645eb53413f8e5af2f142 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:54:51 +0800 Subject: ACPICA: acpiexec: Add support for AML files containing multiple tables ACPICA commit 301f16e4037275888f65b88aec7231c1cd64339f Add support for multi-AML-table files that originate from either acpixtract or iASL. Link: https://github.com/acpica/acpica/commit/301f16e4 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 7495421..5d3ae91 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -356,6 +356,10 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, * utfileio - file operations */ #ifdef ACPI_APPLICATION + +acpi_status +acpi_ut_read_tables_from_file(FILE * file, struct acpi_table_header **table); + acpi_status acpi_ut_read_table_from_file(char *filename, struct acpi_table_header **table); #endif diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c index be49c71..e729486 100644 --- a/drivers/acpi/acpica/utfileio.c +++ b/drivers/acpi/acpica/utfileio.c @@ -292,6 +292,29 @@ acpi_ut_read_table(FILE * fp, ******************************************************************************/ acpi_status +acpi_ut_read_tables_from_file(FILE * file, struct acpi_table_header ** table) +{ + struct acpi_table_header table_header; + s32 count; + long position; + + position = ftell(file); + count = fread(&table_header, 1, sizeof(struct acpi_table_header), file); + if (count < sizeof(struct acpi_table_header)) { + return (AE_CTRL_TERMINATE); + } + + /* Allocate a buffer for the table */ + + *table = acpi_os_allocate((size_t) table_header.length); + fseek(file, position, SEEK_SET); + + count = fread(*table, 1, table_header.length, file); + + return (AE_OK); +} + +acpi_status acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table) { FILE *file; -- cgit v0.10.2 From 2ba7379b5abcaf2e0e7ece01b1e0c925e0057cd4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:54:58 +0800 Subject: ACPICA: Disassembler/tools: Support for multiple ACPI tables in one file ACPICA commit 5be7dc4d0d69b2953d156f5bc4d3e8a65a390837 Matches the support in iASL and acpi_exec. Link: https://github.com/acpica/acpica/commit/5be7dc4d Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index e75f401..f682374 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -197,7 +197,6 @@ acpi-$(ACPI_FUTURE_USAGE) += \ dbfileio.o \ dbtest.o \ utcache.o \ - utfileio.o \ utprint.o \ uttrack.o \ utuuid.o diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index e4cc48f..185c2eb 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -44,6 +44,8 @@ #ifndef _ACAPPS #define _ACAPPS +#include + /* Common info for tool signons */ #define ACPICA_NAME "Intel ACPI Component Architecture" @@ -90,6 +92,18 @@ #define FILE_SUFFIX_DISASSEMBLY "dsl" #define FILE_SUFFIX_BINARY_TABLE ".dat" /* Needs the dot */ +/* acfileio */ + +acpi_status +acpi_ac_get_all_tables_from_file(char *filename, + u8 get_only_aml_tables, + struct acpi_new_table_desc **return_list_head); + +/* Values for get_only_aml_tables */ + +#define ACPI_GET_ONLY_AML_TABLES TRUE +#define ACPI_GET_ALL_TABLES FALSE + /* * getopt */ @@ -107,30 +121,6 @@ extern char *acpi_gbl_optarg; */ u32 cm_get_file_size(ACPI_FILE file); -#ifndef ACPI_DUMP_APP -/* - * adisasm - */ -acpi_status -ad_aml_disassemble(u8 out_to_file, - char *filename, char *prefix, char **out_filename); - -void ad_print_statistics(void); - -acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length); - -void ad_dump_tables(void); - -acpi_status ad_get_local_tables(void); - -acpi_status -ad_parse_table(struct acpi_table_header *table, - acpi_owner_id * owner_id, u8 load_table, u8 external); - -acpi_status ad_display_tables(char *filename, struct acpi_table_header *table); - -acpi_status ad_display_statistics(void); - /* * adwalk */ @@ -168,6 +158,5 @@ char *ad_generate_filename(char *prefix, char *table_id); void ad_write_table(struct acpi_table_header *table, u32 length, char *table_name, char *oem_table_id); -#endif #endif /* _ACAPPS */ diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index dcaa15d..ecb05f1 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -245,10 +245,7 @@ void acpi_db_open_debug_file(char *name); acpi_status acpi_db_load_acpi_table(char *filename); -acpi_status -acpi_db_get_table_from_file(char *filename, - struct acpi_table_header **table, - u8 must_be_aml_table); +acpi_status acpi_db_load_tables(struct acpi_new_table_desc *list_head); /* * dbhistry - debugger HISTORY command diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index e1dd784..4fd5040 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -219,6 +219,13 @@ struct acpi_table_list { #define ACPI_ROOT_ORIGIN_ALLOCATED (1) #define ACPI_ROOT_ALLOW_RESIZE (2) +/* List to manage incoming ACPI tables */ + +struct acpi_new_table_desc { + struct acpi_table_header *table; + struct acpi_new_table_desc *next; +}; + /* Predefined table indexes */ #define ACPI_INVALID_TABLE_INDEX (0xFFFFFFFF) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 5d3ae91..6776348 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -353,18 +353,6 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, u8 method_count, u8 *out_values); /* - * utfileio - file operations - */ -#ifdef ACPI_APPLICATION - -acpi_status -acpi_ut_read_tables_from_file(FILE * file, struct acpi_table_header **table); - -acpi_status -acpi_ut_read_table_from_file(char *filename, struct acpi_table_header **table); -#endif - -/* * utids - device ID support */ acpi_status diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c index d0e6b20..31f54d7 100644 --- a/drivers/acpi/acpica/dbfileio.c +++ b/drivers/acpi/acpica/dbfileio.c @@ -46,6 +46,10 @@ #include "accommon.h" #include "acdebug.h" #include "actables.h" +#include +#ifdef ACPI_APPLICATION +#include "acapps.h" +#endif #define _COMPONENT ACPI_CA_DEBUGGER ACPI_MODULE_NAME("dbfileio") @@ -110,122 +114,31 @@ void acpi_db_open_debug_file(char *name) } #endif -#ifdef ACPI_APPLICATION -#include "acapps.h" - -/******************************************************************************* - * - * FUNCTION: ae_local_load_table - * - * PARAMETERS: table - pointer to a buffer containing the entire - * table to be loaded - * - * RETURN: Status - * - * DESCRIPTION: This function is called to load a table from the caller's - * buffer. The buffer must contain an entire ACPI Table including - * a valid header. The header fields will be verified, and if it - * is determined that the table is invalid, the call will fail. - * - ******************************************************************************/ - -static acpi_status ae_local_load_table(struct acpi_table_header *table) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(ae_local_load_table); - -#if 0 -/* struct acpi_table_desc table_info; */ - - if (!table) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - table_info.pointer = table; - status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Install the new table into the local data structures */ - - status = acpi_tb_init_table_descriptor(&table_info); - if (ACPI_FAILURE(status)) { - if (status == AE_ALREADY_EXISTS) { - - /* Table already exists, no error */ - - status = AE_OK; - } - - /* Free table allocated by acpi_tb_get_table */ - - acpi_tb_delete_single_table(&table_info); - return_ACPI_STATUS(status); - } -#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) - - status = - acpi_ns_load_table(table_info.installed_desc, acpi_gbl_root_node); - if (ACPI_FAILURE(status)) { - - /* Uninstall table and free the buffer */ - - acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_DSDT); - return_ACPI_STATUS(status); - } -#endif -#endif - - return_ACPI_STATUS(status); -} -#endif - /******************************************************************************* * - * FUNCTION: acpi_db_get_table_from_file + * FUNCTION: acpi_db_load_tables * - * PARAMETERS: filename - File where table is located - * return_table - Where a pointer to the table is returned + * PARAMETERS: list_head - List of ACPI tables to load * * RETURN: Status * - * DESCRIPTION: Load an ACPI table from a file + * DESCRIPTION: Load ACPI tables from a previously constructed table list. * ******************************************************************************/ -acpi_status -acpi_db_get_table_from_file(char *filename, - struct acpi_table_header **return_table, - u8 must_be_aml_file) +acpi_status acpi_db_load_tables(struct acpi_new_table_desc *list_head) { -#ifdef ACPI_APPLICATION acpi_status status; + struct acpi_new_table_desc *table_list_head; struct acpi_table_header *table; - u8 is_aml_table = TRUE; - - status = acpi_ut_read_table_from_file(filename, &table); - if (ACPI_FAILURE(status)) { - return (status); - } - - if (must_be_aml_file) { - is_aml_table = acpi_ut_is_aml_table(table); - if (!is_aml_table) { - ACPI_EXCEPTION((AE_INFO, AE_OK, - "Input for -e is not an AML table: " - "\"%4.4s\" (must be DSDT/SSDT)", - table->signature)); - return (AE_TYPE); - } - } - if (is_aml_table) { + /* Load all ACPI tables in the list */ - /* Attempt to recognize and install the table */ + table_list_head = list_head; + while (table_list_head) { + table = table_list_head->table; - status = ae_local_load_table(table); + status = acpi_load_table(table); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { acpi_os_printf @@ -239,18 +152,12 @@ acpi_db_get_table_from_file(char *filename, return (status); } - acpi_tb_print_table_header(0, table); - fprintf(stderr, "Acpi table [%4.4s] successfully installed and loaded\n", table->signature); - } - acpi_gbl_acpi_hardware_present = FALSE; - if (return_table) { - *return_table = table; + table_list_head = table_list_head->next; } -#endif /* ACPI_APPLICATION */ return (AE_OK); } diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 2bf8e6b..71357fe 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -45,6 +45,10 @@ #include "accommon.h" #include "acdebug.h" +#ifdef ACPI_APPLICATION +#include "acapps.h" +#endif + #define _COMPONENT ACPI_CA_DEBUGGER ACPI_MODULE_NAME("dbinput") @@ -1048,11 +1052,18 @@ acpi_db_command_dispatch(char *input_buffer, acpi_db_close_debug_file(); break; - case CMD_LOAD: + case CMD_LOAD:{ + struct acpi_new_table_desc *list_head = NULL; - status = - acpi_db_get_table_from_file(acpi_gbl_db_args[1], NULL, - FALSE); + status = + acpi_ac_get_all_tables_from_file(acpi_gbl_db_args + [1], + ACPI_GET_ALL_TABLES, + &list_head); + if (ACPI_SUCCESS(status)) { + acpi_db_load_tables(list_head); + } + } break; case CMD_OPEN: diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 9a7d72b..ca2f136 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -207,7 +207,7 @@ acpi_status acpi_tb_load_namespace(void) if (!tables_failed) { ACPI_INFO((AE_INFO, - "%u ACPI AML tables successfully acquired and loaded", + "%u ACPI AML tables successfully acquired and loaded\n", tables_loaded)); } else { ACPI_ERROR((AE_INFO, diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c deleted file mode 100644 index e729486..0000000 --- a/drivers/acpi/acpica/utfileio.c +++ /dev/null @@ -1,359 +0,0 @@ -/******************************************************************************* - * - * Module Name: utfileio - simple file I/O routines - * - ******************************************************************************/ - -/* - * Copyright (C) 2000 - 2015, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#include -#include "accommon.h" -#include "actables.h" -#include "acapps.h" -#include "errno.h" - -#ifdef ACPI_ASL_COMPILER -#include "aslcompiler.h" -#endif - -#define _COMPONENT ACPI_CA_DEBUGGER -ACPI_MODULE_NAME("utfileio") - -#ifdef ACPI_APPLICATION -/* Local prototypes */ -static acpi_status -acpi_ut_check_text_mode_corruption(u8 *table, - u32 table_length, u32 file_length); - -static acpi_status -acpi_ut_read_table(FILE * fp, - struct acpi_table_header **table, u32 *table_length); - -/******************************************************************************* - * - * FUNCTION: acpi_ut_check_text_mode_corruption - * - * PARAMETERS: table - Table buffer - * table_length - Length of table from the table header - * file_length - Length of the file that contains the table - * - * RETURN: Status - * - * DESCRIPTION: Check table for text mode file corruption where all linefeed - * characters (LF) have been replaced by carriage return linefeed - * pairs (CR/LF). - * - ******************************************************************************/ - -static acpi_status -acpi_ut_check_text_mode_corruption(u8 *table, u32 table_length, u32 file_length) -{ - u32 i; - u32 pairs = 0; - - if (table_length != file_length) { - ACPI_WARNING((AE_INFO, - "File length (0x%X) is not the same as the table length (0x%X)", - file_length, table_length)); - } - - /* Scan entire table to determine if each LF has been prefixed with a CR */ - - for (i = 1; i < file_length; i++) { - if (table[i] == 0x0A) { - if (table[i - 1] != 0x0D) { - - /* The LF does not have a preceding CR, table not corrupted */ - - return (AE_OK); - } else { - /* Found a CR/LF pair */ - - pairs++; - } - - i++; - } - } - - if (!pairs) { - return (AE_OK); - } - - /* - * Entire table scanned, each CR is part of a CR/LF pair -- - * meaning that the table was treated as a text file somewhere. - * - * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the - * original table are left untouched by the text conversion process -- - * meaning that we cannot simply replace CR/LF pairs with LFs. - */ - acpi_os_printf("Table has been corrupted by text mode conversion\n"); - acpi_os_printf("All LFs (%u) were changed to CR/LF pairs\n", pairs); - acpi_os_printf("Table cannot be repaired!\n"); - - return (AE_BAD_VALUE); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_read_table - * - * PARAMETERS: fp - File that contains table - * table - Return value, buffer with table - * table_length - Return value, length of table - * - * RETURN: Status - * - * DESCRIPTION: Load the DSDT from the file pointer - * - ******************************************************************************/ - -static acpi_status -acpi_ut_read_table(FILE * fp, - struct acpi_table_header **table, u32 *table_length) -{ - struct acpi_table_header table_header; - u32 actual; - acpi_status status; - u32 file_size; - u8 standard_header = TRUE; - s32 count; - - /* Get the file size */ - - file_size = cm_get_file_size(fp); - if (file_size == ACPI_UINT32_MAX) { - return (AE_ERROR); - } - - if (file_size < 4) { - return (AE_BAD_HEADER); - } - - /* Read the signature */ - - fseek(fp, 0, SEEK_SET); - - count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); - if (count != sizeof(struct acpi_table_header)) { - acpi_os_printf("Could not read the table header\n"); - return (AE_BAD_HEADER); - } - - /* The RSDP table does not have standard ACPI header */ - - if (ACPI_VALIDATE_RSDP_SIG(table_header.signature)) { - *table_length = file_size; - standard_header = FALSE; - } else { - -#if 0 - /* Validate the table header/length */ - - status = acpi_tb_validate_table_header(&table_header); - if (ACPI_FAILURE(status)) { - acpi_os_printf("Table header is invalid!\n"); - return (status); - } -#endif - - /* File size must be at least as long as the Header-specified length */ - - if (table_header.length > file_size) { - acpi_os_printf - ("TableHeader length [0x%X] greater than the input file size [0x%X]\n", - table_header.length, file_size); - -#ifdef ACPI_ASL_COMPILER - acpi_os_printf("File is corrupt or is ASCII text -- " - "it must be a binary file\n"); -#endif - return (AE_BAD_HEADER); - } -#ifdef ACPI_OBSOLETE_CODE - /* We only support a limited number of table types */ - - if (!ACPI_COMPARE_NAME - ((char *)table_header.signature, ACPI_SIG_DSDT) - && !ACPI_COMPARE_NAME((char *)table_header.signature, - ACPI_SIG_PSDT) - && !ACPI_COMPARE_NAME((char *)table_header.signature, - ACPI_SIG_SSDT)) { - acpi_os_printf - ("Table signature [%4.4s] is invalid or not supported\n", - (char *)table_header.signature); - ACPI_DUMP_BUFFER(&table_header, - sizeof(struct acpi_table_header)); - return (AE_ERROR); - } -#endif - - *table_length = table_header.length; - } - - /* Allocate a buffer for the table */ - - *table = acpi_os_allocate((size_t) file_size); - if (!*table) { - acpi_os_printf - ("Could not allocate memory for ACPI table %4.4s (size=0x%X)\n", - table_header.signature, *table_length); - return (AE_NO_MEMORY); - } - - /* Get the rest of the table */ - - fseek(fp, 0, SEEK_SET); - actual = fread(*table, 1, (size_t) file_size, fp); - if (actual == file_size) { - if (standard_header) { - - /* Now validate the checksum */ - - status = acpi_tb_verify_checksum((void *)*table, - ACPI_CAST_PTR(struct - acpi_table_header, - *table)-> - length); - - if (status == AE_BAD_CHECKSUM) { - status = - acpi_ut_check_text_mode_corruption((u8 *) - *table, - file_size, - (*table)-> - length); - return (status); - } - } - return (AE_OK); - } - - if (actual > 0) { - acpi_os_printf("Warning - reading table, asked for %X got %X\n", - file_size, actual); - return (AE_OK); - } - - acpi_os_printf("Error - could not read the table file\n"); - acpi_os_free(*table); - *table = NULL; - *table_length = 0; - return (AE_ERROR); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_read_table_from_file - * - * PARAMETERS: filename - File where table is located - * table - Where a pointer to the table is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an ACPI table from a file - * - ******************************************************************************/ - -acpi_status -acpi_ut_read_tables_from_file(FILE * file, struct acpi_table_header ** table) -{ - struct acpi_table_header table_header; - s32 count; - long position; - - position = ftell(file); - count = fread(&table_header, 1, sizeof(struct acpi_table_header), file); - if (count < sizeof(struct acpi_table_header)) { - return (AE_CTRL_TERMINATE); - } - - /* Allocate a buffer for the table */ - - *table = acpi_os_allocate((size_t) table_header.length); - fseek(file, position, SEEK_SET); - - count = fread(*table, 1, table_header.length, file); - - return (AE_OK); -} - -acpi_status -acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table) -{ - FILE *file; - u32 file_size; - u32 table_length; - acpi_status status = AE_ERROR; - - /* Open the file, get current size */ - - file = fopen(filename, "rb"); - if (!file) { - perror("Could not open input file"); - - if (errno == ENOENT) { - return (AE_NOT_EXIST); - } - - return (status); - } - - file_size = cm_get_file_size(file); - if (file_size == ACPI_UINT32_MAX) { - goto exit; - } - - /* Get the entire file */ - - fprintf(stderr, - "Reading ACPI table from file %12s - Length %.8u (0x%06X)\n", - filename, file_size, file_size); - - status = acpi_ut_read_table(file, table, &table_length); - if (ACPI_FAILURE(status)) { - acpi_os_printf("Could not get table from the file\n"); - } - -exit: - fclose(file); - return (status); -} - -#endif -- cgit v0.10.2 From 395ec731969c4bb0cc379a64809a5adab51126dd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:55:05 +0800 Subject: ACPICA: iasl/acpiexec: Update input file handling and verification ACPICA commit 3a6f2a516dd35a4daacbc5b5144d1db763ff2cb0 Improve and cleanup verification of ACPI tables within input files. Share more code between the disassembler and acpiexec. This patch only affects application debugger commands, thus it is a no-op chage for Linux kernel. Link: https://github.com/acpica/acpica/commit/3a6f2a51 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 185c2eb..340350f 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -95,9 +95,13 @@ /* acfileio */ acpi_status -acpi_ac_get_all_tables_from_file(char *filename, - u8 get_only_aml_tables, - struct acpi_new_table_desc **return_list_head); +ac_get_all_tables_from_file(char *filename, + u8 get_only_aml_tables, + struct acpi_new_table_desc **return_list_head); + +u8 ac_is_file_binary(FILE * file); + +acpi_status ac_validate_table_header(FILE * file, long table_offset); /* Values for get_only_aml_tables */ diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 71357fe..802779a 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -1056,10 +1056,9 @@ acpi_db_command_dispatch(char *input_buffer, struct acpi_new_table_desc *list_head = NULL; status = - acpi_ac_get_all_tables_from_file(acpi_gbl_db_args - [1], - ACPI_GET_ALL_TABLES, - &list_head); + ac_get_all_tables_from_file(acpi_gbl_db_args[1], + ACPI_GET_ALL_TABLES, + &list_head); if (ACPI_SUCCESS(status)) { acpi_db_load_tables(list_head); } diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index b5413bb..a8ce8a8 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -98,9 +98,9 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc, default: - ACPI_ERROR((AE_INFO, "Unknown Reference Class 0x%2.2X", + ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X", obj_desc->reference.class)); - return_ACPI_STATUS(AE_AML_INTERNAL); + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } break; diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 72bcccf..7c1b5f8 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -389,7 +389,7 @@ next_table: * * PARAMETERS: signature - Sig string to be validated * - * RETURN: TRUE if signature is correct length and has valid characters + * RETURN: TRUE if signature is has 4 valid ACPI characters * * DESCRIPTION: Validate an ACPI table signature. * @@ -399,12 +399,6 @@ u8 acpi_is_valid_signature(char *signature) { u32 i; - /* Validate the signature length */ - - if (strlen(signature) != ACPI_NAME_SIZE) { - return (FALSE); - } - /* Validate each character in the signature */ for (i = 0; i < ACPI_NAME_SIZE; i++) { -- cgit v0.10.2 From 4d16ca17483440376344abf4d7110ec7d47ed54b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 29 Dec 2015 13:55:27 +0800 Subject: ACPICA: Debugger: Remove some unecessary NULL checks ACPICA commit 36fcc1b98def3fb6e20cf5e877ffc3c1592d0140 Local strupr function already checks for NULL pointers. Original linux patch submitted by: Markus Elfring Link: https://github.com/acpica/acpica/commit/36fcc1b9 Signed-off-by: Markus Elfring Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c index 84ab1c2..328c35b 100644 --- a/drivers/acpi/acpica/dbcmds.c +++ b/drivers/acpi/acpica/dbcmds.c @@ -1131,13 +1131,8 @@ void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg) u32 debug_layer = 0; u32 flags = 0; - if (enable_arg) { - acpi_ut_strupr(enable_arg); - } - - if (once_arg) { - acpi_ut_strupr(once_arg); - } + acpi_ut_strupr(enable_arg); + acpi_ut_strupr(once_arg); if (method_arg) { if (acpi_db_trace_method_name) { diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 802779a..6203001 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -625,9 +625,7 @@ static u32 acpi_db_get_line(char *input_buffer) /* Uppercase the actual command */ - if (acpi_gbl_db_args[0]) { - acpi_ut_strupr(acpi_gbl_db_args[0]); - } + acpi_ut_strupr(acpi_gbl_db_args[0]); count = i; if (count) { -- cgit v0.10.2 From 07cb390f43e7fd9daceb6a1e223a82c832f5f9ab Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:55:47 +0800 Subject: ACPICA: Revert "acpi_get_object_info: Add support for ACPI 5.0 _SUB method." ACPICA commit e4743959b59ad93eab7310adf756adc930be0ddb This reverts commit 8e7a8753827660c3dd1f571f3185610402b756f0. The _SUB method was found to be problematic for this interface because some implementations use control methods. Therefore, it is being removed. Operations cannot be used because this interface is called during the device discovery scan and the region handlers are not fully installed at that time. Link: https://github.com/acpica/acpica/commit/e4743959 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6776348..9e84c05 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -364,10 +364,6 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, struct acpi_pnp_device_id ** return_id); acpi_status -acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, - struct acpi_pnp_device_id **return_id); - -acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, struct acpi_pnp_device_id_list ** return_cid_list); diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index 3acc3a5..390a7ca 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -588,7 +588,7 @@ void acpi_db_display_calling_tree(void) * * FUNCTION: acpi_db_display_object_type * - * PARAMETERS: name - User entered NS node handle or name + * PARAMETERS: object_arg - User entered NS node handle * * RETURN: None * @@ -596,44 +596,34 @@ void acpi_db_display_calling_tree(void) * ******************************************************************************/ -void acpi_db_display_object_type(char *name) +void acpi_db_display_object_type(char *object_arg) { - struct acpi_namespace_node *node; + acpi_handle handle; struct acpi_device_info *info; acpi_status status; u32 i; - node = acpi_db_convert_to_node(name); - if (!node) { - return; - } + handle = ACPI_TO_POINTER(strtoul(object_arg, NULL, 16)); - status = acpi_get_object_info(ACPI_CAST_PTR(acpi_handle, node), &info); + status = acpi_get_object_info(handle, &info); if (ACPI_FAILURE(status)) { acpi_os_printf("Could not get object info, %s\n", acpi_format_exception(status)); return; } - if (info->valid & ACPI_VALID_ADR) { - acpi_os_printf("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n", - ACPI_FORMAT_UINT64(info->address), - info->current_status, info->flags); - } - if (info->valid & ACPI_VALID_SXDS) { - acpi_os_printf("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n", - info->highest_dstates[0], - info->highest_dstates[1], - info->highest_dstates[2], - info->highest_dstates[3]); - } - if (info->valid & ACPI_VALID_SXWS) { - acpi_os_printf - ("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n", - info->lowest_dstates[0], info->lowest_dstates[1], - info->lowest_dstates[2], info->lowest_dstates[3], - info->lowest_dstates[4]); - } + acpi_os_printf("ADR: %8.8X%8.8X, STA: %8.8X, Flags: %X\n", + ACPI_FORMAT_UINT64(info->address), + info->current_status, info->flags); + + acpi_os_printf("S1D-%2.2X S2D-%2.2X S3D-%2.2X S4D-%2.2X\n", + info->highest_dstates[0], info->highest_dstates[1], + info->highest_dstates[2], info->highest_dstates[3]); + + acpi_os_printf("S0W-%2.2X S1W-%2.2X S2W-%2.2X S3W-%2.2X S4W-%2.2X\n", + info->lowest_dstates[0], info->lowest_dstates[1], + info->lowest_dstates[2], info->lowest_dstates[3], + info->lowest_dstates[4]); if (info->valid & ACPI_VALID_HID) { acpi_os_printf("HID: %s\n", info->hardware_id.string); @@ -643,10 +633,6 @@ void acpi_db_display_object_type(char *name) acpi_os_printf("UID: %s\n", info->unique_id.string); } - if (info->valid & ACPI_VALID_SUB) { - acpi_os_printf("SUB: %s\n", info->subsystem_id.string); - } - if (info->valid & ACPI_VALID_CID) { for (i = 0; i < info->compatible_id_list.count; i++) { acpi_os_printf("CID %u: %s\n", i, diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index c19d86c..0e4e6b7 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -238,7 +238,6 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, struct acpi_pnp_device_id *source, char *string_area) { - /* Create the destination PNP_DEVICE_ID */ dest->string = string_area; @@ -263,8 +262,8 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, * namespace node and possibly by running several standard * control methods (Such as in the case of a device.) * - * For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, - * _CLS, _STA, _ADR, _sx_w, and _sx_d methods. + * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA, + * _CLS, _ADR, _sx_w, and _sx_d methods. * * Note: Allocates the return buffer, must be freed by the caller. * @@ -279,7 +278,6 @@ acpi_get_object_info(acpi_handle handle, struct acpi_pnp_device_id_list *cid_list = NULL; struct acpi_pnp_device_id *hid = NULL; struct acpi_pnp_device_id *uid = NULL; - struct acpi_pnp_device_id *sub = NULL; struct acpi_pnp_device_id *cls = NULL; char *next_id_string; acpi_object_type type; @@ -325,7 +323,7 @@ acpi_get_object_info(acpi_handle handle, if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* * Get extra info for ACPI Device/Processor objects only: - * Run the Device _HID, _UID, _SUB, _CID, and _CLS methods. + * Run the Device _HID, _UID, _CLS, and _CID methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used @@ -348,14 +346,6 @@ acpi_get_object_info(acpi_handle handle, valid |= ACPI_VALID_UID; } - /* Execute the Device._SUB method */ - - status = acpi_ut_execute_SUB(node, &sub); - if (ACPI_SUCCESS(status)) { - info_size += sub->length; - valid |= ACPI_VALID_SUB; - } - /* Execute the Device._CID method */ status = acpi_ut_execute_CID(node, &cid_list); @@ -456,9 +446,8 @@ acpi_get_object_info(acpi_handle handle, } /* - * Copy the HID, UID, SUB, and CIDs to the return buffer. - * The variable-length strings are copied to the reserved area - * at the end of the buffer. + * Copy the HID, UID, and CIDs to the return buffer. The variable-length + * strings are copied to the reserved area at the end of the buffer. * * For HID and CID, check if the ID is a PCI Root Bridge. */ @@ -476,11 +465,6 @@ acpi_get_object_info(acpi_handle handle, uid, next_id_string); } - if (sub) { - next_id_string = acpi_ns_copy_device_id(&info->subsystem_id, - sub, next_id_string); - } - if (cid_list) { info->compatible_id_list.count = cid_list->count; info->compatible_id_list.list_size = cid_list->list_size; @@ -522,9 +506,6 @@ cleanup: if (uid) { ACPI_FREE(uid); } - if (sub) { - ACPI_FREE(sub); - } if (cid_list) { ACPI_FREE(cid_list); } diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 7956df1e..05ee76e 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -127,73 +127,6 @@ cleanup: /******************************************************************************* * - * FUNCTION: acpi_ut_execute_SUB - * - * PARAMETERS: device_node - Node for the device - * return_id - Where the _SUB is returned - * - * RETURN: Status - * - * DESCRIPTION: Executes the _SUB control method that returns the subsystem - * ID of the device. The _SUB value is always a string containing - * either a valid PNP or ACPI ID. - * - * NOTE: Internal function, no parameter validation - * - ******************************************************************************/ - -acpi_status -acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, - struct acpi_pnp_device_id **return_id) -{ - union acpi_operand_object *obj_desc; - struct acpi_pnp_device_id *sub; - u32 length; - acpi_status status; - - ACPI_FUNCTION_TRACE(ut_execute_SUB); - - status = acpi_ut_evaluate_object(device_node, METHOD_NAME__SUB, - ACPI_BTYPE_STRING, &obj_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the size of the String to be returned, includes null terminator */ - - length = obj_desc->string.length + 1; - - /* Allocate a buffer for the SUB */ - - sub = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + - (acpi_size) length); - if (!sub) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* Area for the string starts after PNP_DEVICE_ID struct */ - - sub->string = - ACPI_ADD_PTR(char, sub, sizeof(struct acpi_pnp_device_id)); - - /* Simply copy existing string */ - - strcpy(sub->string, obj_desc->string.pointer); - sub->length = length; - *return_id = sub; - -cleanup: - - /* On exit, we must delete the return object */ - - acpi_ut_remove_reference(obj_desc); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * * FUNCTION: acpi_ut_execute_UID * * PARAMETERS: device_node - Node for the device diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index f914958..9633f60 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1148,7 +1148,7 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); #define ACPI_PCICLS_STRING_SIZE 7 /* Includes null terminator */ -/* Structures used for device/processor HID, UID, CID, and SUB */ +/* Structures used for device/processor HID, UID, CID */ struct acpi_pnp_device_id { u32 length; /* Length of string + null */ @@ -1178,7 +1178,6 @@ struct acpi_device_info { u64 address; /* _ADR value */ struct acpi_pnp_device_id hardware_id; /* _HID value */ struct acpi_pnp_device_id unique_id; /* _UID value */ - struct acpi_pnp_device_id subsystem_id; /* _SUB value */ struct acpi_pnp_device_id class_code; /* _CLS value */ struct acpi_pnp_device_id_list compatible_id_list; /* _CID list */ }; @@ -1193,13 +1192,12 @@ struct acpi_device_info { #define ACPI_VALID_ADR 0x0002 #define ACPI_VALID_HID 0x0004 #define ACPI_VALID_UID 0x0008 -#define ACPI_VALID_SUB 0x0010 #define ACPI_VALID_CID 0x0020 #define ACPI_VALID_CLS 0x0040 #define ACPI_VALID_SXDS 0x0100 #define ACPI_VALID_SXWS 0x0200 -/* Flags for _STA return value (current_status above) */ +/* Flags for _STA method */ #define ACPI_STA_DEVICE_PRESENT 0x01 #define ACPI_STA_DEVICE_ENABLED 0x02 -- cgit v0.10.2 From c6c6069cad37952da71d2a24eb6ee0a87074b35c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:56:14 +0800 Subject: ACPICA: Add comment explaining _SUB removal ACPICA commit 81a89968f83bfc3b1d0f0f80f2da08ea69646053 Adds a lengthy comment to acpi_get_object_info explaining the removal of _SUB and why no complex methods can be added ever to this interface. Link: https://github.com/acpica/acpica/commit/81a89968 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 0e4e6b7..669e0f1 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -267,6 +267,13 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, * * Note: Allocates the return buffer, must be freed by the caller. * + * Note: This interface is intended to be used during the initial device + * discovery namespace traversal. Therefore, no complex methods can be + * executed, especially those that access operation regions. Therefore, do + * not add any additional methods that could cause problems in this area. + * this was the fate of the _SUB method which was found to cause such + * problems and was removed (11/2015). + * ******************************************************************************/ acpi_status -- cgit v0.10.2 From 3727ec2a03d3581b2e0d326bedfb92706a9b4d0f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:56:46 +0800 Subject: ACPICA: acpiexec/acpinames: Update for error checking macros ACPICA commit 5bdfb4f43f4d315d23b31b39bac5a0b1ca420c2b Standardize naming, deploy in common header. Link: https://github.com/acpica/acpica/commit/5bdfb4f4 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 340350f..578e37f 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -89,6 +89,19 @@ #define ACPI_OPTION(name, description) \ acpi_os_printf (" %-18s%s\n", name, description); +/* Check for unexpected exceptions */ + +#define ACPI_CHECK_STATUS(name, status, expected) \ + if (status != expected) \ + { \ + acpi_os_printf ("Unexpected %s from %s (%s-%d)\n", \ + acpi_format_exception (status), #name, _acpi_module_name, __LINE__); \ + } + +/* Check for unexpected non-AE_OK errors */ + +#define ACPI_CHECK_OK(name, status) ACPI_CHECK_STATUS (name, status, AE_OK); + #define FILE_SUFFIX_DISASSEMBLY "dsl" #define FILE_SUFFIX_BINARY_TABLE ".dat" /* Needs the dot */ -- cgit v0.10.2 From 7910617efb5188c0b8dedab1857b12d078957a79 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:56:53 +0800 Subject: ACPICA: Concatenate operator: Add extensions to support all ACPI objects ACPICA commit 3420c1f5e6c6dd4fe51be4d98da69b3197d608df Emits strings for all the object types besides int/str/buf. This simplifies and extends the usefulness of the Printf macros. Link: https://github.com/acpica/acpica/commit/3420c1f5 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index f9acf92..db71b02 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -223,7 +223,7 @@ #define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_BYTE_OP ARGI_INVALID_OPCODE #define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE -#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) +#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_ANYTYPE, ARGI_ANYTYPE, ARGI_TARGETREF) #define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) #define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) #define ARGI_CONNECTFIELD_OP ARGI_INVALID_OPCODE diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index a8ce8a8..f598b39 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -247,6 +247,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, union acpi_operand_object *local_operand1 = operand1; union acpi_operand_object *return_desc; char *new_buf; + const char *type_string; acpi_status status; ACPI_FUNCTION_TRACE(ex_do_concatenate); @@ -266,10 +267,41 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, break; case ACPI_TYPE_STRING: + /* + * Per the ACPI spec, Concatenate only supports int/str/buf. + * However, we support all objects here as an extension. + * This improves the usefulness of the Printf() macro. + * 12/2015. + */ + switch (operand1->common.type) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + status = + acpi_ex_convert_to_string(operand1, &local_operand1, + ACPI_IMPLICIT_CONVERT_HEX); + break; - status = - acpi_ex_convert_to_string(operand1, &local_operand1, - ACPI_IMPLICIT_CONVERT_HEX); + default: + /* + * Just emit a string containing the object type. + */ + type_string = + acpi_ut_get_type_name(operand1->common.type); + + local_operand1 = acpi_ut_create_string_object(((acpi_size) strlen(type_string) + 9)); /* 9 For "[Object]" */ + if (!local_operand1) { + status = AE_NO_MEMORY; + goto cleanup; + } + + strcpy(local_operand1->string.pointer, "["); + strcat(local_operand1->string.pointer, type_string); + strcat(local_operand1->string.pointer, " Object]"); + status = AE_OK; + break; + } break; case ACPI_TYPE_BUFFER: @@ -348,8 +380,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Concatenate the strings */ strcpy(new_buf, operand0->string.pointer); - strcpy(new_buf + operand0->string.length, - local_operand1->string.pointer); + strcat(new_buf, local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: -- cgit v0.10.2 From 5e568304a2971332bb7b80fd6cf2a0f77e487d32 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:57:01 +0800 Subject: ACPICA: Debug Object: Cleanup output ACPICA commit 05492c4a7d1e106eb871a5e1357ed564d25740e5 1) Make the timer value output optional 2) Allow empty lines via null string or simple newline 3) No need for the object type name for strings and integers 4) Miscellaneous cleanup of output Link: https://github.com/acpica/acpica/commit/05492c4a Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 815442b..a203335 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -88,20 +88,39 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, return_VOID; } - /* - * We will emit the current timer value (in microseconds) with each - * debug output. Only need the lower 26 bits. This allows for 67 - * million microseconds or 67 seconds before rollover. - */ - timer = ((u32)acpi_os_get_timer() / 10); /* (100 nanoseconds to microseconds) */ - timer &= 0x03FFFFFF; + /* Null string or newline -- don't emit the line header */ + + if ((ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) && + (source_desc->common.type == ACPI_TYPE_STRING)) { + if ((source_desc->string.length == 0) || + ((source_desc->string.length == 1) && + (*source_desc->string.pointer == '\n'))) { + acpi_os_printf("\n"); + return_VOID; + } + } /* * Print line header as long as we are not in the middle of an * object display */ if (!((level > 0) && index == 0)) { - acpi_os_printf("[ACPI Debug %.8u] %*s", timer, level, " "); + if (acpi_gbl_display_debug_timer) { + /* + * We will emit the current timer value (in microseconds) with each + * debug output. Only need the lower 26 bits. This allows for 67 + * million microseconds or 67 seconds before rollover. + * + * Convert 100 nanosecond units to microseconds + */ + timer = ((u32)acpi_os_get_timer() / 10); + timer &= 0x03FFFFFF; + + acpi_os_printf("[ACPI Debug T=0x%8.8X] %*s", timer, + level, " "); + } else { + acpi_os_printf("[ACPI Debug] %*s", level, " "); + } } /* Display the index for package output only */ @@ -116,8 +135,15 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, } if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) { - acpi_os_printf("%s ", - acpi_ut_get_object_type_name(source_desc)); + + /* No object type prefix needed for integers and strings */ + + if ((source_desc->common.type != ACPI_TYPE_INTEGER) && + (source_desc->common.type != ACPI_TYPE_STRING)) { + acpi_os_printf("%s ", + acpi_ut_get_object_type_name + (source_desc)); + } if (!acpi_ut_valid_internal_object(source_desc)) { acpi_os_printf("%p, Invalid Internal Object!\n", @@ -126,7 +152,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, } } else if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_NAMED) { - acpi_os_printf("%s: %p\n", + acpi_os_printf("%s (Node %p)\n", acpi_ut_get_type_name(((struct acpi_namespace_node *) source_desc)->type), @@ -164,14 +190,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_TYPE_STRING: - acpi_os_printf("[0x%.2X] \"%s\"\n", - source_desc->string.length, - source_desc->string.pointer); + acpi_os_printf("\"%s\"\n", source_desc->string.pointer); break; case ACPI_TYPE_PACKAGE: - acpi_os_printf("[Contains 0x%.2X Elements]\n", + acpi_os_printf("(Contains 0x%.2X Elements):\n", source_desc->package.count); /* Output the entire contents of the package */ @@ -250,11 +274,14 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, if (ACPI_GET_DESCRIPTOR_TYPE (source_desc->reference.object) == ACPI_DESC_TYPE_NAMED) { - acpi_ex_do_debug_object(((struct - acpi_namespace_node *) + + /* Reference object is a namespace node */ + + acpi_ex_do_debug_object(ACPI_CAST_PTR + (union + acpi_operand_object, source_desc->reference. - object)->object, - level + 4, 0); + object), level + 4, 0); } else { object_desc = source_desc->reference.object; value = source_desc->reference.value; @@ -300,7 +327,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, default: - acpi_os_printf("%p\n", source_desc); + acpi_os_printf("(Descriptor %p)\n", source_desc); break; } diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 5dfab9c..d60507b7 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -263,6 +263,10 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_layer, ACPI_TRACE_LAYER_DEFAULT); ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); +/* Optionally enable timer output with Debug Object output */ + +ACPI_INIT_GLOBAL(u8, acpi_gbl_display_debug_timer, FALSE); + /* * Debugger command handshake globals. Host OSes need to access these * variables to implement their own command handshake mechanism. -- cgit v0.10.2 From 973da572820c1c85ae828c2e090e9f902546ba96 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:57:07 +0800 Subject: ACPICA: Debug object: Fix output for a NULL object ACPICA commit e4414f067c726ef746dac990c0bae7f433045843 Was broken by addition of "null string" feature to emit simple blank lines. Link: https://github.com/acpica/acpica/commit/e4414f06 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index a203335..ca6e379 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -90,7 +90,8 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, /* Null string or newline -- don't emit the line header */ - if ((ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) && + if (source_desc && + (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) && (source_desc->common.type == ACPI_TYPE_STRING)) { if ((source_desc->string.length == 0) || ((source_desc->string.length == 1) && -- cgit v0.10.2 From 50da9851d009a0a0d10064e73dd6704593333c72 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:57:14 +0800 Subject: ACPICA: Update for output of the Debug Object ACPICA commit b01414f5a822d0879aa9eba91541a21e7e501142 Improve output for the case of an Index() that refers to a Package element that has not been initialized. Link: https://github.com/acpica/acpica/commit/b01414f5 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index ca6e379..b223090 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -310,9 +310,14 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_TYPE_PACKAGE: acpi_os_printf("Package[%u] = ", value); - acpi_ex_do_debug_object(*source_desc-> - reference.where, - level + 4, 0); + if (!(*source_desc->reference.where)) { + acpi_os_printf + ("[Uninitialized Package Element]\n"); + } else { + acpi_ex_do_debug_object + (*source_desc->reference. + where, level + 4, 0); + } break; default: -- cgit v0.10.2 From 4debda539af12ebc55fc99102dca2861e5f325fd Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 13:57:38 +0800 Subject: ACPICA: Namespace: Add scope information to the simple object repair mechanism ACPICA commit 51cbd324420ca5e381cb2c57ce95139053518a35 The acpi_object_converter callbacks are lack in scope information to convert name_string. This patch fixes this issue by passing the evaluation method/object node to the converter callbacks. Lv Zheng. Link: https://github.com/acpica/acpica/commit/51cbd324 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 4fd5040..351a1cd 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -395,7 +395,8 @@ union acpi_predefined_info { /* Return object auto-repair info */ -typedef acpi_status(*acpi_object_converter) (union acpi_operand_object +typedef acpi_status(*acpi_object_converter) (struct acpi_namespace_node * scope, + union acpi_operand_object *original_object, union acpi_operand_object **converted_object); diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 5d261c9..1f42c3c 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -183,11 +183,13 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, union acpi_operand_object **return_object); acpi_status -acpi_ns_convert_to_unicode(union acpi_operand_object *original_object, +acpi_ns_convert_to_unicode(struct acpi_namespace_node *scope, + union acpi_operand_object *original_object, union acpi_operand_object **return_object); acpi_status -acpi_ns_convert_to_resource(union acpi_operand_object *original_object, +acpi_ns_convert_to_resource(struct acpi_namespace_node *scope, + union acpi_operand_object *original_object, union acpi_operand_object **return_object); /* diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index 749a189..ab47a50 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -306,7 +306,8 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, * * FUNCTION: acpi_ns_convert_to_unicode * - * PARAMETERS: original_object - ASCII String Object to be converted + * PARAMETERS: scope - Namespace node for the method/object + * original_object - ASCII String Object to be converted * return_object - Where the new converted object is returned * * RETURN: Status. AE_OK if conversion was successful. @@ -316,7 +317,8 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, ******************************************************************************/ acpi_status -acpi_ns_convert_to_unicode(union acpi_operand_object *original_object, +acpi_ns_convert_to_unicode(struct acpi_namespace_node * scope, + union acpi_operand_object *original_object, union acpi_operand_object **return_object) { union acpi_operand_object *new_object; @@ -370,7 +372,8 @@ acpi_ns_convert_to_unicode(union acpi_operand_object *original_object, * * FUNCTION: acpi_ns_convert_to_resource * - * PARAMETERS: original_object - Object to be converted + * PARAMETERS: scope - Namespace node for the method/object + * original_object - Object to be converted * return_object - Where the new converted object is returned * * RETURN: Status. AE_OK if conversion was successful @@ -381,7 +384,8 @@ acpi_ns_convert_to_unicode(union acpi_operand_object *original_object, ******************************************************************************/ acpi_status -acpi_ns_convert_to_resource(union acpi_operand_object *original_object, +acpi_ns_convert_to_resource(struct acpi_namespace_node * scope, + union acpi_operand_object *original_object, union acpi_operand_object **return_object) { union acpi_operand_object *new_object; diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 360e3ab..4b7dbff 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -172,8 +172,8 @@ acpi_ns_simple_repair(struct acpi_evaluate_info *info, "Missing expected return value")); } - status = - predefined->object_converter(return_object, &new_object); + status = predefined->object_converter(info->node, return_object, + &new_object); if (ACPI_FAILURE(status)) { /* A fatal error occurred during a conversion */ -- cgit v0.10.2 From ee387409ca7d74d83a26915a367bf9b033e29803 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 13:58:02 +0800 Subject: ACPICA: Namespace: Add String -> ObjectReference conversion support ACPICA commit 80e60d72959bb51c5d08c8500d978607a42ed81d BIOS developers may accidently put the quotes around the name strings, which converts the object references in the packages indicated by the name strings into the data objects (strings). Such kind of error has been seen in _DEP control methods on some platforms. This patch implements a workaround to correct it. Reported by Bastien Nocera. Fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/80e60d72 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=106231 Reported-and-tested-by: Bastien Nocera Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 1f42c3c..d082e62 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -77,6 +77,7 @@ /* Object is not a package element */ #define ACPI_NOT_PACKAGE_ELEMENT ACPI_UINT32_MAX +#define ACPI_ALL_PACKAGE_ELEMENTS (ACPI_UINT32_MAX-1) /* Always emit warning message, not dependent on node flags */ @@ -192,6 +193,11 @@ acpi_ns_convert_to_resource(struct acpi_namespace_node *scope, union acpi_operand_object *original_object, union acpi_operand_object **return_object); +acpi_status +acpi_ns_convert_to_reference(struct acpi_namespace_node *scope, + union acpi_operand_object *original_object, + union acpi_operand_object **return_object); + /* * nsdump - Namespace dump/print utilities */ diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index ab47a50..f21568b 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -446,3 +446,78 @@ acpi_ns_convert_to_resource(struct acpi_namespace_node * scope, *return_object = new_object; return (AE_OK); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_convert_to_reference + * + * PARAMETERS: scope - Namespace node for the method/object + * original_object - Object to be converted + * return_object - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful + * + * DESCRIPTION: Attempt to convert a Integer object to a object_reference. + * Buffer. + * + ******************************************************************************/ + +acpi_status +acpi_ns_convert_to_reference(struct acpi_namespace_node * scope, + union acpi_operand_object *original_object, + union acpi_operand_object **return_object) +{ + union acpi_operand_object *new_object = NULL; + acpi_status status; + struct acpi_namespace_node *node; + union acpi_generic_state scope_info; + char *name; + + ACPI_FUNCTION_NAME(ns_convert_to_reference); + + /* Convert path into internal presentation */ + + status = + acpi_ns_internalize_name(original_object->string.pointer, &name); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Find the namespace node */ + + scope_info.scope.node = + ACPI_CAST_PTR(struct acpi_namespace_node, scope); + status = + acpi_ns_lookup(&scope_info, name, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &node); + if (ACPI_FAILURE(status)) { + + /* Check if we are resolving a named reference within a package */ + + ACPI_ERROR_NAMESPACE(original_object->string.pointer, status); + goto error_exit; + } + + /* Create and init a new internal ACPI object */ + + new_object = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); + if (!new_object) { + status = AE_NO_MEMORY; + goto error_exit; + } + new_object->reference.node = node; + new_object->reference.object = node->object; + new_object->reference.class = ACPI_REFCLASS_NAME; + + /* + * Increase reference of the object if needed (the object is likely a + * null for device nodes). + */ + acpi_ut_add_reference(node->object); + +error_exit: + ACPI_FREE(name); + *return_object = new_object; + return (AE_OK); +} diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 4b7dbff..6418863 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -116,6 +116,11 @@ static const struct acpi_simple_repair_info acpi_object_repair_info[] = { ACPI_NOT_PACKAGE_ELEMENT, acpi_ns_convert_to_resource}, + /* Object reference conversions */ + + {"_DEP", ACPI_RTYPE_STRING, ACPI_ALL_PACKAGE_ELEMENTS, + acpi_ns_convert_to_reference}, + /* Unicode conversions */ {"_MLS", ACPI_RTYPE_STRING, 1, @@ -360,7 +365,9 @@ static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct /* Check if we can actually repair this name/type combination */ if ((return_btype & this_name->unexpected_btypes) && - (package_index == this_name->package_index)) { + (this_name->package_index == + ACPI_ALL_PACKAGE_ELEMENTS + || package_index == this_name->package_index)) { return (this_name); } -- cgit v0.10.2 From 5920380c673367a1f348a75aadd45a65c40933f6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:58:27 +0800 Subject: ACPICA: getopt: Comment update, no functional change ACPICA commit 0d784a90bc3aac75227c4459c3553de18b9ebe7a Document one of the option string operators. Link: https://github.com/acpica/acpica/commit/0d784a90 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c index 2496629..efefe30 100644 --- a/tools/power/acpi/common/getopt.c +++ b/tools/power/acpi/common/getopt.c @@ -47,6 +47,7 @@ * Option strings: * "f" - Option has no arguments * "f:" - Option requires an argument + * "f+" - Option has an optional argument * "f^" - Option has optional single-char sub-options * "f|" - Option has required single-char sub-options */ -- cgit v0.10.2 From adeb79dd6ea2e6dbee3e3b907109b22fb9d2f3fd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 29 Dec 2015 13:59:27 +0800 Subject: ACPICA: Tools: Add spacing and missing options in acpibin tool ACPICA commit e7c8ffbbef3f7ce340e012ae4db63ea16cd09714 The -e option is missing from the acpibin help options, so add this. Also, there should be spaces between the filenames for the -c and -d optios, so add this and expand the field size from 18 to 20 characters in the ACPI_OPTION macro. Link: https://github.com/acpica/acpica/commit/e7c8ffbb Signed-off-by: Colin Ian King Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 578e37f..8b4ff40 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -87,7 +87,7 @@ acpi_os_printf (description); #define ACPI_OPTION(name, description) \ - acpi_os_printf (" %-18s%s\n", name, description); + acpi_os_printf (" %-20s%s\n", name, description); /* Check for unexpected exceptions */ -- cgit v0.10.2 From a6a0432e22280fe824e4d7f6a4e4a7b7860b535e Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 13:59:34 +0800 Subject: ACPICA: Add new exception code, AE_IO_ERROR ACPICA commit dcaeaddfc11544f03e6323be4ac8ff8a1e014956 The intent for this exception is for low-level I/O operations, especially Clib functions. Link: https://github.com/acpica/acpica/commit/dcaeaddf Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 204f581..cd84b12 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -126,8 +126,9 @@ struct acpi_exception_info { #define AE_OWNER_ID_LIMIT EXCEP_ENV (0x001B) #define AE_NOT_CONFIGURED EXCEP_ENV (0x001C) #define AE_ACCESS EXCEP_ENV (0x001D) +#define AE_IO_ERROR EXCEP_ENV (0x001E) -#define AE_CODE_ENV_MAX 0x001D +#define AE_CODE_ENV_MAX 0x001E /* * Programmer exceptions @@ -263,7 +264,8 @@ static const struct acpi_exception_info acpi_gbl_exception_names_env[] = { "There are no more Owner IDs available for ACPI tables or control methods"), EXCEP_TXT("AE_NOT_CONFIGURED", "The interface is not part of the current subsystem configuration"), - EXCEP_TXT("AE_ACCESS", "Permission denied for the requested operation") + EXCEP_TXT("AE_ACCESS", "Permission denied for the requested operation"), + EXCEP_TXT("AE_IO_ERROR", "An I/O error occurred") }; static const struct acpi_exception_info acpi_gbl_exception_names_pgm[] = { -- cgit v0.10.2 From 8d0b5b788f9e80707ea7dd5880d74227e6620d09 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:00:00 +0800 Subject: ACPICA: iasl/Disassembler: Support ASL ElseIf operator ACPICA commit 918a840d27d620942e0ecb69de320bb71ea86c5a ElseIf is a macro that resolves to an Else..If in the AML byte code. This support merges an Else followed immediately by an If to an ASL ElseIf operator. Simplifies decoded ASL, especially for large Switch statements. This patch only applies to iasl, and is no-op for Linux kernel. Link: https://github.com/acpica/acpica/commit/918a840d Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 351a1cd..034402d 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -869,6 +869,7 @@ struct acpi_parse_state { #define ACPI_PARSEOP_CLOSING_PAREN 0x10 #define ACPI_PARSEOP_COMPOUND 0x20 #define ACPI_PARSEOP_ASSIGNMENT 0x40 +#define ACPI_PARSEOP_ELSEIF 0x80 /***************************************************************************** * -- cgit v0.10.2 From 89438f96f2c6d31e1d7594714475c582afe03329 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:00:07 +0800 Subject: ACPICA: Parser: Add constants for internal namepath function ACPICA commit b216e39fe85feee955d29fe0a7190dd811e181ea Add true/false constants for the "PossibleMethodCall" parameter for acpi_ps_get_next_namepath. Link: https://github.com/acpica/acpica/commit/b216e39f Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 8fc8c7c..96d510a 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -92,7 +92,13 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, acpi_status acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, struct acpi_parse_state *parser_state, - union acpi_parse_object *arg, u8 method_call); + union acpi_parse_object *arg, + u8 possible_method_call); + +/* Values for u8 above */ + +#define ACPI_NOT_METHOD_CALL FALSE +#define ACPI_POSSIBLE_METHOD_CALL TRUE acpi_status acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 3f0ffee..0fdb7fc 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -821,7 +821,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, status = acpi_ps_get_next_namepath(walk_state, parser_state, arg, - 1); + ACPI_POSSIBLE_METHOD_CALL); /* * If the super_name arg of Unload is a method call, @@ -836,7 +836,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, status = acpi_ps_get_next_namepath(walk_state, parser_state, arg, - 0); + ACPI_NOT_METHOD_CALL); } } else { /* Single complex argument, nothing returned */ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index c660006..a57f473 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -109,10 +109,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ - status = - acpi_ps_get_next_namepath(walk_state, - &(walk_state->parser_state), op, - 1); + status = acpi_ps_get_next_namepath(walk_state, + &(walk_state->parser_state), + op, + ACPI_POSSIBLE_METHOD_CALL); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } -- cgit v0.10.2 From ae90fbf562d733a392c7a0ffefe1e09b5a31c99c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:00:14 +0800 Subject: ACPICA: Parser: Fix for SuperName method invocation ACPICA commit 4b86d1046d06e462dae83ebcd5a66cc132a08f8f SuperName parameters that are in fact control method invocations were not handled correctly by the parser. This change fixes the problem by identifying these properly as method invocations. This affects about 14 different ASL operators that contain SuperName parameters. ACPICA BZ 1002. Link: https://github.com/acpica/acpica/commit/4b86d104 Link: https://bugs.acpica.org/show_bug.cgi?id=1002 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 0fdb7fc..f84e546 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -269,7 +269,8 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { - if (walk_state->opcode == AML_UNLOAD_OP) { + if (GET_CURRENT_ARG_TYPE(walk_state->arg_types) == + ARGP_SUPERNAME) { /* * acpi_ps_get_next_namestring has increased the AML pointer, * so we need to restore the saved AML pointer for method call. @@ -696,7 +697,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state * * PARAMETERS: walk_state - Current state * parser_state - Current parser state object - * arg_type - The argument type (AML_*_ARG) + * arg_type - The parser argument type (ARGP_*) * return_arg - Where the next arg is returned * * RETURN: Status, and an op object containing the next argument. @@ -815,9 +816,9 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NO_MEMORY); } - /* To support super_name arg of Unload */ + /* super_name allows argument to be a method call */ - if (walk_state->opcode == AML_UNLOAD_OP) { + if (arg_type == ARGP_SUPERNAME) { status = acpi_ps_get_next_namepath(walk_state, parser_state, arg, -- cgit v0.10.2 From cca7a6ea0bcf20548369e73817eeb83118bc5604 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:00:21 +0800 Subject: ACPICA: Update parameter type for ObjectType operator ACPICA commit 67953304a34944548f2fa53a4b0786a5db0ca2ea The grammar for this operator changed in ACPI 5.0A, but it was not necessary to update the interpreter/parser until now. The UserTerm (method invocation) element was removed. Previously a SuperName, the lone argument now requires a new ARGP_ type. Link: https://github.com/acpica/acpica/commit/67953304 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index db71b02..05f80de 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -185,7 +185,7 @@ #define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) #define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) #define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF) #define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) #define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 883f20c..2eedfa2 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -238,7 +238,8 @@ #define ARGP_TERMLIST 0x0F #define ARGP_WORDDATA 0x10 #define ARGP_QWORDDATA 0x11 -#define ARGP_SIMPLENAME 0x12 +#define ARGP_SIMPLENAME 0x12 /* name_string | local_term | arg_term */ +#define ARGP_NAME_OR_REF 0x13 /* For object_type only */ /* * Resolved argument types for the AML Interpreter diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index f84e546..f3bcfa2 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -800,6 +800,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, case ARGP_TARGET: case ARGP_SUPERNAME: case ARGP_SIMPLENAME: + case ARGP_NAME_OR_REF: subop = acpi_ps_peek_opcode(parser_state); if (subop == 0 || @@ -825,8 +826,8 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, ACPI_POSSIBLE_METHOD_CALL); /* - * If the super_name arg of Unload is a method call, - * we have restored the AML pointer, just free this Arg + * If the super_name argument is a method call, we have + * already restored the AML pointer, just free this Arg */ if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { -- cgit v0.10.2 From f70008d368b6b5d6c35ecfd0615e1ad119c51aa0 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:00:28 +0800 Subject: ACPICA: Update internal #defines for ObjectType operator. No functional change ACPICA commit 5923a9be36b8cb1b62afa89fe217783c04c92ad3 To improve readability. Rename all *_TYPE_* defines related to ObjectType to *_OBJECT_TYPE_* Link: https://github.com/acpica/acpica/commit/5923a9be Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index 05f80de..c6b2f42 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -152,6 +152,7 @@ #define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_NOOP_OP ARG_NONE #define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF) #define ARGP_ONE_OP ARG_NONE #define ARGP_ONES_OP ARG_NONE #define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) @@ -185,7 +186,6 @@ #define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) #define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) #define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF) #define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) #define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) @@ -285,6 +285,7 @@ #define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE #define ARGI_NOOP_OP ARG_NONE #define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) +#define ARGI_OBJECT_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) #define ARGI_ONE_OP ARG_NONE #define ARGI_ONES_OP ARG_NONE #define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) @@ -318,7 +319,6 @@ #define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) #define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) #define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) #define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) #define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 2eedfa2..ab9f3f1 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -120,7 +120,7 @@ #define AML_CREATE_WORD_FIELD_OP (u16) 0x8b #define AML_CREATE_BYTE_FIELD_OP (u16) 0x8c #define AML_CREATE_BIT_FIELD_OP (u16) 0x8d -#define AML_TYPE_OP (u16) 0x8e +#define AML_OBJECT_TYPE_OP (u16) 0x8e #define AML_CREATE_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */ #define AML_LAND_OP (u16) 0x90 #define AML_LOR_OP (u16) 0x91 diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index bcdf43c..efe7ac3 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -686,7 +686,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) status = acpi_ex_store(return_desc, operand[0], walk_state); break; - case AML_TYPE_OP: /* object_type (source_object) */ + case AML_OBJECT_TYPE_OP: /* object_type (source_object) */ /* * Note: The operand is not resolved at this point because we want to * get the associated object, not its value. For example, we don't diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index c3005bd..40909dd 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -380,7 +380,7 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE), -/* 37 */ ACPI_OP("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP, +/* 37 */ ACPI_OP("ObjectType", ARGP_OBJECT_TYPE_OP, ARGI_OBJECT_TYPE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), -- cgit v0.10.2 From 3c5d3d2543b1c541b601af27998175c3ea8bb617 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:01:46 +0800 Subject: ACPICA: Update for CondRefOf and RefOf operators ACPICA commit 725c094f1a7a2ae28e623ee77be400af1c36b180 The SuperName parameters for these operators were incorrect. This represents two problems in the ACPI specification itself. Link: https://github.com/acpica/acpica/commit/725c094f Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index c6b2f42..324512d 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -92,7 +92,7 @@ #define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) +#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_NAME_OR_REF,ARGP_TARGET) #define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONTINUE_OP ARG_NONE #define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) @@ -159,7 +159,7 @@ #define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) #define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) #define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) -#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_NAME_OR_REF) #define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -- cgit v0.10.2 From 7b73806485ada16059ecc1851793dbe865181c53 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:01:53 +0800 Subject: ACPICA: Cleanup code related to the per-table module level improvement ACPICA commit 071eff738c59eda1792ac24b3b688b61691d7e7c This patch collects cleanups from per-table module level improvement. By splitting this patch from that commit, we can make per-table module level improvement clearer for the revewers. This is a no-op change. Link: https://github.com/acpica/acpica/commit/071eff73 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 3977134..ef0abf4 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -145,6 +145,7 @@ ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_operand_cache); ACPI_INIT_GLOBAL(u32, acpi_gbl_startup_flags, 0); ACPI_INIT_GLOBAL(u8, acpi_gbl_shutdown, TRUE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_early_initialization, TRUE); /* Global handlers */ diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 74e8595f..5d6a3b5 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -55,6 +55,10 @@ static acpi_status acpi_ev_install_handler(acpi_handle obj_handle, u32 level, void *context, void **return_value); +static union acpi_operand_object + *acpi_ev_find_region_handler(acpi_adr_space_type space_id, + union acpi_operand_object *handler_obj); + /* These are the address spaces that will get default handlers */ u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { @@ -309,6 +313,43 @@ acpi_ev_install_handler(acpi_handle obj_handle, /******************************************************************************* * + * FUNCTION: acpi_ev_find_region_handler + * + * PARAMETERS: space_id - The address space ID + * handler_obj - Head of the handler object list + * + * RETURN: Matching handler object. NULL if space ID not matched + * + * DESCRIPTION: Search a handler object list for a match on the address + * space ID. + * + ******************************************************************************/ + +static union acpi_operand_object + *acpi_ev_find_region_handler(acpi_adr_space_type space_id, + union acpi_operand_object *handler_obj) +{ + + /* Walk the handler list for this device */ + + while (handler_obj) { + + /* Same space_id indicates a handler is installed */ + + if (handler_obj->address_space.space_id == space_id) { + return (handler_obj); + } + + /* Next handler object */ + + handler_obj = handler_obj->address_space.next; + } + + return (NULL); +} + +/******************************************************************************* + * * FUNCTION: acpi_ev_install_space_handler * * PARAMETERS: node - Namespace node for the device @@ -332,15 +373,15 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; - acpi_status status; + acpi_status status = AE_OK; acpi_object_type type; u8 flags = 0; ACPI_FUNCTION_TRACE(ev_install_space_handler); /* - * This registration is valid for only the types below and the root. This - * is where the default handlers get placed. + * This registration is valid for only the types below and the root. + * The root node is where the default handlers get installed. */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_PROCESSOR) && @@ -407,38 +448,29 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* - * The attached device object already exists. Make sure the handler - * is not already installed. + * The attached device object already exists. Now make sure + * the handler is not already installed. */ - handler_obj = obj_desc->device.handler; - - /* Walk the handler list for this device */ - - while (handler_obj) { + handler_obj = acpi_ev_find_region_handler(space_id, + obj_desc->device. + handler); - /* Same space_id indicates a handler already installed */ - - if (handler_obj->address_space.space_id == space_id) { - if (handler_obj->address_space.handler == - handler) { - /* - * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen with the - * PCI_Config space. - */ - status = AE_SAME_HANDLER; - goto unlock_and_exit; - } else { - /* A handler is already installed */ - - status = AE_ALREADY_EXISTS; - } + if (handler_obj) { + if (handler_obj->address_space.handler == handler) { + /* + * It is (relatively) OK to attempt to install the SAME + * handler twice. This can easily happen with the + * PCI_Config space. + */ + status = AE_SAME_HANDLER; goto unlock_and_exit; - } + } else { + /* A handler is already installed */ - /* Walk the linked list of handlers */ + status = AE_ALREADY_EXISTS; + } - handler_obj = handler_obj->address_space.next; + goto unlock_and_exit; } } else { ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, @@ -477,7 +509,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, } ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", + "Installing address handler for region %s(%X) " + "on Device %4.4s %p(%p)\n", acpi_ut_get_region_name(space_id), space_id, acpi_ut_get_node_name(node), node, obj_desc)); @@ -515,19 +548,17 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, obj_desc->device.handler = handler_obj; /* - * Walk the namespace finding all of the regions this - * handler will manage. + * Walk the namespace finding all of the regions this handler will + * manage. * - * Start at the device and search the branch toward - * the leaf nodes until either the leaf is encountered or - * a device is detected that has an address handler of the - * same type. + * Start at the device and search the branch toward the leaf nodes + * until either the leaf is encountered or a device is detected that + * has an address handler of the same type. * - * In either case, back up and search down the remainder - * of the branch + * In either case, back up and search down the remainder of the branch */ - status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, + status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, NULL, handler_obj, NULL); diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 5ee79a1..6717e57 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -127,6 +127,12 @@ acpi_status acpi_ev_initialize_op_regions(void) * DESCRIPTION: Dispatch an address space or operation region access to * a previously installed handler. * + * NOTE: During early initialization, we always install the default region + * handlers for Memory, I/O and PCI_Config. This ensures that these operation + * region address spaces are always available as per the ACPI specification. + * This is especially needed in order to support the execution of + * module-level AML code during loading of the ACPI tables. + * ******************************************************************************/ acpi_status diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index da32339..6181f5a 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -552,7 +552,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, /* * The following loop depends upon the root Node having no parent - * ie: acpi_gbl_root_node->parent_entry being set to NULL + * ie: acpi_gbl_root_node->Parent being set to NULL */ while (node) { diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index d836f88..ff976c4 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -508,7 +508,8 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, if (next) { acpi_os_printf("(%s %2.2X)", acpi_ut_get_object_type_name - (next), next->common.type); + (next), + next->address_space.space_id); while (next->address_space.next) { if ((next->common.type == @@ -520,7 +521,8 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, acpi_os_printf("->%p(%s %2.2X)", next, acpi_ut_get_object_type_name (next), - next->common.type); + next->address_space. + space_id); if ((next == start) || (next == data)) { acpi_os_printf diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index a7137ec..8586260 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -147,6 +147,13 @@ acpi_status __init acpi_enable_subsystem(u32 flags) ACPI_FUNCTION_TRACE(acpi_enable_subsystem); + /* + * The early initialization phase is complete. The namespace is loaded, + * and we can now support address spaces other than Memory, I/O, and + * PCI_Config. + */ + acpi_gbl_early_initialization = FALSE; + #if (!ACPI_REDUCED_HARDWARE) /* Enable ACPI mode */ -- cgit v0.10.2 From f31a99cefd05f798eee8b592e22175ff3fe1876b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:02:00 +0800 Subject: ACPICA: Events: Deploys acpi_ev_find_region_handler() ACPICA commit b916a0a0ae9e81db1a85523c63ec6aa32d5c70c8 There are code fragments that can be substituted by acpi_ev_find_region_handler(). This patch cleans up these code fragments. Lv Zheng. Link: https://github.com/acpica/acpica/commit/b916a0a0 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 228704b7..42975ab 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -161,6 +161,11 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* * evhandler - Address space handling */ +union acpi_operand_object *acpi_ev_find_region_handler(acpi_adr_space_type + space_id, + union acpi_operand_object + *handler_obj); + u8 acpi_ev_has_default_handler(struct acpi_namespace_node *node, acpi_adr_space_type space_id); diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index 390a7ca..a66b4ae 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -48,6 +48,7 @@ #include "acnamesp.h" #include "acparser.h" #include "acinterp.h" +#include "acevents.h" #include "acdebug.h" #define _COMPONENT ACPI_CA_DEBUGGER @@ -949,28 +950,25 @@ void acpi_db_display_handlers(void) if (obj_desc) { for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_space_id_list); i++) { space_id = acpi_gbl_space_id_list[i]; - handler_obj = obj_desc->device.handler; acpi_os_printf(ACPI_PREDEFINED_PREFIX, acpi_ut_get_region_name((u8)space_id), space_id); - while (handler_obj) { - if (acpi_gbl_space_id_list[i] == - handler_obj->address_space.space_id) { - acpi_os_printf - (ACPI_HANDLER_PRESENT_STRING, - (handler_obj->address_space. - handler_flags & - ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) - ? "Default" : "User", - handler_obj->address_space. - handler); - - goto found_handler; - } + handler_obj = + acpi_ev_find_region_handler(space_id, + obj_desc->device. + handler); + if (handler_obj) { + acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, + (handler_obj->address_space. + handler_flags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) + ? "Default" : "User", + handler_obj->address_space. + handler); - handler_obj = handler_obj->address_space.next; + goto found_handler; } /* There is no handler for this space_id */ diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 5d6a3b5..6a7fc11 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -55,10 +55,6 @@ static acpi_status acpi_ev_install_handler(acpi_handle obj_handle, u32 level, void *context, void **return_value); -static union acpi_operand_object - *acpi_ev_find_region_handler(acpi_adr_space_type space_id, - union acpi_operand_object *handler_obj); - /* These are the address spaces that will get default handlers */ u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { @@ -251,35 +247,30 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* Check if this Device already has a handler for this address space */ - next_handler_obj = obj_desc->device.handler; - while (next_handler_obj) { + next_handler_obj = + acpi_ev_find_region_handler(handler_obj->address_space. + space_id, + obj_desc->device.handler); + if (next_handler_obj) { /* Found a handler, is it for the same address space? */ - if (next_handler_obj->address_space.space_id == - handler_obj->address_space.space_id) { - ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "Found handler for region [%s] in device %p(%p) " - "handler %p\n", - acpi_ut_get_region_name - (handler_obj->address_space. - space_id), obj_desc, - next_handler_obj, - handler_obj)); - - /* - * Since the object we found it on was a device, then it - * means that someone has already installed a handler for - * the branch of the namespace from this device on. Just - * bail out telling the walk routine to not traverse this - * branch. This preserves the scoping rule for handlers. - */ - return (AE_CTRL_DEPTH); - } - - /* Walk the linked list of handlers attached to this device */ - - next_handler_obj = next_handler_obj->address_space.next; + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, + "Found handler for region [%s] in device %p(%p) handler %p\n", + acpi_ut_get_region_name(handler_obj-> + address_space. + space_id), + obj_desc, next_handler_obj, + handler_obj)); + + /* + * Since the object we found it on was a device, then it means + * that someone has already installed a handler for the branch + * of the namespace from this device on. Just bail out telling + * the walk routine to not traverse this branch. This preserves + * the scoping rule for handlers. + */ + return (AE_CTRL_DEPTH); } /* @@ -325,9 +316,10 @@ acpi_ev_install_handler(acpi_handle obj_handle, * ******************************************************************************/ -static union acpi_operand_object - *acpi_ev_find_region_handler(acpi_adr_space_type space_id, - union acpi_operand_object *handler_obj) +union acpi_operand_object *acpi_ev_find_region_handler(acpi_adr_space_type + space_id, + union acpi_operand_object + *handler_obj) { /* Walk the handler list for this device */ diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 6181f5a..4df81b5 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -602,60 +602,49 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, break; } - while (handler_obj) { + handler_obj = + acpi_ev_find_region_handler(space_id, handler_obj); + if (handler_obj) { - /* Is this handler of the correct type? */ + /* Found correct handler */ - if (handler_obj->address_space.space_id == - space_id) { + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, + "Found handler %p for region %p in obj %p\n", + handler_obj, region_obj, + obj_desc)); - /* Found correct handler */ - - ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "Found handler %p for region %p in obj %p\n", - handler_obj, + status = + acpi_ev_attach_region(handler_obj, region_obj, - obj_desc)); + acpi_ns_locked); + /* + * Tell all users that this region is usable by + * running the _REG method + */ + if (acpi_ns_locked) { status = - acpi_ev_attach_region(handler_obj, - region_obj, - acpi_ns_locked); - - /* - * Tell all users that this region is usable by - * running the _REG method - */ - if (acpi_ns_locked) { - status = - acpi_ut_release_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS - (status); - } + acpi_ut_release_mutex + (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } + } + status = + acpi_ev_execute_reg_method(region_obj, + ACPI_REG_CONNECT); + + if (acpi_ns_locked) { status = - acpi_ev_execute_reg_method - (region_obj, ACPI_REG_CONNECT); - - if (acpi_ns_locked) { - status = - acpi_ut_acquire_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS - (status); - } + acpi_ut_acquire_mutex + (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } - - return_ACPI_STATUS(AE_OK); } - /* Try next handler in the list */ - - handler_obj = handler_obj->address_space.next; + return_ACPI_STATUS(AE_OK); } } -- cgit v0.10.2 From aa6abd2be1cc7fa2593c8377f78420dec0a5d7a5 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:02:08 +0800 Subject: ACPICA: Events: Uses common_notify for address space handlers ACPICA commit 5ea0fb75fdf1aa7c0aba067dfa4d5dc3a9279461 The address space handlers can be attached to not only Device but also Processor/thermal_zone objects, so it is better to use their common class 'CommonNotify' instead. Lv Zheng. Link: https://github.com/acpica/acpica/commit/5ea0fb75 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index a66b4ae..1965b48 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -957,7 +957,7 @@ void acpi_db_display_handlers(void) handler_obj = acpi_ev_find_region_handler(space_id, - obj_desc->device. + obj_desc->common_notify. handler); if (handler_obj) { acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, @@ -980,7 +980,7 @@ found_handler: ; /* Find all handlers for user-defined space_IDs */ - handler_obj = obj_desc->device.handler; + handler_obj = obj_desc->common_notify.handler; while (handler_obj) { if (handler_obj->address_space.space_id >= ACPI_USER_REGION_BEGIN) { @@ -1082,7 +1082,7 @@ acpi_db_display_non_root_handlers(acpi_handle obj_handle, /* Display all handlers associated with this device */ - handler_obj = obj_desc->device.handler; + handler_obj = obj_desc->common_notify.handler; while (handler_obj) { acpi_os_printf(ACPI_PREDEFINED_PREFIX, acpi_ut_get_region_name((u8)handler_obj-> diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 6a7fc11..709419c7 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -159,7 +159,7 @@ acpi_ev_has_default_handler(struct acpi_namespace_node *node, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { - handler_obj = obj_desc->device.handler; + handler_obj = obj_desc->common_notify.handler; /* Walk the linked list of handlers for this object */ @@ -250,7 +250,8 @@ acpi_ev_install_handler(acpi_handle obj_handle, next_handler_obj = acpi_ev_find_region_handler(handler_obj->address_space. space_id, - obj_desc->device.handler); + obj_desc->common_notify. + handler); if (next_handler_obj) { /* Found a handler, is it for the same address space? */ @@ -444,7 +445,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, * the handler is not already installed. */ handler_obj = acpi_ev_find_region_handler(space_id, - obj_desc->device. + obj_desc-> + common_notify. handler); if (handler_obj) { @@ -531,13 +533,13 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, /* Install at head of Device.address_space list */ - handler_obj->address_space.next = obj_desc->device.handler; + handler_obj->address_space.next = obj_desc->common_notify.handler; /* * The Device object is the first reference on the handler_obj. * Each region that uses the handler adds a reference. */ - obj_desc->device.handler = handler_obj; + obj_desc->common_notify.handler = handler_obj; /* * Walk the namespace finding all of the regions this handler will diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 4df81b5..024689d 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -566,18 +566,10 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, switch (node->type) { case ACPI_TYPE_DEVICE: - - handler_obj = obj_desc->device.handler; - break; - case ACPI_TYPE_PROCESSOR: - - handler_obj = obj_desc->processor.handler; - break; - case ACPI_TYPE_THERMAL: - handler_obj = obj_desc->thermal_zone.handler; + handler_obj = obj_desc->common_notify.handler; break; case ACPI_TYPE_METHOD: diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index dbd9f16..3c90508 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -216,8 +216,8 @@ acpi_remove_address_space_handler(acpi_handle device, /* Find the address handler the user requested */ - handler_obj = obj_desc->device.handler; - last_obj_ptr = &obj_desc->device.handler; + handler_obj = obj_desc->common_notify.handler; + last_obj_ptr = &obj_desc->common_notify.handler; while (handler_obj) { /* We have a handler, see if user requested this one */ -- cgit v0.10.2 From 2e1beaf6a91998ad82e11a4c5a7b55b59396983b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:02:18 +0800 Subject: ACPICA: Utilities: Reorder initialization code ACPICA commit 3894fa9d071343e6ebc7ea480255fa4f27a290be This patch re-orders initialization code in acpi_enable_subsystem() so that all hardware reduced stuffs can be collected together. Note this patch contains code from the following 2 ACPICA upstream commits so that the changes can be made clearer for the reviewers: https://github.com/acpica/acpica/commit/071eff73 https://github.com/acpica/acpica/commit/3894fa9d And additional change to remove the global variable and unused code fragments due to the test result. Lv Zheng. Link: https://github.com/acpica/acpica/commit/3894fa9d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 8586260..7d8eb60 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -154,6 +154,21 @@ acpi_status __init acpi_enable_subsystem(u32 flags) */ acpi_gbl_early_initialization = FALSE; + /* + * Install the default operation region handlers. These are the + * handlers that are defined by the ACPI specification to be + * "always accessible" -- namely, system_memory, system_IO, and + * PCI_Config. This also means that no _REG methods need to be + * run for these address spaces. We need to have these handlers + * installed before any AML code can be executed, especially any + * module-level code (11/2015). + */ + status = acpi_ev_install_region_handlers(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "During Region initialization")); + return_ACPI_STATUS(status); + } #if (!ACPI_REDUCED_HARDWARE) /* Enable ACPI mode */ @@ -182,24 +197,8 @@ acpi_status __init acpi_enable_subsystem(u32 flags) return_ACPI_STATUS(status); } } -#endif /* !ACPI_REDUCED_HARDWARE */ /* - * Install the default op_region handlers. These are installed unless - * other handlers have already been installed via the - * install_address_space_handler interface. - */ - if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "[Init] Installing default address space handlers\n")); - - status = acpi_ev_install_region_handlers(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } -#if (!ACPI_REDUCED_HARDWARE) - /* * Initialize ACPI Event handling (Fixed and General Purpose) * * Note1: We must have the hardware and events initialized before we can -- cgit v0.10.2 From 1d65d9a7b642b8d1eb201830e0c1cae6231b5c51 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:02:50 +0800 Subject: ACPICA: Events: Fix an issue that region object is re-attached to another scope when it is already attached ACPICA commit 6ebcb24d3225b6c7715a3ce061c327b4c3a6b76e The logic in acpi_ev_attach_region() is not correct, it can break address space handler link. This patch fixes this problem. But be aware that this fix must be applied along with a region object race issue fix. Lv Zheng. Link: https://github.com/acpica/acpica/commit/6ebcb24d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 6717e57..19a4e69 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -504,6 +504,12 @@ acpi_ev_attach_region(union acpi_operand_object *handler_obj, ACPI_FUNCTION_TRACE(ev_attach_region); + /* Install the region's handler */ + + if (region_obj->region.handler) { + return_ACPI_STATUS(AE_ALREADY_EXISTS); + } + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Adding Region [%4.4s] %p to address handler %p [%s]\n", acpi_ut_get_node_name(region_obj->region.node), @@ -515,13 +521,6 @@ acpi_ev_attach_region(union acpi_operand_object *handler_obj, region_obj->region.next = handler_obj->address_space.region_list; handler_obj->address_space.region_list = region_obj; - - /* Install the region's handler */ - - if (region_obj->region.handler) { - return_ACPI_STATUS(AE_ALREADY_EXISTS); - } - region_obj->region.handler = handler_obj; acpi_ut_add_reference(handler_obj); -- cgit v0.10.2 From 849c25719ac6acc7420515c7b6324f4248a13790 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:02:58 +0800 Subject: ACPICA: Events: Split acpi_ev_associate_reg_method() from region initialization code ACPICA commit 87c85610250ff7141a84507f68dbc1e00f2936db This patch introduces a new region initialization function acpi_ev_associate_reg_method(), which is invoked to associate the _REG method to its related region object. Region object's default value assignments are also sorted by cleaning up the code using this new function. Lv Zheng. Link: https://github.com/acpica/acpica/commit/87c85610 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 42975ab..772ee3c 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -198,6 +198,8 @@ void acpi_ev_detach_region(union acpi_operand_object *region_obj, u8 acpi_ns_is_locked); +void acpi_ev_associate_reg_method(union acpi_operand_object *region_obj); + acpi_status acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, acpi_adr_space_type space_id); diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 19a4e69..432b810 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -529,6 +529,52 @@ acpi_ev_attach_region(union acpi_operand_object *handler_obj, /******************************************************************************* * + * FUNCTION: acpi_ev_associate_reg_method + * + * PARAMETERS: region_obj - Region object + * + * RETURN: Status + * + * DESCRIPTION: Find and associate _REG method to a region + * + ******************************************************************************/ + +void acpi_ev_associate_reg_method(union acpi_operand_object *region_obj) +{ + acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; + struct acpi_namespace_node *method_node; + struct acpi_namespace_node *node; + union acpi_operand_object *region_obj2; + acpi_status status; + + ACPI_FUNCTION_TRACE(ev_associate_reg_method); + + region_obj2 = acpi_ns_get_secondary_object(region_obj); + if (!region_obj2) { + return_VOID; + } + + node = region_obj->region.node->parent; + + /* Find any "_REG" method associated with this region definition */ + + status = + acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, + &method_node); + if (ACPI_SUCCESS(status)) { + /* + * The _REG method is optional and there can be only one per region + * definition. This will be executed when the handler is attached + * or removed + */ + region_obj2->extra.method_REG = method_node; + } + + return_VOID; +} + +/******************************************************************************* + * * FUNCTION: acpi_ev_execute_reg_method * * PARAMETERS: region_obj - Region object diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 024689d..bb2e529 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -507,9 +507,6 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, acpi_adr_space_type space_id; struct acpi_namespace_node *node; acpi_status status; - struct acpi_namespace_node *method_node; - acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; - union acpi_operand_object *region_obj2; ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); @@ -521,35 +518,12 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, return_ACPI_STATUS(AE_OK); } - region_obj2 = acpi_ns_get_secondary_object(region_obj); - if (!region_obj2) { - return_ACPI_STATUS(AE_NOT_EXIST); - } + acpi_ev_associate_reg_method(region_obj); + region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; node = region_obj->region.node->parent; space_id = region_obj->region.space_id; - /* Setup defaults */ - - region_obj->region.handler = NULL; - region_obj2->extra.method_REG = NULL; - region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); - region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; - - /* Find any "_REG" method associated with this region definition */ - - status = - acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, - &method_node); - if (ACPI_SUCCESS(status)) { - /* - * The _REG method is optional and there can be only one per region - * definition. This will be executed when the handler is attached - * or removed - */ - region_obj2->extra.method_REG = method_node; - } - /* * The following loop depends upon the root Node having no parent * ie: acpi_gbl_root_node->Parent being set to NULL diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 0f34446..6a1396e 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -326,9 +326,10 @@ acpi_ex_create_region(u8 * aml_start, * Remember location in AML stream of address & length * operands since they need to be evaluated at run time. */ - region_obj2 = obj_desc->common.next_object; + region_obj2 = acpi_ns_get_secondary_object(obj_desc); region_obj2->extra.aml_start = aml_start; region_obj2->extra.aml_length = aml_length; + region_obj2->extra.method_REG = NULL; if (walk_state->scope_info) { region_obj2->extra.scope_node = walk_state->scope_info->scope.node; @@ -342,6 +343,9 @@ acpi_ex_create_region(u8 * aml_start, obj_desc->region.address = 0; obj_desc->region.length = 0; obj_desc->region.node = node; + obj_desc->region.handler = NULL; + obj_desc->common.flags &= + ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_OBJECT_INITIALIZED); /* Install the new region object in the parent Node */ -- cgit v0.10.2 From efaed9be998b5ae0afb7458e057e5f4402b43fa0 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:03:08 +0800 Subject: ACPICA: Events: Enhance acpi_ev_execute_reg_method() to ensure no _REG evaluations can happen during OS early boot stages ACPICA commit 31178590dde82368fdb0f6b0e466b6c0add96c57 We can ensure no early _REG evaluations by ensuring the following rules in acpi_ev_execute_reg_method(): 1. If an address space handler is installed during early stage, _REG(CONNECT) evaluations are blocked. This is achieved using acpi_gbl_reg_methods_enabled which is renamed from acpi_gbl_reg_methods_executed. 2. If _REG(CONNECT) has never been evalauted for the region object, _REG(DISCONNECT) evaluations are blocked. This is achieved by a new region object flag: AOPOBJ_REG_CONNECTED. Note that, after applying this patch, we can ensure _REG(DISCONNECT) is always paired to _REG(CONNECT). Lv Zheng Link: https://github.com/acpica/acpica/commit/31178590 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index ef0abf4..73462ca 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -165,7 +165,7 @@ ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset); /* Initialization sequencing */ -ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed); +ACPI_INIT_GLOBAL(u8, acpi_gbl_reg_methods_enabled, FALSE); /* Misc */ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 0bd02c4..2b154cf 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -93,9 +93,10 @@ #define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */ #define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */ #define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */ -#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */ -#define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */ -#define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */ +#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized */ +#define AOPOBJ_REG_CONNECTED 0x10 /* _REG was run */ +#define AOPOBJ_SETUP_COMPLETE 0x20 /* Region setup is complete */ +#define AOPOBJ_INVALID 0x40 /* Host OS won't allow a Region address */ /****************************************************************************** * diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 432b810..cf6e878 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -104,8 +104,6 @@ acpi_status acpi_ev_initialize_op_regions(void) } } - acpi_gbl_reg_methods_executed = TRUE; - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); } @@ -601,7 +599,18 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) return_ACPI_STATUS(AE_NOT_EXIST); } - if (region_obj2->extra.method_REG == NULL) { + if (region_obj2->extra.method_REG == NULL || + region_obj->region.handler == NULL || + !acpi_gbl_reg_methods_enabled) { + return_ACPI_STATUS(AE_OK); + } + + /* _REG(DISCONNECT) should be paired with _REG(CONNECT) */ + + if ((function == ACPI_REG_CONNECT && + region_obj->common.flags & AOPOBJ_REG_CONNECTED) || + (function == ACPI_REG_DISCONNECT && + !(region_obj->common.flags & AOPOBJ_REG_CONNECTED))) { return_ACPI_STATUS(AE_OK); } @@ -650,6 +659,16 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) status = acpi_ns_evaluate(info); acpi_ut_remove_reference(args[1]); + if (ACPI_FAILURE(status)) { + goto cleanup2; + } + + if (function == ACPI_REG_CONNECT) { + region_obj->common.flags |= AOPOBJ_REG_CONNECTED; + } else { + region_obj->common.flags &= ~AOPOBJ_REG_CONNECTED; + } + cleanup2: acpi_ut_remove_reference(args[0]); diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 3c90508..29f9f39 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -112,39 +112,6 @@ acpi_install_address_space_handler(acpi_handle device, goto unlock_and_exit; } - /* - * For the default space_IDs, (the IDs for which there are default region handlers - * installed) Only execute the _REG methods if the global initialization _REG - * methods have already been run (via acpi_initialize_objects). In other words, - * we will defer the execution of the _REG methods for these space_IDs until - * execution of acpi_initialize_objects. This is done because we need the handlers - * for the default spaces (mem/io/pci/table) to be installed before we can run - * any control methods (or _REG methods). There is known BIOS code that depends - * on this. - * - * For all other space_IDs, we can safely execute the _REG methods immediately. - * This means that for IDs like embedded_controller, this function should be called - * only after acpi_enable_subsystem has been called. - */ - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_DATA_TABLE: - - if (!acpi_gbl_reg_methods_executed) { - - /* We will defer execution of the _REG methods for this space */ - - goto unlock_and_exit; - } - break; - - default: - - break; - } - /* Run all _REG methods for this address space */ status = acpi_ev_execute_reg_methods(node, space_id); diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 6a1396e..46be5a2 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -345,7 +345,8 @@ acpi_ex_create_region(u8 * aml_start, obj_desc->region.node = node; obj_desc->region.handler = NULL; obj_desc->common.flags &= - ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_OBJECT_INITIALIZED); + ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_REG_CONNECTED | + AOPOBJ_OBJECT_INITIALIZED); /* Install the new region object in the parent Node */ diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index ccd0745..fd82a12 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -206,7 +206,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_next_owner_id_offset = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_osi_mutex = NULL; - acpi_gbl_reg_methods_executed = FALSE; acpi_gbl_max_loop_iterations = 0xFFFF; /* Hardware oriented */ diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 7d8eb60..1c7ed49 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -267,6 +267,7 @@ acpi_status __init acpi_initialize_objects(u32 flags) * initialized, even if they contain executable AML (see the call to * acpi_ns_initialize_objects below). */ + acpi_gbl_reg_methods_enabled = TRUE; if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[Init] Executing _REG OpRegion methods\n")); -- cgit v0.10.2 From d815346f7675e056d904fb3aad5a347e0bb58410 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 29 Dec 2015 14:03:43 +0800 Subject: ACPICA: Events: Introduce ACPI_REG_DISCONNECT invocation to acpi_ev_execute_reg_methods() ACPICA commit 1cf1a1e090f61f0c27f1dcf1905c7cc79a9c51c8 It is likely that we should synchronously invoke _REG(DISCONNECT) only when the acpi_remove_address_space_handler() is invoked because of dependencies. If it is invoked when the object is not referenced, problem may occur if the operation region fields accessed in _REG are no longer driven by any device driver. Noticed that _REG(CONNECT)/_REG(DISCONNECT) only mean to inform the AML of the handler availability, no return value is required for the caller. This patch only introduces ACPI_REG_DISCONNECT invaocation, but doesn't introduce a real change. Lv Zheng. Link: https://github.com/acpica/acpica/commit/1cf1a1e0 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 772ee3c..d18f184 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -200,9 +200,9 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, void acpi_ev_associate_reg_method(union acpi_operand_object *region_obj); -acpi_status +void acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, - acpi_adr_space_type space_id); + acpi_adr_space_type space_id, u32 function); acpi_status acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 034402d..24928ec 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -428,6 +428,7 @@ struct acpi_simple_repair_info { struct acpi_reg_walk_info { acpi_adr_space_type space_id; + u32 function; u32 reg_run_count; }; diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index cf6e878..a43178f 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -97,10 +97,9 @@ acpi_status acpi_ev_initialize_op_regions(void) if (acpi_ev_has_default_handler(acpi_gbl_root_node, acpi_gbl_default_address_spaces [i])) { - status = - acpi_ev_execute_reg_methods(acpi_gbl_root_node, - acpi_gbl_default_address_spaces - [i]); + acpi_ev_execute_reg_methods(acpi_gbl_root_node, + acpi_gbl_default_address_spaces + [i], ACPI_REG_CONNECT); } } @@ -683,24 +682,25 @@ cleanup1: * * PARAMETERS: node - Namespace node for the device * space_id - The address space ID + * function - Passed to _REG: On (1) or Off (0) * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Run all _REG methods for the input Space ID; * Note: assumes namespace is locked, or system init time. * ******************************************************************************/ -acpi_status +void acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, - acpi_adr_space_type space_id) + acpi_adr_space_type space_id, u32 function) { - acpi_status status; struct acpi_reg_walk_info info; ACPI_FUNCTION_TRACE(ev_execute_reg_methods); info.space_id = space_id; + info.function = function; info.reg_run_count = 0; ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, @@ -713,9 +713,9 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, * regions and _REG methods. (i.e. handlers must be installed for all * regions of this Space ID before we can run any _REG methods) */ - status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, - NULL, &info, NULL); + (void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL, + &info, NULL); /* Special case for EC: handle "orphan" _REG methods with no region */ @@ -728,7 +728,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, info.reg_run_count, acpi_ut_get_region_name(info.space_id))); - return_ACPI_STATUS(status); + return_VOID; } /******************************************************************************* @@ -787,7 +787,7 @@ acpi_ev_reg_run(acpi_handle obj_handle, } info->reg_run_count++; - status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT); + status = acpi_ev_execute_reg_method(obj_desc, info->function); return (status); } diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 29f9f39..35f9e60 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -114,7 +114,7 @@ acpi_install_address_space_handler(acpi_handle device, /* Run all _REG methods for this address space */ - status = acpi_ev_execute_reg_methods(node, space_id); + acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); -- cgit v0.10.2 From 2247235379d9e9fa46f725a82e0c05ae96254007 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:04:11 +0800 Subject: ACPICA: Add "root node" case to the ACPI name repair code ACPICA commit 95b40b31aa8148629fbe5de0356725fc01298003 Special-case the namespace root node, it has an unusual name. This case can occur if there are errors during the execution of module-level code. Link: https://github.com/acpica/acpica/commit/95b40b31 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 0c2e2d2..958b2f7 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -240,6 +240,14 @@ void acpi_ut_repair_name(char *name) ACPI_FUNCTION_NAME(ut_repair_name); + /* + * Special case for the root node. This can happen if we get an + * error during the execution of module-level code. + */ + if (ACPI_COMPARE_NAME(name, "\\___")) { + return; + } + ACPI_MOVE_NAME(&original_name, name); /* Check each character in the name */ -- cgit v0.10.2 From 2785ce8d0da1cac9d8f78615e116cf929e9a9123 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:04:19 +0800 Subject: ACPICA: Add per-table execution of module-level code ACPICA commit 071eff738c59eda1792ac24b3b688b61691d7e7c Execute any module-level code after each ACPI table (DSDT or SSDT) is loaded into the namespace (rather than after all AML tables have been loaded). This matches the behavior of other ACPI implementations and is required to support BIOS code that depends on this behavior. Link: https://github.com/acpica/acpica/commit/071eff73 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index c106916..14c953e 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -149,6 +149,23 @@ unlock: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Object Initialization\n")); + /* + * Execute any module-level code that was detected during the table load + * phase. Although illegal since ACPI 2.0, there are many machines that + * contain this type of code. Each block of detected executable AML code + * outside of any control method is wrapped with a temporary control + * method object and placed on a global list. The methods on this list + * are executed below. + * + * This case executes the module-level code for each table immediately + * after the table has been loaded. This provides compatibility with + * other ACPI implementations. Optionally, the execution can be deferred + * until later, see acpi_initialize_objects. + */ + if (!acpi_gbl_group_module_level_code) { + acpi_ns_exec_module_code_list(); + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 1c7ed49..e38facd 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -292,8 +292,14 @@ acpi_status __init acpi_initialize_objects(u32 flags) * outside of any control method is wrapped with a temporary control * method object and placed on a global list. The methods on this list * are executed below. + * + * This case executes the module-level code for all tables only after + * all of the tables have been loaded. It is a legacy option and is + * not compatible with other ACPI implementations. See acpi_ns_load_table. */ - acpi_ns_exec_module_code_list(); + if (acpi_gbl_group_module_level_code) { + acpi_ns_exec_module_code_list(); + } /* * Initialize the objects that remain uninitialized. This runs the diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index d60507b7..8c95e82 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -190,6 +190,11 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); /* + * Optionally support group module level code. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_group_module_level_code, TRUE); + +/* * 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 -- cgit v0.10.2 From 6b0e2b32871b7c10c75d647b0295a092f918f3e7 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 29 Dec 2015 14:04:28 +0800 Subject: ACPICA: Update version to 20151218 ACPICA commit e81cedadd3a847d40f30bc9c52dfe441620ed12f Version 20151218. Link: https://github.com/acpica/acpica/commit/e81cedad Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 8c95e82..1b462d8 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20150930 +#define ACPI_CA_VERSION 0x20151218 #include #include -- cgit v0.10.2 From 41669da03060c5e55e9d3061ddede624f01d7262 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 27 Dec 2015 00:23:48 +0100 Subject: cpufreq: Make cpufreq_boost_supported() static cpufreq_boost_supported() is not used outside of cpufreq.c, so make it static. While at it, refactor it as a one-liner (which it really is). Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8412ce5..49f3f58 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2330,14 +2330,10 @@ int cpufreq_boost_trigger_state(int state) return ret; } -int cpufreq_boost_supported(void) +static bool cpufreq_boost_supported(void) { - if (likely(cpufreq_driver)) - return cpufreq_driver->boost_supported; - - return 0; + return likely(cpufreq_driver) && cpufreq_driver->boost_supported; } -EXPORT_SYMBOL_GPL(cpufreq_boost_supported); static int create_boost_sysfs_file(void) { diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 177c768..f859b72 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -574,7 +574,6 @@ 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); int cpufreq_enable_boost_support(void); bool policy_has_boost_freq(struct cpufreq_policy *policy); @@ -583,10 +582,6 @@ 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; -- cgit v0.10.2 From 17135782b816383b426d280c350467b23ef9c10c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 27 Dec 2015 00:25:35 +0100 Subject: cpufreq: acpi-cpufreq: Simplify boost-related code The store_boost() routine is only used by store_cpb(), so move the code from it directly to that function and rename _store_boost() to set_boost() to make its name reflect the name of the driver callback pointing to it. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index cec1ee2..12da54a 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -135,7 +135,7 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask) wrmsr_on_cpus(cpumask, msr_addr, msrs); } -static int _store_boost(int val) +static int set_boost(int val) { get_online_cpus(); boost_set_msrs(val, cpu_online_mask); @@ -158,29 +158,24 @@ 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) +static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, + size_t count) { int ret; - unsigned long val = 0; + unsigned int val = 0; if (!acpi_cpufreq_driver.boost_supported) return -EINVAL; - ret = kstrtoul(buf, 10, &val); - if (ret || (val > 1)) + ret = kstrtouint(buf, 10, &val); + if (ret || val > 1) return -EINVAL; - _store_boost((int) val); + set_boost(val); return count; } -static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, - size_t count) -{ - return store_boost(buf, count); -} - static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf) { return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled); @@ -905,7 +900,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .resume = acpi_cpufreq_resume, .name = "acpi-cpufreq", .attr = acpi_cpufreq_attr, - .set_boost = _store_boost, + .set_boost = set_boost, }; static void __init acpi_cpufreq_boost_init(void) -- cgit v0.10.2 From 7a6c79f2fe53dac9b7b290f3a4c56b0958e19201 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 27 Dec 2015 00:27:38 +0100 Subject: cpufreq: Simplify core code related to boost support Notice that the boost_supported field in struct cpufreq_driver is redundant, because the driver's ->set_boost callback may be left unset if "boost" is not supported. Moreover, the only driver populating the ->set_boost callback is acpi_cpufreq, so make it avoid populating that callback if "boost" is not supported, rework the core to check ->set_boost instead of boost_supported to verify "boost" support and drop boost_supported which isn't used any more. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 12da54a..51eef87 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -164,7 +164,7 @@ static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, int ret; unsigned int val = 0; - if (!acpi_cpufreq_driver.boost_supported) + if (!acpi_cpufreq_driver.set_boost) return -EINVAL; ret = kstrtouint(buf, 10, &val); @@ -900,7 +900,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .resume = acpi_cpufreq_resume, .name = "acpi-cpufreq", .attr = acpi_cpufreq_attr, - .set_boost = set_boost, }; static void __init acpi_cpufreq_boost_init(void) @@ -911,7 +910,7 @@ static void __init acpi_cpufreq_boost_init(void) if (!msrs) return; - acpi_cpufreq_driver.boost_supported = true; + acpi_cpufreq_driver.set_boost = set_boost; acpi_cpufreq_driver.boost_enabled = boost_state(0); cpu_notifier_register_begin(); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 49f3f58..c35e7da 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2332,23 +2332,13 @@ int cpufreq_boost_trigger_state(int state) static bool cpufreq_boost_supported(void) { - return likely(cpufreq_driver) && cpufreq_driver->boost_supported; + return likely(cpufreq_driver) && cpufreq_driver->set_boost; } static int create_boost_sysfs_file(void) { int ret; - if (!cpufreq_boost_supported()) - return 0; - - /* - * 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 = sysfs_create_file(cpufreq_global_kobject, &boost.attr); if (ret) pr_err("%s: cannot register global BOOST sysfs file\n", @@ -2371,7 +2361,7 @@ int cpufreq_enable_boost_support(void) if (cpufreq_boost_supported()) return 0; - cpufreq_driver->boost_supported = true; + cpufreq_driver->set_boost = cpufreq_boost_set_sw; /* This will get removed on driver unregister */ return create_boost_sysfs_file(); @@ -2431,9 +2421,11 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) if (driver_data->setpolicy) driver_data->flags |= CPUFREQ_CONST_LOOPS; - ret = create_boost_sysfs_file(); - if (ret) - goto err_null_driver; + if (cpufreq_boost_supported()) { + ret = create_boost_sysfs_file(); + if (ret) + goto err_null_driver; + } ret = subsys_interface_register(&cpufreq_interface); if (ret) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index f859b72..88a4215 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -278,7 +278,6 @@ struct cpufreq_driver { struct freq_attr **attr; /* platform specific boost support code */ - bool boost_supported; bool boost_enabled; int (*set_boost)(int state); }; -- cgit v0.10.2 From 600c395bf6c4e44ec831e850d7f93ce53d7373be Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 23 Dec 2015 22:59:55 +0100 Subject: powercap: constify powercap_zone_ops and powercap_zone_constraint_ops structures The powercap_zone_ops and powercap_zone_constraint_ops structures are never modified, so declare them as const. Most of the actual changes adjust indentation to accomodate the const keyword. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Rafael J. Wysocki diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 48747c2..fa8c8e8 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -388,7 +388,7 @@ static int get_domain_enable(struct powercap_zone *power_zone, bool *mode) } /* per RAPL domain ops, in the order of rapl_domain_type */ -static struct powercap_zone_ops zone_ops[] = { +static const struct powercap_zone_ops zone_ops[] = { /* RAPL_DOMAIN_PACKAGE */ { .get_energy_uj = get_energy_counter, @@ -584,7 +584,7 @@ static int get_max_power(struct powercap_zone *power_zone, int id, return ret; } -static struct powercap_zone_constraint_ops constraint_ops = { +static const struct powercap_zone_constraint_ops constraint_ops = { .set_power_limit_uw = set_power_limit, .get_power_limit_uw = get_current_power_limit, .set_time_window_us = set_time_window, diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 84419af..14bde0d 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -293,8 +293,8 @@ err_alloc: } static int create_constraints(struct powercap_zone *power_zone, - int nr_constraints, - struct powercap_zone_constraint_ops *const_ops) + int nr_constraints, + const struct powercap_zone_constraint_ops *const_ops) { int i; int ret = 0; @@ -492,13 +492,13 @@ static struct class powercap_class = { }; struct powercap_zone *powercap_register_zone( - struct powercap_zone *power_zone, - struct powercap_control_type *control_type, - const char *name, - struct powercap_zone *parent, - const struct powercap_zone_ops *ops, - int nr_constraints, - struct powercap_zone_constraint_ops *const_ops) + struct powercap_zone *power_zone, + struct powercap_control_type *control_type, + const char *name, + struct powercap_zone *parent, + const struct powercap_zone_ops *ops, + int nr_constraints, + const struct powercap_zone_constraint_ops *const_ops) { int result; int nr_attrs; diff --git a/include/linux/powercap.h b/include/linux/powercap.h index 4e25041..f0a4e62 100644 --- a/include/linux/powercap.h +++ b/include/linux/powercap.h @@ -208,7 +208,7 @@ struct powercap_zone_constraint_ops { struct powercap_zone_constraint { int id; struct powercap_zone *power_zone; - struct powercap_zone_constraint_ops *ops; + const struct powercap_zone_constraint_ops *ops; }; @@ -309,7 +309,7 @@ struct powercap_zone *powercap_register_zone( struct powercap_zone *parent, const struct powercap_zone_ops *ops, int nr_constraints, - struct powercap_zone_constraint_ops *const_ops); + const struct powercap_zone_constraint_ops *const_ops); /** * powercap_unregister_zone() - Unregister a zone device -- cgit v0.10.2 From 4295733eee4e69eda432d95765b7762dc6013271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 29 Dec 2015 11:03:21 +0100 Subject: PM / core: fix typo in documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation for detach() said attach. Signed-off-by: Manuel Pégourié-Gonnard Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index f32b802..f48e333 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -112,7 +112,7 @@ EXPORT_SYMBOL_GPL(dev_pm_domain_attach); /** * dev_pm_domain_detach - Detach a device from its PM domain. - * @dev: Device to attach. + * @dev: Device to detach. * @power_off: Used to indicate whether we should power off the device. * * This functions will reverse the actions from dev_pm_domain_attach() and thus -- cgit v0.10.2 From d9de19b1cc013433ad293365b5b3902ec73dfd60 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Mon, 28 Dec 2015 21:06:17 +0800 Subject: PM / OPP: Set cpu_dev->id in cpumask first Set cpu_dev->id in cpumask first when setting up cpumask for CPUs that share the same OPP table. This might be helpful when handling cpumask without the original CPU bitfield set. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index 7b445e8..9f0c155 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c @@ -214,7 +214,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table); /* * Works only for OPP v2 bindings. * - * cpumask should be already set to mask of cpu_dev->id. * Returns -ENOENT if operating-points-v2 bindings aren't supported. */ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) @@ -230,6 +229,8 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask return -ENOENT; } + cpumask_set_cpu(cpu_dev->id, cpumask); + /* OPPs are shared ? */ if (!of_property_read_bool(np, "opp-shared")) goto put_cpu_node; -- cgit v0.10.2 From a889331d759453fa7f424330f75ae4e2b9e02db4 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Sun, 27 Dec 2015 14:21:57 +0800 Subject: cpufreq: mt8173: migrate to use operating-points-v2 bindings Modify mt8173-cpufreq driver to get OPP-sharing information and set up OPP table provided by operating-points-v2 bindings. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index fd601b9..1efba34 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -390,7 +390,15 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) /* Both presence and absence of sram regulator are valid cases. */ sram_reg = regulator_get_exclusive(cpu_dev, "sram"); - ret = dev_pm_opp_of_add_table(cpu_dev); + /* Get OPP-sharing information from "operating-points-v2" bindings */ + ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus); + if (ret) { + pr_err("failed to get OPP-sharing information for cpu%d\n", + cpu); + goto out_free_resources; + } + + ret = dev_pm_opp_of_cpumask_add_table(&info->cpus); if (ret) { pr_warn("no OPP table for cpu%d\n", cpu); goto out_free_resources; @@ -421,13 +429,10 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) */ info->need_voltage_tracking = !IS_ERR(sram_reg); - /* CPUs in the same cluster share a clock and power domain. */ - cpumask_copy(&info->cpus, &cpu_topology[cpu].core_sibling); - return 0; out_free_opp_table: - dev_pm_opp_of_remove_table(cpu_dev); + dev_pm_opp_of_cpumask_remove_table(&info->cpus); out_free_resources: if (!IS_ERR(proc_reg)) @@ -453,7 +458,7 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) if (!IS_ERR(info->inter_clk)) clk_put(info->inter_clk); - dev_pm_opp_of_remove_table(info->cpu_dev); + dev_pm_opp_of_cpumask_remove_table(&info->cpus); } static int mtk_cpufreq_init(struct cpufreq_policy *policy) -- cgit v0.10.2 From 9d128ed17c672b1dffde4a328e9b3ee26d87a8f0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 2 Jan 2016 03:10:29 +0100 Subject: ACPI / OSL: Add kerneldoc comments to memory mapping functions Add kerneldoc comments to acpi_os_map_iomem() and acpi_os_unmap_iomem() and explain why the latter needs the __ref annotation in one of them (as suggested by Mathias Krause). Signed-off-by: Rafael J. Wysocki Acked-by: Mathias Krause diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 32d684a..d0ecf4ef 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -364,6 +364,19 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) iounmap(vaddr); } +/** + * acpi_os_map_iomem - Get a virtual address for a given physical address range. + * @phys: Start of the physical address range to map. + * @size: Size of the physical address range to map. + * + * Look up the given physical address range in the list of existing ACPI memory + * mappings. If found, get a reference to it and return a pointer to it (its + * virtual address). If not found, map it, add it to that list and return a + * pointer to it. + * + * During early init (when acpi_gbl_permanent_mmap has not been set yet) this + * routine simply calls __acpi_map_table() to get the job done. + */ void __iomem *__init_refok acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) { @@ -439,6 +452,20 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map) } } +/** + * acpi_os_unmap_iomem - Drop a memory mapping reference. + * @virt: Start of the address range to drop a reference to. + * @size: Size of the address range to drop a reference to. + * + * Look up the given virtual address range in the list of existing ACPI memory + * mappings, drop a reference to it and unmap it if there are no more active + * references to it. + * + * During early init (when acpi_gbl_permanent_mmap has not been set yet) this + * routine simply calls __acpi_unmap_table() to get the job done. Since + * __acpi_unmap_table() is an __init function, the __ref annotation is needed + * here. + */ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; -- cgit v0.10.2 From a77060f07ffc6ac978e280e738302f3e5572a99e Mon Sep 17 00:00:00 2001 From: Christophe Le Roy Date: Fri, 11 Dec 2015 09:13:42 +0100 Subject: PNP: Add Broadwell to Intel MCH size workaround Add device ID 0x1604 for Broadwell to commit cb171f7abb9a ("PNP: Work around BIOS defects in Intel MCH area reporting"). >From a Lenovo ThinkPad T550: system 00:01: [io 0x1800-0x189f] could not be reserved system 00:01: [io 0x0800-0x087f] has been reserved system 00:01: [io 0x0880-0x08ff] has been reserved system 00:01: [io 0x0900-0x097f] has been reserved system 00:01: [io 0x0980-0x09ff] has been reserved system 00:01: [io 0x0a00-0x0a7f] has been reserved system 00:01: [io 0x0a80-0x0aff] has been reserved system 00:01: [io 0x0b00-0x0b7f] has been reserved system 00:01: [io 0x0b80-0x0bff] has been reserved system 00:01: [io 0x15e0-0x15ef] has been reserved system 00:01: [io 0x1600-0x167f] has been reserved system 00:01: [io 0x1640-0x165f] has been reserved system 00:01: [mem 0xf8000000-0xfbffffff] could not be reserved system 00:01: [mem 0xfed1c000-0xfed1ffff] has been reserved system 00:01: [mem 0xfed10000-0xfed13fff] has been reserved system 00:01: [mem 0xfed18000-0xfed18fff] has been reserved system 00:01: [mem 0xfed19000-0xfed19fff] has been reserved system 00:01: [mem 0xfed45000-0xfed4bfff] has been reserved system 00:01: Plug and Play ACPI device, IDs PNP0c02 (active) [...] resource sanity check: requesting [mem 0xfed10000-0xfed15fff], which spans more than pnp 00:01 [mem 0xfed10000-0xfed13fff] ------------[ cut here ]------------ WARNING: CPU: 2 PID: 1 at /build/linux-CrHvZ_/linux-4.2.6/arch/x86/mm/ioremap.c:198 __ioremap_caller+0x2ee/0x360() Info: mapping multiple BARs. Your kernel is fine. Modules linked in: CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.2.0-1-amd64 #1 Debian 4.2.6-1 Hardware name: LENOVO 20CKCTO1WW/20CKCTO1WW, BIOS N11ET34W (1.10 ) 08/20/2015 0000000000000000 ffffffff817e6868 ffffffff8154e2f6 ffff8802241efbf8 ffffffff8106e5b1 ffffc90000e98000 0000000000006000 ffffc90000e98000 0000000000006000 0000000000000000 ffffffff8106e62a ffffffff817e68c8 Call Trace: [] ? dump_stack+0x40/0x50 [] ? warn_slowpath_common+0x81/0xb0 [] ? warn_slowpath_fmt+0x4a/0x50 [] ? iomem_map_sanity_check+0xb3/0xc0 [] ? __ioremap_caller+0x2ee/0x360 [] ? snb_uncore_imc_init_box+0x66/0x90 [] ? uncore_pci_probe+0xc8/0x1a0 [] ? local_pci_probe+0x3f/0xa0 [] ? pci_device_probe+0xc4/0x110 [] ? driver_probe_device+0x1ee/0x450 [] ? __driver_attach+0x7b/0x80 [] ? driver_probe_device+0x450/0x450 [] ? bus_for_each_dev+0x5a/0x90 [] ? bus_add_driver+0x1f1/0x290 [] ? uncore_cpu_setup+0xc/0xc [] ? driver_register+0x5f/0xe0 [] ? intel_uncore_init+0xcc/0x2b0 [] ? uncore_cpu_setup+0xc/0xc [] ? do_one_initcall+0xce/0x200 [] ? parse_args+0x140/0x4e0 [] ? kernel_init_freeable+0x162/0x1e8 [] ? rest_init+0x80/0x80 [] ? kernel_init+0xe/0xf0 [] ? ret_from_fork+0x3f/0x70 [] ? rest_init+0x80/0x80 ---[ end trace 472e7959536abf12 ]--- 00:00.0 Host bridge: Intel Corporation Broadwell-U Host Bridge -OPI (rev 09) Subsystem: Lenovo Device 2223 Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx- Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- SERR- Kernel driver in use: bdw_uncore 00: 86 80 04 16 06 00 90 20 09 00 00 06 00 00 00 00 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 aa 17 23 22 30: 00 00 00 00 e0 00 00 00 00 00 00 00 00 00 00 00 Signed-off-by: Christophe Le Roy Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 943c1cb..f700723 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -343,6 +343,7 @@ static void quirk_amd_mmconfig_area(struct pnp_dev *dev) static const unsigned int mch_quirk_devices[] = { 0x0154, /* Ivy Bridge */ 0x0c00, /* Haswell */ + 0x1604, /* Broadwell */ }; static struct pci_dev *get_intel_host(void) -- cgit v0.10.2 From e3e9b577b477edbf50e6c1f93beee89f450f2b68 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 4 Jan 2016 22:05:20 +0100 Subject: ACPICA: Drop Linux-specific waking vector functions Commit f06147f9fbf1 (ACPICA: Hardware: Enable firmware waking vector for both 32-bit and 64-bit FACS) added three functions that aren't present in upstream ACPICA, acpi_hw_set_firmware_waking_vectors(), acpi_set_firmware_waking_vectors() and acpi_set_firmware_waking_vector64(), to allow Linux to use the previously existing API for setting the platform firmware waking vector. However, that wasn't necessary, since the ACPI sleep support code in Linux can be modified to use the upstream ACPICA's API easily and the additional functions may be dropped which reduces the code size and puts the kernel's ACPICA code more in line with the upstream. Make the changes as per the above. While at it, make the relevant function desctiption comments reflect the upstream ACPICA's ones. Signed-off-by: Rafael J. Wysocki Acked-by: Lv Zheng diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index f8af1ab..1ce4efa 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -52,9 +52,9 @@ ACPI_MODULE_NAME("hwxfsleep") /* Local prototypes */ #if (!ACPI_REDUCED_HARDWARE) static acpi_status -acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, - acpi_physical_address physical_address, - acpi_physical_address physical_address64); +acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs, + acpi_physical_address physical_address, + acpi_physical_address physical_address64); #endif static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); @@ -79,22 +79,20 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { /* * These functions are removed for the ACPI_REDUCED_HARDWARE case: - * acpi_set_firmware_waking_vectors * acpi_set_firmware_waking_vector - * acpi_set_firmware_waking_vector64 * acpi_enter_sleep_state_s4bios */ #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * - * FUNCTION: acpi_hw_set_firmware_waking_vectors + * FUNCTION: acpi_hw_set_firmware_waking_vector * * PARAMETERS: facs - Pointer to FACS table * physical_address - 32-bit physical address of ACPI real mode - * entry point. + * entry point * physical_address64 - 64-bit physical address of ACPI protected - * mode entry point. + * mode entry point * * RETURN: Status * @@ -103,11 +101,11 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { ******************************************************************************/ static acpi_status -acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, - acpi_physical_address physical_address, - acpi_physical_address physical_address64) +acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs, + acpi_physical_address physical_address, + acpi_physical_address physical_address64) { - ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vectors); + ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vector); /* @@ -140,12 +138,12 @@ acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, /******************************************************************************* * - * FUNCTION: acpi_set_firmware_waking_vectors + * FUNCTION: acpi_set_firmware_waking_vector * * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode - * entry point. + * entry point * physical_address64 - 64-bit physical address of ACPI protected - * mode entry point. + * mode entry point * * RETURN: Status * @@ -154,79 +152,23 @@ acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, ******************************************************************************/ acpi_status -acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, - acpi_physical_address physical_address64) +acpi_set_firmware_waking_vector(acpi_physical_address physical_address, + acpi_physical_address physical_address64) { - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); if (acpi_gbl_FACS) { - (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_FACS, - physical_address, - physical_address64); + (void)acpi_hw_set_firmware_waking_vector(acpi_gbl_FACS, + physical_address, + physical_address64); } return_ACPI_STATUS(AE_OK); } -ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors) - -/******************************************************************************* - * - * FUNCTION: acpi_set_firmware_waking_vector - * - * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode - * entry point. - * - * RETURN: Status - * - * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS - * - ******************************************************************************/ -acpi_status acpi_set_firmware_waking_vector(u32 physical_address) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); - - status = acpi_set_firmware_waking_vectors((acpi_physical_address) - physical_address, 0); - - return_ACPI_STATUS(status); -} - ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) -#if ACPI_MACHINE_WIDTH == 64 -/******************************************************************************* - * - * FUNCTION: acpi_set_firmware_waking_vector64 - * - * PARAMETERS: physical_address - 64-bit physical address of ACPI protected - * mode entry point. - * - * RETURN: Status - * - * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if - * it exists in the table. This function is intended for use with - * 64-bit host operating systems. - * - ******************************************************************************/ -acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - - status = acpi_set_firmware_waking_vectors(0, - (acpi_physical_address) - physical_address); - - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) -#endif /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_s4bios diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 0d94621..9cb9752 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -61,7 +61,7 @@ static int acpi_sleep_prepare(u32 acpi_state) if (acpi_state == ACPI_STATE_S3) { if (!acpi_wakeup_address) return -EFAULT; - acpi_set_firmware_waking_vector(acpi_wakeup_address); + acpi_set_waking_vector(acpi_wakeup_address); } ACPI_FLUSH_CPU_CACHE(); @@ -410,7 +410,7 @@ static void acpi_pm_finish(void) acpi_leave_sleep_state(acpi_state); /* reset firmware waking vector */ - acpi_set_firmware_waking_vector((acpi_physical_address) 0); + acpi_set_waking_vector(0); acpi_target_sleep_state = ACPI_STATE_S0; diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h index c797ffa..a9cc34e 100644 --- a/drivers/acpi/sleep.h +++ b/drivers/acpi/sleep.h @@ -6,3 +6,9 @@ extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; extern void acpi_resume_power_resources(void); + +static inline acpi_status acpi_set_waking_vector(u32 wakeup_address) +{ + return acpi_set_firmware_waking_vector( + (acpi_physical_address)wakeup_address, 0); +} diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 1b462d8..012b2ee 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -863,17 +863,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_firmware_waking_vectors + acpi_set_firmware_waking_vector (acpi_physical_address physical_address, acpi_physical_address physical_address64)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_firmware_waking_vector(u32 - physical_address)) -#if ACPI_MACHINE_WIDTH == 64 -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_firmware_waking_vector64(u64 - physical_address)) -#endif /* * ACPI Timer interfaces */ -- cgit v0.10.2 From 0971686954f9cdde502c7bce4794c5ad53ea2e66 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 4 Jan 2016 22:07:39 +0100 Subject: ACPI / PCI: Simplify acpi_penalize_isa_irq() acpi_penalize_isa_irq() can be written in fewer lines of code, so do that. No functional change. Signed-off-by: Rafael J. Wysocki Works-for: Andy Shevchenko diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 5114d80..fa28635 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -877,17 +877,9 @@ static int __init acpi_irq_penalty_update(char *str, int used) */ void acpi_penalize_isa_irq(int irq, int active) { - int penalty; - - if (irq < 0) - return; - - if (active) - penalty = PIRQ_PENALTY_ISA_USED; - else - penalty = PIRQ_PENALTY_PCI_USING; - - acpi_irq_add_penalty(irq, penalty); + if (irq >= 0) + acpi_irq_add_penalty(irq, active ? + PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING); } bool acpi_isa_irq_available(int irq) -- cgit v0.10.2 From 38a234b9f08883bbcb475b798e0a3d6b44bd37d7 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sat, 2 Jan 2016 11:30:09 +0100 Subject: ACPI / PNP: constify device IDs Instead of re-creating the array on the stack each time is_cmos_rtc_device() gets called, make the array 'static const'. Signed-off-by: Mathias Krause Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index 48fc3ad..67d97c0 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -367,7 +367,7 @@ static struct acpi_scan_handler acpi_pnp_handler = { */ static int is_cmos_rtc_device(struct acpi_device *adev) { - struct acpi_device_id ids[] = { + static const struct acpi_device_id ids[] = { { "PNP0B00" }, { "PNP0B01" }, { "PNP0B02" }, -- cgit v0.10.2 From e0f03e87fc6f27a8af9896f430f2945b3b1664c0 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Dec 2015 07:33:22 +0100 Subject: PNP: respect PNP_DRIVER_RES_DO_NOT_CHANGE when detaching I have a device (Nuvoton 6779D Super-IO IR RC with nuvoton-cir driver) which works after initial boot but not any longer if I unload and re-load the driver module. Digging into the issue I found that unloading the driver calls pnp_disable_dev although the driver has flag PNP_DRIVER_RES_DO_NOT_CHANGE set. IMHO this is not right. Let's have a look at the call chain when probing a device: pnp_device_probe 1. attaches the device 2. if it's not active and PNP_DRIVER_RES_DO_NOT_CHANGE is not set it gets activated 3. probes driver I think pnp_device_remove should do it in reverse order and also respect PNP_DRIVER_RES_DO_NOT_CHANGE. Therefore: 1. call drivers remove callback 2. if device is active and PNP_DRIVER_RES_DO_NOT_CHANGE is not set disable it 3. detach device The change works for me and sounds logical to me. However I don't know the pnp driver in detail so I might be wrong. Signed-off-by: Heiner Kallweit Signed-off-by: Rafael J. Wysocki diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 153a493..63452f2 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -74,7 +74,6 @@ void pnp_device_detach(struct pnp_dev *pnp_dev) if (pnp_dev->status == PNP_ATTACHED) pnp_dev->status = PNP_READY; mutex_unlock(&pnp_lock); - pnp_disable_dev(pnp_dev); } static int pnp_device_probe(struct device *dev) @@ -131,6 +130,11 @@ static int pnp_device_remove(struct device *dev) drv->remove(pnp_dev); pnp_dev->driver = NULL; } + + if (pnp_dev->active && + (!drv || !(drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE))) + pnp_disable_dev(pnp_dev); + pnp_device_detach(pnp_dev); return 0; } -- cgit v0.10.2 From a84bc8cfb2f2e2bb59f2ebdf531464c547f5026f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 1 Jan 2016 23:53:45 +0000 Subject: ACPI / SBS: fix inconsistent indenting inside if statement The indenting in acpi_battery_set_alarm is inconsistent and has been so since 2007; commit 94f6c0860139da9219255b8ff45ad42117dda859 ("ACPI: SBS: Add support for power_supply class (and sysfs)"). Minor fix for this, no code functionality change. Signed-off-by: Colin Ian King Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index cb3dedb..ad0b13a 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -417,11 +417,11 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) if ((value & 0xf000) != sel) { value &= 0x0fff; value |= sel; - ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, + ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_MANAGER, 0x01, (u8 *)&value, 2); - if (ret) - goto end; + if (ret) + goto end; } } ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, -- cgit v0.10.2 From edc345d88462c78cd43d44e38efc9cadae4266f1 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 1 Jan 2016 22:52:15 +0100 Subject: ACPI: Fix white space in a structure definition Add a missing space in the definition of struct acpi_device_bus_id. Signed-off-by: Lukas Wunner [ rjw: Subject and changelog ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 60bda0d..1e6833a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -88,7 +88,7 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); extern struct list_head acpi_bus_id_list; -struct acpi_device_bus_id{ +struct acpi_device_bus_id { char bus_id[15]; unsigned int instance_no; struct list_head node; -- cgit v0.10.2 From a1e9ca6967d68209c70e616a224efa89a6b86ca6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 2 Jan 2016 03:09:16 +0100 Subject: PM / sleep: Add support for read-only sysfs attributes Some sysfs attributes in /sys/power/ should really be read-only, so add support for that, convert those attributes to read-only and drop the stub .show() routines from them. Original-by: Sergey Senozhatsky Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/main.c b/kernel/power/main.c index b2dd4d9..2794697 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -280,13 +280,7 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj, return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA; } -static ssize_t pm_wakeup_irq_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t n) -{ - return -EINVAL; -} -power_attr(pm_wakeup_irq); +power_attr_ro(pm_wakeup_irq); #else /* !CONFIG_PM_SLEEP_DEBUG */ static inline void pm_print_times_init(void) {} @@ -564,14 +558,7 @@ static ssize_t pm_trace_dev_match_show(struct kobject *kobj, return show_trace_dev_match(buf, PAGE_SIZE); } -static ssize_t -pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t n) -{ - return -EINVAL; -} - -power_attr(pm_trace_dev_match); +power_attr_ro(pm_trace_dev_match); #endif /* CONFIG_PM_TRACE */ diff --git a/kernel/power/power.h b/kernel/power/power.h index caadb56..efe1b3b 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -77,6 +77,15 @@ static struct kobj_attribute _name##_attr = { \ .store = _name##_store, \ } +#define power_attr_ro(_name) \ +static struct kobj_attribute _name##_attr = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = S_IRUGO, \ + }, \ + .show = _name##_show, \ +} + /* Preferred image size in bytes (default 500 MB) */ extern unsigned long image_size; /* Size of memory reserved for drivers (default SPARE_PAGES x PAGE_SIZE) */ -- cgit v0.10.2 From 0df35026c6a527e65b53bc895ad672d648a248f3 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Wed, 16 Dec 2015 12:20:29 +0800 Subject: cpufreq: governor: Fix negative idle_time when configured with CONFIG_HZ_PERIODIC It is reported that, with CONFIG_HZ_PERIODIC=y cpu stays at the lowest frequency even if the usage goes to 100%, neither ondemand nor conservative governor works, however performance and userspace work as expected. If set with CONFIG_NO_HZ_FULL=y, everything goes well. This problem is caused by improper calculation of the idle_time when the load is extremely high(near 100%). Firstly, cpufreq_governor uses get_cpu_idle_time to get the total idle time for specific cpu, then: 1.If the system is configured with CONFIG_NO_HZ_FULL, the idle time is returned by ktime_get, which is always increasing, it's OK. 2.However, if the system is configured with CONFIG_HZ_PERIODIC, get_cpu_idle_time might not guarantee to be always increasing, because it will leverage get_cpu_idle_time_jiffy to calculate the idle_time, consider the following scenario: At T1: idle_tick_1 = total_tick_1 - user_tick_1 sample period(80ms)... At T2: ( T2 = T1 + 80ms): idle_tick_2 = total_tick_2 - user_tick_2 Currently the algorithm is using (idle_tick_2 - idle_tick_1) to get the delta idle_time during the past sample period, however it CAN NOT guarantee that idle_tick_2 >= idle_tick_1, especially when cpu load is high. (Yes, total_tick_2 >= total_tick_1, and user_tick_2 >= user_tick_1, but how about idle_tick_2 and idle_tick_1? No guarantee.) So governor might get a negative value of idle_time during the past sample period, which might mislead the system that the idle time is very big(converted to unsigned int), and the busy time is nearly zero, which causes the governor to always choose the lowest cpufreq, then cause this problem. In theory there are two solutions: 1.The logic should not rely on the idle tick during every sample period, but be based on the busy tick directly, as this is how 'top' is implemented. 2.Or the logic must make sure that the idle_time is strictly increasing during each sample period, then there would be no negative idle_time anymore. This solution requires minimum modification to current code and this patch uses method 2. Link: https://bugzilla.kernel.org/show_bug.cgi?id=69821 Reported-by: Jan Fikar Signed-off-by: Chen Yu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 4de12fd..bab3a51 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -84,6 +84,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) (cur_wall_time - j_cdbs->prev_cpu_wall); j_cdbs->prev_cpu_wall = cur_wall_time; + if (cur_idle_time < j_cdbs->prev_cpu_idle) + cur_idle_time = j_cdbs->prev_cpu_idle; + idle_time = (unsigned int) (cur_idle_time - j_cdbs->prev_cpu_idle); j_cdbs->prev_cpu_idle = cur_idle_time; -- cgit v0.10.2 From 929ca89c305a6ed7a4149115be99af6d73c36918 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 30 Dec 2015 12:18:42 +0100 Subject: cpufreq-dt: fix handling regulator_get_voltage() result The function can return negative values so it should be assigned to signed type. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci. Link: http://permalink.gmane.org/gmane.linux.kernel/2038576 Signed-off-by: Andrzej Hajda Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 1ceece9..9bc37c4 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -50,7 +50,8 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index) struct private_data *priv = policy->driver_data; struct device *cpu_dev = priv->cpu_dev; struct regulator *cpu_reg = priv->cpu_reg; - unsigned long volt = 0, volt_old = 0, tol = 0; + unsigned long volt = 0, tol = 0; + int volt_old = 0; unsigned int old_freq, new_freq; long freq_Hz, freq_exact; int ret; @@ -83,7 +84,7 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index) opp_freq / 1000, volt); } - dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", + dev_dbg(cpu_dev, "%u MHz, %d mV --> %u MHz, %ld mV\n", old_freq / 1000, (volt_old > 0) ? volt_old / 1000 : -1, new_freq / 1000, volt ? volt / 1000 : -1); -- cgit v0.10.2 From aecbd9b1bff6afbe349921b406b99d285b412820 Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Mon, 4 Jan 2016 23:22:28 +0100 Subject: ACPI / video: driver must be registered before checking for keypresses acpi_video_handles_brightness_key_presses() may use an uninitialized mutex. The error has been reported by lockdep: DEBUG_LOCKS_WARN_ON(l->magic != l). The function assumes that the video driver has been registered before being called. As explained in the comment of acpi_video_init(), the registration of the video class may be defered and thus may not take place in the init function of the module. Use completion mechanisms to make sure that acpi_video_handles_brightness_key_presses() wait for the completion of acpi_video_register() before using the mutex. Also get rid of register_count since task completion can replace it. Signed-off-by: Adrien Schildknecht Reviewed-by: Hans de Goede Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 80b13d4..06a006f 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -90,8 +90,8 @@ module_param(device_id_scheme, bool, 0444); static bool only_lcd = false; module_param(only_lcd, bool, 0444); -static int register_count; -static DEFINE_MUTEX(register_count_mutex); +static DECLARE_COMPLETION(register_done); +static DEFINE_MUTEX(register_done_mutex); static struct mutex video_list_lock; static struct list_head video_bus_head; static int acpi_video_bus_add(struct acpi_device *device); @@ -2049,8 +2049,8 @@ int acpi_video_register(void) { int ret = 0; - mutex_lock(®ister_count_mutex); - if (register_count) { + mutex_lock(®ister_done_mutex); + if (completion_done(®ister_done)) { /* * if the function of acpi_video_register is already called, * don't register the acpi_vide_bus again and return no error. @@ -2071,22 +2071,22 @@ int acpi_video_register(void) * When the acpi_video_bus is loaded successfully, increase * the counter reference. */ - register_count = 1; + complete(®ister_done); leave: - mutex_unlock(®ister_count_mutex); + mutex_unlock(®ister_done_mutex); return ret; } EXPORT_SYMBOL(acpi_video_register); void acpi_video_unregister(void) { - mutex_lock(®ister_count_mutex); - if (register_count) { + mutex_lock(®ister_done_mutex); + if (completion_done(®ister_done)) { acpi_bus_unregister_driver(&acpi_video_bus); - register_count = 0; + reinit_completion(®ister_done); } - mutex_unlock(®ister_count_mutex); + mutex_unlock(®ister_done_mutex); } EXPORT_SYMBOL(acpi_video_unregister); @@ -2094,20 +2094,21 @@ void acpi_video_unregister_backlight(void) { struct acpi_video_bus *video; - mutex_lock(®ister_count_mutex); - if (register_count) { + mutex_lock(®ister_done_mutex); + if (completion_done(®ister_done)) { mutex_lock(&video_list_lock); list_for_each_entry(video, &video_bus_head, entry) acpi_video_bus_unregister_backlight(video); mutex_unlock(&video_list_lock); } - mutex_unlock(®ister_count_mutex); + mutex_unlock(®ister_done_mutex); } bool acpi_video_handles_brightness_key_presses(void) { bool have_video_busses; + wait_for_completion(®ister_done); mutex_lock(&video_list_lock); have_video_busses = !list_empty(&video_bus_head); mutex_unlock(&video_list_lock); -- cgit v0.10.2 From 45288978859119c019eff93f0cb838a0de100bcc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Jan 2016 10:57:11 +0000 Subject: ACPI, PCI, irq: remove redundant check for null string pointer source is decleared as a 4 byte char array in struct acpi_pci_routing_table so !prt->source is a redundant null string pointer check. Detected with smatch: drivers/acpi/pci_irq.c:134 do_prt_fixups() warn: this array is probably non-NULL. 'prt->source' Signed-off-by: Colin Ian King Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index c933675..d30184c 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -131,9 +131,6 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, quirk = &prt_quirks[i]; /* All current quirks involve link devices, not GSIs */ - if (!prt->source) - continue; - if (dmi_check_system(quirk->system) && entry->id.segment == quirk->segment && entry->id.bus == quirk->bus && -- cgit v0.10.2 From a032d2de0b5f17631844b34481c61cb799d0af6b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 30 Dec 2015 17:45:19 -0800 Subject: Documentation: cpufreq: intel_pstate: enhance documentation This is an attempt to make documentation more user friendly. Signed-off-by: Srinivas Pandruvada Reviewed-by: Doug Smythies Reviewed-by: Chen, Yu C Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt index be8d400..f7b12c0 100644 --- a/Documentation/cpu-freq/intel-pstate.txt +++ b/Documentation/cpu-freq/intel-pstate.txt @@ -1,61 +1,131 @@ -Intel P-state driver +Intel P-State driver -------------------- -This driver provides an interface to control the P state selection for -SandyBridge+ Intel processors. The driver can operate two different -modes based on the processor model, legacy mode and Hardware P state (HWP) -mode. - -In legacy mode, the Intel P-state implements two internal governors, -performance and powersave, that differ from the general cpufreq governors of -the same name (the general cpufreq governors implement target(), whereas the -internal Intel P-state governors implement setpolicy()). The internal -performance governor sets the max_perf_pct and min_perf_pct to 100; that is, -the governor selects the highest available P state to maximize the performance -of the core. The internal powersave governor selects the appropriate P state -based on the current load on the CPU. - -In HWP mode P state selection is implemented in the processor -itself. The driver provides the interfaces between the cpufreq core and -the processor to control P state selection based on user preferences -and reporting frequency to the cpufreq core. In this mode the -internal Intel P-state governor code is disabled. - -In addition to the interfaces provided by the cpufreq core for -controlling frequency the driver provides sysfs files for -controlling P state selection. These files have been added to -/sys/devices/system/cpu/intel_pstate/ - - max_perf_pct: limits the maximum P state that will be requested by - the driver stated as a percentage of the available performance. The - available (P states) performance may be reduced by the no_turbo +This driver provides an interface to control the P-State selection for the +SandyBridge+ Intel processors. + +The following document explains P-States: +http://events.linuxfoundation.org/sites/events/files/slides/LinuxConEurope_2015.pdf +As stated in the document, P-State doesn’t exactly mean a frequency. However, for +the sake of the relationship with cpufreq, P-State and frequency are used +interchangeably. + +Understanding the cpufreq core governors and policies are important before +discussing more details about the Intel P-State driver. Based on what callbacks +a cpufreq driver provides to the cpufreq core, it can support two types of +drivers: +- with target_index() callback: In this mode, the drivers using cpufreq core +simply provide the minimum and maximum frequency limits and an additional +interface target_index() to set the current frequency. The cpufreq subsystem +has a number of scaling governors ("performance", "powersave", "ondemand", +etc.). Depending on which governor is in use, cpufreq core will call for +transitions to a specific frequency using target_index() callback. +- setpolicy() callback: In this mode, drivers do not provide target_index() +callback, so cpufreq core can't request a transition to a specific frequency. +The driver provides minimum and maximum frequency limits and callbacks to set a +policy. The policy in cpufreq sysfs is referred to as the "scaling governor". +The cpufreq core can request the driver to operate in any of the two policies: +"performance: and "powersave". The driver decides which frequency to use based +on the above policy selection considering minimum and maximum frequency limits. + +The Intel P-State driver falls under the latter category, which implements the +setpolicy() callback. This driver decides what P-State to use based on the +requested policy from the cpufreq core. If the processor is capable of +selecting its next P-State internally, then the driver will offload this +responsibility to the processor (aka HWP: Hardware P-States). If not, the +driver implements algorithms to select the next P-State. + +Since these policies are implemented in the driver, they are not same as the +cpufreq scaling governors implementation, even if they have the same name in +the cpufreq sysfs (scaling_governors). For example the "performance" policy is +similar to cpufreq’s "performance" governor, but "powersave" is completely +different than the cpufreq "powersave" governor. The strategy here is similar +to cpufreq "ondemand", where the requested P-State is related to the system load. + +Sysfs Interface + +In addition to the frequency-controlling interfaces provided by the cpufreq +core, the driver provides its own sysfs files to control the P-State selection. +These files have been added to /sys/devices/system/cpu/intel_pstate/. +Any changes made to these files are applicable to all CPUs (even in a +multi-package system). + + max_perf_pct: Limits the maximum P-State that will be requested by + the driver. It states it as a percentage of the available performance. The + available (P-State) performance may be reduced by the no_turbo setting described below. - min_perf_pct: limits the minimum P state that will be requested by - the driver stated as a percentage of the max (non-turbo) + min_perf_pct: Limits the minimum P-State that will be requested by + the driver. It states it as a percentage of the max (non-turbo) performance level. - no_turbo: limits the driver to selecting P states below the turbo + no_turbo: Limits the driver to selecting P-State below the turbo frequency range. - turbo_pct: displays the percentage of the total performance that - is supported by hardware that is in the turbo range. This number + turbo_pct: Displays the percentage of the total performance that + is supported by hardware that is in the turbo range. This number is independent of whether turbo has been disabled or not. - num_pstates: displays the number of pstates that are supported - by hardware. This number is independent of whether turbo has + num_pstates: Displays the number of P-States that are supported + by hardware. This number is independent of whether turbo has been disabled or not. +For example, if a system has these parameters: + Max 1 core turbo ratio: 0x21 (Max 1 core ratio is the maximum P-State) + Max non turbo ratio: 0x17 + Minimum ratio : 0x08 (Here the ratio is called max efficiency ratio) + +Sysfs will show : + max_perf_pct:100, which corresponds to 1 core ratio + min_perf_pct:24, max_efficiency_ratio / max 1 Core ratio + no_turbo:0, turbo is not disabled + num_pstates:26 = (max 1 Core ratio - Max Efficiency Ratio + 1) + turbo_pct:39 = (max 1 core ratio - max non turbo ratio) / num_pstates + +Refer to "Intel® 64 and IA-32 Architectures Software Developer’s Manual +Volume 3: System Programming Guide" to understand ratios. + +cpufreq sysfs for Intel P-State + +Since this driver registers with cpufreq, cpufreq sysfs is also presented. +There are some important differences, which need to be considered. + +scaling_cur_freq: This displays the real frequency which was used during +the last sample period instead of what is requested. Some other cpufreq driver, +like acpi-cpufreq, displays what is requested (Some changes are on the +way to fix this for acpi-cpufreq driver). The same is true for frequencies +displayed at /proc/cpuinfo. + +scaling_governor: This displays current active policy. Since each CPU has a +cpufreq sysfs, it is possible to set a scaling governor to each CPU. But this +is not possible with Intel P-States, as there is one common policy for all +CPUs. Here, the last requested policy will be applicable to all CPUs. It is +suggested that one use the cpupower utility to change policy to all CPUs at the +same time. + +scaling_setspeed: This attribute can never be used with Intel P-State. + +scaling_max_freq/scaling_min_freq: This interface can be used similarly to +the max_perf_pct/min_perf_pct of Intel P-State sysfs. However since frequencies +are converted to nearest possible P-State, this is prone to rounding errors. +This method is not preferred to limit performance. + +affected_cpus: Not used +related_cpus: Not used + For contemporary Intel processors, the frequency is controlled by the -processor itself and the P-states exposed to software are related to +processor itself and the P-State exposed to software is related to performance levels. The idea that frequency can be set to a single -frequency is fiction for Intel Core processors. Even if the scaling -driver selects a single P state the actual frequency the processor +frequency is fictional for Intel Core processors. Even if the scaling +driver selects a single P-State, the actual frequency the processor will run at is selected by the processor itself. -For legacy mode debugfs files have also been added to allow tuning of -the internal governor algorythm. These files are located at -/sys/kernel/debug/pstate_snb/ These files are NOT present in HWP mode. +Tuning Intel P-State driver + +When HWP mode is not used, debugfs files have also been added to allow the +tuning of the internal governor algorithm. These files are located at +/sys/kernel/debug/pstate_snb/. The algorithm uses a PID (Proportional +Integral Derivative) controller. The PID tunable parameters are: deadband d_gain_pct @@ -63,3 +133,90 @@ the internal governor algorythm. These files are located at p_gain_pct sample_rate_ms setpoint + +To adjust these parameters, some understanding of driver implementation is +necessary. There are some tweeks described here, but be very careful. Adjusting +them requires expert level understanding of power and performance relationship. +These limits are only useful when the "powersave" policy is active. + +-To make the system more responsive to load changes, sample_rate_ms can +be adjusted (current default is 10ms). +-To make the system use higher performance, even if the load is lower, setpoint +can be adjusted to a lower number. This will also lead to faster ramp up time +to reach the maximum P-State. +If there are no derivative and integral coefficients, The next P-State will be +equal to: + current P-State - ((setpoint - current cpu load) * p_gain_pct) + +For example, if the current PID parameters are (Which are defaults for the core +processors like SandyBridge): + deadband = 0 + d_gain_pct = 0 + i_gain_pct = 0 + p_gain_pct = 20 + sample_rate_ms = 10 + setpoint = 97 + +If the current P-State = 0x08 and current load = 100, this will result in the +next P-State = 0x08 - ((97 - 100) * 0.2) = 8.6 (rounded to 9). Here the P-State +goes up by only 1. If during next sample interval the current load doesn't +change and still 100, then P-State goes up by one again. This process will +continue as long as the load is more than the setpoint until the maximum P-State +is reached. + +For the same load at setpoint = 60, this will result in the next P-State += 0x08 - ((60 - 100) * 0.2) = 16 +So by changing the setpoint from 97 to 60, there is an increase of the +next P-State from 9 to 16. So this will make processor execute at higher +P-State for the same CPU load. If the load continues to be more than the +setpoint during next sample intervals, then P-State will go up again till the +maximum P-State is reached. But the ramp up time to reach the maximum P-State +will be much faster when the setpoint is 60 compared to 97. + +Debugging Intel P-State driver + +Event tracing +To debug P-State transition, the Linux event tracing interface can be used. +There are two specific events, which can be enabled (Provided the kernel +configs related to event tracing are enabled). + +# cd /sys/kernel/debug/tracing/ +# echo 1 > events/power/pstate_sample/enable +# echo 1 > events/power/cpu_frequency/enable +# cat trace +gnome-terminal--4510 [001] ..s. 1177.680733: pstate_sample: core_busy=107 + scaled=94 from=26 to=26 mperf=1143818 aperf=1230607 tsc=29838618 + freq=2474476 +cat-5235 [002] ..s. 1177.681723: cpu_frequency: state=2900000 cpu_id=2 + + +Using ftrace + +If function level tracing is required, the Linux ftrace interface can be used. +For example if we want to check how often a function to set a P-State is +called, we can set ftrace filter to intel_pstate_set_pstate. + +# cd /sys/kernel/debug/tracing/ +# cat available_filter_functions | grep -i pstate +intel_pstate_set_pstate +intel_pstate_cpu_init +... + +# echo intel_pstate_set_pstate > set_ftrace_filter +# echo function > current_tracer +# cat trace | head -15 +# tracer: function +# +# entries-in-buffer/entries-written: 80/80 #P:4 +# +# _-----=> irqs-off +# / _----=> need-resched +# | / _---=> hardirq/softirq +# || / _--=> preempt-depth +# ||| / delay +# TASK-PID CPU# |||| TIMESTAMP FUNCTION +# | | | |||| | | + Xorg-3129 [000] ..s. 2537.644844: intel_pstate_set_pstate <-intel_pstate_timer_func + gnome-terminal--4510 [002] ..s. 2537.649844: intel_pstate_set_pstate <-intel_pstate_timer_func + gnome-shell-3409 [001] ..s. 2537.650850: intel_pstate_set_pstate <-intel_pstate_timer_func + -0 [000] ..s. 2537.654843: intel_pstate_set_pstate <-intel_pstate_timer_func -- cgit v0.10.2 From 5ff24d601092b222340b28466e263b1c4559407e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 5 Jan 2016 16:15:54 +0530 Subject: PM / OPP: Use snprintf() instead of sprintf() sprintf() can access memory outside of the range of the character array, and is risky in some situations. The driver specified prop_name string can be longer than NAME_MAX here (only an attacker will do that though) and so blindly copying it into the character array of size NAME_MAX isn't safe. Instead we must use snprintf() here. Reported-by: Geert Uytterhoeven Signed-off-by: Viresh Kumar Acked-by: Geert Uytterhoeven Acked-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index cd230c6..cf351d3 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -808,7 +808,8 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, /* Search for "opp-microvolt-" */ if (dev_opp->prop_name) { - sprintf(name, "opp-microvolt-%s", dev_opp->prop_name); + snprintf(name, sizeof(name), "opp-microvolt-%s", + dev_opp->prop_name); prop = of_find_property(opp->np, name, NULL); } @@ -849,7 +850,8 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, /* Search for "opp-microamp-" */ prop = NULL; if (dev_opp->prop_name) { - sprintf(name, "opp-microamp-%s", dev_opp->prop_name); + snprintf(name, sizeof(name), "opp-microamp-%s", + dev_opp->prop_name); prop = of_find_property(opp->np, name, NULL); } -- cgit v0.10.2 From eebb3e8d8aaf28f4bcaf12fd3645350bfd2f0b36 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 12 Dec 2015 02:45:06 +0100 Subject: ACPI / LPSS: override power state for LPSS DMA device This is a third approach to workaround long standing issue with LPSS on BayTrail. First one [1] was reverted since it didn't resolve the issue comprehensively. Second one [2] was rejected by internal review. The LPSS DMA controller does not have neither _PS0 nor _PS3 method. Moreover it can be powered off automatically whenever the last LPSS device goes down. In case of no power any access to the DMA controller will hang the system. The behaviour is reproduced on some HP laptops based on Intel BayTrail [3,4] as well as on ASuS T100TA transformer. Power on the LPSS island through the registers accessible in a specific way. [1] http://www.spinics.net/lists/linux-acpi/msg53963.html [2] https://bugzilla.redhat.com/attachment.cgi?id=1066779&action=diff [3] https://bugzilla.redhat.com/show_bug.cgi?id=1184273 [4] http://www.spinics.net/lists/dmaengine/msg01514.html Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index db3622f..790aa3e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -523,9 +523,10 @@ config X86_INTEL_QUARK config X86_INTEL_LPSS bool "Intel Low Power Subsystem Support" - depends on ACPI + depends on X86 && ACPI select COMMON_CLK select PINCTRL + select IOSF_MBI ---help--- Select to build support for Intel Low Power Subsystem such as found on Intel Lynxpoint PCH. Selecting this option enables diff --git a/arch/x86/include/asm/iosf_mbi.h b/arch/x86/include/asm/iosf_mbi.h index cdc5f63..b41ee16 100644 --- a/arch/x86/include/asm/iosf_mbi.h +++ b/arch/x86/include/asm/iosf_mbi.h @@ -19,6 +19,8 @@ /* IOSF SB read/write opcodes */ #define MBI_MMIO_READ 0x00 #define MBI_MMIO_WRITE 0x01 +#define MBI_CFG_READ 0x04 +#define MBI_CFG_WRITE 0x05 #define MBI_CR_READ 0x06 #define MBI_CR_WRITE 0x07 #define MBI_REG_READ 0x10 diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index a10c2d6..84d3d90 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,10 @@ ACPI_MODULE_NAME("acpi_lpss"); #ifdef CONFIG_X86_INTEL_LPSS +#include +#include +#include + #define LPSS_ADDR(desc) ((unsigned long)&desc) #define LPSS_CLK_SIZE 0x04 @@ -71,7 +76,7 @@ struct lpss_device_desc { void (*setup)(struct lpss_private_data *pdata); }; -static struct lpss_device_desc lpss_dma_desc = { +static const struct lpss_device_desc lpss_dma_desc = { .flags = LPSS_CLK, }; @@ -84,6 +89,23 @@ struct lpss_private_data { u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; }; +/* LPSS run time quirks */ +static unsigned int lpss_quirks; + +/* + * LPSS_QUIRK_ALWAYS_POWER_ON: override power state for LPSS DMA device. + * + * The LPSS DMA controller does not have neither _PS0 nor _PS3 method. Moreover + * it can be powered off automatically whenever the last LPSS device goes down. + * In case of no power any access to the DMA controller will hang the system. + * The behaviour is reproduced on some HP laptops based on Intel BayTrail as + * well as on ASuS T100TA transformer. + * + * This quirk overrides power state of entire LPSS island to keep DMA powered + * on whenever we have at least one other device in use. + */ +#define LPSS_QUIRK_ALWAYS_POWER_ON BIT(0) + /* UART Component Parameter Register */ #define LPSS_UART_CPR 0xF4 #define LPSS_UART_CPR_AFCE BIT(4) @@ -196,13 +218,21 @@ static const struct lpss_device_desc bsw_i2c_dev_desc = { .setup = byt_i2c_setup, }; -static struct lpss_device_desc bsw_spi_dev_desc = { +static const struct lpss_device_desc bsw_spi_dev_desc = { .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, .prv_offset = 0x400, .setup = lpss_deassert_reset, }; +#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } + +static const struct x86_cpu_id lpss_cpu_ids[] = { + ICPU(0x37), /* Valleyview, Bay Trail */ + ICPU(0x4c), /* Braswell, Cherry Trail */ + {} +}; + #else #define LPSS_ADDR(desc) (0UL) @@ -661,6 +691,89 @@ static int acpi_lpss_resume_early(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ +/* IOSF SB for LPSS island */ +#define LPSS_IOSF_UNIT_LPIOEP 0xA0 +#define LPSS_IOSF_UNIT_LPIO1 0xAB +#define LPSS_IOSF_UNIT_LPIO2 0xAC + +#define LPSS_IOSF_PMCSR 0x84 +#define LPSS_PMCSR_D0 0 +#define LPSS_PMCSR_D3hot 3 +#define LPSS_PMCSR_Dx_MASK GENMASK(1, 0) + +#define LPSS_IOSF_GPIODEF0 0x154 +#define LPSS_GPIODEF0_DMA1_D3 BIT(2) +#define LPSS_GPIODEF0_DMA2_D3 BIT(3) +#define LPSS_GPIODEF0_DMA_D3_MASK GENMASK(3, 2) + +static DEFINE_MUTEX(lpss_iosf_mutex); + +static void lpss_iosf_enter_d3_state(void) +{ + u32 value1 = 0; + u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK; + u32 value2 = LPSS_PMCSR_D3hot; + u32 mask2 = LPSS_PMCSR_Dx_MASK; + /* + * PMC provides an information about actual status of the LPSS devices. + * Here we read the values related to LPSS power island, i.e. LPSS + * devices, excluding both LPSS DMA controllers, along with SCC domain. + */ + u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe; + int ret; + + ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis); + if (ret) + return; + + mutex_lock(&lpss_iosf_mutex); + + ret = pmc_atom_read(PMC_D3_STS_0, &d3_sts_0); + if (ret) + goto exit; + + /* + * Get the status of entire LPSS power island per device basis. + * Shutdown both LPSS DMA controllers if and only if all other devices + * are already in D3hot. + */ + pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask; + if (pmc_status) + goto exit; + + iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO1, MBI_CFG_WRITE, + LPSS_IOSF_PMCSR, value2, mask2); + + iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO2, MBI_CFG_WRITE, + LPSS_IOSF_PMCSR, value2, mask2); + + iosf_mbi_modify(LPSS_IOSF_UNIT_LPIOEP, MBI_CR_WRITE, + LPSS_IOSF_GPIODEF0, value1, mask1); +exit: + mutex_unlock(&lpss_iosf_mutex); +} + +static void lpss_iosf_exit_d3_state(void) +{ + u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3; + u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK; + u32 value2 = LPSS_PMCSR_D0; + u32 mask2 = LPSS_PMCSR_Dx_MASK; + + mutex_lock(&lpss_iosf_mutex); + + iosf_mbi_modify(LPSS_IOSF_UNIT_LPIOEP, MBI_CR_WRITE, + LPSS_IOSF_GPIODEF0, value1, mask1); + + iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO2, MBI_CFG_WRITE, + LPSS_IOSF_PMCSR, value2, mask2); + + iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO1, MBI_CFG_WRITE, + LPSS_IOSF_PMCSR, value2, mask2); + + mutex_unlock(&lpss_iosf_mutex); +} + static int acpi_lpss_runtime_suspend(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); @@ -673,7 +786,17 @@ static int acpi_lpss_runtime_suspend(struct device *dev) if (pdata->dev_desc->flags & LPSS_SAVE_CTX) acpi_lpss_save_ctx(dev, pdata); - return acpi_dev_runtime_suspend(dev); + ret = acpi_dev_runtime_suspend(dev); + + /* + * This call must be last in the sequence, otherwise PMC will return + * wrong status for devices being about to be powered off. See + * lpss_iosf_enter_d3_state() for further information. + */ + if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available()) + lpss_iosf_enter_d3_state(); + + return ret; } static int acpi_lpss_runtime_resume(struct device *dev) @@ -681,6 +804,13 @@ static int acpi_lpss_runtime_resume(struct device *dev) struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; + /* + * This call is kept first to be in symmetry with + * acpi_lpss_runtime_suspend() one. + */ + if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available()) + lpss_iosf_exit_d3_state(); + ret = acpi_dev_runtime_resume(dev); if (ret) return ret; @@ -798,10 +928,19 @@ static struct acpi_scan_handler lpss_handler = { void __init acpi_lpss_init(void) { - if (!lpt_clk_init()) { - bus_register_notifier(&platform_bus_type, &acpi_lpss_nb); - acpi_scan_add_handler(&lpss_handler); - } + const struct x86_cpu_id *id; + int ret; + + ret = lpt_clk_init(); + if (ret) + return; + + id = x86_match_cpu(lpss_cpu_ids); + if (id) + lpss_quirks |= LPSS_QUIRK_ALWAYS_POWER_ON; + + bus_register_notifier(&platform_bus_type, &acpi_lpss_nb); + acpi_scan_add_handler(&lpss_handler); } #else -- cgit v0.10.2 From 3214658855c01a0dd62f02feb2ce79846524c6a0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:23 +0200 Subject: dmaengine: dw: platform: power on device on shutdown We have to call dw_dma_disable() to stop any ongoing transfer. On some platforms we can't do that since DMA device is powered off. Moreover we have no possibility at that point to check if the platform is affected or not. That's why we call pm_runtime_get_sync() / pm_runtime_put() unconditionally. On the other hand we can't use pm_runtime_suspended() because runtime PM framework is not fully used by the driver. Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Rafael J. Wysocki diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 68a4815..d0734e9 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -239,7 +239,19 @@ static void dw_shutdown(struct platform_device *pdev) { struct dw_dma_chip *chip = platform_get_drvdata(pdev); + /* + * We have to call dw_dma_disable() to stop any ongoing transfer. On + * some platforms we can't do that since DMA device is powered off. + * Moreover we have no possibility to check if the platform is affected + * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put() + * unconditionally. On the other hand we can't use + * pm_runtime_suspended() because runtime PM framework is not fully + * used by the driver. + */ + pm_runtime_get_sync(chip->dev); dw_dma_disable(chip); + pm_runtime_put_sync_suspend(chip->dev); + clk_disable_unprepare(chip->clk); } -- cgit v0.10.2 From 02a21b79acdb48b312f1351fd7cc728e66e81149 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:24 +0200 Subject: dmaengine: dw: return immediately from IRQ when DMA isn't in use There is no need to bother the hardware when all channels are idle. We have not to get any interrupts. Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Rafael J. Wysocki diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 7067b6d..8b20930 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -622,12 +622,17 @@ static void dw_dma_tasklet(unsigned long data) static irqreturn_t dw_dma_interrupt(int irq, void *dev_id) { struct dw_dma *dw = dev_id; - u32 status = dma_readl(dw, STATUS_INT); + u32 status; + /* Check if we have any interrupt from the DMAC which is not in use */ + if (!dw->in_use) + return IRQ_NONE; + + status = dma_readl(dw, STATUS_INT); dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status); /* Check if we have any interrupt from the DMAC */ - if (!status || !dw->in_use) + if (!status) return IRQ_NONE; /* -- cgit v0.10.2 From bc0bb1fd5b0d72fba589b46be05c945171f9d6f3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 4 Dec 2015 23:49:25 +0200 Subject: Revert "dmaengine: dw: platform: provide platform data for Intel" Since we have a work around to prevent a system hangup we don't need to provide a platform data explicitly anymore. This reverts commit 175267b389f781748e2bbb6c737e76b5c9bc4c88. Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Rafael J. Wysocki diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index d0734e9..127093a 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -155,7 +155,6 @@ static int dw_probe(struct platform_device *pdev) struct dw_dma_chip *chip; struct device *dev = &pdev->dev; struct resource *mem; - const struct acpi_device_id *id; struct dw_dma_platform_data *pdata; int err; @@ -179,11 +178,6 @@ static int dw_probe(struct platform_device *pdev) pdata = dev_get_platdata(dev); if (!pdata) pdata = dw_dma_parse_dt(pdev); - if (!pdata && has_acpi_companion(dev)) { - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (id) - pdata = (struct dw_dma_platform_data *)id->driver_data; - } chip->dev = dev; @@ -264,17 +258,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); #endif #ifdef CONFIG_ACPI -static struct dw_dma_platform_data dw_dma_acpi_pdata = { - .nr_channels = 8, - .is_private = true, - .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, - .chan_priority = CHAN_PRIORITY_ASCENDING, - .block_size = 4095, - .nr_masters = 2, -}; - static const struct acpi_device_id dw_dma_acpi_id_table[] = { - { "INTL9C60", (kernel_ulong_t)&dw_dma_acpi_pdata }, + { "INTL9C60", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); -- cgit v0.10.2 From fa9e93b11c6716b115f485f03930fa5a5c529e14 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 21 Dec 2015 22:31:09 +0200 Subject: ACPI / LPSS: change 'does not have' to 'has' in comment The LPSS DMA device has neither _PS0 nor _PS3 method. Fix the wording in the comment line. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 84d3d90..047281a6 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -95,7 +95,7 @@ static unsigned int lpss_quirks; /* * LPSS_QUIRK_ALWAYS_POWER_ON: override power state for LPSS DMA device. * - * The LPSS DMA controller does not have neither _PS0 nor _PS3 method. Moreover + * The LPSS DMA controller has neither _PS0 nor _PS3 method. Moreover * it can be powered off automatically whenever the last LPSS device goes down. * In case of no power any access to the DMA controller will hang the system. * The behaviour is reproduced on some HP laptops based on Intel BayTrail as -- cgit v0.10.2 From b790eb20b8e4a5c913fc62c49562c821165b4fad Mon Sep 17 00:00:00 2001 From: Loc Ho Date: Thu, 10 Dec 2015 14:19:16 -0700 Subject: ACPI / APD: Add APM X-Gene ACPI I2C device support Add APM X-Gene ACPI I2C device support by hooks into existent ACPI APD driver. To fully enable support, require another patch to add the X-Gene ACPI node into the DW I2C driver. Signed-off-by: Loc Ho Reviewed-by: Ken Xue Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index a450e7a..d507cf6 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -51,7 +51,7 @@ struct apd_private_data { const struct apd_device_desc *dev_desc; }; -#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE +#if defined(CONFIG_X86_AMD_PLATFORM_DEVICE) || defined(CONFIG_ARM64) #define APD_ADDR(desc) ((unsigned long)&desc) static int acpi_apd_setup(struct apd_private_data *pdata) @@ -71,6 +71,7 @@ static int acpi_apd_setup(struct apd_private_data *pdata) return 0; } +#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE static struct apd_device_desc cz_i2c_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 133000000, @@ -80,6 +81,14 @@ static struct apd_device_desc cz_uart_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 48000000, }; +#endif + +#ifdef CONFIG_ARM64 +static struct apd_device_desc xgene_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 100000000, +}; +#endif #else @@ -132,9 +141,14 @@ static int acpi_apd_create_device(struct acpi_device *adev, static const struct acpi_device_id acpi_apd_device_ids[] = { /* Generic apd devices */ +#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE { "AMD0010", APD_ADDR(cz_i2c_desc) }, { "AMD0020", APD_ADDR(cz_uart_desc) }, { "AMD0030", }, +#endif +#ifdef CONFIG_ARM64 + { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, +#endif { } }; -- cgit v0.10.2 From 04a407f6b129b6e35de3250c313976a3a154476e Mon Sep 17 00:00:00 2001 From: Loc Ho Date: Thu, 10 Dec 2015 14:19:17 -0700 Subject: i2c: dw: Add APM X-Gene ACPI I2C device support Enable APM X-Gene ACPI I2C device support by adding the corresponding ACPI ID. The platform ACPI APD corresponding change is required to provide the proper clock frequency input. Signed-off-by: Loc Ho Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 809579e..423371d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -117,6 +117,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "80860F41", 0 }, { "808622C1", 0 }, { "AMD0010", 0 }, + { "APMC0D0F", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); -- cgit v0.10.2 From d35818a9153e7f230fd65dc935e001a1b9bc08ff Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 7 Jan 2016 12:49:31 +0200 Subject: PM / clk: don't leave clocks enabled when driver not bound There is a new notification BUS_NOTIFY_DRIVER_NOT_BOUND that is issued when driver fails during binding. In such case pm_clk_notify(), when PM_CLK=n, leaves clocks enabled. Undo operations that have been done in BUS_NOTIFY_BIND_DRIVER case. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 60ee559..c39b861 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -473,6 +473,7 @@ static int pm_clk_notify(struct notifier_block *nb, enable_clock(dev, NULL); } break; + case BUS_NOTIFY_DRIVER_NOT_BOUND: case BUS_NOTIFY_UNBOUND_DRIVER: if (clknb->con_ids[0]) { for (con_id = clknb->con_ids; *con_id; con_id++) -- cgit v0.10.2