From 5f986c590fcf4284924fcda991cf14ab32bff49f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 23 Oct 2012 01:07:27 +0200 Subject: PM / QoS: Prepare device structure for adding more constraint types Currently struct dev_pm_info contains only one PM QoS constraints pointer reserved for latency requirements. Since one more device constraints type (i.e. flags) will be necessary, introduce a new structure, struct dev_pm_qos, that eventually will contain all of the available device PM QoS constraints and replace the "constraints" pointer in struct dev_pm_info with a pointer to the new structure called "qos". Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet --- drivers/base/power/qos.c | 42 ++++++++++++++++++++++-------------------- include/linux/pm.h | 2 +- include/linux/pm_qos.h | 4 ++++ 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 74a67e0019a..40ff1b02a7c 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -55,9 +55,7 @@ static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); */ s32 __dev_pm_qos_read_value(struct device *dev) { - struct pm_qos_constraints *c = dev->power.constraints; - - return c ? pm_qos_read_value(c) : 0; + return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0; } /** @@ -91,12 +89,12 @@ static int apply_constraint(struct dev_pm_qos_request *req, { int ret, curr_value; - ret = pm_qos_update_target(req->dev->power.constraints, + ret = pm_qos_update_target(&req->dev->power.qos->latency, &req->node, action, value); if (ret) { /* Call the global callbacks if needed */ - curr_value = pm_qos_read_value(req->dev->power.constraints); + curr_value = pm_qos_read_value(&req->dev->power.qos->latency); blocking_notifier_call_chain(&dev_pm_notifiers, (unsigned long)curr_value, req); @@ -114,20 +112,22 @@ static int apply_constraint(struct dev_pm_qos_request *req, */ static int dev_pm_qos_constraints_allocate(struct device *dev) { + struct dev_pm_qos *qos; struct pm_qos_constraints *c; struct blocking_notifier_head *n; - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) + qos = kzalloc(sizeof(*qos), GFP_KERNEL); + if (!qos) return -ENOMEM; n = kzalloc(sizeof(*n), GFP_KERNEL); if (!n) { - kfree(c); + kfree(qos); return -ENOMEM; } BLOCKING_INIT_NOTIFIER_HEAD(n); + c = &qos->latency; plist_head_init(&c->list); c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE; c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE; @@ -135,7 +135,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) c->notifiers = n; spin_lock_irq(&dev->power.lock); - dev->power.constraints = c; + dev->power.qos = qos; spin_unlock_irq(&dev->power.lock); return 0; @@ -151,7 +151,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) void dev_pm_qos_constraints_init(struct device *dev) { mutex_lock(&dev_pm_qos_mtx); - dev->power.constraints = NULL; + dev->power.qos = NULL; dev->power.power_state = PMSG_ON; mutex_unlock(&dev_pm_qos_mtx); } @@ -164,6 +164,7 @@ void dev_pm_qos_constraints_init(struct device *dev) */ void dev_pm_qos_constraints_destroy(struct device *dev) { + struct dev_pm_qos *qos; struct dev_pm_qos_request *req, *tmp; struct pm_qos_constraints *c; @@ -176,10 +177,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev) mutex_lock(&dev_pm_qos_mtx); dev->power.power_state = PMSG_INVALID; - c = dev->power.constraints; - if (!c) + qos = dev->power.qos; + if (!qos) goto out; + c = &qos->latency; /* Flush the constraints list for the device */ plist_for_each_entry_safe(req, tmp, &c->list, node) { /* @@ -191,7 +193,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) } spin_lock_irq(&dev->power.lock); - dev->power.constraints = NULL; + dev->power.qos = NULL; spin_unlock_irq(&dev->power.lock); kfree(c->notifiers); @@ -235,7 +237,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, mutex_lock(&dev_pm_qos_mtx); - if (!dev->power.constraints) { + if (!dev->power.qos) { if (dev->power.power_state.event == PM_EVENT_INVALID) { /* The device has been removed from the system. */ req->dev = NULL; @@ -290,7 +292,7 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, mutex_lock(&dev_pm_qos_mtx); - if (req->dev->power.constraints) { + if (req->dev->power.qos) { if (new_value != req->node.prio) ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); @@ -329,7 +331,7 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req) mutex_lock(&dev_pm_qos_mtx); - if (req->dev->power.constraints) { + if (req->dev->power.qos) { ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); @@ -362,13 +364,13 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier) mutex_lock(&dev_pm_qos_mtx); - if (!dev->power.constraints) + if (!dev->power.qos) ret = dev->power.power_state.event != PM_EVENT_INVALID ? dev_pm_qos_constraints_allocate(dev) : -ENODEV; if (!ret) ret = blocking_notifier_chain_register( - dev->power.constraints->notifiers, notifier); + dev->power.qos->latency.notifiers, notifier); mutex_unlock(&dev_pm_qos_mtx); return ret; @@ -393,9 +395,9 @@ int dev_pm_qos_remove_notifier(struct device *dev, mutex_lock(&dev_pm_qos_mtx); /* Silently return if the constraints object is not present. */ - if (dev->power.constraints) + if (dev->power.qos) retval = blocking_notifier_chain_unregister( - dev->power.constraints->notifiers, + dev->power.qos->latency.notifiers, notifier); mutex_unlock(&dev_pm_qos_mtx); diff --git a/include/linux/pm.h b/include/linux/pm.h index 007e687c4f6..0ce6df94221 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -549,7 +549,7 @@ struct dev_pm_info { struct dev_pm_qos_request *pq_req; #endif struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ - struct pm_qos_constraints *constraints; + struct dev_pm_qos *qos; }; extern void update_pm_runtime_accounting(struct device *dev); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 9924ea1f22e..30e9ad72e79 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -57,6 +57,10 @@ struct pm_qos_constraints { struct blocking_notifier_head *notifiers; }; +struct dev_pm_qos { + struct pm_qos_constraints latency; +}; + /* Action requested to pm_qos_update_target */ enum pm_qos_req_action { PM_QOS_ADD_REQ, /* Add a new request */ -- cgit v1.2.3 From 5efbe4279f959a3f5ed26adf5f05cb78dd1ffa7e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 23 Oct 2012 01:07:46 +0200 Subject: PM / QoS: Introduce request and constraint data types for PM QoS flags Introduce struct pm_qos_flags_request and struct pm_qos_flags representing PM QoS flags request type and PM QoS flags constraint type, respectively. With these definitions the data structures will be arranged so that the list member of a struct pm_qos_flags object will contain the head of a list of struct pm_qos_flags_request objects representing all of the "flags" requests present for the given device. Then, the effective_flags member of a struct pm_qos_flags object will contain the bitwise OR of the flags members of all the struct pm_qos_flags_request objects in the list. Additionally, introduce helper function pm_qos_update_flags() allowing the caller to manage the list of struct pm_qos_flags_request pointed to by the list member of struct pm_qos_flags. The flags are of type s32 so that the request's "value" field is always of the same type regardless of what kind of request it is (latency requests already have value fields of type s32). Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet Acked-by: mark gross --- include/linux/pm_qos.h | 17 ++++++++++++-- kernel/power/qos.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 30e9ad72e79..413ada3c7c9 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -33,6 +33,11 @@ struct pm_qos_request { struct delayed_work work; /* for pm_qos_update_request_timeout */ }; +struct pm_qos_flags_request { + struct list_head node; + s32 flags; /* Do not change to 64 bit */ +}; + struct dev_pm_qos_request { struct plist_node node; struct device *dev; @@ -45,8 +50,8 @@ enum pm_qos_type { }; /* - * Note: The lockless read path depends on the CPU accessing - * target_value atomically. Atomic access is only guaranteed on all CPU + * Note: The lockless read path depends on the CPU accessing target_value + * or effective_flags atomically. Atomic access is only guaranteed on all CPU * types linux supports for 32 bit quantites */ struct pm_qos_constraints { @@ -57,6 +62,11 @@ struct pm_qos_constraints { struct blocking_notifier_head *notifiers; }; +struct pm_qos_flags { + struct list_head list; + s32 effective_flags; /* Do not change to 64 bit */ +}; + struct dev_pm_qos { struct pm_qos_constraints latency; }; @@ -75,6 +85,9 @@ static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req) int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, enum pm_qos_req_action action, int value); +bool pm_qos_update_flags(struct pm_qos_flags *pqf, + struct pm_qos_flags_request *req, + enum pm_qos_req_action action, s32 val); void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class, s32 value); void pm_qos_update_request(struct pm_qos_request *req, diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 846bd42c7ed..2ab2819aee6 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -212,6 +212,69 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, } } +/** + * pm_qos_flags_remove_req - Remove device PM QoS flags request. + * @pqf: Device PM QoS flags set to remove the request from. + * @req: Request to remove from the set. + */ +static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf, + struct pm_qos_flags_request *req) +{ + s32 val = 0; + + list_del(&req->node); + list_for_each_entry(req, &pqf->list, node) + val |= req->flags; + + pqf->effective_flags = val; +} + +/** + * pm_qos_update_flags - Update a set of PM QoS flags. + * @pqf: Set of flags to update. + * @req: Request to add to the set, to modify, or to remove from the set. + * @action: Action to take on the set. + * @val: Value of the request to add or modify. + * + * Update the given set of PM QoS flags and call notifiers if the aggregate + * value has changed. Returns 1 if the aggregate constraint value has changed, + * 0 otherwise. + */ +bool pm_qos_update_flags(struct pm_qos_flags *pqf, + struct pm_qos_flags_request *req, + enum pm_qos_req_action action, s32 val) +{ + unsigned long irqflags; + s32 prev_value, curr_value; + + spin_lock_irqsave(&pm_qos_lock, irqflags); + + prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags; + + switch (action) { + case PM_QOS_REMOVE_REQ: + pm_qos_flags_remove_req(pqf, req); + break; + case PM_QOS_UPDATE_REQ: + pm_qos_flags_remove_req(pqf, req); + case PM_QOS_ADD_REQ: + req->flags = val; + INIT_LIST_HEAD(&req->node); + list_add_tail(&req->node, &pqf->list); + pqf->effective_flags |= val; + break; + default: + /* no action */ + ; + } + + curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags; + + spin_unlock_irqrestore(&pm_qos_lock, irqflags); + + return prev_value != curr_value; +} + /** * pm_qos_request - returns current system wide qos expectation * @pm_qos_class: identification of which qos value is requested -- cgit v1.2.3 From 021c870ba4ab4bc9a23d5db4e324f50f26d8ab24 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 23 Oct 2012 01:09:00 +0200 Subject: PM / QoS: Prepare struct dev_pm_qos_request for more request types The subsequent patches will use struct dev_pm_qos_request for representing both latency requests and flags requests. To make that easier, put the node member of struct dev_pm_qos_request (under the name "pnode") into a union called "data" that will represent the request's value and list node depending on its type. Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet Reviewed-by: mark gross --- drivers/base/power/qos.c | 6 +++--- drivers/base/power/sysfs.c | 2 +- include/linux/pm_qos.h | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 40ff1b02a7c..96d27b821bb 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -90,7 +90,7 @@ static int apply_constraint(struct dev_pm_qos_request *req, int ret, curr_value; ret = pm_qos_update_target(&req->dev->power.qos->latency, - &req->node, action, value); + &req->data.pnode, action, value); if (ret) { /* Call the global callbacks if needed */ @@ -183,7 +183,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) c = &qos->latency; /* Flush the constraints list for the device */ - plist_for_each_entry_safe(req, tmp, &c->list, node) { + plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { /* * Update constraints list and call the notification * callbacks if needed @@ -293,7 +293,7 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, mutex_lock(&dev_pm_qos_mtx); if (req->dev->power.qos) { - if (new_value != req->node.prio) + if (new_value != req->data.pnode.prio) ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); } else { diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index b91dc6f1e91..54c61ffa204 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -221,7 +221,7 @@ static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, static ssize_t pm_qos_latency_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev->power.pq_req->node.prio); + return sprintf(buf, "%d\n", dev->power.pq_req->data.pnode.prio); } static ssize_t pm_qos_latency_store(struct device *dev, diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 413ada3c7c9..3b9d14964d2 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -39,7 +39,9 @@ struct pm_qos_flags_request { }; struct dev_pm_qos_request { - struct plist_node node; + union { + struct plist_node pnode; + } data; struct device *dev; }; -- cgit v1.2.3 From ae0fb4b72c8db7e6c4ef32bc58a43a759ad414b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 23 Oct 2012 01:09:12 +0200 Subject: PM / QoS: Introduce PM QoS device flags support Modify the device PM QoS core code to support PM QoS flags requests. First, add a new field of type struct pm_qos_flags called "flags" to struct dev_pm_qos for representing the list of PM QoS flags requests for the given device. Accordingly, add a new "type" field to struct dev_pm_qos_request (along with an enum for representing request types) and a new member called "flr" to its data union for representig flags requests. Second, modify dev_pm_qos_add_request(), dev_pm_qos_update_request(), the internal routine apply_constraint() used by them and their existing callers to cover flags requests as well as latency requests. In particular, dev_pm_qos_add_request() gets a new argument called "type" for specifying the type of a request to be added. Finally, introduce two routines, __dev_pm_qos_flags() and dev_pm_qos_flags(), allowing their callers to check which PM QoS flags have been requested for the given device (the caller is supposed to pass the mask of flags to check as the routine's second argument and examine its return value for the result). Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet Reviewed-by: mark gross --- Documentation/power/pm_qos_interface.txt | 2 +- drivers/base/power/qos.c | 124 ++++++++++++++++++++++++------- drivers/mtd/nand/sh_flctl.c | 4 +- include/linux/pm_qos.h | 26 ++++++- 4 files changed, 127 insertions(+), 29 deletions(-) diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt index 17e130a8034..79a2a58425e 100644 --- a/Documentation/power/pm_qos_interface.txt +++ b/Documentation/power/pm_qos_interface.txt @@ -99,7 +99,7 @@ reading the aggregated value does not require any locking mechanism. From kernel mode the use of this interface is the following: -int dev_pm_qos_add_request(device, handle, value): +int dev_pm_qos_add_request(device, handle, type, value): Will insert an element into the list for that identified device with the target value. Upon change to this list the new target is recomputed and any registered notifiers are called only if the target value is now different. diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 96d27b821bb..3c66f75d14b 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -47,6 +47,50 @@ static DEFINE_MUTEX(dev_pm_qos_mtx); static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); +/** + * __dev_pm_qos_flags - Check PM QoS flags for a given device. + * @dev: Device to check the PM QoS flags for. + * @mask: Flags to check against. + * + * This routine must be called with dev->power.lock held. + */ +enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask) +{ + struct dev_pm_qos *qos = dev->power.qos; + struct pm_qos_flags *pqf; + s32 val; + + if (!qos) + return PM_QOS_FLAGS_UNDEFINED; + + pqf = &qos->flags; + if (list_empty(&pqf->list)) + return PM_QOS_FLAGS_UNDEFINED; + + val = pqf->effective_flags & mask; + if (val) + return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME; + + return PM_QOS_FLAGS_NONE; +} + +/** + * dev_pm_qos_flags - Check PM QoS flags for a given device (locked). + * @dev: Device to check the PM QoS flags for. + * @mask: Flags to check against. + */ +enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask) +{ + unsigned long irqflags; + enum pm_qos_flags_status ret; + + spin_lock_irqsave(&dev->power.lock, irqflags); + ret = __dev_pm_qos_flags(dev, mask); + spin_unlock_irqrestore(&dev->power.lock, irqflags); + + return ret; +} + /** * __dev_pm_qos_read_value - Get PM QoS constraint for a given device. * @dev: Device to get the PM QoS constraint value for. @@ -74,30 +118,39 @@ s32 dev_pm_qos_read_value(struct device *dev) return ret; } -/* - * apply_constraint - * @req: constraint request to apply - * @action: action to perform add/update/remove, of type enum pm_qos_req_action - * @value: defines the qos request +/** + * apply_constraint - Add/modify/remove device PM QoS request. + * @req: Constraint request to apply + * @action: Action to perform (add/update/remove). + * @value: Value to assign to the QoS request. * * Internal function to update the constraints list using the PM QoS core * code and if needed call the per-device and the global notification * callbacks */ static int apply_constraint(struct dev_pm_qos_request *req, - enum pm_qos_req_action action, int value) + enum pm_qos_req_action action, s32 value) { - int ret, curr_value; - - ret = pm_qos_update_target(&req->dev->power.qos->latency, - &req->data.pnode, action, value); + struct dev_pm_qos *qos = req->dev->power.qos; + int ret; - if (ret) { - /* Call the global callbacks if needed */ - curr_value = pm_qos_read_value(&req->dev->power.qos->latency); - blocking_notifier_call_chain(&dev_pm_notifiers, - (unsigned long)curr_value, - req); + switch(req->type) { + case DEV_PM_QOS_LATENCY: + ret = pm_qos_update_target(&qos->latency, &req->data.pnode, + action, value); + if (ret) { + value = pm_qos_read_value(&qos->latency); + blocking_notifier_call_chain(&dev_pm_notifiers, + (unsigned long)value, + req); + } + break; + case DEV_PM_QOS_FLAGS: + ret = pm_qos_update_flags(&qos->flags, &req->data.flr, + action, value); + break; + default: + ret = -EINVAL; } return ret; @@ -134,6 +187,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) c->type = PM_QOS_MIN; c->notifiers = n; + INIT_LIST_HEAD(&qos->flags.list); + spin_lock_irq(&dev->power.lock); dev->power.qos = qos; spin_unlock_irq(&dev->power.lock); @@ -207,6 +262,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) * dev_pm_qos_add_request - inserts new qos request into the list * @dev: target device for the constraint * @req: pointer to a preallocated handle + * @type: type of the request * @value: defines the qos request * * This function inserts a new entry in the device constraints list of @@ -222,7 +278,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) * from the system. */ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, - s32 value) + enum dev_pm_qos_req_type type, s32 value) { int ret = 0; @@ -253,8 +309,10 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, } } - if (!ret) + if (!ret) { + req->type = type; ret = apply_constraint(req, PM_QOS_ADD_REQ, value); + } out: mutex_unlock(&dev_pm_qos_mtx); @@ -281,6 +339,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value) { + s32 curr_value; int ret = 0; if (!req) /*guard against callers passing in null */ @@ -292,15 +351,27 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, mutex_lock(&dev_pm_qos_mtx); - if (req->dev->power.qos) { - if (new_value != req->data.pnode.prio) - ret = apply_constraint(req, PM_QOS_UPDATE_REQ, - new_value); - } else { - /* Return if the device has been removed */ + if (!req->dev->power.qos) { ret = -ENODEV; + goto out; } + switch(req->type) { + case DEV_PM_QOS_LATENCY: + curr_value = req->data.pnode.prio; + break; + case DEV_PM_QOS_FLAGS: + curr_value = req->data.flr.flags; + break; + default: + ret = -EINVAL; + goto out; + } + + if (curr_value != new_value) + ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); + + out: mutex_unlock(&dev_pm_qos_mtx); return ret; } @@ -451,7 +522,8 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, ancestor = ancestor->parent; if (ancestor) - error = dev_pm_qos_add_request(ancestor, req, value); + error = dev_pm_qos_add_request(ancestor, req, + DEV_PM_QOS_LATENCY, value); if (error) req->dev = NULL; @@ -487,7 +559,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) if (!req) return -ENOMEM; - ret = dev_pm_qos_add_request(dev, req, value); + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value); if (ret < 0) return ret; diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 4fbfe96e37a..f48ac5d80bb 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -727,7 +727,9 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) if (!flctl->qos_request) { ret = dev_pm_qos_add_request(&flctl->pdev->dev, - &flctl->pm_qos, 100); + &flctl->pm_qos, + DEV_PM_QOS_LATENCY, + 100); if (ret < 0) dev_err(&flctl->pdev->dev, "PM QoS request failed: %d\n", ret); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 3b9d14964d2..3af7d8573c2 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -20,6 +20,13 @@ enum { PM_QOS_NUM_CLASSES, }; +enum pm_qos_flags_status { + PM_QOS_FLAGS_UNDEFINED = -1, + PM_QOS_FLAGS_NONE, + PM_QOS_FLAGS_SOME, + PM_QOS_FLAGS_ALL, +}; + #define PM_QOS_DEFAULT_VALUE -1 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) @@ -38,9 +45,16 @@ struct pm_qos_flags_request { s32 flags; /* Do not change to 64 bit */ }; +enum dev_pm_qos_req_type { + DEV_PM_QOS_LATENCY = 1, + DEV_PM_QOS_FLAGS, +}; + struct dev_pm_qos_request { + enum dev_pm_qos_req_type type; union { struct plist_node pnode; + struct pm_qos_flags_request flr; } data; struct device *dev; }; @@ -71,6 +85,7 @@ struct pm_qos_flags { struct dev_pm_qos { struct pm_qos_constraints latency; + struct pm_qos_flags flags; }; /* Action requested to pm_qos_update_target */ @@ -105,10 +120,12 @@ int pm_qos_request_active(struct pm_qos_request *req); s32 pm_qos_read_value(struct pm_qos_constraints *c); #ifdef CONFIG_PM +enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask); +enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask); s32 __dev_pm_qos_read_value(struct device *dev); s32 dev_pm_qos_read_value(struct device *dev); int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, - s32 value); + enum dev_pm_qos_req_type type, s32 value); int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value); int dev_pm_qos_remove_request(struct dev_pm_qos_request *req); int dev_pm_qos_add_notifier(struct device *dev, @@ -122,12 +139,19 @@ void dev_pm_qos_constraints_destroy(struct device *dev); int dev_pm_qos_add_ancestor_request(struct device *dev, struct dev_pm_qos_request *req, s32 value); #else +static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, + s32 mask) + { return PM_QOS_FLAGS_UNDEFINED; } +static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, + s32 mask) + { return PM_QOS_FLAGS_UNDEFINED; } static inline s32 __dev_pm_qos_read_value(struct device *dev) { return 0; } static inline s32 dev_pm_qos_read_value(struct device *dev) { return 0; } static inline int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, + enum dev_pm_qos_req_type type, s32 value) { return 0; } static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req, -- cgit v1.2.3 From e39473d0b9448e770f49b0b15e514be884264438 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 24 Oct 2012 02:08:18 +0200 Subject: PM / QoS: Make it possible to expose PM QoS device flags to user space Define two device PM QoS flags, PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP, and introduce routines dev_pm_qos_expose_flags() and dev_pm_qos_hide_flags() allowing the caller to expose those two flags to user space or to hide them from it, respectively. After the flags have been exposed, user space will see two additional sysfs attributes, pm_qos_no_power_off and pm_qos_remote_wakeup, under the device's /sys/devices/.../power/ directory. Then, writing 1 to one of them will update the PM QoS flags request owned by user space so that the corresponding flag is requested to be set. In turn, writing 0 to one of them will cause the corresponding flag in the user space's request to be cleared (however, the owners of the other PM QoS flags requests for the same device may still request the flag to be set and it may be effectively set even if user space doesn't request that). Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet Acked-by: mark gross --- Documentation/ABI/testing/sysfs-devices-power | 31 +++++ drivers/base/power/power.h | 6 +- drivers/base/power/qos.c | 168 ++++++++++++++++++++------ drivers/base/power/sysfs.c | 94 ++++++++++++-- include/linux/pm.h | 1 - include/linux/pm_qos.h | 26 ++++ 6 files changed, 278 insertions(+), 48 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power index 45000f0db4d..7fc2997b23a 100644 --- a/Documentation/ABI/testing/sysfs-devices-power +++ b/Documentation/ABI/testing/sysfs-devices-power @@ -204,3 +204,34 @@ Description: This attribute has no effect on system-wide suspend/resume and hibernation. + +What: /sys/devices/.../power/pm_qos_no_power_off +Date: September 2012 +Contact: Rafael J. Wysocki +Description: + The /sys/devices/.../power/pm_qos_no_power_off attribute + is used for manipulating the PM QoS "no power off" flag. If + set, this flag indicates to the kernel that power should not + be removed entirely from the device. + + Not all drivers support this attribute. If it isn't supported, + it is not present. + + This attribute has no effect on system-wide suspend/resume and + hibernation. + +What: /sys/devices/.../power/pm_qos_remote_wakeup +Date: September 2012 +Contact: Rafael J. Wysocki +Description: + The /sys/devices/.../power/pm_qos_remote_wakeup attribute + is used for manipulating the PM QoS "remote wakeup required" + flag. If set, this flag indicates to the kernel that the + device is a source of user events that have to be signaled from + its low-power states. + + Not all drivers support this attribute. If it isn't supported, + it is not present. + + This attribute has no effect on system-wide suspend/resume and + hibernation. diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 0dbfdf4419a..b16686a0a5a 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -93,8 +93,10 @@ extern void dpm_sysfs_remove(struct device *dev); extern void rpm_sysfs_remove(struct device *dev); extern int wakeup_sysfs_add(struct device *dev); extern void wakeup_sysfs_remove(struct device *dev); -extern int pm_qos_sysfs_add(struct device *dev); -extern void pm_qos_sysfs_remove(struct device *dev); +extern int pm_qos_sysfs_add_latency(struct device *dev); +extern void pm_qos_sysfs_remove_latency(struct device *dev); +extern int pm_qos_sysfs_add_flags(struct device *dev); +extern void pm_qos_sysfs_remove_flags(struct device *dev); #else /* CONFIG_PM */ diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 3c66f75d14b..167834dcc82 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "power.h" @@ -321,6 +322,37 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, } EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); +/** + * __dev_pm_qos_update_request - Modify an existing device PM QoS request. + * @req : PM QoS request to modify. + * @new_value: New value to request. + */ +static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, + s32 new_value) +{ + s32 curr_value; + int ret = 0; + + if (!req->dev->power.qos) + return -ENODEV; + + switch(req->type) { + case DEV_PM_QOS_LATENCY: + curr_value = req->data.pnode.prio; + break; + case DEV_PM_QOS_FLAGS: + curr_value = req->data.flr.flags; + break; + default: + return -EINVAL; + } + + if (curr_value != new_value) + ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); + + return ret; +} + /** * dev_pm_qos_update_request - modifies an existing qos request * @req : handle to list element holding a dev_pm_qos request to use @@ -336,11 +368,9 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); * -EINVAL in case of wrong parameters, -ENODEV if the device has been * removed from the system */ -int dev_pm_qos_update_request(struct dev_pm_qos_request *req, - s32 new_value) +int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value) { - s32 curr_value; - int ret = 0; + int ret; if (!req) /*guard against callers passing in null */ return -EINVAL; @@ -350,29 +380,9 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, return -EINVAL; mutex_lock(&dev_pm_qos_mtx); - - if (!req->dev->power.qos) { - ret = -ENODEV; - goto out; - } - - switch(req->type) { - case DEV_PM_QOS_LATENCY: - curr_value = req->data.pnode.prio; - break; - case DEV_PM_QOS_FLAGS: - curr_value = req->data.flr.flags; - break; - default: - ret = -EINVAL; - goto out; - } - - if (curr_value != new_value) - ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); - - out: + __dev_pm_qos_update_request(req, new_value); mutex_unlock(&dev_pm_qos_mtx); + return ret; } EXPORT_SYMBOL_GPL(dev_pm_qos_update_request); @@ -533,10 +543,19 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); #ifdef CONFIG_PM_RUNTIME -static void __dev_pm_qos_drop_user_request(struct device *dev) +static void __dev_pm_qos_drop_user_request(struct device *dev, + enum dev_pm_qos_req_type type) { - dev_pm_qos_remove_request(dev->power.pq_req); - dev->power.pq_req = NULL; + switch(type) { + case DEV_PM_QOS_LATENCY: + dev_pm_qos_remove_request(dev->power.qos->latency_req); + dev->power.qos->latency_req = NULL; + break; + case DEV_PM_QOS_FLAGS: + dev_pm_qos_remove_request(dev->power.qos->flags_req); + dev->power.qos->flags_req = NULL; + break; + } } /** @@ -552,7 +571,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) if (!device_is_registered(dev) || value < 0) return -EINVAL; - if (dev->power.pq_req) + if (dev->power.qos && dev->power.qos->latency_req) return -EEXIST; req = kzalloc(sizeof(*req), GFP_KERNEL); @@ -563,10 +582,10 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) if (ret < 0) return ret; - dev->power.pq_req = req; - ret = pm_qos_sysfs_add(dev); + dev->power.qos->latency_req = req; + ret = pm_qos_sysfs_add_latency(dev); if (ret) - __dev_pm_qos_drop_user_request(dev); + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); return ret; } @@ -578,10 +597,87 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); */ void dev_pm_qos_hide_latency_limit(struct device *dev) { - if (dev->power.pq_req) { - pm_qos_sysfs_remove(dev); - __dev_pm_qos_drop_user_request(dev); + if (dev->power.qos && dev->power.qos->latency_req) { + pm_qos_sysfs_remove_latency(dev); + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); } } EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); + +/** + * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space. + * @dev: Device whose PM QoS flags are to be exposed to user space. + * @val: Initial values of the flags. + */ +int dev_pm_qos_expose_flags(struct device *dev, s32 val) +{ + struct dev_pm_qos_request *req; + int ret; + + if (!device_is_registered(dev)) + return -EINVAL; + + if (dev->power.qos && dev->power.qos->flags_req) + return -EEXIST; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val); + if (ret < 0) + return ret; + + dev->power.qos->flags_req = req; + ret = pm_qos_sysfs_add_flags(dev); + if (ret) + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags); + +/** + * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space. + * @dev: Device whose PM QoS flags are to be hidden from user space. + */ +void dev_pm_qos_hide_flags(struct device *dev) +{ + if (dev->power.qos && dev->power.qos->flags_req) { + pm_qos_sysfs_remove_flags(dev); + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); + } +} +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags); + +/** + * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space. + * @dev: Device to update the PM QoS flags request for. + * @mask: Flags to set/clear. + * @set: Whether to set or clear the flags (true means set). + */ +int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set) +{ + s32 value; + int ret; + + if (!dev->power.qos || !dev->power.qos->flags_req) + return -EINVAL; + + pm_runtime_get_sync(dev); + mutex_lock(&dev_pm_qos_mtx); + + value = dev_pm_qos_requested_flags(dev); + if (set) + value |= mask; + else + value &= ~mask; + + ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value); + + mutex_unlock(&dev_pm_qos_mtx); + pm_runtime_put(dev); + + return ret; +} #endif /* CONFIG_PM_RUNTIME */ diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 54c61ffa204..50d16e3cb0a 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -221,7 +221,7 @@ static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, static ssize_t pm_qos_latency_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev->power.pq_req->data.pnode.prio); + return sprintf(buf, "%d\n", dev_pm_qos_requested_latency(dev)); } static ssize_t pm_qos_latency_store(struct device *dev, @@ -237,12 +237,66 @@ static ssize_t pm_qos_latency_store(struct device *dev, if (value < 0) return -EINVAL; - ret = dev_pm_qos_update_request(dev->power.pq_req, value); + ret = dev_pm_qos_update_request(dev->power.qos->latency_req, value); return ret < 0 ? ret : n; } static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, pm_qos_latency_show, pm_qos_latency_store); + +static ssize_t pm_qos_no_power_off_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev) + & PM_QOS_FLAG_NO_POWER_OFF)); +} + +static ssize_t pm_qos_no_power_off_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + int ret; + + if (kstrtoint(buf, 0, &ret)) + return -EINVAL; + + if (ret != 0 && ret != 1) + return -EINVAL; + + ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_NO_POWER_OFF, ret); + return ret < 0 ? ret : n; +} + +static DEVICE_ATTR(pm_qos_no_power_off, 0644, + pm_qos_no_power_off_show, pm_qos_no_power_off_store); + +static ssize_t pm_qos_remote_wakeup_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev) + & PM_QOS_FLAG_REMOTE_WAKEUP)); +} + +static ssize_t pm_qos_remote_wakeup_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + int ret; + + if (kstrtoint(buf, 0, &ret)) + return -EINVAL; + + if (ret != 0 && ret != 1) + return -EINVAL; + + ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP, ret); + return ret < 0 ? ret : n; +} + +static DEVICE_ATTR(pm_qos_remote_wakeup, 0644, + pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store); #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP @@ -564,15 +618,27 @@ static struct attribute_group pm_runtime_attr_group = { .attrs = runtime_attrs, }; -static struct attribute *pm_qos_attrs[] = { +static struct attribute *pm_qos_latency_attrs[] = { #ifdef CONFIG_PM_RUNTIME &dev_attr_pm_qos_resume_latency_us.attr, #endif /* CONFIG_PM_RUNTIME */ NULL, }; -static struct attribute_group pm_qos_attr_group = { +static struct attribute_group pm_qos_latency_attr_group = { .name = power_group_name, - .attrs = pm_qos_attrs, + .attrs = pm_qos_latency_attrs, +}; + +static struct attribute *pm_qos_flags_attrs[] = { +#ifdef CONFIG_PM_RUNTIME + &dev_attr_pm_qos_no_power_off.attr, + &dev_attr_pm_qos_remote_wakeup.attr, +#endif /* CONFIG_PM_RUNTIME */ + NULL, +}; +static struct attribute_group pm_qos_flags_attr_group = { + .name = power_group_name, + .attrs = pm_qos_flags_attrs, }; int dpm_sysfs_add(struct device *dev) @@ -615,14 +681,24 @@ void wakeup_sysfs_remove(struct device *dev) sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); } -int pm_qos_sysfs_add(struct device *dev) +int pm_qos_sysfs_add_latency(struct device *dev) +{ + return sysfs_merge_group(&dev->kobj, &pm_qos_latency_attr_group); +} + +void pm_qos_sysfs_remove_latency(struct device *dev) +{ + sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_attr_group); +} + +int pm_qos_sysfs_add_flags(struct device *dev) { - return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group); + return sysfs_merge_group(&dev->kobj, &pm_qos_flags_attr_group); } -void pm_qos_sysfs_remove(struct device *dev) +void pm_qos_sysfs_remove_flags(struct device *dev) { - sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group); + sysfs_unmerge_group(&dev->kobj, &pm_qos_flags_attr_group); } void rpm_sysfs_remove(struct device *dev) diff --git a/include/linux/pm.h b/include/linux/pm.h index 0ce6df94221..03d7bb14531 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -546,7 +546,6 @@ struct dev_pm_info { unsigned long active_jiffies; unsigned long suspended_jiffies; unsigned long accounting_timestamp; - struct dev_pm_qos_request *pq_req; #endif struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ struct dev_pm_qos *qos; diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 3af7d8573c2..5a95013905c 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -34,6 +34,9 @@ enum pm_qos_flags_status { #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 #define PM_QOS_DEV_LAT_DEFAULT_VALUE 0 +#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) +#define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1) + struct pm_qos_request { struct plist_node node; int pm_qos_class; @@ -86,6 +89,8 @@ struct pm_qos_flags { struct dev_pm_qos { struct pm_qos_constraints latency; struct pm_qos_flags flags; + struct dev_pm_qos_request *latency_req; + struct dev_pm_qos_request *flags_req; }; /* Action requested to pm_qos_update_target */ @@ -187,10 +192,31 @@ static inline int dev_pm_qos_add_ancestor_request(struct device *dev, #ifdef CONFIG_PM_RUNTIME int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value); void dev_pm_qos_hide_latency_limit(struct device *dev); +int dev_pm_qos_expose_flags(struct device *dev, s32 value); +void dev_pm_qos_hide_flags(struct device *dev); +int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set); + +static inline s32 dev_pm_qos_requested_latency(struct device *dev) +{ + return dev->power.qos->latency_req->data.pnode.prio; +} + +static inline s32 dev_pm_qos_requested_flags(struct device *dev) +{ + return dev->power.qos->flags_req->data.flr.flags; +} #else static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) { return 0; } static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {} +static inline int dev_pm_qos_expose_flags(struct device *dev, s32 value) + { return 0; } +static inline void dev_pm_qos_hide_flags(struct device *dev) {} +static inline int dev_pm_qos_update_flags(struct device *dev, s32 m, bool set) + { return 0; } + +static inline s32 dev_pm_qos_requested_latency(struct device *dev) { return 0; } +static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; } #endif #endif -- cgit v1.2.3 From 34b1f76275a2cb8c1ce8e00095d200552b235122 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 24 Oct 2012 02:08:30 +0200 Subject: PM / Domains: Check device PM QoS flags in pm_genpd_poweroff() Make the generic PM domains pm_genpd_poweroff() function take device PM QoS flags into account when deciding whether or not to remove power from the domain. After this change the routine will return -EBUSY without executing the domain's .power_off() callback if there is at least one PM QoS flags request for at least one device in the domain and at least of those request has at least one of the NO_POWER_OFF and REMOTE_WAKEUP flags set. Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet Reviewed-by: mark gross --- drivers/base/power/domain.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index c22b869245d..e2cf392d99d 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -470,10 +470,19 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) return -EBUSY; not_suspended = 0; - list_for_each_entry(pdd, &genpd->dev_list, list_node) + list_for_each_entry(pdd, &genpd->dev_list, list_node) { + enum pm_qos_flags_status stat; + + stat = dev_pm_qos_flags(pdd->dev, + PM_QOS_FLAG_NO_POWER_OFF + | PM_QOS_FLAG_REMOTE_WAKEUP); + if (stat > PM_QOS_FLAGS_NONE) + return -EBUSY; + if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) || pdd->dev->power.irq_safe)) not_suspended++; + } if (not_suspended > genpd->in_progress) return -EBUSY; -- cgit v1.2.3 From 8b713a88cc8b746f975958183fa641e9f1c8086d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 24 Oct 2012 02:08:38 +0200 Subject: PM / ACPI: Take device PM QoS flags into account Make ACPI power management routines and PCI power management routines depending on ACPI take device PM QoS flags into account when deciding what power state to put the device into. In particular, after this change acpi_pm_device_sleep_state() will not return ACPI_STATE_D3_COLD as the deepest available low-power state if PM_QOS_FLAG_NO_POWER_OFF is requested for the device and it will not require remote wakeup to work for the device in the returned low-power state if there is at least one PM QoS flags request for the device, but PM_QOS_FLAG_REMOTE_WAKEUP is not requested for it. Accordingly, acpi_pci_set_power_state() will refuse to put the device into D3cold if PM_QOS_FLAG_NO_POWER_OFF is requested for it. Signed-off-by: Rafael J. Wysocki Reviewed-by: Jean Pihet Reviewed-by: Huang Ying --- drivers/acpi/sleep.c | 21 +++++++++++++++++---- drivers/pci/pci-acpi.c | 8 +++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fdcdbb65291..69134653909 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -711,6 +712,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) struct acpi_device *adev; char acpi_method[] = "_SxD"; unsigned long long d_min, d_max; + bool wakeup = false; if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3) return -EINVAL; @@ -718,6 +720,13 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) printk(KERN_DEBUG "ACPI handle has no context!\n"); return -ENODEV; } + if (d_max_in > ACPI_STATE_D3_HOT) { + enum pm_qos_flags_status stat; + + stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF); + if (stat == PM_QOS_FLAGS_ALL) + d_max_in = ACPI_STATE_D3_HOT; + } acpi_method[2] = '0' + acpi_target_sleep_state; /* @@ -737,8 +746,14 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer * provided -- that's our fault recovery, we ignore retval. */ - if (acpi_target_sleep_state > ACPI_STATE_S0) + if (acpi_target_sleep_state > ACPI_STATE_S0) { acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); + wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid + && adev->wakeup.sleep_state >= acpi_target_sleep_state; + } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) != + PM_QOS_FLAGS_NONE) { + wakeup = adev->wakeup.flags.valid; + } /* * If _PRW says we can wake up the system from the target sleep state, @@ -747,9 +762,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) * (ACPI 3.x), it should return the maximum (lowest power) D-state that * can wake the system. _S0W may be valid, too. */ - if (acpi_target_sleep_state == ACPI_STATE_S0 || - (device_may_wakeup(dev) && adev->wakeup.flags.valid && - adev->wakeup.sleep_state >= acpi_target_sleep_state)) { + if (wakeup) { acpi_status status; acpi_method[3] = 'W'; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c5792d622dc..63d6618a480 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -17,6 +17,7 @@ #include #include +#include #include "pci.h" static DEFINE_MUTEX(pci_acpi_pm_notify_mtx); @@ -257,11 +258,16 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) return -ENODEV; switch (state) { + case PCI_D3cold: + if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == + PM_QOS_FLAGS_ALL) { + error = -EBUSY; + break; + } case PCI_D0: case PCI_D1: case PCI_D2: case PCI_D3hot: - case PCI_D3cold: error = acpi_bus_set_power(handle, state_conv[state]); } -- cgit v1.2.3 From f9652875dcd49d400b775aecc8e0bf76e405b70a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Oct 2012 20:00:30 +0100 Subject: PM / QoS: Fix the return value of dev_pm_qos_update_request() Commit e39473d (PM / QoS: Make it possible to expose PM QoS device flags to user space) introduced __dev_pm_qos_update_request() to be called internally by dev_pm_qos_update_request(), but forgot to make the latter actually use the return value of the former. Fix this mistake. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 167834dcc82..3a7687ae5a4 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -380,7 +380,7 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value) return -EINVAL; mutex_lock(&dev_pm_qos_mtx); - __dev_pm_qos_update_request(req, new_value); + ret = __dev_pm_qos_update_request(req, new_value); mutex_unlock(&dev_pm_qos_mtx); return ret; -- cgit v1.2.3 From 9eaee2cdcf9ead20f234b15ed26f82a96a4fa8fb Mon Sep 17 00:00:00 2001 From: "Lan,Tianyu" Date: Thu, 1 Nov 2012 22:45:30 +0100 Subject: PM / QoS: Fix a free error in the dev_pm_qos_constraints_destroy() Free a wrong point to struct dev_pm_qos->latency which suppose to be the point to struct dev_pm_qos. The patch is to fix the issue. Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 3a7687ae5a4..31d3f4842b9 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -253,7 +253,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) spin_unlock_irq(&dev->power.lock); kfree(c->notifiers); - kfree(c); + kfree(qos); out: mutex_unlock(&dev_pm_qos_mtx); -- cgit v1.2.3 From 436ede8942ab43474182c6454f420d71f7bb1163 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 13:10:09 +0100 Subject: PM / QoS: Document request manipulation requirement for flags In fact, the callers of dev_pm_qos_add_request(), dev_pm_qos_update_request() and dev_pm_qos_remove_request() for requests of type DEV_PM_QOS_FLAGS need to ensure that the target device is not RPM_SUSPENDED before using any of these functions (or be prepared for the new PM QoS flags to take effect after the device has been resumed). Document this in their kerneldoc comments. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 31d3f4842b9..081db2d25da 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -277,6 +277,9 @@ void dev_pm_qos_constraints_destroy(struct device *dev) * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory * to allocate for data structures, -ENODEV if the device has just been removed * from the system. + * + * Callers should ensure that the target device is not RPM_SUSPENDED before + * using this function for requests of type DEV_PM_QOS_FLAGS. */ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, enum dev_pm_qos_req_type type, s32 value) @@ -367,6 +370,9 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, * 0 if the aggregated constraint value has not changed, * -EINVAL in case of wrong parameters, -ENODEV if the device has been * removed from the system + * + * Callers should ensure that the target device is not RPM_SUSPENDED before + * using this function for requests of type DEV_PM_QOS_FLAGS. */ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value) { @@ -398,6 +404,9 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_update_request); * 0 if the aggregated constraint value has not changed, * -EINVAL in case of wrong parameters, -ENODEV if the device has been * removed from the system + * + * Callers should ensure that the target device is not RPM_SUSPENDED before + * using this function for requests of type DEV_PM_QOS_FLAGS. */ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req) { -- cgit v1.2.3 From 7e4d68443a80574392d1027ff34992ab945934a6 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 8 Nov 2012 11:14:08 +0800 Subject: PM / QoS: Resume device before exposing/hiding PM QoS flags Since dev_pm_qos_add_request(), dev_pm_qos_update_request() and dev_pm_qos_remove_request() for PM QoS flags should not be invoked when device in RPM_SUSPENDED, add pm_runtime_get_sync() and pm_runtime_put() around these functions in dev_pm_qos_expose_flags() and dev_pm_qos_hide_flags(). [rjw: Modified the subject and changelog to better reflect the code changes made.] Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 081db2d25da..fdc3894bc33 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -633,15 +633,18 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val) if (!req) return -ENOMEM; + pm_runtime_get_sync(dev); ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val); if (ret < 0) - return ret; + goto fail; dev->power.qos->flags_req = req; ret = pm_qos_sysfs_add_flags(dev); if (ret) __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); +fail: + pm_runtime_put(dev); return ret; } EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags); @@ -654,7 +657,9 @@ void dev_pm_qos_hide_flags(struct device *dev) { if (dev->power.qos && dev->power.qos->flags_req) { pm_qos_sysfs_remove_flags(dev); + pm_runtime_get_sync(dev); __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); + pm_runtime_put(dev); } } EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags); -- cgit v1.2.3 From bdda27fb98463244f056852f800bbce7db67dc4a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 26 Oct 2012 13:40:04 +0200 Subject: ACPI / PM: Fix device PM kernedoc comments and #ifdefs The kerneldoc comments for acpi_pm_device_sleep_state(), acpi_pm_device_run_wake(), and acpi_pm_device_sleep_wake() are outdated or otherwise inaccurate and/or don't follow the common kerneldoc patterns, so fix them. Additionally, notice that acpi_pm_device_run_wake() should be under CONFIG_PM_RUNTIME rather than under CONFIG_PM_SLEEP, so fix that too. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 53 ++++++++++++++++++++++--------------------------- include/acpi/acpi_bus.h | 8 ++++++-- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 69134653909..4defa0297ee 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -684,28 +684,21 @@ int acpi_suspend(u32 acpi_state) #ifdef CONFIG_PM /** - * acpi_pm_device_sleep_state - return preferred power state of ACPI device - * in the system sleep state given by %acpi_target_sleep_state - * @dev: device to examine; its driver model wakeup flags control - * whether it should be able to wake up the system - * @d_min_p: used to store the upper limit of allowed states range - * @d_max_in: specify the lowest allowed states - * Return value: preferred power state of the device on success, -ENODEV - * (ie. if there's no 'struct acpi_device' for @dev) or -EINVAL on failure + * acpi_pm_device_sleep_state - Get preferred power state of ACPI device. + * @dev: Device whose preferred target power state to return. + * @d_min_p: Location to store the upper limit of the allowed states range. + * @d_max_in: Deepest low-power state to take into consideration. + * Return value: Preferred power state of the device on success, -ENODEV + * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure * - * Find the lowest power (highest number) ACPI device power state that - * device @dev can be in while the system is in the sleep state represented - * by %acpi_target_sleep_state. If @wake is nonzero, the device should be - * able to wake up the system from this sleep state. If @d_min_p is set, - * the highest power (lowest number) device power state of @dev allowed - * in this system sleep state is stored at the location pointed to by it. + * Find the lowest power (highest number) ACPI device power state that the + * device can be in while the system is in the sleep state represented + * by %acpi_target_sleep_state. If @d_min_p is set, the highest power (lowest + * number) device power state that @dev can be in for the given system sleep + * state is stored at the location pointed to by it. * - * The caller must ensure that @dev is valid before using this function. - * The caller is also responsible for figuring out if the device is - * supposed to be able to wake up the system and passing this information - * via @wake. + * The caller must ensure that @dev is valid before using this function. */ - int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) { acpi_handle handle = DEVICE_ACPI_HANDLE(dev); @@ -797,14 +790,15 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) EXPORT_SYMBOL(acpi_pm_device_sleep_state); #endif /* CONFIG_PM */ -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM_RUNTIME /** - * acpi_pm_device_run_wake - Enable/disable wake-up for given device. - * @phys_dev: Device to enable/disable the platform to wake-up the system for. - * @enable: Whether enable or disable the wake-up functionality. + * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. + * @phys_dev: Device to enable/disable the platform to wake up. + * @enable: Whether to enable or disable the wakeup functionality. * - * Find the ACPI device object corresponding to @pci_dev and try to - * enable/disable the GPE associated with it. + * Find the ACPI device object corresponding to @phys_dev and try to + * enable/disable the GPE associated with it, so that it can generate + * wakeup signals for the device in response to external (remote) events. */ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) { @@ -832,12 +826,13 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) return 0; } EXPORT_SYMBOL(acpi_pm_device_run_wake); +#endif /* CONFIG_PM_RUNTIME */ +#ifdef CONFIG_PM_SLEEP /** - * acpi_pm_device_sleep_wake - enable or disable the system wake-up - * capability of given device - * @dev: device to handle - * @enable: 'true' - enable, 'false' - disable the wake-up capability + * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. + * @dev: Device to enable/desible to wake up the system from sleep states. + * @enable: Whether to enable or disable @dev to wake up the system. */ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0daa0fbd865..72053db9c2e 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -426,14 +426,18 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) } #endif -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM_RUNTIME int acpi_pm_device_run_wake(struct device *, bool); -int acpi_pm_device_sleep_wake(struct device *, bool); #else static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) { return -ENODEV; } +#endif + +#ifdef CONFIG_PM_SLEEP +int acpi_pm_device_sleep_wake(struct device *, bool); +#else static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) { return -ENODEV; -- cgit v1.2.3 From ec2cd81ccfc055155ef4ca673f207168f516d287 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:40:09 +0100 Subject: ACPI / PM: Move routines for adding/removing device wakeup notifiers ACPI routines for adding and removing device wakeup notifiers are currently defined in a PCI-specific file, but they will be necessary for non-PCI devices too, so move them to a separate file under drivers/acpi and rename them to indicate their ACPI origins. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 3 +- drivers/acpi/device_pm.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci-acpi.c | 71 +++---------------------------------- include/acpi/acpi_bus.h | 15 ++++++++ 4 files changed, 112 insertions(+), 68 deletions(-) create mode 100644 drivers/acpi/device_pm.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 82422fe90f8..a2711fae62d 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -21,9 +21,10 @@ obj-y += acpi.o \ acpi-y += osl.o utils.o reboot.o acpi-y += nvs.o -# sleep related files +# Power management related files acpi-y += wakeup.o acpi-y += sleep.o +acpi-$(CONFIG_PM) += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c new file mode 100644 index 00000000000..2d2e0bc8891 --- /dev/null +++ b/drivers/acpi/device_pm.c @@ -0,0 +1,91 @@ +/* + * drivers/acpi/device_pm.c - ACPI device power management routines. + * + * Copyright (C) 2012, Intel Corp. + * Author: Rafael J. Wysocki + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include + +#include +#include + +static DEFINE_MUTEX(acpi_pm_notifier_lock); + +/** + * acpi_add_pm_notifier - Register PM notifier for given ACPI device. + * @adev: ACPI device to add the notifier for. + * @context: Context information to pass to the notifier routine. + * + * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of + * PM wakeup events. For example, wakeup events may be generated for bridges + * if one of the devices below the bridge is signaling wakeup, even if the + * bridge itself doesn't have a wakeup GPE associated with it. + */ +acpi_status acpi_add_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler, void *context) +{ + acpi_status status = AE_ALREADY_EXISTS; + + mutex_lock(&acpi_pm_notifier_lock); + + if (adev->wakeup.flags.notifier_present) + goto out; + + status = acpi_install_notify_handler(adev->handle, + ACPI_SYSTEM_NOTIFY, + handler, context); + if (ACPI_FAILURE(status)) + goto out; + + adev->wakeup.flags.notifier_present = true; + + out: + mutex_unlock(&acpi_pm_notifier_lock); + return status; +} + +/** + * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. + * @adev: ACPI device to remove the notifier from. + */ +acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler) +{ + acpi_status status = AE_BAD_PARAMETER; + + mutex_lock(&acpi_pm_notifier_lock); + + if (!adev->wakeup.flags.notifier_present) + goto out; + + status = acpi_remove_notify_handler(adev->handle, + ACPI_SYSTEM_NOTIFY, + handler); + if (ACPI_FAILURE(status)) + goto out; + + adev->wakeup.flags.notifier_present = false; + + out: + mutex_unlock(&acpi_pm_notifier_lock); + return status; +} diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 63d6618a480..1af4008182f 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -20,8 +20,6 @@ #include #include "pci.h" -static DEFINE_MUTEX(pci_acpi_pm_notify_mtx); - /** * pci_acpi_wake_bus - Wake-up notification handler for root buses. * @handle: ACPI handle of a device the notification is for. @@ -68,67 +66,6 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) pci_pme_wakeup_bus(pci_dev->subordinate); } -/** - * add_pm_notifier - Register PM notifier for given ACPI device. - * @dev: ACPI device to add the notifier for. - * @context: PCI device or bus to check for PME status if an event is signaled. - * - * NOTE: @dev need not be a run-wake or wake-up device to be a valid source of - * PM wake-up events. For example, wake-up events may be generated for bridges - * if one of the devices below the bridge is signaling PME, even if the bridge - * itself doesn't have a wake-up GPE associated with it. - */ -static acpi_status add_pm_notifier(struct acpi_device *dev, - acpi_notify_handler handler, - void *context) -{ - acpi_status status = AE_ALREADY_EXISTS; - - mutex_lock(&pci_acpi_pm_notify_mtx); - - if (dev->wakeup.flags.notifier_present) - goto out; - - status = acpi_install_notify_handler(dev->handle, - ACPI_SYSTEM_NOTIFY, - handler, context); - if (ACPI_FAILURE(status)) - goto out; - - dev->wakeup.flags.notifier_present = true; - - out: - mutex_unlock(&pci_acpi_pm_notify_mtx); - return status; -} - -/** - * remove_pm_notifier - Unregister PM notifier from given ACPI device. - * @dev: ACPI device to remove the notifier from. - */ -static acpi_status remove_pm_notifier(struct acpi_device *dev, - acpi_notify_handler handler) -{ - acpi_status status = AE_BAD_PARAMETER; - - mutex_lock(&pci_acpi_pm_notify_mtx); - - if (!dev->wakeup.flags.notifier_present) - goto out; - - status = acpi_remove_notify_handler(dev->handle, - ACPI_SYSTEM_NOTIFY, - handler); - if (ACPI_FAILURE(status)) - goto out; - - dev->wakeup.flags.notifier_present = false; - - out: - mutex_unlock(&pci_acpi_pm_notify_mtx); - return status; -} - /** * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus. * @dev: ACPI device to add the notifier for. @@ -137,7 +74,7 @@ static acpi_status remove_pm_notifier(struct acpi_device *dev, acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, struct pci_bus *pci_bus) { - return add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus); + return acpi_add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus); } /** @@ -146,7 +83,7 @@ acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, */ acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev) { - return remove_pm_notifier(dev, pci_acpi_wake_bus); + return acpi_remove_pm_notifier(dev, pci_acpi_wake_bus); } /** @@ -157,7 +94,7 @@ acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev) acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, struct pci_dev *pci_dev) { - return add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev); + return acpi_add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev); } /** @@ -166,7 +103,7 @@ acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, */ acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) { - return remove_pm_notifier(dev, pci_acpi_wake_dev); + return acpi_remove_pm_notifier(dev, pci_acpi_wake_dev); } phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 72053db9c2e..6983272f9d0 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -416,8 +416,23 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); int acpi_disable_wakeup_device_power(struct acpi_device *dev); #ifdef CONFIG_PM +acpi_status acpi_add_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler, void *context); +acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler); int acpi_pm_device_sleep_state(struct device *, int *, int); #else +static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler, + void *context) +{ + return AE_SUPPORT; +} +static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler) +{ + return AE_SUPPORT; +} static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) { if (p) -- cgit v1.2.3 From 86b3832c64b6d01092216d84dc6a6b300875d0bb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:40:18 +0100 Subject: ACPI / PM: Move device power state selection routine to device_pm.c The ACPI function for choosing device power state is now located in drivers/acpi/sleep.c, but drivers/acpi/device_pm.c is a more logical place for it, so move it there. However, instead of moving the function entirely, move its core only under a different name and with a different list of arguments, so that it is more flexible, and leave a wrapper around it in the original location. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/sleep.c | 88 ++------------------------------------ include/acpi/acpi_bus.h | 15 ++++++- 3 files changed, 124 insertions(+), 86 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 2d2e0bc8891..c017b801171 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -23,7 +23,9 @@ */ #include +#include #include +#include #include #include @@ -89,3 +91,108 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, mutex_unlock(&acpi_pm_notifier_lock); return status; } + +/** + * acpi_device_power_state - Get preferred power state of ACPI device. + * @dev: Device whose preferred target power state to return. + * @adev: ACPI device node corresponding to @dev. + * @target_state: System state to match the resultant device state. + * @d_max_in: Deepest low-power state to take into consideration. + * @d_min_p: Location to store the upper limit of the allowed states range. + * Return value: Preferred power state of the device on success, -ENODEV + * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure + * + * Find the lowest power (highest number) ACPI device power state that the + * device can be in while the system is in the state represented by + * @target_state. If @d_min_p is set, the highest power (lowest number) device + * power state that @dev can be in for the given system sleep state is stored + * at the location pointed to by it. + * + * Callers must ensure that @dev and @adev are valid pointers and that @adev + * actually corresponds to @dev before using this function. + */ +int acpi_device_power_state(struct device *dev, struct acpi_device *adev, + u32 target_state, int d_max_in, int *d_min_p) +{ + char acpi_method[] = "_SxD"; + unsigned long long d_min, d_max; + bool wakeup = false; + + if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3) + return -EINVAL; + + if (d_max_in > ACPI_STATE_D3_HOT) { + enum pm_qos_flags_status stat; + + stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF); + if (stat == PM_QOS_FLAGS_ALL) + d_max_in = ACPI_STATE_D3_HOT; + } + + acpi_method[2] = '0' + target_state; + /* + * If the sleep state is S0, the lowest limit from ACPI is D3, + * but if the device has _S0W, we will use the value from _S0W + * as the lowest limit from ACPI. Finally, we will constrain + * the lowest limit with the specified one. + */ + d_min = ACPI_STATE_D0; + d_max = ACPI_STATE_D3; + + /* + * If present, _SxD methods return the minimum D-state (highest power + * state) we can use for the corresponding S-states. Otherwise, the + * minimum D-state is D0 (ACPI 3.x). + * + * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer + * provided -- that's our fault recovery, we ignore retval. + */ + if (target_state > ACPI_STATE_S0) { + acpi_evaluate_integer(adev->handle, acpi_method, NULL, &d_min); + wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid + && adev->wakeup.sleep_state >= target_state; + } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) != + PM_QOS_FLAGS_NONE) { + wakeup = adev->wakeup.flags.valid; + } + + /* + * If _PRW says we can wake up the system from the target sleep state, + * the D-state returned by _SxD is sufficient for that (we assume a + * wakeup-aware driver if wake is set). Still, if _SxW exists + * (ACPI 3.x), it should return the maximum (lowest power) D-state that + * can wake the system. _S0W may be valid, too. + */ + if (wakeup) { + acpi_status status; + + acpi_method[3] = 'W'; + status = acpi_evaluate_integer(adev->handle, acpi_method, NULL, + &d_max); + if (ACPI_FAILURE(status)) { + if (target_state != ACPI_STATE_S0 || + status != AE_NOT_FOUND) + d_max = d_min; + } else if (d_max < d_min) { + /* Warn the user of the broken DSDT */ + printk(KERN_WARNING "ACPI: Wrong value from %s\n", + acpi_method); + /* Sanitize it */ + d_min = d_max; + } + } + + if (d_max_in < d_min) + return -EINVAL; + if (d_min_p) + *d_min_p = d_min; + /* constrain d_max with specified lowest limit (max number) */ + if (d_max > d_max_in) { + for (d_max = d_max_in; d_max > d_min; d_max--) { + if (adev->power.states[d_max].flags.valid) + break; + } + } + return d_max; +} +EXPORT_SYMBOL_GPL(acpi_device_power_state); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 4defa0297ee..fa20d017188 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -19,7 +19,6 @@ #include #include #include -#include #include @@ -691,101 +690,20 @@ int acpi_suspend(u32 acpi_state) * Return value: Preferred power state of the device on success, -ENODEV * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure * - * Find the lowest power (highest number) ACPI device power state that the - * device can be in while the system is in the sleep state represented - * by %acpi_target_sleep_state. If @d_min_p is set, the highest power (lowest - * number) device power state that @dev can be in for the given system sleep - * state is stored at the location pointed to by it. - * * The caller must ensure that @dev is valid before using this function. */ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) { acpi_handle handle = DEVICE_ACPI_HANDLE(dev); struct acpi_device *adev; - char acpi_method[] = "_SxD"; - unsigned long long d_min, d_max; - bool wakeup = false; - if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3) - return -EINVAL; if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { - printk(KERN_DEBUG "ACPI handle has no context!\n"); + dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); return -ENODEV; } - if (d_max_in > ACPI_STATE_D3_HOT) { - enum pm_qos_flags_status stat; - - stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF); - if (stat == PM_QOS_FLAGS_ALL) - d_max_in = ACPI_STATE_D3_HOT; - } - - acpi_method[2] = '0' + acpi_target_sleep_state; - /* - * If the sleep state is S0, the lowest limit from ACPI is D3, - * but if the device has _S0W, we will use the value from _S0W - * as the lowest limit from ACPI. Finally, we will constrain - * the lowest limit with the specified one. - */ - d_min = ACPI_STATE_D0; - d_max = ACPI_STATE_D3; - - /* - * If present, _SxD methods return the minimum D-state (highest power - * state) we can use for the corresponding S-states. Otherwise, the - * minimum D-state is D0 (ACPI 3.x). - * - * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer - * provided -- that's our fault recovery, we ignore retval. - */ - if (acpi_target_sleep_state > ACPI_STATE_S0) { - acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); - wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid - && adev->wakeup.sleep_state >= acpi_target_sleep_state; - } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) != - PM_QOS_FLAGS_NONE) { - wakeup = adev->wakeup.flags.valid; - } - - /* - * If _PRW says we can wake up the system from the target sleep state, - * the D-state returned by _SxD is sufficient for that (we assume a - * wakeup-aware driver if wake is set). Still, if _SxW exists - * (ACPI 3.x), it should return the maximum (lowest power) D-state that - * can wake the system. _S0W may be valid, too. - */ - if (wakeup) { - acpi_status status; - - acpi_method[3] = 'W'; - status = acpi_evaluate_integer(handle, acpi_method, NULL, - &d_max); - if (ACPI_FAILURE(status)) { - if (acpi_target_sleep_state != ACPI_STATE_S0 || - status != AE_NOT_FOUND) - d_max = d_min; - } else if (d_max < d_min) { - /* Warn the user of the broken DSDT */ - printk(KERN_WARNING "ACPI: Wrong value from %s\n", - acpi_method); - /* Sanitize it */ - d_min = d_max; - } - } - if (d_max_in < d_min) - return -EINVAL; - if (d_min_p) - *d_min_p = d_min; - /* constrain d_max with specified lowest limit (max number) */ - if (d_max > d_max_in) { - for (d_max = d_max_in; d_max > d_min; d_max--) { - if (adev->power.states[d_max].flags.valid) - break; - } - } - return d_max; + return acpi_device_power_state(dev, adev, acpi_target_sleep_state, + d_max_in, d_min_p); } EXPORT_SYMBOL(acpi_pm_device_sleep_state); #endif /* CONFIG_PM */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6983272f9d0..a8080dfe718 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -420,6 +420,8 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, acpi_notify_handler handler, void *context); acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, acpi_notify_handler handler); +int acpi_device_power_state(struct device *dev, struct acpi_device *adev, + u32 target_state, int d_max_in, int *d_min_p); int acpi_pm_device_sleep_state(struct device *, int *, int); #else static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev, @@ -433,12 +435,23 @@ static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, { return AE_SUPPORT; } -static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) +static inline int __acpi_device_power_state(int m, int *p) { if (p) *p = ACPI_STATE_D0; return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0; } +static inline int acpi_device_power_state(struct device *dev, + struct acpi_device *adev, + u32 target_state, int d_max_in, + int *d_min_p) +{ + return __acpi_device_power_state(d_max_in, d_min_p); +} +static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) +{ + return __acpi_device_power_state(m, p); +} #endif #ifdef CONFIG_PM_RUNTIME -- cgit v1.2.3 From cd7bd02d319eb34fa33d1705cf63f64928643708 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:40:28 +0100 Subject: ACPI / PM: Move runtime remote wakeup setup routine to device_pm.c The ACPI function for setting up devices to do runtime remote wakeup is now located in drivers/acpi/sleep.c, but drivers/acpi/device_pm.c is a more logical place for it, so move it there. No functional changes should result from this modification. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/acpi/sleep.c | 39 --------------------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index c017b801171..81052981045 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -196,3 +197,41 @@ int acpi_device_power_state(struct device *dev, struct acpi_device *adev, return d_max; } EXPORT_SYMBOL_GPL(acpi_device_power_state); + +#ifdef CONFIG_PM_RUNTIME +/** + * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. + * @phys_dev: Device to enable/disable the platform to wake up. + * @enable: Whether to enable or disable the wakeup functionality. + * + * Find the ACPI device object corresponding to @phys_dev and try to + * enable/disable the GPE associated with it, so that it can generate + * wakeup signals for the device in response to external (remote) events. + */ +int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) +{ + struct acpi_device *dev; + acpi_handle handle; + + if (!device_run_wake(phys_dev)) + return -EINVAL; + + handle = DEVICE_ACPI_HANDLE(phys_dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) { + dev_dbg(phys_dev, "ACPI handle has no context in %s!\n", + __func__); + return -ENODEV; + } + + if (enable) { + acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); + acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); + } else { + acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); + acpi_disable_wakeup_device_power(dev); + } + + return 0; +} +EXPORT_SYMBOL(acpi_pm_device_run_wake); +#endif /* CONFIG_PM_RUNTIME */ diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fa20d017188..241304ee406 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -18,7 +18,6 @@ #include #include #include -#include #include @@ -708,44 +707,6 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) EXPORT_SYMBOL(acpi_pm_device_sleep_state); #endif /* CONFIG_PM */ -#ifdef CONFIG_PM_RUNTIME -/** - * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. - * @phys_dev: Device to enable/disable the platform to wake up. - * @enable: Whether to enable or disable the wakeup functionality. - * - * Find the ACPI device object corresponding to @phys_dev and try to - * enable/disable the GPE associated with it, so that it can generate - * wakeup signals for the device in response to external (remote) events. - */ -int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) -{ - struct acpi_device *dev; - acpi_handle handle; - - if (!device_run_wake(phys_dev)) - return -EINVAL; - - handle = DEVICE_ACPI_HANDLE(phys_dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) { - dev_dbg(phys_dev, "ACPI handle has no context in %s!\n", - __func__); - return -ENODEV; - } - - if (enable) { - acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); - acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - } else { - acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - acpi_disable_wakeup_device_power(dev); - } - - return 0; -} -EXPORT_SYMBOL(acpi_pm_device_run_wake); -#endif /* CONFIG_PM_RUNTIME */ - #ifdef CONFIG_PM_SLEEP /** * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. -- cgit v1.2.3 From dee8370cc87e505ef39567f0974e73d59e75d76b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:40:36 +0100 Subject: ACPI / PM: Split device wakeup management routines Two device wakeup management routines in device_pm.c and sleep.c, acpi_pm_device_run_wake() and acpi_pm_device_sleep_wake(), take a device pointer argument and use it to obtain the ACPI handle of the corresponding ACPI namespace node. That handle is then used to get the address of the struct acpi_device object corresponding to the struct device passed as the argument. Unfortunately, that last operation may be costly, because it involves taking the global ACPI namespace mutex, so it shouldn't be carried out too often. However, the callers of those routines usually call them in a row with acpi_pm_device_sleep_state() which also takes that mutex for the same reason, so it would be more efficient if they ran acpi_bus_get_device() themselves to obtain a pointer to the struct acpi_device object in question and then passed that pointer to the appropriate PM routines. To make that possible, split each of the PM routines mentioned above in two parts, one taking a struct acpi_device pointer argument and the other implementing the current interface for compatibility. Additionally, change acpi_pm_device_run_wake() to actually return an error code if there is an error while setting up runtime remote wakeup for the device. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 74 +++++++++++++++++++++++++++++++++++++----------- drivers/acpi/sleep.c | 8 ++---- include/acpi/acpi_bus.h | 11 +++++++ 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 81052981045..b4f03f91b0b 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -200,38 +200,78 @@ EXPORT_SYMBOL_GPL(acpi_device_power_state); #ifdef CONFIG_PM_RUNTIME /** - * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. - * @phys_dev: Device to enable/disable the platform to wake up. + * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. + * @adev: ACPI device to enable/disable the remote wakeup for. * @enable: Whether to enable or disable the wakeup functionality. * - * Find the ACPI device object corresponding to @phys_dev and try to - * enable/disable the GPE associated with it, so that it can generate - * wakeup signals for the device in response to external (remote) events. + * Enable/disable the GPE associated with @adev so that it can generate + * wakeup signals for the device in response to external (remote) events and + * enable/disable device wakeup power. + * + * Callers must ensure that @adev is a valid ACPI device node before executing + * this function. + */ +int __acpi_device_run_wake(struct acpi_device *adev, bool enable) +{ + struct acpi_device_wakeup *wakeup = &adev->wakeup; + + if (enable) { + acpi_status res; + int error; + + error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0); + if (error) + return error; + + res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); + if (ACPI_FAILURE(res)) { + acpi_disable_wakeup_device_power(adev); + return -EIO; + } + } else { + acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); + acpi_disable_wakeup_device_power(adev); + } + return 0; +} + +/** + * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. + * @dev: Device to enable/disable the platform to wake up. + * @enable: Whether to enable or disable the wakeup functionality. */ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) { - struct acpi_device *dev; + struct acpi_device *adev; acpi_handle handle; if (!device_run_wake(phys_dev)) return -EINVAL; handle = DEVICE_ACPI_HANDLE(phys_dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) { - dev_dbg(phys_dev, "ACPI handle has no context in %s!\n", + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { + dev_dbg(phys_dev, "ACPI handle without context in %s!\n", __func__); return -ENODEV; } - if (enable) { - acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); - acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - } else { - acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - acpi_disable_wakeup_device_power(dev); - } - - return 0; + return __acpi_device_run_wake(adev, enable); } EXPORT_SYMBOL(acpi_pm_device_run_wake); #endif /* CONFIG_PM_RUNTIME */ + + #ifdef CONFIG_PM_SLEEP +/** + * __acpi_device_sleep_wake - Enable or disable device to wake up the system. + * @dev: Device to enable/desible to wake up the system. + * @target_state: System state the device is supposed to wake up from. + * @enable: Whether to enable or disable @dev to wake up the system. + */ +int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state, + bool enable) +{ + return enable ? + acpi_enable_wakeup_device_power(adev, target_state) : + acpi_disable_wakeup_device_power(adev); +} +#endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 241304ee406..77c517f6f6d 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -724,15 +724,13 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) handle = DEVICE_ACPI_HANDLE(dev); if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { - dev_dbg(dev, "ACPI handle has no context in %s!\n", __func__); + dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); return -ENODEV; } - error = enable ? - acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : - acpi_disable_wakeup_device_power(adev); + error = __acpi_device_sleep_wake(adev, acpi_target_sleep_state, enable); if (!error) - dev_info(dev, "wake-up capability %s by ACPI\n", + dev_info(dev, "System wakeup %s by ACPI\n", enable ? "enabled" : "disabled"); return error; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a8080dfe718..a635942bcd5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -455,8 +455,13 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) #endif #ifdef CONFIG_PM_RUNTIME +int __acpi_device_run_wake(struct acpi_device *, bool); int acpi_pm_device_run_wake(struct device *, bool); #else +static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en) +{ + return -ENODEV; +} static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) { return -ENODEV; @@ -464,8 +469,14 @@ static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) #endif #ifdef CONFIG_PM_SLEEP +int __acpi_device_sleep_wake(struct acpi_device *, u32, bool); int acpi_pm_device_sleep_wake(struct device *, bool); #else +static inline int __acpi_device_sleep_wake(struct acpi_device *adev, + u32 target_state, bool enable) +{ + return -ENODEV; +} static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) { return -ENODEV; -- cgit v1.2.3 From 078eb12648c2f8bba48921f60ec2cec3e1bbc051 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:40:45 +0100 Subject: ACPI / PM: Provide device PM functions operating on struct acpi_device If the caller of acpi_bus_set_power() already has a pointer to the struct acpi_device object corresponding to the device in question, it doesn't make sense for it to go through acpi_bus_get_device(), which may be costly, because it involves acquiring the global ACPI namespace mutex. For this reason, export the function operating on struct acpi_device objects used internally by acpi_bus_set_power(), so that it may be called instead of acpi_bus_set_power() in the above case, and change its name to acpi_device_set_power(). Additionally, introduce two inline wrappers for checking ACPI PM capabilities of devices represented by struct acpi_device objects. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 15 ++++++++++++--- include/acpi/acpi_bus.h | 11 +++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d59175efc42..07a20ee3e69 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -257,7 +257,15 @@ static int __acpi_bus_get_power(struct acpi_device *device, int *state) } -static int __acpi_bus_set_power(struct acpi_device *device, int state) +/** + * acpi_device_set_power - Set power state of an ACPI device. + * @device: Device to set the power state of. + * @state: New power state to set. + * + * Callers must ensure that the device is power manageable before using this + * function. + */ +int acpi_device_set_power(struct acpi_device *device, int state) { int result = 0; acpi_status status = AE_OK; @@ -341,6 +349,7 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) return result; } +EXPORT_SYMBOL(acpi_device_set_power); int acpi_bus_set_power(acpi_handle handle, int state) @@ -359,7 +368,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) return -ENODEV; } - return __acpi_bus_set_power(device, state); + return acpi_device_set_power(device, state); } EXPORT_SYMBOL(acpi_bus_set_power); @@ -402,7 +411,7 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) if (result) return result; - result = __acpi_bus_set_power(device, state); + result = acpi_device_set_power(device, state); if (!result && state_p) *state_p = state; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a635942bcd5..35812b6e042 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -339,6 +339,7 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_set_power(acpi_handle handle, int state); +int acpi_device_set_power(struct acpi_device *device, int state); int acpi_bus_update_power(acpi_handle handle, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); bool acpi_bus_can_wakeup(acpi_handle handle); @@ -483,6 +484,16 @@ static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) } #endif +static inline bool acpi_device_power_manageable(struct acpi_device *adev) +{ + return adev->flags.power_manageable; +} + +static inline bool acpi_device_can_wakeup(struct acpi_device *adev) +{ + return adev->wakeup.flags.valid; +} + #else /* CONFIG_ACPI */ static inline int register_acpi_bus_type(void *bus) { return 0; } -- cgit v1.2.3 From a6ae7594b1b157e0e7976ed105a7be27d69a5361 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:40:53 +0100 Subject: ACPI / PM: Move device PM functions related to sleep states Introduce helper function returning the target sleep state of the system and use it to move the remaining device power management functions from sleep.c to device_pm.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 54 +++++++++++++++++++++++++++++++++++++++++ drivers/acpi/sleep.c | 63 +++++------------------------------------------- include/acpi/acpi_bus.h | 2 ++ 3 files changed, 62 insertions(+), 57 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index b4f03f91b0b..7ddd93463a2 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -198,6 +198,31 @@ int acpi_device_power_state(struct device *dev, struct acpi_device *adev, } EXPORT_SYMBOL_GPL(acpi_device_power_state); +/** + * acpi_pm_device_sleep_state - Get preferred power state of ACPI device. + * @dev: Device whose preferred target power state to return. + * @d_min_p: Location to store the upper limit of the allowed states range. + * @d_max_in: Deepest low-power state to take into consideration. + * Return value: Preferred power state of the device on success, -ENODEV + * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure + * + * The caller must ensure that @dev is valid before using this function. + */ +int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + struct acpi_device *adev; + + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { + dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); + return -ENODEV; + } + + return acpi_device_power_state(dev, adev, acpi_target_system_state(), + d_max_in, d_min_p); +} +EXPORT_SYMBOL(acpi_pm_device_sleep_state); + #ifdef CONFIG_PM_RUNTIME /** * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. @@ -274,4 +299,33 @@ int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state, acpi_enable_wakeup_device_power(adev, target_state) : acpi_disable_wakeup_device_power(adev); } + +/** + * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. + * @dev: Device to enable/desible to wake up the system from sleep states. + * @enable: Whether to enable or disable @dev to wake up the system. + */ +int acpi_pm_device_sleep_wake(struct device *dev, bool enable) +{ + acpi_handle handle; + struct acpi_device *adev; + int error; + + if (!device_can_wakeup(dev)) + return -EINVAL; + + handle = DEVICE_ACPI_HANDLE(dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { + dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); + return -ENODEV; + } + + error = __acpi_device_sleep_wake(adev, acpi_target_system_state(), + enable); + if (!error) + dev_info(dev, "System wakeup %s by ACPI\n", + enable ? "enabled" : "disabled"); + + return error; +} #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 77c517f6f6d..13a285dffac 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -80,6 +80,12 @@ static int acpi_sleep_prepare(u32 acpi_state) #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; + +u32 acpi_target_system_state(void) +{ + return acpi_target_sleep_state; +} + static bool pwr_btn_event_pending; /* @@ -680,63 +686,6 @@ int acpi_suspend(u32 acpi_state) return -EINVAL; } -#ifdef CONFIG_PM -/** - * acpi_pm_device_sleep_state - Get preferred power state of ACPI device. - * @dev: Device whose preferred target power state to return. - * @d_min_p: Location to store the upper limit of the allowed states range. - * @d_max_in: Deepest low-power state to take into consideration. - * Return value: Preferred power state of the device on success, -ENODEV - * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure - * - * The caller must ensure that @dev is valid before using this function. - */ -int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) -{ - acpi_handle handle = DEVICE_ACPI_HANDLE(dev); - struct acpi_device *adev; - - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { - dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); - return -ENODEV; - } - - return acpi_device_power_state(dev, adev, acpi_target_sleep_state, - d_max_in, d_min_p); -} -EXPORT_SYMBOL(acpi_pm_device_sleep_state); -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_SLEEP -/** - * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. - * @dev: Device to enable/desible to wake up the system from sleep states. - * @enable: Whether to enable or disable @dev to wake up the system. - */ -int acpi_pm_device_sleep_wake(struct device *dev, bool enable) -{ - acpi_handle handle; - struct acpi_device *adev; - int error; - - if (!device_can_wakeup(dev)) - return -EINVAL; - - handle = DEVICE_ACPI_HANDLE(dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { - dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); - return -ENODEV; - } - - error = __acpi_device_sleep_wake(adev, acpi_target_sleep_state, enable); - if (!error) - dev_info(dev, "System wakeup %s by ACPI\n", - enable ? "enabled" : "disabled"); - - return error; -} -#endif /* CONFIG_PM_SLEEP */ - static void acpi_power_off_prepare(void) { /* Prepare to power off the system */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 35812b6e042..bf8709a1844 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -470,9 +470,11 @@ static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) #endif #ifdef CONFIG_PM_SLEEP +u32 acpi_target_system_state(void); int __acpi_device_sleep_wake(struct acpi_device *, u32, bool); int acpi_pm_device_sleep_wake(struct device *, bool); #else +static inline u32 acpi_target_system_state(void) { return ACPI_STATE_S0; } static inline int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state, bool enable) { -- cgit v1.2.3 From e5cc8ef31267317f3e177415c84e3f3602e5bfc9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 01:41:01 +0100 Subject: ACPI / PM: Provide ACPI PM callback routines for subsystems Some bus types don't support power management natively, but generally there may be device nodes in ACPI tables corresponding to the devices whose bus types they are (under ACPI 5 those bus types may be SPI, I2C and platform). If that is the case, standard ACPI power management may be applied to those devices, although currently the kernel has no means for that. For this reason, provide a set of routines that may be used as power management callbacks for such devices. This may be done in three different ways. (1) Device drivers handling the devices in question may run acpi_dev_pm_attach() in their .probe() routines, which (on success) will cause the devices to be added to the general ACPI PM domain and ACPI power management will be used for them going forward. Then, acpi_dev_pm_detach() may be used to remove the devices from the general ACPI PM domain if ACPI power management is not necessary for them any more. (2) The devices' subsystems may use acpi_subsys_runtime_suspend(), acpi_subsys_runtime_resume(), acpi_subsys_prepare(), acpi_subsys_suspend_late(), acpi_subsys_resume_early() as their power management callbacks in the same way as the general ACPI PM domain does that. (3) The devices' drivers may execute acpi_dev_suspend_late(), acpi_dev_resume_early(), acpi_dev_runtime_suspend(), acpi_dev_runtime_resume() from their power management callbacks as appropriate, if that's absolutely necessary, but it is not recommended to do that, because such drivers may not work without ACPI support as a result. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 34 +++++ 2 files changed, 351 insertions(+) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 7ddd93463a2..a8e059f69d5 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -224,6 +224,22 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) EXPORT_SYMBOL(acpi_pm_device_sleep_state); #ifdef CONFIG_PM_RUNTIME +/** + * acpi_wakeup_device - Wakeup notification handler for ACPI devices. + * @handle: ACPI handle of the device the notification is for. + * @event: Type of the signaled event. + * @context: Device corresponding to @handle. + */ +static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context) +{ + struct device *dev = context; + + if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) { + pm_wakeup_event(dev, 0); + pm_runtime_resume(dev); + } +} + /** * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. * @adev: ACPI device to enable/disable the remote wakeup for. @@ -283,6 +299,9 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) return __acpi_device_run_wake(adev, enable); } EXPORT_SYMBOL(acpi_pm_device_run_wake); +#else +static inline void acpi_wakeup_device(acpi_handle handle, u32 event, + void *context) {} #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP @@ -329,3 +348,301 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) return error; } #endif /* CONFIG_PM_SLEEP */ + +/** + * acpi_dev_pm_get_node - Get ACPI device node for the given physical device. + * @dev: Device to get the ACPI node for. + */ +static struct acpi_device *acpi_dev_pm_get_node(struct device *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + struct acpi_device *adev; + + return handle && ACPI_SUCCESS(acpi_bus_get_device(handle, &adev)) ? + adev : NULL; +} + +/** + * acpi_dev_pm_low_power - Put ACPI device into a low-power state. + * @dev: Device to put into a low-power state. + * @adev: ACPI device node corresponding to @dev. + * @system_state: System state to choose the device state for. + */ +static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev, + u32 system_state) +{ + int power_state; + + if (!acpi_device_power_manageable(adev)) + return 0; + + power_state = acpi_device_power_state(dev, adev, system_state, + ACPI_STATE_D3, NULL); + if (power_state < ACPI_STATE_D0 || power_state > ACPI_STATE_D3) + return -EIO; + + return acpi_device_set_power(adev, power_state); +} + +/** + * acpi_dev_pm_full_power - Put ACPI device into the full-power state. + * @adev: ACPI device node to put into the full-power state. + */ +static int acpi_dev_pm_full_power(struct acpi_device *adev) +{ + return acpi_device_power_manageable(adev) ? + acpi_device_set_power(adev, ACPI_STATE_D0) : 0; +} + +#ifdef CONFIG_PM_RUNTIME +/** + * acpi_dev_runtime_suspend - Put device into a low-power state using ACPI. + * @dev: Device to put into a low-power state. + * + * Put the given device into a runtime low-power state using the standard ACPI + * mechanism. Set up remote wakeup if desired, choose the state to put the + * device into (this checks if remote wakeup is expected to work too), and set + * the power state of the device. + */ +int acpi_dev_runtime_suspend(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + bool remote_wakeup; + int error; + + if (!adev) + return 0; + + remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) > + PM_QOS_FLAGS_NONE; + error = __acpi_device_run_wake(adev, remote_wakeup); + if (remote_wakeup && error) + return -EAGAIN; + + error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); + if (error) + __acpi_device_run_wake(adev, false); + + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend); + +/** + * acpi_dev_runtime_resume - Put device into the full-power state using ACPI. + * @dev: Device to put into the full-power state. + * + * Put the given device into the full-power state using the standard ACPI + * mechanism at run time. Set the power state of the device to ACPI D0 and + * disable remote wakeup. + */ +int acpi_dev_runtime_resume(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + int error; + + if (!adev) + return 0; + + error = acpi_dev_pm_full_power(adev); + __acpi_device_run_wake(adev, false); + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume); + +/** + * acpi_subsys_runtime_suspend - Suspend device using ACPI. + * @dev: Device to suspend. + * + * Carry out the generic runtime suspend procedure for @dev and use ACPI to put + * it into a runtime low-power state. + */ +int acpi_subsys_runtime_suspend(struct device *dev) +{ + int ret = pm_generic_runtime_suspend(dev); + return ret ? ret : acpi_dev_runtime_suspend(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend); + +/** + * acpi_subsys_runtime_resume - Resume device using ACPI. + * @dev: Device to Resume. + * + * Use ACPI to put the given device into the full-power state and carry out the + * generic runtime resume procedure for it. + */ +int acpi_subsys_runtime_resume(struct device *dev) +{ + int ret = acpi_dev_runtime_resume(dev); + return ret ? ret : pm_generic_runtime_resume(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * acpi_dev_suspend_late - Put device into a low-power state using ACPI. + * @dev: Device to put into a low-power state. + * + * Put the given device into a low-power state during system transition to a + * sleep state using the standard ACPI mechanism. Set up system wakeup if + * desired, choose the state to put the device into (this checks if system + * wakeup is expected to work too), and set the power state of the device. + */ +int acpi_dev_suspend_late(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + u32 target_state; + bool wakeup; + int error; + + if (!adev) + return 0; + + target_state = acpi_target_system_state(); + wakeup = device_may_wakeup(dev); + error = __acpi_device_sleep_wake(adev, target_state, wakeup); + if (wakeup && error) + return error; + + error = acpi_dev_pm_low_power(dev, adev, target_state); + if (error) + __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); + + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_suspend_late); + +/** + * acpi_dev_resume_early - Put device into the full-power state using ACPI. + * @dev: Device to put into the full-power state. + * + * Put the given device into the full-power state using the standard ACPI + * mechanism during system transition to the working state. Set the power + * state of the device to ACPI D0 and disable remote wakeup. + */ +int acpi_dev_resume_early(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + int error; + + if (!adev) + return 0; + + error = acpi_dev_pm_full_power(adev); + __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_resume_early); + +/** + * acpi_subsys_prepare - Prepare device for system transition to a sleep state. + * @dev: Device to prepare. + */ +int acpi_subsys_prepare(struct device *dev) +{ + /* + * Follow PCI and resume devices suspended at run time before running + * their system suspend callbacks. + */ + pm_runtime_resume(dev); + return pm_generic_prepare(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_prepare); + +/** + * acpi_subsys_suspend_late - Suspend device using ACPI. + * @dev: Device to suspend. + * + * Carry out the generic late suspend procedure for @dev and use ACPI to put + * it into a low-power state during system transition into a sleep state. + */ +int acpi_subsys_suspend_late(struct device *dev) +{ + int ret = pm_generic_suspend_late(dev); + return ret ? ret : acpi_dev_suspend_late(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); + +/** + * acpi_subsys_resume_early - Resume device using ACPI. + * @dev: Device to Resume. + * + * Use ACPI to put the given device into the full-power state and carry out the + * generic early resume procedure for it during system transition into the + * working state. + */ +int acpi_subsys_resume_early(struct device *dev) +{ + int ret = acpi_dev_resume_early(dev); + return ret ? ret : pm_generic_resume_early(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); +#endif /* CONFIG_PM_SLEEP */ + +static struct dev_pm_domain acpi_general_pm_domain = { + .ops = { +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = acpi_subsys_runtime_suspend, + .runtime_resume = acpi_subsys_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +#ifdef CONFIG_PM_SLEEP + .prepare = acpi_subsys_prepare, + .suspend_late = acpi_subsys_suspend_late, + .resume_early = acpi_subsys_resume_early, + .poweroff_late = acpi_subsys_suspend_late, + .restore_early = acpi_subsys_resume_early, +#endif + }, +}; + +/** + * acpi_dev_pm_attach - Prepare device for ACPI power management. + * @dev: Device to prepare. + * + * If @dev has a valid ACPI handle that has a valid struct acpi_device object + * attached to it, install a wakeup notification handler for the device and + * add it to the general ACPI PM domain. + * + * This assumes that the @dev's bus type uses generic power management callbacks + * (or doesn't use any power management callbacks at all). + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +int acpi_dev_pm_attach(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + + if (!adev) + return -ENODEV; + + if (dev->pm_domain) + return -EEXIST; + + acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); + dev->pm_domain = &acpi_general_pm_domain; + return 0; +} +EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); + +/** + * acpi_dev_pm_detach - Remove ACPI power management from the device. + * @dev: Device to take care of. + * + * Remove the device from the general ACPI PM domain and remove its wakeup + * notifier. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +void acpi_dev_pm_detach(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + + if (adev && dev->pm_domain == &acpi_general_pm_domain) { + dev->pm_domain = NULL; + acpi_remove_pm_notifier(adev, acpi_wakeup_device); + } +} +EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 90be9898110..0676b6ac57f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -430,4 +430,38 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, #define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0) #endif +#if defined(CONFIG_ACPI) && defined(CONFIG_PM_RUNTIME) +int acpi_dev_runtime_suspend(struct device *dev); +int acpi_dev_runtime_resume(struct device *dev); +int acpi_subsys_runtime_suspend(struct device *dev); +int acpi_subsys_runtime_resume(struct device *dev); +#else +static inline int acpi_dev_runtime_suspend(struct device *dev) { return 0; } +static inline int acpi_dev_runtime_resume(struct device *dev) { return 0; } +static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; } +static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; } +#endif + +#ifdef CONFIG_ACPI_SLEEP +int acpi_dev_suspend_late(struct device *dev); +int acpi_dev_resume_early(struct device *dev); +int acpi_subsys_prepare(struct device *dev); +int acpi_subsys_suspend_late(struct device *dev); +int acpi_subsys_resume_early(struct device *dev); +#else +static inline int acpi_dev_suspend_late(struct device *dev) { return 0; } +static inline int acpi_dev_resume_early(struct device *dev) { return 0; } +static inline int acpi_subsys_prepare(struct device *dev) { return 0; } +static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } +static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } +#endif + +#if defined(CONFIG_ACPI) && defined(CONFIG_PM) +int acpi_dev_pm_attach(struct device *dev); +int acpi_dev_pm_detach(struct device *dev); +#else +static inline int acpi_dev_pm_attach(struct device *dev) { return -ENODEV; } +static inline void acpi_dev_pm_detach(struct device *dev) {} +#endif + #endif /*_LINUX_ACPI_H*/ -- cgit v1.2.3 From 99926a8cd36b6088448fec41aed4a3b5b05b3679 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Sat, 10 Nov 2012 22:48:33 +0100 Subject: ACPI / PM: Fix build problem related to acpi_target_system_state() Commit b87b49cd0efd ("ACPI / PM: Move device PM functions related to sleep states") declared acpi_target_system_state() for CONFIG_PM_SLEEP whereas it is only defined for CONFIG_ACPI_SLEEP, resulting in the following link error: drivers/built-in.o: In function `acpi_pm_device_sleep_wake': drivers/acpi/device_pm.c:342: undefined reference to `acpi_target_system_state' drivers/built-in.o: In function `acpi_dev_suspend_late': drivers/acpi/device_pm.c:501: undefined reference to `acpi_target_system_state' drivers/built-in.o: In function `acpi_pm_device_sleep_state': drivers/acpi/device_pm.c:221: undefined reference to `acpi_target_system_state' Define it only for CONFIG_ACPI_SLEEP and fallback to a dummy definition for other configs. [rjw: The problem only occurs for exotic .configs in which HIBERNATE_CALLBACKS is selected by XEN_SAVE_RESTORE and neither SUSPEND nor HIBERNATION is set.] Signed-off-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi_bus.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index bf8709a1844..80155fda517 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -470,11 +470,9 @@ static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) #endif #ifdef CONFIG_PM_SLEEP -u32 acpi_target_system_state(void); int __acpi_device_sleep_wake(struct acpi_device *, u32, bool); int acpi_pm_device_sleep_wake(struct device *, bool); #else -static inline u32 acpi_target_system_state(void) { return ACPI_STATE_S0; } static inline int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state, bool enable) { @@ -486,6 +484,12 @@ static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) } #endif +#ifdef CONFIG_ACPI_SLEEP +u32 acpi_target_system_state(void); +#else +static inline u32 acpi_target_system_state(void) { return ACPI_STATE_S0; } +#endif + static inline bool acpi_device_power_manageable(struct acpi_device *adev) { return adev->flags.power_manageable; -- cgit v1.2.3 From f351d027eea545a7996af54fce99f5668a67fec5 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 23 Oct 2012 01:29:27 +0200 Subject: ACPI / EC: Cleanup the member name for spinlock/mutex in struct Current member names for mutex/spinlock are a little confusing. Change the { struct mutex lock; spinlock_t curr_lock; } to { struct mutex mutex; spinlock_t lock; } So that the code is cleaner and easier to read. Signed-off-by: Feng Tang Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 52 ++++++++++++++++++++++++------------------------- drivers/acpi/internal.h | 4 ++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a51df968131..29f349ccf62 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -158,10 +158,10 @@ static int ec_transaction_done(struct acpi_ec *ec) { unsigned long flags; int ret = 0; - spin_lock_irqsave(&ec->curr_lock, flags); + spin_lock_irqsave(&ec->lock, flags); if (!ec->curr || ec->curr->done) ret = 1; - spin_unlock_irqrestore(&ec->curr_lock, flags); + spin_unlock_irqrestore(&ec->lock, flags); return ret; } @@ -175,7 +175,7 @@ static void start_transaction(struct acpi_ec *ec) static void advance_transaction(struct acpi_ec *ec, u8 status) { unsigned long flags; - spin_lock_irqsave(&ec->curr_lock, flags); + spin_lock_irqsave(&ec->lock, flags); if (!ec->curr) goto unlock; if (ec->curr->wlen > ec->curr->wi) { @@ -200,7 +200,7 @@ err: if (in_interrupt()) ++ec->curr->irq_count; unlock: - spin_unlock_irqrestore(&ec->curr_lock, flags); + spin_unlock_irqrestore(&ec->lock, flags); } static int acpi_ec_sync_query(struct acpi_ec *ec); @@ -238,9 +238,9 @@ static int ec_poll(struct acpi_ec *ec) if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) break; pr_debug(PREFIX "controller reset, restart transaction\n"); - spin_lock_irqsave(&ec->curr_lock, flags); + spin_lock_irqsave(&ec->lock, flags); start_transaction(ec); - spin_unlock_irqrestore(&ec->curr_lock, flags); + spin_unlock_irqrestore(&ec->lock, flags); } return -ETIME; } @@ -253,17 +253,17 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, if (EC_FLAGS_MSI) udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ - spin_lock_irqsave(&ec->curr_lock, tmp); + spin_lock_irqsave(&ec->lock, tmp); /* following two actions should be kept atomic */ ec->curr = t; start_transaction(ec); if (ec->curr->command == ACPI_EC_COMMAND_QUERY) clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - spin_unlock_irqrestore(&ec->curr_lock, tmp); + spin_unlock_irqrestore(&ec->lock, tmp); ret = ec_poll(ec); - spin_lock_irqsave(&ec->curr_lock, tmp); + spin_lock_irqsave(&ec->lock, tmp); ec->curr = NULL; - spin_unlock_irqrestore(&ec->curr_lock, tmp); + spin_unlock_irqrestore(&ec->lock, tmp); return ret; } @@ -292,7 +292,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) return -EINVAL; if (t->rdata) memset(t->rdata, 0, t->rlen); - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { status = -EINVAL; goto unlock; @@ -335,7 +335,7 @@ end: if (ec->global_lock) acpi_release_global_lock(glk); unlock: - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); return status; } @@ -468,10 +468,10 @@ void acpi_ec_block_transactions(void) if (!ec) return; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); /* Prevent transactions from being carried out */ set_bit(EC_FLAGS_BLOCKED, &ec->flags); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } void acpi_ec_unblock_transactions(void) @@ -481,10 +481,10 @@ void acpi_ec_unblock_transactions(void) if (!ec) return; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); /* Allow transactions to be carried out again */ clear_bit(EC_FLAGS_BLOCKED, &ec->flags); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } void acpi_ec_unblock_transactions_early(void) @@ -536,9 +536,9 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->handle = handle; handler->func = func; handler->data = data; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); list_add(&handler->node, &ec->list); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); return 0; } @@ -547,14 +547,14 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) { struct acpi_ec_query_handler *handler, *tmp; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { if (query_bit == handler->query_bit) { list_del(&handler->node); kfree(handler); } } - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); @@ -601,9 +601,9 @@ static void acpi_ec_gpe_query(void *ec_cxt) struct acpi_ec *ec = ec_cxt; if (!ec) return; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); acpi_ec_sync_query(ec); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } static int ec_check_sci(struct acpi_ec *ec, u8 state) @@ -691,10 +691,10 @@ static struct acpi_ec *make_acpi_ec(void) if (!ec) return NULL; ec->flags = 1 << EC_FLAGS_QUERY_PENDING; - mutex_init(&ec->lock); + mutex_init(&ec->mutex); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); - spin_lock_init(&ec->curr_lock); + spin_lock_init(&ec->lock); return ec; } @@ -853,12 +853,12 @@ static int acpi_ec_remove(struct acpi_device *device, int type) ec = acpi_driver_data(device); ec_remove_handlers(ec); - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { list_del(&handler->node); kfree(handler); } - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); release_region(ec->data_addr, 1); release_region(ec->command_addr, 1); device->driver_data = NULL; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ca75b9ce048..509dcaa1755 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -58,11 +58,11 @@ struct acpi_ec { unsigned long data_addr; unsigned long global_lock; unsigned long flags; - struct mutex lock; + struct mutex mutex; wait_queue_head_t wait; struct list_head list; struct transaction *curr; - spinlock_t curr_lock; + spinlock_t lock; }; extern struct acpi_ec *first_ec; -- cgit v1.2.3 From b76b51ba0cef13980813373a548a12206e3cd3c9 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 23 Oct 2012 01:29:38 +0200 Subject: ACPI / EC: Add more debug info and trivial code cleanup Add more debug info for EC transaction debugging, like the interrupt status register value, the detail info of a EC transaction. Signed-off-by: Feng Tang Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 29f349ccf62..8f8b644bba8 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -175,30 +175,32 @@ static void start_transaction(struct acpi_ec *ec) static void advance_transaction(struct acpi_ec *ec, u8 status) { unsigned long flags; + struct transaction *t = ec->curr; + spin_lock_irqsave(&ec->lock, flags); - if (!ec->curr) + if (!t) goto unlock; - if (ec->curr->wlen > ec->curr->wi) { + if (t->wlen > t->wi) { if ((status & ACPI_EC_FLAG_IBF) == 0) acpi_ec_write_data(ec, - ec->curr->wdata[ec->curr->wi++]); + t->wdata[t->wi++]); else goto err; - } else if (ec->curr->rlen > ec->curr->ri) { + } else if (t->rlen > t->ri) { if ((status & ACPI_EC_FLAG_OBF) == 1) { - ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec); - if (ec->curr->rlen == ec->curr->ri) - ec->curr->done = true; + t->rdata[t->ri++] = acpi_ec_read_data(ec); + if (t->rlen == t->ri) + t->done = true; } else goto err; - } else if (ec->curr->wlen == ec->curr->wi && + } else if (t->wlen == t->wi && (status & ACPI_EC_FLAG_IBF) == 0) - ec->curr->done = true; + t->done = true; goto unlock; err: /* false interrupt, state didn't change */ if (in_interrupt()) - ++ec->curr->irq_count; + ++t->irq_count; unlock: spin_unlock_irqrestore(&ec->lock, flags); } @@ -310,7 +312,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = -ETIME; goto end; } - pr_debug(PREFIX "transaction start\n"); + pr_debug(PREFIX "transaction start (cmd=0x%02x, addr=0x%02x)\n", + t->command, t->wdata ? t->wdata[0] : 0); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* It has to be disabled, so that it doesn't trigger. */ @@ -326,8 +329,9 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) /* It is safe to enable the GPE outside of the transaction. */ acpi_enable_gpe(NULL, ec->gpe); } else if (t->irq_count > ec_storm_threshold) { - pr_info(PREFIX "GPE storm detected, " - "transactions will use polling mode\n"); + pr_info(PREFIX "GPE storm detected(%d GPEs), " + "transactions will use polling mode\n", + t->irq_count); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } pr_debug(PREFIX "transaction end\n"); @@ -403,7 +407,7 @@ int ec_burst_disable(void) EXPORT_SYMBOL(ec_burst_disable); -int ec_read(u8 addr, u8 * val) +int ec_read(u8 addr, u8 *val) { int err; u8 temp_data; @@ -622,10 +626,11 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number, void *data) { struct acpi_ec *ec = data; + u8 status = acpi_ec_read_status(ec); - pr_debug(PREFIX "~~~> interrupt\n"); + pr_debug(PREFIX "~~~> interrupt, status:0x%02x\n", status); - advance_transaction(ec, acpi_ec_read_status(ec)); + advance_transaction(ec, status); if (ec_transaction_done(ec) && (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { wake_up(&ec->wait); -- cgit v1.2.3 From a3cd8d2789c2e265e09377f260e7d2ac9cec81bb Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 23 Oct 2012 01:30:12 +0200 Subject: ACPI / EC: Don't count a SCI interrupt as a false one Currently when advance_transaction() is called in EC interrupt handler, if there is nothing driver can do with the interrupt, it will be taken as a false one. But this is not always true, as there may be a SCI EC interrupt fired during normal read/write operation, which should not be counted as a false one. This patch fixes the problem. Signed-off-by: Feng Tang Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 8f8b644bba8..354007d490d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -198,9 +198,13 @@ static void advance_transaction(struct acpi_ec *ec, u8 status) t->done = true; goto unlock; err: - /* false interrupt, state didn't change */ - if (in_interrupt()) + /* + * If SCI bit is set, then don't think it's a false IRQ + * otherwise will take a not handled IRQ as a false one. + */ + if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI)) ++t->irq_count; + unlock: spin_unlock_irqrestore(&ec->lock, flags); } -- cgit v1.2.3 From 8ab0ab2570cfc48303e545944f53690a6983a898 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 23 Oct 2012 01:30:26 +0200 Subject: ACPI: dock: Remove redundant ACPI NS walk Combined two ACPI namespace walks, which look for dock stations and then bays separately, into a single walk. Signed-off-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 88eb1430466..ae4ebf2d4cd 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -1016,44 +1016,32 @@ static int dock_remove(struct dock_station *ds) } /** - * find_dock - look for a dock station + * find_dock_and_bay - look for dock stations and bays * @handle: acpi handle of a device * @lvl: unused - * @context: counter of dock stations found + * @context: unused * @rv: unused * - * This is called by acpi_walk_namespace to look for dock stations. + * This is called by acpi_walk_namespace to look for dock stations and bays. */ static __init acpi_status -find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) +find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) { - if (is_dock(handle)) + if (is_dock(handle) || is_ejectable_bay(handle)) dock_add(handle); return AE_OK; } -static __init acpi_status -find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - /* If bay is a dock, it's already handled */ - if (is_ejectable_bay(handle) && !is_dock(handle)) - dock_add(handle); - return AE_OK; -} - static int __init dock_init(void) { if (acpi_disabled) return 0; - /* look for a dock station */ + /* look for dock stations and bays */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock, NULL, NULL, NULL); + ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); - /* look for bay */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_bay, NULL, NULL, NULL); if (!dock_station_count) { printk(KERN_INFO PREFIX "No dock devices found.\n"); return 0; -- cgit v1.2.3 From 73d4511a5f1e208399b2f7a058b73578c1977611 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 23 Oct 2012 01:30:40 +0200 Subject: ACPI: strict_strtoul() and printk() cleanup in acpi_pad Replace a few calls to strict_strtoul() in acpi_pad.c with kstrtoul() and use pr_warn() instead of printk() in the same file. [rjw: Modified the subject and changelog.] Signed-off-by: Josh Taylor Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_pad.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index af4aad6ee2e..16fa979f718 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -286,7 +286,7 @@ static ssize_t acpi_pad_rrtime_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; - if (strict_strtoul(buf, 0, &num)) + if (kstrtoul(buf, 0, &num)) return -EINVAL; if (num < 1 || num >= 100) return -EINVAL; @@ -309,7 +309,7 @@ static ssize_t acpi_pad_idlepct_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; - if (strict_strtoul(buf, 0, &num)) + if (kstrtoul(buf, 0, &num)) return -EINVAL; if (num < 1 || num >= 100) return -EINVAL; @@ -332,7 +332,7 @@ static ssize_t acpi_pad_idlecpus_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; - if (strict_strtoul(buf, 0, &num)) + if (kstrtoul(buf, 0, &num)) return -EINVAL; mutex_lock(&isolated_cpus_lock); acpi_pad_idle_cpus(num); @@ -457,7 +457,7 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, dev_name(&device->dev), event, 0); break; default: - printk(KERN_WARNING "Unsupported event [0x%x]\n", event); + pr_warn("Unsupported event [0x%x]\n", event); break; } } -- cgit v1.2.3 From 5e5041f3527b36b58e864886ba34c179ad40ff92 Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Tue, 23 Oct 2012 01:30:54 +0200 Subject: ACPI / processor: prevent cpu from becoming online Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus(). Why does the patch change _cpu_up() logic? The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race. hot-remove cpu | _cpu_up() ------------------------------------- ------------------------------------ call acpi_processor_handle_eject() | call cpu_down() | call get_online_cpus() | | call cpu_hotplug_begin() and stop here call arch_unregister_cpu() | call acpi_unmap_lsapic() | call put_online_cpus() | | start and continue _cpu_up() return acpi_processor_remove() | continue hot-remove the cpu | So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below: hot-remove cpu | _cpu_up() ----------------------------------------------------------------------- call acpi_processor_handle_eject() | call cpu_down() | call get_online_cpus() | | call cpu_hotplug_begin() and stop here call arch_unregister_cpu() | call acpi_unmap_lsapic() | cpu's cpu_present is set | to false by set_cpu_present()| call put_online_cpus() | | start _cpu_up() | check cpu_present() and return -EINVAL return acpi_processor_remove() | continue hot-remove the cpu | Signed-off-by: Yasuaki Ishimatsu Reviewed-by: Srivatsa S. Bhat Reviewed-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 14 ++++++++++++++ kernel/cpu.c | 8 +++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bd4e5dca3ff..a4352b88a33 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -852,8 +852,22 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) if (cpu_online(pr->id)) cpu_down(pr->id); + get_online_cpus(); + /* + * The cpu might become online again at this point. So we check whether + * the cpu has been onlined or not. If the cpu became online, it means + * that someone wants to use the cpu. So acpi_processor_handle_eject() + * returns -EAGAIN. + */ + if (unlikely(cpu_online(pr->id))) { + put_online_cpus(); + pr_warn("Failed to remove CPU %d, because other task " + "brought the CPU back online\n", pr->id); + return -EAGAIN; + } arch_unregister_cpu(pr->id); acpi_unmap_lsapic(pr->id); + put_online_cpus(); return (0); } #else diff --git a/kernel/cpu.c b/kernel/cpu.c index 42bd331ee0a..f45657f1eb8 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -348,11 +348,13 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; struct task_struct *idle; - if (cpu_online(cpu) || !cpu_present(cpu)) - return -EINVAL; - cpu_hotplug_begin(); + if (cpu_online(cpu) || !cpu_present(cpu)) { + ret = -EINVAL; + goto out; + } + idle = idle_thread_get(cpu); if (IS_ERR(idle)) { ret = PTR_ERR(idle); -- cgit v1.2.3 From 0a290ac4252c85205cb924ff7f6da10cfd20fb01 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 23 Oct 2012 01:31:14 +0200 Subject: ACPI / x86: Add quirk for "CheckPoint P-20-00" to not use bridge _CRS_ info This is to fix a regression https://bugzilla.kernel.org/show_bug.cgi?id=47981 The CheckPoint P-20-00 works ok before new machines (2008 and later) are forced to use the bridge _CRS info by default in 2.6.34. Add this quirk to restore its old way of working: not using bridge _CRS info. Signed-off-by: Feng Tang Signed-off-by: Rafael J. Wysocki --- arch/x86/pci/acpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 192397c9860..7010c199b4f 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -98,6 +98,16 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = { DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), }, }, + /* https://bugzilla.kernel.org/show_bug.cgi?id=47981 */ + { + .callback = set_nouse_crs, + .ident = "CheckPoint P-20-00", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "CheckPoint"), + DMI_MATCH(DMI_PRODUCT_NAME, "P-20-00"), + DMI_MATCH(DMI_BOARD_NAME, "Bridgeport"), + }, + }, {} }; -- cgit v1.2.3 From 594df89a59cf2a2afc22fe27f508dd864d1edb5f Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Fri, 26 Oct 2012 13:38:16 +0200 Subject: ACPI: Fix a hard coding style when determining if a device is a container, v3 "ACPI0004","PNP0A05" and "PNP0A06" are all defined in array container_device_ids[], so use it, but not the hard coding style. Also, introduce a new API is_container_device() to determine if a device is a container device. Signed-off-by: Tang Chen Signed-off-by: Yasuaki Ishimatsu Reviewed-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- drivers/acpi/container.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 1f9f7d7d7bc..69e2d6be910 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -92,6 +92,19 @@ static int is_device_present(acpi_handle handle) return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT); } +static bool is_container_device(const char *hid) +{ + const struct acpi_device_id *container_id; + + for (container_id = container_device_ids; + container_id->id[0]; container_id++) { + if (!strcmp((char *)container_id->id, hid)) + return true; + } + + return false; +} + /*******************************************************************/ static int acpi_container_add(struct acpi_device *device) { @@ -232,10 +245,8 @@ container_walk_namespace_cb(acpi_handle handle, goto end; } - if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") && - strcmp(hid, "PNP0A06")) { + if (!is_container_device(hid)) goto end; - } switch (*action) { case INSTALL_NOTIFY_HANDLER: -- cgit v1.2.3 From b3c450c38075f414077e58439cff6bdce9e47df8 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Fri, 26 Oct 2012 13:38:57 +0200 Subject: ACPI: Fix stale pointer access to flags.lockable During hot-remove, acpi_bus_hot_remove_device() calls ACPI _LCK method when device->flags.lockable is set. However, this device pointer is stale since the target acpi_device object has been already kfree'd by acpi_bus_trim(). The flags.lockable indicates whether or not this ACPI object implements _LCK method. Fix the stable pointer access by replacing it with acpi_get_handle() to check if _LCK is implemented. Signed-off-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1fcb8678665..ed87f433cec 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -97,6 +97,7 @@ void acpi_bus_hot_remove_device(void *context) struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context; struct acpi_device *device; acpi_handle handle = ej_event->handle; + acpi_handle temp; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; @@ -117,13 +118,16 @@ void acpi_bus_hot_remove_device(void *context) goto err_out; } + /* device has been freed */ + device = NULL; + /* power off device */ status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) printk(KERN_WARNING PREFIX "Power-off device failed\n"); - if (device->flags.lockable) { + if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; -- cgit v1.2.3 From f4fa0e018a175ea92a3187ade8f678599dc5980a Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Fri, 26 Oct 2012 13:39:06 +0200 Subject: ACPI: Remove unused lockable in acpi_device_flags Removed lockable in struct acpi_device_flags since it is no longer used by any code. acpi_bus_hot_remove_device() cannot use this flag because acpi_bus_trim() frees up its acpi_device object. Furthermore, the dock driver calls _LCK method without using this lockable flag. Signed-off-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 5 ----- include/acpi/acpi_bus.h | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ed87f433cec..19d3d4a1274 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1017,11 +1017,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) device->flags.ejectable = 1; } - /* Presence of _LCK indicates 'lockable' */ - status = acpi_get_handle(device->handle, "_LCK", &temp); - if (ACPI_SUCCESS(status)) - device->flags.lockable = 1; - /* Power resources cannot be power manageable. */ if (device->device_type == ACPI_BUS_TYPE_POWER) return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0daa0fbd865..e8b2877aea3 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -144,12 +144,11 @@ struct acpi_device_flags { u32 bus_address:1; u32 removable:1; u32 ejectable:1; - u32 lockable:1; u32 suprise_removal_ok:1; u32 power_manageable:1; u32 performance_manageable:1; u32 eject_pending:1; - u32 reserved:23; + u32 reserved:24; }; /* File System */ -- cgit v1.2.3 From 1bad2f19f7f79d1ec9e6c48168fd7ce8dc1c305f Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Fri, 26 Oct 2012 13:39:15 +0200 Subject: ACPI / Sleep: add acpi_sleep=nonvs_s3 parameter The ACPI specificiation would like us to save NVS at hibernation time, but makes no mention of saving NVS over S3. Not all versions of Windows do this either, and it is clear that not all machines need NVS saved/restored over S3. Allow the user to improve their suspend/resume time by disabling the NVS save/restore at S3 time, but continue to do the NVS save/restore for S4 as specified. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep.c | 17 ++++++++++++++++- include/linux/acpi.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 11676cf65ae..d5e0d717005 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -101,6 +101,8 @@ static int __init acpi_sleep_setup(char *str) #endif if (strncmp(str, "nonvs", 5) == 0) acpi_nvs_nosave(); + if (strncmp(str, "nonvs_s3", 8) == 0) + acpi_nvs_nosave_s3(); if (strncmp(str, "old_ordering", 12) == 0) acpi_old_suspend_ordering(); str = strchr(str, ','); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fdcdbb65291..8640782944c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -97,6 +97,21 @@ void __init acpi_nvs_nosave(void) nvs_nosave = true; } +/* + * The ACPI specification wants us to save NVS memory regions during hibernation + * but says nothing about saving NVS during S3. Not all versions of Windows + * save NVS on S3 suspend either, and it is clear that not all systems need + * NVS to be saved at S3 time. To improve suspend/resume time, allow the + * user to disable saving NVS on S3 if their system does not require it, but + * continue to save/restore NVS for S4 as specified. + */ +static bool nvs_nosave_s3; + +void __init acpi_nvs_nosave_s3(void) +{ + nvs_nosave_s3 = true; +} + /* * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * user to request that behavior by using the 'acpi_old_suspend_ordering' @@ -243,7 +258,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state) u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; - error = nvs_nosave ? 0 : suspend_nvs_alloc(); + error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc(); if (error) return error; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 90be9898110..3cf93491125 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -261,6 +261,7 @@ int acpi_resources_are_enforced(void); void __init acpi_no_s4_hw_signature(void); void __init acpi_old_suspend_ordering(void); void __init acpi_nvs_nosave(void); +void __init acpi_nvs_nosave_s3(void); #endif /* CONFIG_PM_SLEEP */ struct acpi_osc_context { -- cgit v1.2.3 From 9743fdea9f9473cd2440741342a5ed8e19eb51bd Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Fri, 26 Oct 2012 13:39:24 +0200 Subject: ACPI: move acpi_no_s4_hw_signature() declaration into #ifdef CONFIG_HIBERNATION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_no_s4_hw_signature is defined in #ifdef CONFIG_HIBERNATION block, but the current code put the declaration in #ifdef CONFIG_PM_SLEEP block. I happened to meet this issue when I turned off PM_SLEEP config manually: arch/x86/kernel/acpi/sleep.c:100:4: error: implicit declaration of function ‘acpi_no_s4_hw_signature’ [-Werror=implicit-function-declaration] Signed-off-by: Yuanhan Liu Reviewed-by: Fengguang Wu Signed-off-by: Rafael J. Wysocki --- include/linux/acpi.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3cf93491125..87edfcc0ab6 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -257,8 +257,11 @@ int acpi_check_region(resource_size_t start, resource_size_t n, int acpi_resources_are_enforced(void); -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_HIBERNATION void __init acpi_no_s4_hw_signature(void); +#endif + +#ifdef CONFIG_PM_SLEEP void __init acpi_old_suspend_ordering(void); void __init acpi_nvs_nosave(void); void __init acpi_nvs_nosave_s3(void); -- cgit v1.2.3 From ccf78040265bfce2aac5766e1ddf4fc3dde36899 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 30 Oct 2012 14:41:07 +0100 Subject: ACPI: Add _UID support for ACPI devices. The _UID object is optional, but is required when the device has no other way to report a persistent unique device ID. This patch is required for ACPI 5.0 ACPI enumerated IP cores. Signed-off-by: Lv Zheng Signed-off-by: Rui Zhang Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 19d3d4a1274..daa88d527e8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -381,6 +381,7 @@ static void acpi_device_release(struct device *dev) struct acpi_device *acpi_dev = to_acpi_device(dev); acpi_free_ids(acpi_dev); + kfree(acpi_dev->pnp.unique_id); kfree(acpi_dev); } @@ -1211,6 +1212,9 @@ static void acpi_device_set_id(struct acpi_device *device) device->pnp.bus_address = info->address; device->flags.bus_address = 1; } + if (info->valid & ACPI_VALID_UID) + device->pnp.unique_id = kstrdup(info->unique_id.string, + GFP_KERNEL); kfree(info); -- cgit v1.2.3 From 923d4a45a9d2e350c27b7b7e1c724c19eb921c92 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 30 Oct 2012 14:43:26 +0100 Subject: ACPI: Add user space interface for identification objects ACPI devices are glued with physical devices through _ADR object, ACPI enumerated devices are identified with _UID object. Currently we can observe _HID/_CID through sysfs interfaces (hid/modalias), but there's no way for us to check _ADR/_UID from user space. This patch closes this gap for ACPI developers and users. [rjw: Modified the subject and changelog slightly.] Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index daa88d527e8..86bfa690bc6 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -220,6 +220,25 @@ acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *bu } static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); +static ssize_t acpi_device_uid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); +} +static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); + +static ssize_t acpi_device_adr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "0x%08x\n", + (unsigned int)(acpi_dev->pnp.bus_address)); +} +static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); + static ssize_t acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { struct acpi_device *acpi_dev = to_acpi_device(dev); @@ -304,6 +323,11 @@ static int acpi_device_setup_files(struct acpi_device *dev) goto end; } + if (dev->flags.bus_address) + result = device_create_file(&dev->dev, &dev_attr_adr); + if (dev->pnp.unique_id) + result = device_create_file(&dev->dev, &dev_attr_uid); + /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. @@ -335,6 +359,10 @@ static void acpi_device_remove_files(struct acpi_device *dev) if (ACPI_SUCCESS(status)) device_remove_file(&dev->dev, &dev_attr_eject); + if (dev->pnp.unique_id) + device_remove_file(&dev->dev, &dev_attr_uid); + if (dev->flags.bus_address) + device_remove_file(&dev->dev, &dev_attr_adr); device_remove_file(&dev->dev, &dev_attr_modalias); device_remove_file(&dev->dev, &dev_attr_hid); if (dev->handle) -- cgit v1.2.3 From 61622accd05b158d05f967b627e72da23d64f2ed Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 1 Nov 2012 14:42:12 +0000 Subject: ACPI: Export functions for hot-remove Exported acpi_os_hotplug_execute() and acpi_bus_hot_remove_device() so that they can be called from modules for hot-remove operations. Signed-off-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 1 + drivers/acpi/scan.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 9eaf708f588..7dfe91d0173 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -986,6 +986,7 @@ acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, { return __acpi_os_execute(0, function, context, 1); } +EXPORT_SYMBOL(acpi_os_hotplug_execute); void acpi_os_wait_events_complete(void) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 86bfa690bc6..9d43532d69b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -161,6 +161,7 @@ err_out: kfree(context); return; } +EXPORT_SYMBOL(acpi_bus_hot_remove_device); static ssize_t acpi_eject_store(struct device *d, struct device_attribute *attr, -- cgit v1.2.3 From c5b18e22e74dc7dbd3f7729997a3a553ce761d2b Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 1 Nov 2012 14:42:13 +0000 Subject: ACPI: Add ACPI CPU hot-remove support Added support of CPU hot-remove via an ACPI eject notification. It calls acpi_bus_hot_remove_device(), which shares the same code path with the sysfs eject operation. acpi_os_hotplug_execute() runs the hot-remove operation in kacpi_hotplug_wq and serializes it between ACPI hot-remove and sysfs eject requests. Signed-off-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Tested-by: IgorMammedov Tested-by: Vijay Mohan Pandarathil Tested-by: Prarit Bhargava Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index a4352b88a33..8cc33d0e5d8 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -695,8 +695,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) static void acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_processor *pr; struct acpi_device *device = NULL; + struct acpi_eject_event *ej_event = NULL; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ int result; @@ -728,20 +728,27 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, "received ACPI_NOTIFY_EJECT_REQUEST\n")); if (acpi_bus_get_device(handle, &device)) { - printk(KERN_ERR PREFIX - "Device don't exist, dropping EJECT\n"); + pr_err(PREFIX "Device don't exist, dropping EJECT\n"); break; } - pr = acpi_driver_data(device); - if (!pr) { - printk(KERN_ERR PREFIX - "Driver data is NULL, dropping EJECT\n"); + if (!acpi_driver_data(device)) { + pr_err(PREFIX "Driver data is NULL, dropping EJECT\n"); break; } - /* REVISIT: update when eject is supported */ - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - break; + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); + if (!ej_event) { + pr_err(PREFIX "No memory, dropping EJECT\n"); + break; + } + + ej_event->handle = handle; + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; + acpi_os_hotplug_execute(acpi_bus_hot_remove_device, + (void *)ej_event); + + /* eject is performed asynchronously */ + return; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, -- cgit v1.2.3 From 3ae45a27df74358b4bcd3d5a67e47ad734a48945 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Nov 2012 13:09:08 +0100 Subject: ACPI: Make seemingly useless check in osl.c more understandable There is a seemingly useless check in drivers/acpi/osl.c added by commit bc73675 (ACPI: fixes a false alarm from lockdep), which really is necessary to avoid false positive lockdep complaints. Document this and rearrange the code related to it so that it makes fewer checks. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/osl.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 7dfe91d0173..6dc4a2b1e95 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -932,7 +932,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, * having a static work_struct. */ - dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); + dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) return AE_NO_MEMORY; @@ -944,17 +944,22 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, * because the hotplug code may call driver .remove() functions, * which invoke flush_scheduled_work/acpi_os_wait_events_complete * to flush these workqueues. + * + * To prevent lockdep from complaining unnecessarily, make sure that + * there is a different static lockdep key for each workqueue by using + * INIT_WORK() for each of them separately. */ - queue = hp ? kacpi_hotplug_wq : - (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); - dpc->wait = hp ? 1 : 0; - - if (queue == kacpi_hotplug_wq) + if (hp) { + queue = kacpi_hotplug_wq; + dpc->wait = 1; INIT_WORK(&dpc->work, acpi_os_execute_deferred); - else if (queue == kacpi_notify_wq) + } else if (type == OSL_NOTIFY_HANDLER) { + queue = kacpi_notify_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); - else + } else { + queue = kacpid_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); + } /* * On some machines, a software-initiated SMI causes corruption unless -- cgit v1.2.3 From acacb5f211e99fa2c98cf4ef4c632ab43724adb6 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 29 Oct 2012 17:25:19 +0000 Subject: ACPI: add newline in power.c message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add newline to printk so that the message is on a line by itself and not merged with something unrelated to it. Reported-by: Toralf Förster Signed-off-by: Randy Dunlap Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 40e38a06ba8..7db61b8fa11 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -473,7 +473,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle) return ret; no_power_resource: - printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!"); + printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!\n"); return -ENODEV; } EXPORT_SYMBOL_GPL(acpi_power_resource_register_device); -- cgit v1.2.3 From 54c4c7db6cb94d7d1217df6d7fca6847c61744ab Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Thu, 15 Nov 2012 00:22:27 +0100 Subject: ACPI / memory-hotplug: call acpi_bus_trim() to remove memory device The memory device has been ejected and powoffed, so we can call acpi_bus_trim() to remove the memory device from acpi bus. Signed-off-by: Wen Congyang Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 24c807f9663..1e90e8f0100 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -401,8 +401,9 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) } /* - * TBD: Invoke acpi_bus_remove to cleanup data structures + * Invoke acpi_bus_trim() to remove memory device */ + acpi_bus_trim(device, 1); /* _EJ0 succeeded; _OST is not necessary */ return; -- cgit v1.2.3 From 06f64c8f239a47b359c60301914c783b56b32c13 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 31 Oct 2012 22:44:33 +0100 Subject: driver core / ACPI: Move ACPI support to core device and driver types With ACPI 5 we are starting to see devices that don't natively support discovery but can be enumerated with the help of the ACPI namespace. Typically, these devices can be represented in the Linux device driver model as platform devices or some serial bus devices, like SPI or I2C devices. Since we want to re-use existing drivers for those devices, we need a way for drivers to specify the ACPI IDs of supported devices, so that they can be matched against device nodes in the ACPI namespace. To this end, it is sufficient to add a pointer to an array of supported ACPI device IDs, that can be provided by the driver, to struct device. Moreover, things like ACPI power management need to have access to the ACPI handle of each supported device, because that handle is used to invoke AML methods associated with the corresponding ACPI device node. The ACPI handles of devices are now stored in the archdata member structure of struct device whose definition depends on the architecture and includes the ACPI handle only on x86 and ia64. Since the pointer to an array of supported ACPI IDs is added to struct device_driver in an architecture-independent way, it is logical to move the ACPI handle from archdata to struct device itself at the same time. This also makes code more straightforward in some places and follows the example of Device Trees that have a poiter to struct device_node in there too. This changeset is based on Mika Westerberg's work. Signed-off-by: Mika Westerberg Acked-by: Greg Kroah-Hartman Acked-by: H. Peter Anvin Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/device.h | 3 --- arch/x86/include/asm/device.h | 3 --- drivers/acpi/glue.c | 14 ++++++-------- include/acpi/acpi_bus.h | 2 +- include/linux/device.h | 4 ++++ 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/arch/ia64/include/asm/device.h b/arch/ia64/include/asm/device.h index d05e78f6db9..f69c32ffbe6 100644 --- a/arch/ia64/include/asm/device.h +++ b/arch/ia64/include/asm/device.h @@ -7,9 +7,6 @@ #define _ASM_IA64_DEVICE_H struct dev_archdata { -#ifdef CONFIG_ACPI - void *acpi_handle; -#endif #ifdef CONFIG_INTEL_IOMMU void *iommu; /* hook for IOMMU specific extension */ #endif diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h index 93e1c55f14a..03dd72957d2 100644 --- a/arch/x86/include/asm/device.h +++ b/arch/x86/include/asm/device.h @@ -2,9 +2,6 @@ #define _ASM_X86_DEVICE_H struct dev_archdata { -#ifdef CONFIG_ACPI - void *acpi_handle; -#endif #ifdef CONFIG_X86_DEV_DMA_OPS struct dma_map_ops *dma_ops; #endif diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 08373086cd7..2f3849aedc9 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -134,7 +134,7 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2]; int retval = -EINVAL; - if (dev->archdata.acpi_handle) { + if (dev->acpi_handle) { dev_warn(dev, "Drivers changed 'acpi_handle'\n"); return -EINVAL; } @@ -169,7 +169,7 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) acpi_dev->physical_node_count++; mutex_unlock(&acpi_dev->physical_node_lock); - dev->archdata.acpi_handle = handle; + dev->acpi_handle = handle; if (!physical_node->node_id) strcpy(physical_node_name, PHYSICAL_NODE_STRING); @@ -198,11 +198,10 @@ static int acpi_unbind_one(struct device *dev) acpi_status status; struct list_head *node, *next; - if (!dev->archdata.acpi_handle) + if (!dev->acpi_handle) return 0; - status = acpi_bus_get_device(dev->archdata.acpi_handle, - &acpi_dev); + status = acpi_bus_get_device(dev->acpi_handle, &acpi_dev); if (ACPI_FAILURE(status)) goto err; @@ -228,7 +227,7 @@ static int acpi_unbind_one(struct device *dev) sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name); sysfs_remove_link(&dev->kobj, "firmware_node"); - dev->archdata.acpi_handle = NULL; + dev->acpi_handle = NULL; /* acpi_bind_one increase refcnt by one */ put_device(dev); kfree(entry); @@ -269,8 +268,7 @@ static int acpi_platform_notify(struct device *dev) if (!ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_get_name(dev->archdata.acpi_handle, - ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(dev->acpi_handle, ACPI_FULL_PATHNAME, &buffer); DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); kfree(buffer.pointer); } else diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0daa0fbd865..bb1537c5e67 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -410,7 +410,7 @@ acpi_handle acpi_get_child(acpi_handle, u64); int acpi_is_root_bridge(acpi_handle); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) +#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->acpi_handle)) int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); int acpi_disable_wakeup_device_power(struct acpi_device *dev); diff --git a/include/linux/device.h b/include/linux/device.h index 86ef6ab553b..cc3aee57a46 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -190,6 +190,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus); * @mod_name: Used for built-in modules. * @suppress_bind_attrs: Disables bind/unbind via sysfs. * @of_match_table: The open firmware table. + * @acpi_match_table: The ACPI match table. * @probe: Called to query the existence of a specific device, * whether this driver can work with it, and bind the driver * to a specific device. @@ -223,6 +224,7 @@ struct device_driver { bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; + const struct acpi_device_id *acpi_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); @@ -616,6 +618,7 @@ struct device_dma_parameters { * @dma_mem: Internal for coherent mem override. * @archdata: For arch-specific additions. * @of_node: Associated device tree node. + * @acpi_handle: Associated ACPI device node's namespace handle. * @devt: For creating the sysfs "dev". * @id: device instance * @devres_lock: Spinlock to protect the resource of the device. @@ -680,6 +683,7 @@ struct device { struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ + void *acpi_handle; /* associated ACPI device node */ dev_t devt; /* dev_t, creates the sysfs "dev" */ u32 id; /* device instance */ -- cgit v1.2.3 From cf761af9ee0f2c172710ad2b7ca029016b5d4c45 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 31 Oct 2012 22:44:41 +0100 Subject: ACPI: Provide generic functions for matching ACPI device nodes Introduce function acpi_match_device() allowing callers to match struct device objects with populated acpi_handle fields against arrays of ACPI device IDs. Also introduce function acpi_driver_match_device() using acpi_match_device() internally and allowing callers to match a struct device object against an array of ACPI device IDs provided by a device driver. Additionally, introduce macro ACPI_PTR() that may be used by device drivers to escape pointers to data structures whose definitions depend on CONFIG_ACPI. Signed-off-by: Mika Westerberg Acked-by: Greg Kroah-Hartman Acked-by: H. Peter Anvin Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 40 +++++++++++++++++++++++++++++++++++----- include/linux/acpi.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1fcb8678665..a0dfdffe54d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -340,8 +340,8 @@ static void acpi_device_remove_files(struct acpi_device *dev) ACPI Bus operations -------------------------------------------------------------------------- */ -int acpi_match_device_ids(struct acpi_device *device, - const struct acpi_device_id *ids) +static const struct acpi_device_id *__acpi_match_device( + struct acpi_device *device, const struct acpi_device_id *ids) { const struct acpi_device_id *id; struct acpi_hardware_id *hwid; @@ -351,14 +351,44 @@ int acpi_match_device_ids(struct acpi_device *device, * driver for it. */ if (!device->status.present) - return -ENODEV; + return NULL; for (id = ids; id->id[0]; id++) list_for_each_entry(hwid, &device->pnp.ids, list) if (!strcmp((char *) id->id, hwid->id)) - return 0; + return id; + + return NULL; +} - return -ENOENT; +/** + * acpi_match_device - Match a struct device against a given list of ACPI IDs + * @ids: Array of struct acpi_device_id object to match against. + * @dev: The device structure to match. + * + * Check if @dev has a valid ACPI handle and if there is a struct acpi_device + * object for that handle and use that object to match against a given list of + * device IDs. + * + * Return a pointer to the first matching ID on success or %NULL on failure. + */ +const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev) +{ + struct acpi_device *adev; + + if (!ids || !dev->acpi_handle + || ACPI_FAILURE(acpi_bus_get_device(dev->acpi_handle, &adev))) + return NULL; + + return __acpi_match_device(adev, ids); +} +EXPORT_SYMBOL_GPL(acpi_match_device); + +int acpi_match_device_ids(struct acpi_device *device, + const struct acpi_device_id *ids) +{ + return __acpi_match_device(device, ids) ? 0 : -ENOENT; } EXPORT_SYMBOL(acpi_match_device_ids); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 90be9898110..48761cb481d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -26,6 +26,7 @@ #define _LINUX_ACPI_H #include /* for struct resource */ +#include #ifdef CONFIG_ACPI @@ -364,6 +365,17 @@ extern int acpi_nvs_register(__u64 start, __u64 size); extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), void *data); +const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev); + +static inline bool acpi_driver_match_device(struct device *dev, + const struct device_driver *drv) +{ + return !!acpi_match_device(drv->acpi_match_table, dev); +} + +#define ACPI_PTR(_ptr) (_ptr) + #else /* !CONFIG_ACPI */ #define acpi_disabled 1 @@ -418,6 +430,22 @@ static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), return 0; } +struct acpi_device_id; + +static inline const struct acpi_device_id *acpi_match_device( + const struct acpi_device_id *ids, const struct device *dev) +{ + return NULL; +} + +static inline bool acpi_driver_match_device(struct device *dev, + const struct device_driver *drv) +{ + return false; +} + +#define ACPI_PTR(_ptr) (NULL) + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI -- cgit v1.2.3 From 35e92b78c1d327b1624e94d1c9c65ea7065d6b95 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Oct 2012 22:44:48 +0100 Subject: ACPI / x86: Export acpi_[un]register_gsi() These functions might be called from modules as well so make sure they are exported. In addition, implement empty version of acpi_unregister_gsi() and remove the one from pci_irq.c. Signed-off-by: Andy Shevchenko Signed-off-by: Mika Westerberg Acked-by: Greg Kroah-Hartman Acked-by: H. Peter Anvin Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/boot.c | 6 ++++++ drivers/acpi/pci_irq.c | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index e651f7a589a..e48cafcf92a 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -574,6 +574,12 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) return irq; } +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +void acpi_unregister_gsi(u32 gsi) +{ +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); void __init acpi_set_irq_model_pic(void) { diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 0eefa12e648..1be25a590dc 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -495,11 +495,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } -/* FIXME: implement x86/x86_64 version */ -void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) -{ -} - void acpi_pci_irq_disable(struct pci_dev *dev) { struct acpi_prt_entry *entry; -- cgit v1.2.3 From a42b9bfe959519772fd8d97557c760f7cda4d325 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 31 Oct 2012 22:44:55 +0100 Subject: ACPI / ia64: Export acpi_[un]register_gsi() These functions might be called from modules as well so make sure they are exported. Signed-off-by: Mika Westerberg Acked-by: Greg Kroah-Hartman Acked-by: H. Peter Anvin Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- arch/ia64/kernel/acpi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 440578850ae..e9682f5be34 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -633,6 +633,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int triggering, int polarity) ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); } +EXPORT_SYMBOL_GPL(acpi_register_gsi); void acpi_unregister_gsi(u32 gsi) { @@ -644,6 +645,7 @@ void acpi_unregister_gsi(u32 gsi) iosapic_unregister_intr(gsi); } +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); static int __init acpi_parse_fadt(struct acpi_table_header *table) { -- cgit v1.2.3 From 91e5687805885f9fceb60b95e950a3d3bdcf4764 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 31 Oct 2012 22:45:02 +0100 Subject: ACPI: Add support for platform bus type With ACPI 5 it is now possible to enumerate traditional SoC peripherals, like serial bus controllers and slave devices behind them. These devices are typically based on IP-blocks used in many existing SoC platforms and platform drivers for them may already be present in the kernel tree. To make driver "porting" more straightforward, add ACPI support to the platform bus type. Instead of writing ACPI "glue" drivers for the existing platform drivers, register the platform bus type with ACPI to create platform device objects for the drivers and bind the corresponding ACPI handles to those platform devices. This should allow us to reuse the existing platform drivers for the devices in question with the minimum amount of modifications. This changeset is based on Mika Westerberg's and Mathias Nyman's work. Signed-off-by: Mathias Nyman Signed-off-by: Mika Westerberg Acked-by: Greg Kroah-Hartman Acked-by: H. Peter Anvin Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 1 + drivers/acpi/acpi_platform.c | 285 +++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/internal.h | 7 ++ drivers/acpi/scan.c | 16 ++- drivers/base/platform.c | 5 + 5 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 drivers/acpi/acpi_platform.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 82422fe90f8..227c82bbe9a 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -36,6 +36,7 @@ acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o +acpi-y += acpi_platform.o acpi-y += power.o acpi-y += event.o acpi-y += sysfs.o diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c new file mode 100644 index 00000000000..a5a23462287 --- /dev/null +++ b/drivers/acpi/acpi_platform.c @@ -0,0 +1,285 @@ +/* + * ACPI support for platform bus type. + * + * Copyright (C) 2012, Intel Corporation + * Authors: Mika Westerberg + * Mathias Nyman + * Rafael J. Wysocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +ACPI_MODULE_NAME("platform"); + +struct resource_info { + struct device *dev; + struct resource *res; + size_t n, cur; +}; + +static acpi_status acpi_platform_count_resources(struct acpi_resource *res, + void *data) +{ + struct acpi_resource_extended_irq *acpi_xirq; + struct resource_info *ri = data; + + switch (res->type) { + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + case ACPI_RESOURCE_TYPE_IRQ: + ri->n++; + break; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + acpi_xirq = &res->data.extended_irq; + ri->n += acpi_xirq->interrupt_count; + break; + case ACPI_RESOURCE_TYPE_ADDRESS32: + if (res->data.address32.resource_type == ACPI_IO_RANGE) + ri->n++; + break; + } + + return AE_OK; +} + +static acpi_status acpi_platform_add_resources(struct acpi_resource *res, + void *data) +{ + struct acpi_resource_fixed_memory32 *acpi_mem; + struct acpi_resource_address32 *acpi_add32; + struct acpi_resource_extended_irq *acpi_xirq; + struct acpi_resource_irq *acpi_irq; + struct resource_info *ri = data; + struct resource *r; + int irq, i; + + switch (res->type) { + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + acpi_mem = &res->data.fixed_memory32; + r = &ri->res[ri->cur++]; + + r->start = acpi_mem->address; + r->end = r->start + acpi_mem->address_length - 1; + r->flags = IORESOURCE_MEM; + + dev_dbg(ri->dev, "Memory32Fixed %pR\n", r); + break; + + case ACPI_RESOURCE_TYPE_ADDRESS32: + acpi_add32 = &res->data.address32; + + if (acpi_add32->resource_type == ACPI_IO_RANGE) { + r = &ri->res[ri->cur++]; + r->start = acpi_add32->minimum; + r->end = r->start + acpi_add32->address_length - 1; + r->flags = IORESOURCE_IO; + dev_dbg(ri->dev, "Address32 %pR\n", r); + } + break; + + case ACPI_RESOURCE_TYPE_IRQ: + acpi_irq = &res->data.irq; + r = &ri->res[ri->cur++]; + + irq = acpi_register_gsi(ri->dev, + acpi_irq->interrupts[0], + acpi_irq->triggering, + acpi_irq->polarity); + + r->start = r->end = irq; + r->flags = IORESOURCE_IRQ; + + dev_dbg(ri->dev, "IRQ %pR\n", r); + break; + + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + acpi_xirq = &res->data.extended_irq; + + for (i = 0; i < acpi_xirq->interrupt_count; i++, ri->cur++) { + r = &ri->res[ri->cur]; + irq = acpi_register_gsi(ri->dev, + acpi_xirq->interrupts[i], + acpi_xirq->triggering, + acpi_xirq->polarity); + + r->start = r->end = irq; + r->flags = IORESOURCE_IRQ; + + dev_dbg(ri->dev, "Interrupt %pR\n", r); + } + break; + } + + return AE_OK; +} + +static acpi_status acpi_platform_get_device_uid(struct acpi_device *adev, + int *uid) +{ + struct acpi_device_info *info; + acpi_status status; + + status = acpi_get_object_info(adev->handle, &info); + if (ACPI_FAILURE(status)) + return status; + + status = AE_NOT_EXIST; + if ((info->valid & ACPI_VALID_UID) && + !kstrtoint(info->unique_id.string, 0, uid)) + status = AE_OK; + + kfree(info); + return status; +} + +/** + * acpi_create_platform_device - Create platform device for ACPI device node + * @adev: ACPI device node to create a platform device for. + * + * Check if the given @adev can be represented as a platform device and, if + * that's the case, create and register a platform device, populate its common + * resources and returns a pointer to it. Otherwise, return %NULL. + * + * The platform device's name will be taken from the @adev's _HID and _UID. + */ +struct platform_device *acpi_create_platform_device(struct acpi_device *adev) +{ + struct platform_device *pdev = NULL; + struct acpi_device *acpi_parent; + struct device *parent = NULL; + struct resource_info ri; + acpi_status status; + int devid; + + /* If the ACPI node already has a physical device attached, skip it. */ + if (adev->physical_node_count) + return NULL; + + /* Use the UID of the device as the new platform device id if found. */ + status = acpi_platform_get_device_uid(adev, &devid); + if (ACPI_FAILURE(status)) + devid = -1; + + memset(&ri, 0, sizeof(ri)); + + /* First, count the resources. */ + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, + acpi_platform_count_resources, &ri); + if (ACPI_FAILURE(status) || !ri.n) + return NULL; + + /* Next, allocate memory for all the resources and populate it. */ + ri.dev = &adev->dev; + ri.res = kzalloc(ri.n * sizeof(struct resource), GFP_KERNEL); + if (!ri.res) { + dev_err(&adev->dev, + "failed to allocate memory for resources\n"); + return NULL; + } + + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, + acpi_platform_add_resources, &ri); + if (ACPI_FAILURE(status)) { + dev_err(&adev->dev, "failed to walk resources\n"); + goto out; + } + + if (WARN_ON(ri.n != ri.cur)) + goto out; + + /* + * If the ACPI node has a parent and that parent has a physical device + * attached to it, that physical device should be the parent of the + * platform device we are about to create. + */ + acpi_parent = adev->parent; + if (acpi_parent) { + struct acpi_device_physical_node *entry; + struct list_head *list; + + mutex_lock(&acpi_parent->physical_node_lock); + list = &acpi_parent->physical_node_list; + if (!list_empty(list)) { + entry = list_first_entry(list, + struct acpi_device_physical_node, + node); + parent = entry->dev; + } + mutex_unlock(&acpi_parent->physical_node_lock); + } + pdev = platform_device_register_resndata(parent, acpi_device_hid(adev), + devid, ri.res, ri.n, NULL, 0); + if (IS_ERR(pdev)) { + dev_err(&adev->dev, "platform device creation failed: %ld\n", + PTR_ERR(pdev)); + pdev = NULL; + } else { + dev_dbg(&adev->dev, "created platform device %s\n", + dev_name(&pdev->dev)); + } + + out: + kfree(ri.res); + return pdev; +} + +static acpi_status acpi_platform_match(acpi_handle handle, u32 depth, + void *data, void **return_value) +{ + struct platform_device *pdev = data; + struct acpi_device *adev; + acpi_status status; + + status = acpi_bus_get_device(handle, &adev); + if (ACPI_FAILURE(status)) + return status; + + /* Skip ACPI devices that have physical device attached */ + if (adev->physical_node_count) + return AE_OK; + + if (!strcmp(pdev->name, acpi_device_hid(adev))) { + int devid; + + /* Check that both name and UID match if it exists */ + status = acpi_platform_get_device_uid(adev, &devid); + if (ACPI_FAILURE(status)) + devid = -1; + + if (pdev->id != devid) + return AE_OK; + + *(acpi_handle *)return_value = handle; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +static int acpi_platform_find_device(struct device *dev, acpi_handle *handle) +{ + struct platform_device *pdev = to_platform_device(dev); + + *handle = NULL; + acpi_get_devices(pdev->name, acpi_platform_match, pdev, handle); + + return *handle ? 0 : -ENODEV; +} + +static struct acpi_bus_type acpi_platform_bus = { + .bus = &platform_bus_type, + .find_device = acpi_platform_find_device, +}; + +static int __init acpi_platform_init(void) +{ + return register_acpi_bus_type(&acpi_platform_bus); +} +arch_initcall(acpi_platform_init); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ca75b9ce048..57d41f6e144 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -93,4 +93,11 @@ static inline int suspend_nvs_save(void) { return 0; } static inline void suspend_nvs_restore(void) {} #endif +/*-------------------------------------------------------------------------- + Platform bus support + -------------------------------------------------------------------------- */ +struct platform_device; + +struct platform_device *acpi_create_platform_device(struct acpi_device *adev); + #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a0dfdffe54d..d842569395a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -29,6 +29,15 @@ extern struct acpi_device *acpi_root; static const char *dummy_hid = "device"; +/* + * The following ACPI IDs are known to be suitable for representing as + * platform devices. + */ +static const struct acpi_device_id acpi_platform_device_ids[] = { + + { } +}; + static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); DEFINE_MUTEX(acpi_device_lock); @@ -1513,8 +1522,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, */ device = NULL; acpi_bus_get_device(handle, &device); - if (ops->acpi_op_add && !device) + if (ops->acpi_op_add && !device) { acpi_add_single_object(&device, handle, type, sta, ops); + /* Is the device a known good platform device? */ + if (device + && !acpi_match_device_ids(device, acpi_platform_device_ids)) + acpi_create_platform_device(device); + } if (!device) return AE_CTRL_DEPTH; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 72c776f2a1f..7de29ebfce7 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -709,6 +710,10 @@ static int platform_match(struct device *dev, struct device_driver *drv) if (of_driver_match_device(dev, drv)) return 1; + /* Then try ACPI style match */ + if (acpi_driver_match_device(dev, drv)) + return 1; + /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; -- cgit v1.2.3 From b4b6cae2f36d92b31788f10816709d5290a1119a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 10 Nov 2012 23:16:02 +0100 Subject: ACPI / platform: use ACPI device name instead of _HID._UID Using _UID makes the ACPI platform bus code depend on BIOS to get it right. If it doesn't we fail to create the platform device as the name should be unique. The ACPI core already makes a unique name when it first creates the ACPI device so we can use that same name as the platform device name instead of trusting that the BIOS sets the _UIDs correctly. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_platform.c | 62 ++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index a5a23462287..dbb31d61e31 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -120,25 +120,6 @@ static acpi_status acpi_platform_add_resources(struct acpi_resource *res, return AE_OK; } -static acpi_status acpi_platform_get_device_uid(struct acpi_device *adev, - int *uid) -{ - struct acpi_device_info *info; - acpi_status status; - - status = acpi_get_object_info(adev->handle, &info); - if (ACPI_FAILURE(status)) - return status; - - status = AE_NOT_EXIST; - if ((info->valid & ACPI_VALID_UID) && - !kstrtoint(info->unique_id.string, 0, uid)) - status = AE_OK; - - kfree(info); - return status; -} - /** * acpi_create_platform_device - Create platform device for ACPI device node * @adev: ACPI device node to create a platform device for. @@ -156,19 +137,12 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) struct device *parent = NULL; struct resource_info ri; acpi_status status; - int devid; /* If the ACPI node already has a physical device attached, skip it. */ if (adev->physical_node_count) return NULL; - /* Use the UID of the device as the new platform device id if found. */ - status = acpi_platform_get_device_uid(adev, &devid); - if (ACPI_FAILURE(status)) - devid = -1; - memset(&ri, 0, sizeof(ri)); - /* First, count the resources. */ status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, acpi_platform_count_resources, &ri); @@ -214,8 +188,8 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) } mutex_unlock(&acpi_parent->physical_node_lock); } - pdev = platform_device_register_resndata(parent, acpi_device_hid(adev), - devid, ri.res, ri.n, NULL, 0); + pdev = platform_device_register_resndata(parent, dev_name(&adev->dev), + -1, ri.res, ri.n, NULL, 0); if (IS_ERR(pdev)) { dev_err(&adev->dev, "platform device creation failed: %ld\n", PTR_ERR(pdev)); @@ -245,17 +219,7 @@ static acpi_status acpi_platform_match(acpi_handle handle, u32 depth, if (adev->physical_node_count) return AE_OK; - if (!strcmp(pdev->name, acpi_device_hid(adev))) { - int devid; - - /* Check that both name and UID match if it exists */ - status = acpi_platform_get_device_uid(adev, &devid); - if (ACPI_FAILURE(status)) - devid = -1; - - if (pdev->id != devid) - return AE_OK; - + if (!strcmp(dev_name(&pdev->dev), dev_name(&adev->dev))) { *(acpi_handle *)return_value = handle; return AE_CTRL_TERMINATE; } @@ -266,10 +230,28 @@ static acpi_status acpi_platform_match(acpi_handle handle, u32 depth, static int acpi_platform_find_device(struct device *dev, acpi_handle *handle) { struct platform_device *pdev = to_platform_device(dev); + char *name, *tmp, *hid; + + /* + * The platform device is named using the ACPI device name + * _HID:INSTANCE so we strip the INSTANCE out in order to find the + * correct device using its _HID. + */ + name = kstrdup(dev_name(dev), GFP_KERNEL); + if (!name) + return -ENOMEM; + + tmp = name; + hid = strsep(&tmp, ":"); + if (!hid) { + kfree(name); + return -ENODEV; + } *handle = NULL; - acpi_get_devices(pdev->name, acpi_platform_match, pdev, handle); + acpi_get_devices(hid, acpi_platform_match, pdev, handle); + kfree(name); return *handle ? 0 : -ENODEV; } -- cgit v1.2.3 From 046d9ce6820e99087e81511284045eada94950e8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Nov 2012 00:30:01 +0100 Subject: ACPI: Move device resources interpretation code from PNP to ACPI core Move some code used for parsing ACPI device resources from the PNP subsystem to the ACPI core, so that other bus types (platform, SPI, I2C) can use the same routines for parsing resources in a consistent way, without duplicating code. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg --- drivers/acpi/Makefile | 1 + drivers/acpi/resource.c | 393 +++++++++++++++++++++++++++++++++++++++++ drivers/pnp/base.h | 2 + drivers/pnp/pnpacpi/rsparser.c | 296 ++++--------------------------- drivers/pnp/resource.c | 16 ++ include/linux/acpi.h | 10 ++ 6 files changed, 454 insertions(+), 264 deletions(-) create mode 100644 drivers/acpi/resource.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 227c82bbe9a..3223edfb23b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -32,6 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # acpi-y += bus.o glue.o acpi-y += scan.o +acpi-y += resource.o acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c new file mode 100644 index 00000000000..3e7fd349e29 --- /dev/null +++ b/drivers/acpi/resource.c @@ -0,0 +1,393 @@ +/* + * drivers/acpi/resource.c - ACPI device resources interpretation. + * + * Copyright (C) 2012, Intel Corp. + * Author: Rafael J. Wysocki + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include + +#ifdef CONFIG_X86 +#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) +#else +#define valid_IRQ(i) (true) +#endif + +static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, + bool window) +{ + unsigned long flags = IORESOURCE_MEM; + + if (len == 0) + flags |= IORESOURCE_DISABLED; + + if (write_protect == ACPI_READ_WRITE_MEMORY) + flags |= IORESOURCE_MEM_WRITEABLE; + + if (window) + flags |= IORESOURCE_WINDOW; + + return flags; +} + +static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, + u8 write_protect) +{ + res->start = start; + res->end = start + len - 1; + res->flags = acpi_dev_memresource_flags(len, write_protect, false); +} + +/** + * acpi_dev_resource_memory - Extract ACPI memory resource information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents a memory resource and + * if that's the case, use the information in it to populate the generic + * resource object pointed to by @res. + */ +bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) +{ + struct acpi_resource_memory24 *memory24; + struct acpi_resource_memory32 *memory32; + struct acpi_resource_fixed_memory32 *fixed_memory32; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + memory24 = &ares->data.memory24; + acpi_dev_get_memresource(res, memory24->minimum, + memory24->address_length, + memory24->write_protect); + break; + case ACPI_RESOURCE_TYPE_MEMORY32: + memory32 = &ares->data.memory32; + acpi_dev_get_memresource(res, memory32->minimum, + memory32->address_length, + memory32->write_protect); + break; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + fixed_memory32 = &ares->data.fixed_memory32; + acpi_dev_get_memresource(res, fixed_memory32->address, + fixed_memory32->address_length, + fixed_memory32->write_protect); + break; + default: + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); + +static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, + bool window) +{ + int flags = IORESOURCE_IO; + + if (io_decode == ACPI_DECODE_16) + flags |= IORESOURCE_IO_16BIT_ADDR; + + if (start > end || end >= 0x10003) + flags |= IORESOURCE_DISABLED; + + if (window) + flags |= IORESOURCE_WINDOW; + + return flags; +} + +static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, + u8 io_decode) +{ + u64 end = start + len - 1; + + res->start = start; + res->end = end; + res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); +} + +/** + * acpi_dev_resource_io - Extract ACPI I/O resource information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an I/O resource and + * if that's the case, use the information in it to populate the generic + * resource object pointed to by @res. + */ +bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) +{ + struct acpi_resource_io *io; + struct acpi_resource_fixed_io *fixed_io; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IO: + io = &ares->data.io; + acpi_dev_get_ioresource(res, io->minimum, + io->address_length, + io->io_decode); + break; + case ACPI_RESOURCE_TYPE_FIXED_IO: + fixed_io = &ares->data.fixed_io; + acpi_dev_get_ioresource(res, fixed_io->address, + fixed_io->address_length, + ACPI_DECODE_10); + break; + default: + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_io); + +/** + * acpi_dev_resource_address_space - Extract ACPI address space information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an address space resource + * and if that's the case, use the information in it to populate the generic + * resource object pointed to by @res. + */ +bool acpi_dev_resource_address_space(struct acpi_resource *ares, + struct resource *res) +{ + acpi_status status; + struct acpi_resource_address64 addr; + bool window; + u64 len; + u8 io_decode; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + break; + default: + return false; + } + + status = acpi_resource_to_address64(ares, &addr); + if (ACPI_FAILURE(status)) + return true; + + res->start = addr.minimum; + res->end = addr.maximum; + window = addr.producer_consumer == ACPI_PRODUCER; + + switch(addr.resource_type) { + case ACPI_MEMORY_RANGE: + len = addr.maximum - addr.minimum + 1; + res->flags = acpi_dev_memresource_flags(len, + addr.info.mem.write_protect, + window); + break; + case ACPI_IO_RANGE: + io_decode = addr.granularity == 0xfff ? + ACPI_DECODE_10 : ACPI_DECODE_16; + res->flags = acpi_dev_ioresource_flags(addr.minimum, + addr.maximum, + io_decode, window); + break; + case ACPI_BUS_NUMBER_RANGE: + res->flags = IORESOURCE_BUS; + break; + default: + res->flags = 0; + } + + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); + +/** + * acpi_dev_resource_ext_address_space - Extract ACPI address space information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an extended address space + * resource and if that's the case, use the information in it to populate the + * generic resource object pointed to by @res. + */ +bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, + struct resource *res) +{ + struct acpi_resource_extended_address64 *ext_addr; + bool window; + u64 len; + u8 io_decode; + + if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) + return false; + + ext_addr = &ares->data.ext_address64; + + res->start = ext_addr->minimum; + res->end = ext_addr->maximum; + window = ext_addr->producer_consumer == ACPI_PRODUCER; + + switch(ext_addr->resource_type) { + case ACPI_MEMORY_RANGE: + len = ext_addr->maximum - ext_addr->minimum + 1; + res->flags = acpi_dev_memresource_flags(len, + ext_addr->info.mem.write_protect, + window); + break; + case ACPI_IO_RANGE: + io_decode = ext_addr->granularity == 0xfff ? + ACPI_DECODE_10 : ACPI_DECODE_16; + res->flags = acpi_dev_ioresource_flags(ext_addr->minimum, + ext_addr->maximum, + io_decode, window); + break; + case ACPI_BUS_NUMBER_RANGE: + res->flags = IORESOURCE_BUS; + break; + default: + res->flags = 0; + } + + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); + +/** + * acpi_dev_irq_flags - Determine IRQ resource flags. + * @triggering: Triggering type as provided by ACPI. + * @polarity: Interrupt polarity as provided by ACPI. + * @shareable: Whether or not the interrupt is shareable. + */ +unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable) +{ + unsigned long flags; + + if (triggering == ACPI_LEVEL_SENSITIVE) + flags = polarity == ACPI_ACTIVE_LOW ? + IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL; + else + flags = polarity == ACPI_ACTIVE_LOW ? + IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE; + + if (shareable == ACPI_SHARED) + flags |= IORESOURCE_IRQ_SHAREABLE; + + return flags | IORESOURCE_IRQ; +} +EXPORT_SYMBOL_GPL(acpi_dev_irq_flags); + +static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) +{ + res->start = gsi; + res->end = gsi; + res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; +} + +static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, + u8 triggering, u8 polarity, u8 shareable) +{ + int irq, p, t; + + if (!valid_IRQ(gsi)) { + acpi_dev_irqresource_disabled(res, gsi); + return; + } + + /* + * In IO-APIC mode, use overrided attribute. Two reasons: + * 1. BIOS bug in DSDT + * 2. BIOS uses IO-APIC mode Interrupt Source Override + */ + if (!acpi_get_override_irq(gsi, &t, &p)) { + u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; + u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + + if (triggering != trig || polarity != pol) { + pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi, + t ? "edge" : "level", p ? "low" : "high"); + triggering = trig; + polarity = pol; + } + } + + res->flags = acpi_dev_irq_flags(triggering, polarity, shareable); + irq = acpi_register_gsi(NULL, gsi, triggering, polarity); + if (irq >= 0) { + res->start = irq; + res->end = irq; + } else { + acpi_dev_irqresource_disabled(res, gsi); + } +} + +/** + * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information. + * @ares: Input ACPI resource object. + * @index: Index into the array of GSIs represented by the resource. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an interrupt resource + * and @index does not exceed the resource's interrupt count (true is returned + * in that case regardless of the results of the other checks)). If that's the + * case, register the GSI corresponding to @index from the array of interrupts + * represented by the resource and populate the generic resource object pointed + * to by @res accordingly. If the registration of the GSI is not successful, + * IORESOURCE_DISABLED will be set it that object's flags. + */ +bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, + struct resource *res) +{ + struct acpi_resource_irq *irq; + struct acpi_resource_extended_irq *ext_irq; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IRQ: + /* + * Per spec, only one interrupt per descriptor is allowed in + * _CRS, but some firmware violates this, so parse them all. + */ + irq = &ares->data.irq; + if (index >= irq->interrupt_count) { + acpi_dev_irqresource_disabled(res, 0); + return false; + } + acpi_dev_get_irqresource(res, irq->interrupts[index], + irq->triggering, irq->polarity, + irq->sharable); + break; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + ext_irq = &ares->data.extended_irq; + if (index >= ext_irq->interrupt_count) { + acpi_dev_irqresource_disabled(res, 0); + return false; + } + acpi_dev_get_irqresource(res, ext_irq->interrupts[index], + ext_irq->triggering, ext_irq->polarity, + ext_irq->sharable); + break; + default: + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index fa4e0a5db3f..ffd53e3eb92 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -159,6 +159,8 @@ struct pnp_resource { void pnp_free_resource(struct pnp_resource *pnp_res); +struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, + struct resource *res); struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags); struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 5be4a392a3a..b8f4ea7b27f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -28,37 +28,6 @@ #include "../base.h" #include "pnpacpi.h" -#ifdef CONFIG_IA64 -#define valid_IRQ(i) (1) -#else -#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) -#endif - -/* - * Allocated Resources - */ -static int irq_flags(int triggering, int polarity, int shareable) -{ - int flags; - - if (triggering == ACPI_LEVEL_SENSITIVE) { - if (polarity == ACPI_ACTIVE_LOW) - flags = IORESOURCE_IRQ_LOWLEVEL; - else - flags = IORESOURCE_IRQ_HIGHLEVEL; - } else { - if (polarity == ACPI_ACTIVE_LOW) - flags = IORESOURCE_IRQ_LOWEDGE; - else - flags = IORESOURCE_IRQ_HIGHEDGE; - } - - if (shareable == ACPI_SHARED) - flags |= IORESOURCE_IRQ_SHAREABLE; - - return flags; -} - static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, int *polarity, int *shareable) { @@ -94,45 +63,6 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, *shareable = ACPI_EXCLUSIVE; } -static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, - u32 gsi, int triggering, - int polarity, int shareable) -{ - int irq, flags; - int p, t; - - if (!valid_IRQ(gsi)) { - pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED); - return; - } - - /* - * in IO-APIC mode, use overrided attribute. Two reasons: - * 1. BIOS bug in DSDT - * 2. BIOS uses IO-APIC mode Interrupt Source Override - */ - if (!acpi_get_override_irq(gsi, &t, &p)) { - t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; - p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; - - if (triggering != t || polarity != p) { - dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", - gsi, t ? "edge":"level", p ? "low":"high"); - triggering = t; - polarity = p; - } - } - - flags = irq_flags(triggering, polarity, shareable); - irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); - if (irq >= 0) - pcibios_penalize_isa_irq(irq, 1); - else - flags |= IORESOURCE_DISABLED; - - pnp_add_irq_resource(dev, irq, flags); -} - static int dma_flags(struct pnp_dev *dev, int type, int bus_master, int transfer) { @@ -177,21 +107,16 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master, return flags; } -static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, - u64 len, int io_decode, - int window) -{ - int flags = 0; - u64 end = start + len - 1; +/* + * Allocated Resources + */ - if (io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; - if (len == 0 || end >= 0x10003) - flags |= IORESOURCE_DISABLED; - if (window) - flags |= IORESOURCE_WINDOW; +static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) +{ + if (!(r->flags & IORESOURCE_DISABLED)) + pcibios_penalize_isa_irq(r->start, 1); - pnp_add_io_resource(dev, start, end, flags); + pnp_add_resource(dev, r); } /* @@ -249,130 +174,49 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, } } -static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, - u64 start, u64 len, - int write_protect, int window) -{ - int flags = 0; - u64 end = start + len - 1; - - if (len == 0) - flags |= IORESOURCE_DISABLED; - if (write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; - if (window) - flags |= IORESOURCE_WINDOW; - - pnp_add_mem_resource(dev, start, end, flags); -} - -static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev, - u64 start, u64 len) -{ - u64 end = start + len - 1; - - pnp_add_bus_resource(dev, start, end); -} - -static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, - struct acpi_resource *res) -{ - struct acpi_resource_address64 addr, *p = &addr; - acpi_status status; - int window; - u64 len; - - status = acpi_resource_to_address64(res, p); - if (!ACPI_SUCCESS(status)) { - dev_warn(&dev->dev, "failed to convert resource type %d\n", - res->type); - return; - } - - /* Windows apparently computes length rather than using _LEN */ - len = p->maximum - p->minimum + 1; - window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; - - if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(dev, p->minimum, len, - p->info.mem.write_protect, window); - else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, - p->granularity == 0xfff ? ACPI_DECODE_10 : - ACPI_DECODE_16, window); - else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) - pnpacpi_parse_allocated_busresource(dev, p->minimum, len); -} - -static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, - struct acpi_resource *res) -{ - struct acpi_resource_extended_address64 *p = &res->data.ext_address64; - int window; - u64 len; - - /* Windows apparently computes length rather than using _LEN */ - len = p->maximum - p->minimum + 1; - window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; - - if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(dev, p->minimum, len, - p->info.mem.write_protect, window); - else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, - p->granularity == 0xfff ? ACPI_DECODE_10 : - ACPI_DECODE_16, window); - else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) - pnpacpi_parse_allocated_busresource(dev, p->minimum, len); -} - static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, void *data) { struct pnp_dev *dev = data; - struct acpi_resource_irq *irq; struct acpi_resource_dma *dma; - struct acpi_resource_io *io; - struct acpi_resource_fixed_io *fixed_io; struct acpi_resource_vendor_typed *vendor_typed; - struct acpi_resource_memory24 *memory24; - struct acpi_resource_memory32 *memory32; - struct acpi_resource_fixed_memory32 *fixed_memory32; - struct acpi_resource_extended_irq *extended_irq; + struct resource r; int i, flags; - switch (res->type) { - case ACPI_RESOURCE_TYPE_IRQ: - /* - * Per spec, only one interrupt per descriptor is allowed in - * _CRS, but some firmware violates this, so parse them all. - */ - irq = &res->data.irq; - if (irq->interrupt_count == 0) - pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); - else { - for (i = 0; i < irq->interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(dev, - irq->interrupts[i], - irq->triggering, - irq->polarity, - irq->sharable); - } + if (acpi_dev_resource_memory(res, &r) + || acpi_dev_resource_io(res, &r) + || acpi_dev_resource_address_space(res, &r) + || acpi_dev_resource_ext_address_space(res, &r)) { + pnp_add_resource(dev, &r); + return AE_OK; + } + r.flags = 0; + if (acpi_dev_resource_interrupt(res, 0, &r)) { + pnpacpi_add_irqresource(dev, &r); + for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) + pnpacpi_add_irqresource(dev, &r); + + if (i > 1) { /* * The IRQ encoder puts a single interrupt in each * descriptor, so if a _CRS descriptor has more than * one interrupt, we won't be able to re-encode it. */ - if (pnp_can_write(dev) && irq->interrupt_count > 1) { + if (pnp_can_write(dev)) { dev_warn(&dev->dev, "multiple interrupts in " "_CRS descriptor; configuration can't " "be changed\n"); dev->capabilities &= ~PNP_WRITE; } } - break; + return AE_OK; + } else if (r.flags & IORESOURCE_DISABLED) { + pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); + return AE_OK; + } + switch (res->type) { case ACPI_RESOURCE_TYPE_DMA: dma = &res->data.dma; if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) @@ -383,26 +227,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, pnp_add_dma_resource(dev, dma->channels[0], flags); break; - case ACPI_RESOURCE_TYPE_IO: - io = &res->data.io; - pnpacpi_parse_allocated_ioresource(dev, - io->minimum, - io->address_length, - io->io_decode, 0); - break; - case ACPI_RESOURCE_TYPE_START_DEPENDENT: case ACPI_RESOURCE_TYPE_END_DEPENDENT: break; - case ACPI_RESOURCE_TYPE_FIXED_IO: - fixed_io = &res->data.fixed_io; - pnpacpi_parse_allocated_ioresource(dev, - fixed_io->address, - fixed_io->address_length, - ACPI_DECODE_10, 0); - break; - case ACPI_RESOURCE_TYPE_VENDOR: vendor_typed = &res->data.vendor_typed; pnpacpi_parse_allocated_vendor(dev, vendor_typed); @@ -411,66 +239,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_END_TAG: break; - case ACPI_RESOURCE_TYPE_MEMORY24: - memory24 = &res->data.memory24; - pnpacpi_parse_allocated_memresource(dev, - memory24->minimum, - memory24->address_length, - memory24->write_protect, 0); - break; - case ACPI_RESOURCE_TYPE_MEMORY32: - memory32 = &res->data.memory32; - pnpacpi_parse_allocated_memresource(dev, - memory32->minimum, - memory32->address_length, - memory32->write_protect, 0); - break; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - fixed_memory32 = &res->data.fixed_memory32; - pnpacpi_parse_allocated_memresource(dev, - fixed_memory32->address, - fixed_memory32->address_length, - fixed_memory32->write_protect, 0); - break; - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_allocated_address_space(dev, res); - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: - pnpacpi_parse_allocated_ext_address_space(dev, res); - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - extended_irq = &res->data.extended_irq; - - if (extended_irq->interrupt_count == 0) - pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); - else { - for (i = 0; i < extended_irq->interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(dev, - extended_irq->interrupts[i], - extended_irq->triggering, - extended_irq->polarity, - extended_irq->sharable); - } - - /* - * The IRQ encoder puts a single interrupt in each - * descriptor, so if a _CRS descriptor has more than - * one interrupt, we won't be able to re-encode it. - */ - if (pnp_can_write(dev) && - extended_irq->interrupt_count > 1) { - dev_warn(&dev->dev, "multiple interrupts in " - "_CRS descriptor; configuration can't " - "be changed\n"); - dev->capabilities &= ~PNP_WRITE; - } - } - break; - case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: break; @@ -531,7 +299,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, if (p->interrupts[i]) __set_bit(p->interrupts[i], map.bits); - flags = irq_flags(p->triggering, p->polarity, p->sharable); + flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -555,7 +323,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, } } - flags = irq_flags(p->triggering, p->polarity, p->sharable); + flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index b0ecacbe53b..3e6db1c1dc2 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -503,6 +503,22 @@ static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev) return pnp_res; } +struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, + struct resource *res) +{ + struct pnp_resource *pnp_res; + + pnp_res = pnp_new_resource(dev); + if (!pnp_res) { + dev_err(&dev->dev, "can't add resource %pR\n", res); + return NULL; + } + + pnp_res->res = *res; + dev_dbg(&dev->dev, "%pR\n", res); + return pnp_res; +} + struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 48761cb481d..16fcaf8dad3 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -251,6 +251,16 @@ extern int pnpacpi_disabled; #define PXM_INVAL (-1) +bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res); +bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); +bool acpi_dev_resource_address_space(struct acpi_resource *ares, + struct resource *res); +bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, + struct resource *res); +unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); +bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, + struct resource *res); + int acpi_check_resource_conflict(const struct resource *res); int acpi_check_region(resource_size_t start, resource_size_t n, -- cgit v1.2.3 From 97d69dc061e968b5e9e56f48bb223b9ab7764b48 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Nov 2012 00:30:12 +0100 Subject: ACPI / platform: Use common ACPI device resource parsing routines Use common routines in drivers/acpi/resource.c to parse ACPI device resources while creating platform device objects. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg --- drivers/acpi/acpi_platform.c | 89 ++++++++++---------------------------------- 1 file changed, 20 insertions(+), 69 deletions(-) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index dbb31d61e31..bcbb00ce6d9 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -29,21 +29,20 @@ static acpi_status acpi_platform_count_resources(struct acpi_resource *res, void *data) { struct acpi_resource_extended_irq *acpi_xirq; + struct acpi_resource_irq *acpi_irq; struct resource_info *ri = data; switch (res->type) { - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: case ACPI_RESOURCE_TYPE_IRQ: - ri->n++; + acpi_irq = &res->data.irq; + ri->n += acpi_irq->interrupt_count; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: acpi_xirq = &res->data.extended_irq; ri->n += acpi_xirq->interrupt_count; break; - case ACPI_RESOURCE_TYPE_ADDRESS32: - if (res->data.address32.resource_type == ACPI_IO_RANGE) - ri->n++; - break; + default: + ri->n++; } return AE_OK; @@ -52,71 +51,26 @@ static acpi_status acpi_platform_count_resources(struct acpi_resource *res, static acpi_status acpi_platform_add_resources(struct acpi_resource *res, void *data) { - struct acpi_resource_fixed_memory32 *acpi_mem; - struct acpi_resource_address32 *acpi_add32; - struct acpi_resource_extended_irq *acpi_xirq; - struct acpi_resource_irq *acpi_irq; struct resource_info *ri = data; struct resource *r; - int irq, i; - - switch (res->type) { - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - acpi_mem = &res->data.fixed_memory32; - r = &ri->res[ri->cur++]; - r->start = acpi_mem->address; - r->end = r->start + acpi_mem->address_length - 1; - r->flags = IORESOURCE_MEM; - - dev_dbg(ri->dev, "Memory32Fixed %pR\n", r); - break; - - case ACPI_RESOURCE_TYPE_ADDRESS32: - acpi_add32 = &res->data.address32; - - if (acpi_add32->resource_type == ACPI_IO_RANGE) { - r = &ri->res[ri->cur++]; - r->start = acpi_add32->minimum; - r->end = r->start + acpi_add32->address_length - 1; - r->flags = IORESOURCE_IO; - dev_dbg(ri->dev, "Address32 %pR\n", r); - } - break; - - case ACPI_RESOURCE_TYPE_IRQ: - acpi_irq = &res->data.irq; - r = &ri->res[ri->cur++]; - - irq = acpi_register_gsi(ri->dev, - acpi_irq->interrupts[0], - acpi_irq->triggering, - acpi_irq->polarity); - - r->start = r->end = irq; - r->flags = IORESOURCE_IRQ; - - dev_dbg(ri->dev, "IRQ %pR\n", r); - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - acpi_xirq = &res->data.extended_irq; - - for (i = 0; i < acpi_xirq->interrupt_count; i++, ri->cur++) { - r = &ri->res[ri->cur]; - irq = acpi_register_gsi(ri->dev, - acpi_xirq->interrupts[i], - acpi_xirq->triggering, - acpi_xirq->polarity); + r = ri->res + ri->cur; + if (acpi_dev_resource_memory(res, r) + || acpi_dev_resource_io(res, r) + || acpi_dev_resource_address_space(res, r) + || acpi_dev_resource_ext_address_space(res, r)) { + ri->cur++; + return AE_OK; + } + if (acpi_dev_resource_interrupt(res, 0, r)) { + int i; - r->start = r->end = irq; - r->flags = IORESOURCE_IRQ; + r++; + for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) + r++; - dev_dbg(ri->dev, "Interrupt %pR\n", r); - } - break; + ri->cur += i; } - return AE_OK; } @@ -165,9 +119,6 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) goto out; } - if (WARN_ON(ri.n != ri.cur)) - goto out; - /* * If the ACPI node has a parent and that parent has a physical device * attached to it, that physical device should be the parent of the @@ -189,7 +140,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) mutex_unlock(&acpi_parent->physical_node_lock); } pdev = platform_device_register_resndata(parent, dev_name(&adev->dev), - -1, ri.res, ri.n, NULL, 0); + -1, ri.res, ri.cur, NULL, 0); if (IS_ERR(pdev)) { dev_err(&adev->dev, "platform device creation failed: %ld\n", PTR_ERR(pdev)); -- cgit v1.2.3 From 8e345c991c8c7a3c081199ef77deada79e37618a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Nov 2012 00:30:21 +0100 Subject: ACPI: Centralized processing of ACPI device resources Currently, whoever wants to use ACPI device resources has to call acpi_walk_resources() to browse the buffer returned by the _CRS method for the given device and create filters passed to that routine to apply to the individual resource items. This generally is cumbersome, time-consuming and inefficient. Moreover, it may be problematic if resource conflicts need to be resolved, because the different users of _CRS will need to do that in a consistent way. However, if there are resource conflicts, the ACPI core should be able to resolve them centrally instead of relying on various users of acpi_walk_resources() to handle them correctly together. For this reason, introduce a new function, acpi_dev_get_resources(), that can be used by subsystems to obtain a list of struct resource objects corresponding to the ACPI device resources returned by _CRS and, if necessary, to apply additional preprocessing routine to the ACPI resources before converting them to the struct resource format. Make the ACPI code that creates platform device objects use acpi_dev_get_resources() for resource processing instead of executing acpi_walk_resources() twice by itself, which causes it to be much more straightforward and easier to follow. In the future, acpi_dev_get_resources() can be extended to meet the needs of the ACPI PNP subsystem and other users of _CRS in the kernel. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg --- drivers/acpi/acpi_platform.c | 94 ++++++------------------------ drivers/acpi/resource.c | 134 +++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 10 ++++ 3 files changed, 161 insertions(+), 77 deletions(-) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index bcbb00ce6d9..7ac20d8b8f0 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -19,61 +19,6 @@ ACPI_MODULE_NAME("platform"); -struct resource_info { - struct device *dev; - struct resource *res; - size_t n, cur; -}; - -static acpi_status acpi_platform_count_resources(struct acpi_resource *res, - void *data) -{ - struct acpi_resource_extended_irq *acpi_xirq; - struct acpi_resource_irq *acpi_irq; - struct resource_info *ri = data; - - switch (res->type) { - case ACPI_RESOURCE_TYPE_IRQ: - acpi_irq = &res->data.irq; - ri->n += acpi_irq->interrupt_count; - break; - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - acpi_xirq = &res->data.extended_irq; - ri->n += acpi_xirq->interrupt_count; - break; - default: - ri->n++; - } - - return AE_OK; -} - -static acpi_status acpi_platform_add_resources(struct acpi_resource *res, - void *data) -{ - struct resource_info *ri = data; - struct resource *r; - - r = ri->res + ri->cur; - if (acpi_dev_resource_memory(res, r) - || acpi_dev_resource_io(res, r) - || acpi_dev_resource_address_space(res, r) - || acpi_dev_resource_ext_address_space(res, r)) { - ri->cur++; - return AE_OK; - } - if (acpi_dev_resource_interrupt(res, 0, r)) { - int i; - - r++; - for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) - r++; - - ri->cur += i; - } - return AE_OK; -} - /** * acpi_create_platform_device - Create platform device for ACPI device node * @adev: ACPI device node to create a platform device for. @@ -89,35 +34,31 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) struct platform_device *pdev = NULL; struct acpi_device *acpi_parent; struct device *parent = NULL; - struct resource_info ri; - acpi_status status; + struct resource_list_entry *rentry; + struct list_head resource_list; + struct resource *resources; + int count; /* If the ACPI node already has a physical device attached, skip it. */ if (adev->physical_node_count) return NULL; - memset(&ri, 0, sizeof(ri)); - /* First, count the resources. */ - status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, - acpi_platform_count_resources, &ri); - if (ACPI_FAILURE(status) || !ri.n) + INIT_LIST_HEAD(&resource_list); + count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (count <= 0) return NULL; - /* Next, allocate memory for all the resources and populate it. */ - ri.dev = &adev->dev; - ri.res = kzalloc(ri.n * sizeof(struct resource), GFP_KERNEL); - if (!ri.res) { - dev_err(&adev->dev, - "failed to allocate memory for resources\n"); + resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL); + if (!resources) { + dev_err(&adev->dev, "No memory for resources\n"); + acpi_dev_free_resource_list(&resource_list); return NULL; } + count = 0; + list_for_each_entry(rentry, &resource_list, node) + resources[count++] = rentry->res; - status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, - acpi_platform_add_resources, &ri); - if (ACPI_FAILURE(status)) { - dev_err(&adev->dev, "failed to walk resources\n"); - goto out; - } + acpi_dev_free_resource_list(&resource_list); /* * If the ACPI node has a parent and that parent has a physical device @@ -140,7 +81,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) mutex_unlock(&acpi_parent->physical_node_lock); } pdev = platform_device_register_resndata(parent, dev_name(&adev->dev), - -1, ri.res, ri.cur, NULL, 0); + -1, resources, count, NULL, 0); if (IS_ERR(pdev)) { dev_err(&adev->dev, "platform device creation failed: %ld\n", PTR_ERR(pdev)); @@ -150,8 +91,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) dev_name(&pdev->dev)); } - out: - kfree(ri.res); + kfree(resources); return pdev; } diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3e7fd349e29..2bafc25482b 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CONFIG_X86 #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) @@ -391,3 +392,136 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, return true; } EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); + +/** + * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources(). + * @list: The head of the resource list to free. + */ +void acpi_dev_free_resource_list(struct list_head *list) +{ + struct resource_list_entry *rentry, *re; + + list_for_each_entry_safe(rentry, re, list, node) { + list_del(&rentry->node); + kfree(rentry); + } +} +EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); + +struct res_proc_context { + struct list_head *list; + int (*preproc)(struct acpi_resource *, void *); + void *preproc_data; + int count; + int error; +}; + +static acpi_status acpi_dev_new_resource_entry(struct resource *r, + struct res_proc_context *c) +{ + struct resource_list_entry *rentry; + + rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); + if (!rentry) { + c->error = -ENOMEM; + return AE_NO_MEMORY; + } + INIT_LIST_HEAD(&rentry->node); + rentry->res = *r; + list_add_tail(&rentry->node, c->list); + c->count++; + return AE_OK; +} + +static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, + void *context) +{ + struct res_proc_context *c = context; + struct resource r; + int i; + + if (c->preproc) { + int ret; + + ret = c->preproc(ares, c->preproc_data); + if (ret < 0) { + c->error = ret; + return AE_ABORT_METHOD; + } else if (ret > 0) { + return AE_OK; + } + } + + memset(&r, 0, sizeof(r)); + + if (acpi_dev_resource_memory(ares, &r) + || acpi_dev_resource_io(ares, &r) + || acpi_dev_resource_address_space(ares, &r) + || acpi_dev_resource_ext_address_space(ares, &r)) + return acpi_dev_new_resource_entry(&r, c); + + for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { + acpi_status status; + + status = acpi_dev_new_resource_entry(&r, c); + if (ACPI_FAILURE(status)) + return status; + } + + return AE_OK; +} + +/** + * acpi_dev_get_resources - Get current resources of a device. + * @adev: ACPI device node to get the resources for. + * @list: Head of the resultant list of resources (must be empty). + * @preproc: The caller's preprocessing routine. + * @preproc_data: Pointer passed to the caller's preprocessing routine. + * + * Evaluate the _CRS method for the given device node and process its output by + * (1) executing the @preproc() rountine provided by the caller, passing the + * resource pointer and @preproc_data to it as arguments, for each ACPI resource + * returned and (2) converting all of the returned ACPI resources into struct + * resource objects if possible. If the return value of @preproc() in step (1) + * is different from 0, step (2) is not applied to the given ACPI resource and + * if that value is negative, the whole processing is aborted and that value is + * returned as the final error code. + * + * The resultant struct resource objects are put on the list pointed to by + * @list, that must be empty initially, as members of struct resource_list_entry + * objects. Callers of this routine should use %acpi_dev_free_resource_list() to + * free that list. + * + * The number of resources in the output list is returned on success, an error + * code reflecting the error condition is returned otherwise. + */ +int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, + int (*preproc)(struct acpi_resource *, void *), + void *preproc_data) +{ + struct res_proc_context c; + acpi_handle not_used; + acpi_status status; + + if (!adev || !adev->handle || !list_empty(list)) + return -EINVAL; + + status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, ¬_used); + if (ACPI_FAILURE(status)) + return 0; + + c.list = list; + c.preproc = preproc; + c.preproc_data = preproc_data; + c.count = 0; + c.error = 0; + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, + acpi_dev_process_resource, &c); + if (ACPI_FAILURE(status)) { + acpi_dev_free_resource_list(list); + return c.error ? c.error : -EIO; + } + + return c.count; +} +EXPORT_SYMBOL_GPL(acpi_dev_get_resources); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 16fcaf8dad3..32fbc4e73a5 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -261,6 +261,16 @@ unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res); +struct resource_list_entry { + struct list_head node; + struct resource res; +}; + +void acpi_dev_free_resource_list(struct list_head *list); +int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, + int (*preproc)(struct acpi_resource *, void *), + void *preproc_data); + int acpi_check_resource_conflict(const struct resource *res); int acpi_check_region(resource_size_t start, resource_size_t n, -- cgit v1.2.3 From 45dcd31547fcd58273423799b12efe0e8371127e Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:24:51 +0000 Subject: Cleanup of invalid ACPI name handling and repair Implemented a change/cleanup for the handling of invalid ACPI names. Names are now validated and repaired only when 1) entering a new name into the namespace and 2) disassembling a named AML opcode. A warning is only displayed in debug mode or when the interpreter is in "strict" mode, since some working machines do in fact contain invalid ACPI names. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 2 +- drivers/acpi/acpica/nsdump.c | 8 -------- drivers/acpi/acpica/nssearch.c | 17 +---------------- drivers/acpi/acpica/utmisc.c | 34 ++++++++++++++++++++++++++-------- 4 files changed, 28 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 5035327ebcc..68cb6de26d1 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -483,7 +483,7 @@ void acpi_ut_print_string(char *string, u8 max_length); u8 acpi_ut_valid_acpi_name(u32 name); -acpi_name acpi_ut_repair_name(char *name); +void acpi_ut_repair_name(char *name); u8 acpi_ut_valid_acpi_char(char character, u32 position); diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 2526aaf945e..993b12417e7 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -209,14 +209,6 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, "Invalid ACPI Object Type 0x%08X", type)); } - if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { - this_node->name.integer = - acpi_ut_repair_name(this_node->name.ascii); - - ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", - this_node->name.integer)); - } - acpi_os_printf("%4.4s", acpi_ut_get_node_name(this_node)); } diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 456cc859f86..1d2d8ffc1bc 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -314,22 +314,7 @@ acpi_ns_search_and_enter(u32 target_name, * this problem, and we want to be able to enable ACPI support for them, * even though there are a few bad names. */ - if (!acpi_ut_valid_acpi_name(target_name)) { - target_name = - acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); - - /* Report warning only if in strict mode or debug mode */ - - if (!acpi_gbl_enable_interpreter_slack) { - ACPI_WARNING((AE_INFO, - "Found bad character(s) in name, repaired: [%4.4s]\n", - ACPI_CAST_PTR(char, &target_name))); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found bad character(s) in name, repaired: [%4.4s]\n", - ACPI_CAST_PTR(char, &target_name))); - } - } + acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); /* Try to find the name in the namespace level specified by the caller */ diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 33c6cf7ff46..d91d88df2a9 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -642,25 +642,43 @@ u8 acpi_ut_valid_acpi_name(u32 name) * ******************************************************************************/ -acpi_name acpi_ut_repair_name(char *name) +void acpi_ut_repair_name(char *name) { - u32 i; - char new_name[ACPI_NAME_SIZE]; + u32 i; + u8 found_bad_char = FALSE; + + ACPI_FUNCTION_NAME(ut_repair_name); + + /* Check each character in the name */ for (i = 0; i < ACPI_NAME_SIZE; i++) { - new_name[i] = name[i]; + if (acpi_ut_valid_acpi_char(name[i], i)) { + continue; + } /* * Replace a bad character with something printable, yet technically * still invalid. This prevents any collisions with existing "good" * names in the namespace. */ - if (!acpi_ut_valid_acpi_char(name[i], i)) { - new_name[i] = '*'; - } + name[i] = '*'; + found_bad_char = TRUE; } - return (*(u32 *) new_name); + if (found_bad_char) { + + /* Report warning only if in strict mode or debug mode */ + + if (!acpi_gbl_enable_interpreter_slack) { + ACPI_WARNING((AE_INFO, + "Found bad character(s) in name, repaired: [%4.4s]\n", + name)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found bad character(s) in name, repaired: [%4.4s]\n", + name)); + } + } } /******************************************************************************* -- cgit v1.2.3 From 6d33b6be17dd6a0934396704f969ceb7f3206347 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 31 Oct 2012 02:25:05 +0000 Subject: ACPICA: Fix unmerged utility divergences. Utility improvements in ACPICA are partial ignored by ACPICA Linux release. This will lead to divergences between Linux and ACPICA. This patch ports the entire "utility" into Linux and makes them igored in the compilation stage by "ACPI_FUTURE_USAGE". The following "Utility" files have been ported into the Linux: drivers/acpi/uttrack.c drivers/acpi/utcache.c drivers/acpi/utids.c This patch will not affect the generated vmlinx binary. This will decrease 274 lines of 20120913 divergence.diff. Signed-off-by: Robert Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 3 + drivers/acpi/acpica/acutils.h | 51 ++- drivers/acpi/acpica/utcache.c | 323 ++++++++++++++++++ drivers/acpi/acpica/utclib.c | 748 ++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/utdebug.c | 9 +- drivers/acpi/acpica/utmisc.c | 99 +++++- drivers/acpi/acpica/uttrack.c | 650 ++++++++++++++++++++++++++++++++++++ 7 files changed, 1852 insertions(+), 31 deletions(-) create mode 100644 drivers/acpi/acpica/utcache.c create mode 100644 drivers/acpi/acpica/utclib.c create mode 100644 drivers/acpi/acpica/uttrack.c diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 7f1d40797e8..c8bc24bd1f7 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -161,3 +161,6 @@ acpi-y += \ utxfinit.o \ utxferror.o \ utxfmutex.o + +acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o utclib.o + diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 68cb6de26d1..82d6025332e 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -69,6 +69,22 @@ extern const char *acpi_gbl_siz_decode[]; extern const char *acpi_gbl_trs_decode[]; extern const char *acpi_gbl_ttp_decode[]; extern const char *acpi_gbl_typ_decode[]; +extern const char *acpi_gbl_ppc_decode[]; +extern const char *acpi_gbl_ior_decode[]; +extern const char *acpi_gbl_dts_decode[]; +extern const char *acpi_gbl_ct_decode[]; +extern const char *acpi_gbl_sbt_decode[]; +extern const char *acpi_gbl_am_decode[]; +extern const char *acpi_gbl_sm_decode[]; +extern const char *acpi_gbl_wm_decode[]; +extern const char *acpi_gbl_cph_decode[]; +extern const char *acpi_gbl_cpo_decode[]; +extern const char *acpi_gbl_dp_decode[]; +extern const char *acpi_gbl_ed_decode[]; +extern const char *acpi_gbl_bpb_decode[]; +extern const char *acpi_gbl_sb_decode[]; +extern const char *acpi_gbl_fc_decode[]; +extern const char *acpi_gbl_pt_decode[]; #endif /* Types for Resource descriptor entries */ @@ -79,14 +95,14 @@ extern const char *acpi_gbl_typ_decode[]; #define ACPI_SMALL_VARIABLE_LENGTH 3 typedef -acpi_status(*acpi_walk_aml_callback) (u8 * aml, +acpi_status(*acpi_walk_aml_callback) (u8 *aml, u32 length, u32 offset, u8 resource_index, void **context); typedef acpi_status(*acpi_pkg_callback) (u8 object_type, - union acpi_operand_object * source_object, + union acpi_operand_object *source_object, union acpi_generic_state * state, void *context); @@ -202,7 +218,9 @@ extern const u8 _acpi_ctype[]; #define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_SP | _ACPI_PU)) #define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) -#endif /* ACPI_USE_SYSTEM_CLIBRARY */ +#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ + +#define ACPI_IS_ASCII(c) ((c) < 0x80) /* * utcopy - Object construction and conversion interfaces @@ -210,11 +228,11 @@ extern const u8 _acpi_ctype[]; acpi_status acpi_ut_build_simple_object(union acpi_operand_object *obj, union acpi_object *user_obj, - u8 * data_space, u32 * buffer_space_used); + u8 *data_space, u32 *buffer_space_used); acpi_status acpi_ut_build_package_object(union acpi_operand_object *obj, - u8 * buffer, u32 * space_used); + u8 *buffer, u32 *space_used); acpi_status acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *obj, @@ -287,9 +305,9 @@ acpi_ut_ptr_exit(u32 line_number, const char *function_name, const char *module_name, u32 component_id, u8 *ptr); -void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id); +void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id); -void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display); +void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display); void acpi_ut_report_error(char *module_name, u32 line_number); @@ -337,15 +355,15 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, */ acpi_status acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id); + struct acpica_device_id ** return_id); acpi_status acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id); + struct acpica_device_id ** return_id); acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, - struct acpica_device_id_list **return_cid_list); + struct acpica_device_id_list ** return_cid_list); /* * utlock - reader/writer locks @@ -479,6 +497,10 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, void acpi_ut_strupr(char *src_string); +void acpi_ut_strlwr(char *src_string); + +int acpi_ut_stricmp(char *string1, char *string2); + void acpi_ut_print_string(char *string, u8 max_length); u8 acpi_ut_valid_acpi_name(u32 name); @@ -487,7 +509,7 @@ void acpi_ut_repair_name(char *name); u8 acpi_ut_valid_acpi_char(char character, u32 position); -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer); +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); /* Values for Base above (16=Hex, 10=Decimal) */ @@ -508,12 +530,12 @@ acpi_ut_display_init_pathname(u8 type, * utresrc */ acpi_status -acpi_ut_walk_aml_resources(u8 * aml, +acpi_ut_walk_aml_resources(u8 *aml, acpi_size aml_length, acpi_walk_aml_callback user_function, void **context); -acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index); +acpi_status acpi_ut_validate_resource(void *aml, u8 *return_index); u32 acpi_ut_get_descriptor_length(void *aml); @@ -524,8 +546,7 @@ u8 acpi_ut_get_resource_header_length(void *aml); u8 acpi_ut_get_resource_type(void *aml); acpi_status -acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, - u8 ** end_tag); +acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag); /* * utmutex - mutex support diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c new file mode 100644 index 00000000000..eacb9ba2b9e --- /dev/null +++ b/drivers/acpi/acpica/utcache.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Module Name: utcache - local cache allocation routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utcache") + +#ifdef ACPI_USE_LOCAL_CACHE +/******************************************************************************* + * + * FUNCTION: acpi_os_create_cache + * + * PARAMETERS: cache_name - Ascii name for the cache + * object_size - Size of each cached object + * max_depth - Maximum depth of the cache (in objects) + * return_cache - Where the new cache object is returned + * + * RETURN: Status + * + * DESCRIPTION: Create a cache object + * + ******************************************************************************/ +acpi_status +acpi_os_create_cache(char *cache_name, + u16 object_size, + u16 max_depth, struct acpi_memory_list ** return_cache) +{ + struct acpi_memory_list *cache; + + ACPI_FUNCTION_ENTRY(); + + if (!cache_name || !return_cache || (object_size < 16)) { + return (AE_BAD_PARAMETER); + } + + /* Create the cache object */ + + cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); + if (!cache) { + return (AE_NO_MEMORY); + } + + /* Populate the cache object and return it */ + + ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + cache->link_offset = 8; + cache->list_name = cache_name; + cache->object_size = object_size; + cache->max_depth = max_depth; + + *return_cache = cache; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_purge_cache + * + * PARAMETERS: cache - Handle to cache object + * + * RETURN: Status + * + * DESCRIPTION: Free all objects within the requested cache. + * + ******************************************************************************/ + +acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) +{ + char *next; + acpi_status status; + + ACPI_FUNCTION_ENTRY(); + + if (!cache) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Walk the list of objects in this cache */ + + while (cache->list_head) { + + /* Delete and unlink one cached state object */ + + next = *(ACPI_CAST_INDIRECT_PTR(char, + &(((char *)cache-> + list_head)[cache-> + link_offset]))); + ACPI_FREE(cache->list_head); + + cache->list_head = next; + cache->current_depth--; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_delete_cache + * + * PARAMETERS: cache - Handle to cache object + * + * RETURN: Status + * + * DESCRIPTION: Free all objects within the requested cache and delete the + * cache object. + * + ******************************************************************************/ + +acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) +{ + acpi_status status; + + ACPI_FUNCTION_ENTRY(); + + /* Purge all objects in the cache */ + + status = acpi_os_purge_cache(cache); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Now we can delete the cache object */ + + acpi_os_free(cache); + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_release_object + * + * PARAMETERS: cache - Handle to cache object + * object - The object to be released + * + * RETURN: None + * + * DESCRIPTION: Release an object to the specified cache. If cache is full, + * the object is deleted. + * + ******************************************************************************/ + +acpi_status +acpi_os_release_object(struct acpi_memory_list * cache, void *object) +{ + acpi_status status; + + ACPI_FUNCTION_ENTRY(); + + if (!cache || !object) { + return (AE_BAD_PARAMETER); + } + + /* If cache is full, just free this object */ + + if (cache->current_depth >= cache->max_depth) { + ACPI_FREE(object); + ACPI_MEM_TRACKING(cache->total_freed++); + } + + /* Otherwise put this object back into the cache */ + + else { + status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Mark the object as cached */ + + ACPI_MEMSET(object, 0xCA, cache->object_size); + ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); + + /* Put the object at the head of the cache list */ + + *(ACPI_CAST_INDIRECT_PTR(char, + &(((char *)object)[cache-> + link_offset]))) = + cache->list_head; + cache->list_head = object; + cache->current_depth++; + + (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); + } + + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_acquire_object + * + * PARAMETERS: cache - Handle to cache object + * + * RETURN: the acquired object. NULL on error + * + * DESCRIPTION: Get an object from the specified cache. If cache is empty, + * the object is allocated. + * + ******************************************************************************/ + +void *acpi_os_acquire_object(struct acpi_memory_list *cache) +{ + acpi_status status; + void *object; + + ACPI_FUNCTION_NAME(os_acquire_object); + + if (!cache) { + return (NULL); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (NULL); + } + + ACPI_MEM_TRACKING(cache->requests++); + + /* Check the cache first */ + + if (cache->list_head) { + + /* There is an object available, use it */ + + object = cache->list_head; + cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char, + &(((char *) + object)[cache-> + link_offset]))); + + cache->current_depth--; + + ACPI_MEM_TRACKING(cache->hits++); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Object %p from %s cache\n", object, + cache->list_name)); + + status = acpi_ut_release_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (NULL); + } + + /* Clear (zero) the previously used Object */ + + ACPI_MEMSET(object, 0, cache->object_size); + } else { + /* The cache is empty, create a new object */ + + ACPI_MEM_TRACKING(cache->total_allocated++); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + if ((cache->total_allocated - cache->total_freed) > + cache->max_occupied) { + cache->max_occupied = + cache->total_allocated - cache->total_freed; + } +#endif + + /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ + + status = acpi_ut_release_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (NULL); + } + + object = ACPI_ALLOCATE_ZEROED(cache->object_size); + if (!object) { + return (NULL); + } + } + + return (object); +} +#endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/drivers/acpi/acpica/utclib.c b/drivers/acpi/acpica/utclib.c new file mode 100644 index 00000000000..f887f93e56a --- /dev/null +++ b/drivers/acpi/acpica/utclib.c @@ -0,0 +1,748 @@ +/****************************************************************************** + * + * Module Name: cmclib - Local implementation of C library functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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" + +/* + * These implementations of standard C Library routines can optionally be + * used if a C library is not available. In general, they are less efficient + * than an inline or assembly implementation + */ + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("cmclib") + +#ifndef ACPI_USE_SYSTEM_CLIBRARY +#define NEGATIVE 1 +#define POSITIVE 0 +/******************************************************************************* + * + * FUNCTION: acpi_ut_memcmp (memcmp) + * + * PARAMETERS: buffer1 - First Buffer + * buffer2 - Second Buffer + * count - Maximum # of bytes to compare + * + * RETURN: Index where Buffers mismatched, or 0 if Buffers matched + * + * DESCRIPTION: Compare two Buffers, with a maximum length + * + ******************************************************************************/ +int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count) +{ + + return ((count == ACPI_SIZE_MAX) ? 0 : ((unsigned char)*buffer1 - + (unsigned char)*buffer2)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_memcpy (memcpy) + * + * PARAMETERS: dest - Target of the copy + * src - Source buffer to copy + * count - Number of bytes to copy + * + * RETURN: Dest + * + * DESCRIPTION: Copy arbitrary bytes of memory + * + ******************************************************************************/ + +void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count) +{ + char *new = (char *)dest; + char *old = (char *)src; + + while (count) { + *new = *old; + new++; + old++; + count--; + } + + return (dest); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_memset (memset) + * + * PARAMETERS: dest - Buffer to set + * value - Value to set each byte of memory + * count - Number of bytes to set + * + * RETURN: Dest + * + * DESCRIPTION: Initialize a buffer to a known value. + * + ******************************************************************************/ + +void *acpi_ut_memset(void *dest, u8 value, acpi_size count) +{ + char *new = (char *)dest; + + while (count) { + *new = (char)value; + new++; + count--; + } + + return (dest); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strlen (strlen) + * + * PARAMETERS: string - Null terminated string + * + * RETURN: Length + * + * DESCRIPTION: Returns the length of the input string + * + ******************************************************************************/ + +acpi_size acpi_ut_strlen(const char *string) +{ + u32 length = 0; + + /* Count the string until a null is encountered */ + + while (*string) { + length++; + string++; + } + + return (length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strcpy (strcpy) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Copy a null terminated string + * + ******************************************************************************/ + +char *acpi_ut_strcpy(char *dst_string, const char *src_string) +{ + char *string = dst_string; + + /* Move bytes brute force */ + + while (*src_string) { + *string = *src_string; + + string++; + src_string++; + } + + /* Null terminate */ + + *string = 0; + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strncpy (strncpy) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * count - Maximum # of bytes to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Copy a null terminated string, with a maximum length + * + ******************************************************************************/ + +char *acpi_ut_strncpy(char *dst_string, const char *src_string, acpi_size count) +{ + char *string = dst_string; + + /* Copy the string */ + + for (string = dst_string; + count && (count--, (*string++ = *src_string++));) {; + } + + /* Pad with nulls if necessary */ + + while (count--) { + *string = 0; + string++; + } + + /* Return original pointer */ + + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strcmp (strcmp) + * + * PARAMETERS: string1 - First string + * string2 - Second string + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings + * + ******************************************************************************/ + +int acpi_ut_strcmp(const char *string1, const char *string2) +{ + + for (; (*string1 == *string2); string2++) { + if (!*string1++) { + return (0); + } + } + + return ((unsigned char)*string1 - (unsigned char)*string2); +} + +#ifdef ACPI_FUTURE_IMPLEMENTATION +/* Not used at this time */ +/******************************************************************************* + * + * FUNCTION: acpi_ut_strchr (strchr) + * + * PARAMETERS: string - Search string + * ch - character to search for + * + * RETURN: Ptr to char or NULL if not found + * + * DESCRIPTION: Search a string for a character + * + ******************************************************************************/ + +char *acpi_ut_strchr(const char *string, int ch) +{ + + for (; (*string); string++) { + if ((*string) == (char)ch) { + return ((char *)string); + } + } + + return (NULL); +} +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strncmp (strncmp) + * + * PARAMETERS: string1 - First string + * string2 - Second string + * count - Maximum # of bytes to compare + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings, with a maximum length + * + ******************************************************************************/ + +int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count) +{ + + for (; count-- && (*string1 == *string2); string2++) { + if (!*string1++) { + return (0); + } + } + + return ((count == ACPI_SIZE_MAX) ? 0 : ((unsigned char)*string1 - + (unsigned char)*string2)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strcat (Strcat) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Append a null terminated string to a null terminated string + * + ******************************************************************************/ + +char *acpi_ut_strcat(char *dst_string, const char *src_string) +{ + char *string; + + /* Find end of the destination string */ + + for (string = dst_string; *string++;) {; + } + + /* Concatenate the string */ + + for (--string; (*string++ = *src_string++);) {; + } + + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strncat (strncat) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * count - Maximum # of bytes to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Append a null terminated string to a null terminated string, + * with a maximum count. + * + ******************************************************************************/ + +char *acpi_ut_strncat(char *dst_string, const char *src_string, acpi_size count) +{ + char *string; + + if (count) { + + /* Find end of the destination string */ + + for (string = dst_string; *string++;) {; + } + + /* Concatenate the string */ + + for (--string; (*string++ = *src_string++) && --count;) {; + } + + /* Null terminate if necessary */ + + if (!count) { + *string = 0; + } + } + + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strstr (strstr) + * + * PARAMETERS: string1 - Target string + * string2 - Substring to search for + * + * RETURN: Where substring match starts, Null if no match found + * + * DESCRIPTION: Checks if String2 occurs in String1. This is not really a + * full implementation of strstr, only sufficient for command + * matching + * + ******************************************************************************/ + +char *acpi_ut_strstr(char *string1, char *string2) +{ + char *string; + + if (acpi_ut_strlen(string2) > acpi_ut_strlen(string1)) { + return (NULL); + } + + /* Walk entire string, comparing the letters */ + + for (string = string1; *string2;) { + if (*string2 != *string) { + return (NULL); + } + + string2++; + string++; + } + + return (string1); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strtoul (strtoul) + * + * PARAMETERS: string - Null terminated string + * terminater - Where a pointer to the terminating byte is + * returned + * base - Radix of the string + * + * RETURN: Converted value + * + * DESCRIPTION: Convert a string into a 32-bit unsigned value. + * Note: use acpi_ut_strtoul64 for 64-bit integers. + * + ******************************************************************************/ + +u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base) +{ + u32 converted = 0; + u32 index; + u32 sign; + const char *string_start; + u32 return_value = 0; + acpi_status status = AE_OK; + + /* + * Save the value of the pointer to the buffer's first + * character, save the current errno value, and then + * skip over any white space in the buffer: + */ + string_start = string; + while (ACPI_IS_SPACE(*string) || *string == '\t') { + ++string; + } + + /* + * The buffer may contain an optional plus or minus sign. + * If it does, then skip over it but remember what is was: + */ + if (*string == '-') { + sign = NEGATIVE; + ++string; + } else if (*string == '+') { + ++string; + sign = POSITIVE; + } else { + sign = POSITIVE; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is octal, decimal, or hexadecimal: + */ + if (base == 0) { + if (*string == '0') { + if (acpi_ut_to_lower(*(++string)) == 'x') { + base = 16; + ++string; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base < 2 || base > 36) { + /* + * The specified Base parameter is not in the domain of + * this function: + */ + goto done; + } + + /* + * For octal and hexadecimal bases, skip over the leading + * 0 or 0x, if they are present. + */ + if (base == 8 && *string == '0') { + string++; + } + + if (base == 16 && + *string == '0' && acpi_ut_to_lower(*(++string)) == 'x') { + string++; + } + + /* + * Main loop: convert the string to an unsigned long: + */ + while (*string) { + if (ACPI_IS_DIGIT(*string)) { + index = (u32)((u8)*string - '0'); + } else { + index = (u32)acpi_ut_to_upper(*string); + if (ACPI_IS_UPPER(index)) { + index = index - 'A' + 10; + } else { + goto done; + } + } + + if (index >= base) { + goto done; + } + + /* + * Check to see if value is out of range: + */ + + if (return_value > ((ACPI_UINT32_MAX - (u32)index) / (u32)base)) { + status = AE_ERROR; + return_value = 0; /* reset */ + } else { + return_value *= base; + return_value += index; + converted = 1; + } + + ++string; + } + + done: + /* + * If appropriate, update the caller's pointer to the next + * unconverted character in the buffer. + */ + if (terminator) { + if (converted == 0 && return_value == 0 && string != NULL) { + *terminator = (char *)string_start; + } else { + *terminator = (char *)string; + } + } + + if (status == AE_ERROR) { + return_value = ACPI_UINT32_MAX; + } + + /* + * If a minus sign was present, then "the conversion is negated": + */ + if (sign == NEGATIVE) { + return_value = (ACPI_UINT32_MAX - return_value) + 1; + } + + return (return_value); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_to_upper (TOUPPER) + * + * PARAMETERS: c - Character to convert + * + * RETURN: Converted character as an int + * + * DESCRIPTION: Convert character to uppercase + * + ******************************************************************************/ + +int acpi_ut_to_upper(int c) +{ + + return (ACPI_IS_LOWER(c) ? ((c) - 0x20) : (c)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_to_lower (TOLOWER) + * + * PARAMETERS: c - Character to convert + * + * RETURN: Converted character as an int + * + * DESCRIPTION: Convert character to lowercase + * + ******************************************************************************/ + +int acpi_ut_to_lower(int c) +{ + + return (ACPI_IS_UPPER(c) ? ((c) + 0x20) : (c)); +} + +/******************************************************************************* + * + * FUNCTION: is* functions + * + * DESCRIPTION: is* functions use the ctype table below + * + ******************************************************************************/ + +const u8 _acpi_ctype[257] = { + _ACPI_CN, /* 0x0 0. */ + _ACPI_CN, /* 0x1 1. */ + _ACPI_CN, /* 0x2 2. */ + _ACPI_CN, /* 0x3 3. */ + _ACPI_CN, /* 0x4 4. */ + _ACPI_CN, /* 0x5 5. */ + _ACPI_CN, /* 0x6 6. */ + _ACPI_CN, /* 0x7 7. */ + _ACPI_CN, /* 0x8 8. */ + _ACPI_CN | _ACPI_SP, /* 0x9 9. */ + _ACPI_CN | _ACPI_SP, /* 0xA 10. */ + _ACPI_CN | _ACPI_SP, /* 0xB 11. */ + _ACPI_CN | _ACPI_SP, /* 0xC 12. */ + _ACPI_CN | _ACPI_SP, /* 0xD 13. */ + _ACPI_CN, /* 0xE 14. */ + _ACPI_CN, /* 0xF 15. */ + _ACPI_CN, /* 0x10 16. */ + _ACPI_CN, /* 0x11 17. */ + _ACPI_CN, /* 0x12 18. */ + _ACPI_CN, /* 0x13 19. */ + _ACPI_CN, /* 0x14 20. */ + _ACPI_CN, /* 0x15 21. */ + _ACPI_CN, /* 0x16 22. */ + _ACPI_CN, /* 0x17 23. */ + _ACPI_CN, /* 0x18 24. */ + _ACPI_CN, /* 0x19 25. */ + _ACPI_CN, /* 0x1A 26. */ + _ACPI_CN, /* 0x1B 27. */ + _ACPI_CN, /* 0x1C 28. */ + _ACPI_CN, /* 0x1D 29. */ + _ACPI_CN, /* 0x1E 30. */ + _ACPI_CN, /* 0x1F 31. */ + _ACPI_XS | _ACPI_SP, /* 0x20 32. ' ' */ + _ACPI_PU, /* 0x21 33. '!' */ + _ACPI_PU, /* 0x22 34. '"' */ + _ACPI_PU, /* 0x23 35. '#' */ + _ACPI_PU, /* 0x24 36. '$' */ + _ACPI_PU, /* 0x25 37. '%' */ + _ACPI_PU, /* 0x26 38. '&' */ + _ACPI_PU, /* 0x27 39. ''' */ + _ACPI_PU, /* 0x28 40. '(' */ + _ACPI_PU, /* 0x29 41. ')' */ + _ACPI_PU, /* 0x2A 42. '*' */ + _ACPI_PU, /* 0x2B 43. '+' */ + _ACPI_PU, /* 0x2C 44. ',' */ + _ACPI_PU, /* 0x2D 45. '-' */ + _ACPI_PU, /* 0x2E 46. '.' */ + _ACPI_PU, /* 0x2F 47. '/' */ + _ACPI_XD | _ACPI_DI, /* 0x30 48. '0' */ + _ACPI_XD | _ACPI_DI, /* 0x31 49. '1' */ + _ACPI_XD | _ACPI_DI, /* 0x32 50. '2' */ + _ACPI_XD | _ACPI_DI, /* 0x33 51. '3' */ + _ACPI_XD | _ACPI_DI, /* 0x34 52. '4' */ + _ACPI_XD | _ACPI_DI, /* 0x35 53. '5' */ + _ACPI_XD | _ACPI_DI, /* 0x36 54. '6' */ + _ACPI_XD | _ACPI_DI, /* 0x37 55. '7' */ + _ACPI_XD | _ACPI_DI, /* 0x38 56. '8' */ + _ACPI_XD | _ACPI_DI, /* 0x39 57. '9' */ + _ACPI_PU, /* 0x3A 58. ':' */ + _ACPI_PU, /* 0x3B 59. ';' */ + _ACPI_PU, /* 0x3C 60. '<' */ + _ACPI_PU, /* 0x3D 61. '=' */ + _ACPI_PU, /* 0x3E 62. '>' */ + _ACPI_PU, /* 0x3F 63. '?' */ + _ACPI_PU, /* 0x40 64. '@' */ + _ACPI_XD | _ACPI_UP, /* 0x41 65. 'A' */ + _ACPI_XD | _ACPI_UP, /* 0x42 66. 'B' */ + _ACPI_XD | _ACPI_UP, /* 0x43 67. 'C' */ + _ACPI_XD | _ACPI_UP, /* 0x44 68. 'D' */ + _ACPI_XD | _ACPI_UP, /* 0x45 69. 'E' */ + _ACPI_XD | _ACPI_UP, /* 0x46 70. 'F' */ + _ACPI_UP, /* 0x47 71. 'G' */ + _ACPI_UP, /* 0x48 72. 'H' */ + _ACPI_UP, /* 0x49 73. 'I' */ + _ACPI_UP, /* 0x4A 74. 'J' */ + _ACPI_UP, /* 0x4B 75. 'K' */ + _ACPI_UP, /* 0x4C 76. 'L' */ + _ACPI_UP, /* 0x4D 77. 'M' */ + _ACPI_UP, /* 0x4E 78. 'N' */ + _ACPI_UP, /* 0x4F 79. 'O' */ + _ACPI_UP, /* 0x50 80. 'P' */ + _ACPI_UP, /* 0x51 81. 'Q' */ + _ACPI_UP, /* 0x52 82. 'R' */ + _ACPI_UP, /* 0x53 83. 'S' */ + _ACPI_UP, /* 0x54 84. 'T' */ + _ACPI_UP, /* 0x55 85. 'U' */ + _ACPI_UP, /* 0x56 86. 'V' */ + _ACPI_UP, /* 0x57 87. 'W' */ + _ACPI_UP, /* 0x58 88. 'X' */ + _ACPI_UP, /* 0x59 89. 'Y' */ + _ACPI_UP, /* 0x5A 90. 'Z' */ + _ACPI_PU, /* 0x5B 91. '[' */ + _ACPI_PU, /* 0x5C 92. '\' */ + _ACPI_PU, /* 0x5D 93. ']' */ + _ACPI_PU, /* 0x5E 94. '^' */ + _ACPI_PU, /* 0x5F 95. '_' */ + _ACPI_PU, /* 0x60 96. '`' */ + _ACPI_XD | _ACPI_LO, /* 0x61 97. 'a' */ + _ACPI_XD | _ACPI_LO, /* 0x62 98. 'b' */ + _ACPI_XD | _ACPI_LO, /* 0x63 99. 'c' */ + _ACPI_XD | _ACPI_LO, /* 0x64 100. 'd' */ + _ACPI_XD | _ACPI_LO, /* 0x65 101. 'e' */ + _ACPI_XD | _ACPI_LO, /* 0x66 102. 'f' */ + _ACPI_LO, /* 0x67 103. 'g' */ + _ACPI_LO, /* 0x68 104. 'h' */ + _ACPI_LO, /* 0x69 105. 'i' */ + _ACPI_LO, /* 0x6A 106. 'j' */ + _ACPI_LO, /* 0x6B 107. 'k' */ + _ACPI_LO, /* 0x6C 108. 'l' */ + _ACPI_LO, /* 0x6D 109. 'm' */ + _ACPI_LO, /* 0x6E 110. 'n' */ + _ACPI_LO, /* 0x6F 111. 'o' */ + _ACPI_LO, /* 0x70 112. 'p' */ + _ACPI_LO, /* 0x71 113. 'q' */ + _ACPI_LO, /* 0x72 114. 'r' */ + _ACPI_LO, /* 0x73 115. 's' */ + _ACPI_LO, /* 0x74 116. 't' */ + _ACPI_LO, /* 0x75 117. 'u' */ + _ACPI_LO, /* 0x76 118. 'v' */ + _ACPI_LO, /* 0x77 119. 'w' */ + _ACPI_LO, /* 0x78 120. 'x' */ + _ACPI_LO, /* 0x79 121. 'y' */ + _ACPI_LO, /* 0x7A 122. 'z' */ + _ACPI_PU, /* 0x7B 123. '{' */ + _ACPI_PU, /* 0x7C 124. '|' */ + _ACPI_PU, /* 0x7D 125. '}' */ + _ACPI_PU, /* 0x7E 126. '~' */ + _ACPI_CN, /* 0x7F 127. */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 to 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 to 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 to 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 to 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 to 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 to 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 to 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0 to 0x100 */ +}; + +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index e810894149a..6e3ae6a23f0 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -47,8 +47,9 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") + #ifdef ACPI_DEBUG_OUTPUT -static acpi_thread_id acpi_gbl_prev_thread_id; +static acpi_thread_id acpi_gbl_prev_thread_id = (acpi_thread_id) 0xFFFFFFFF; static char *acpi_gbl_fn_entry_str = "----Entry"; static char *acpi_gbl_fn_exit_str = "----Exit-"; @@ -109,7 +110,7 @@ void acpi_ut_track_stack_ptr(void) * RETURN: Updated pointer to the function name * * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. - * This allows compiler macros such as __func__ to be used + * This allows compiler macros such as __FUNCTION__ to be used * with no change to the debug output. * ******************************************************************************/ @@ -519,7 +520,7 @@ acpi_ut_ptr_exit(u32 line_number, * ******************************************************************************/ -void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) +void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display) { u32 i = 0; u32 j; @@ -636,7 +637,7 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) * ******************************************************************************/ -void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) +void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) { /* Only dump the buffer if tracing is enabled */ diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index d91d88df2a9..0fed4bcc84b 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include "accommon.h" #include "acnamesp.h" @@ -201,8 +199,8 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) */ acpi_gbl_owner_id_mask[j] |= (1 << k); - acpi_gbl_last_owner_id_index = (u8) j; - acpi_gbl_next_owner_id_offset = (u8) (k + 1); + acpi_gbl_last_owner_id_index = (u8)j; + acpi_gbl_next_owner_id_offset = (u8)(k + 1); /* * Construct encoded ID from the index and bit position @@ -339,6 +337,73 @@ void acpi_ut_strupr(char *src_string) return; } +#ifdef ACPI_ASL_COMPILER +/******************************************************************************* + * + * FUNCTION: acpi_ut_strlwr (strlwr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert string to lowercase + * + * NOTE: This is not a POSIX function, so it appears here, not in utclib.c + * + ******************************************************************************/ + +void acpi_ut_strlwr(char *src_string) +{ + char *string; + + ACPI_FUNCTION_ENTRY(); + + if (!src_string) { + return; + } + + /* Walk entire string, lowercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char)ACPI_TOLOWER(*string); + } + + return; +} + +/****************************************************************************** + * + * FUNCTION: acpi_ut_stricmp + * + * PARAMETERS: string1 - first string to compare + * string2 - second string to compare + * + * RETURN: int that signifies string relationship. Zero means strings + * are equal. + * + * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare + * strings with no case sensitivity) + * + ******************************************************************************/ + +int acpi_ut_stricmp(char *string1, char *string2) +{ + int c1; + int c2; + + do { + c1 = tolower((int)*string1); + c2 = tolower((int)*string2); + + string1++; + string2++; + } + while ((c1 == c2) && (c1)); + + return (c1 - c2); +} +#endif + /******************************************************************************* * * FUNCTION: acpi_ut_print_string @@ -638,7 +703,16 @@ u8 acpi_ut_valid_acpi_name(u32 name) * RETURN: Repaired version of the name * * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and - * return the new name. + * return the new name. NOTE: the Name parameter must reside in + * read/write memory, cannot be a const. + * + * An ACPI Name must consist of valid ACPI characters. We will repair the name + * if necessary because we don't want to abort because of this, but we want + * all namespace names to be printable. A warning message is appropriate. + * + * This issue came up because there are in fact machines that exhibit + * this problem, and we want to be able to enable ACPI support for them, + * even though there are a few bad names. * ******************************************************************************/ @@ -699,7 +773,7 @@ void acpi_ut_repair_name(char *name) * ******************************************************************************/ -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) { u32 this_digit = 0; u64 return_value = 0; @@ -772,14 +846,14 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) /* Convert ASCII 0-9 to Decimal value */ - this_digit = ((u8) * string) - '0'; + this_digit = ((u8)*string) - '0'; } else if (base == 10) { /* Digit is out of range; possible in to_integer case only */ term = 1; } else { - this_digit = (u8) ACPI_TOUPPER(*string); + this_digit = (u8)ACPI_TOUPPER(*string); if (ACPI_IS_XDIGIT((char)this_digit)) { /* Convert ASCII Hex char to value */ @@ -806,8 +880,9 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) valid_digits++; - if (sign_of0x && ((valid_digits > 16) - || ((valid_digits > 8) && mode32))) { + if (sign_of0x + && ((valid_digits > 16) + || ((valid_digits > 8) && mode32))) { /* * This is to_integer operation case. * No any restrictions for string-to-integer conversion, @@ -818,7 +893,7 @@ 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), + (void)acpi_ut_short_divide((dividend - (u64)this_digit), base, "ient, NULL); if (return_value > quotient) { @@ -908,7 +983,7 @@ acpi_ut_create_update_state_and_push(union acpi_operand_object *object, ******************************************************************************/ acpi_status -acpi_ut_walk_package_tree(union acpi_operand_object * source_object, +acpi_ut_walk_package_tree(union acpi_operand_object *source_object, void *target_object, acpi_pkg_callback walk_callback, void *context) { diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c new file mode 100644 index 00000000000..73ca27d40f9 --- /dev/null +++ b/drivers/acpi/acpica/uttrack.c @@ -0,0 +1,650 @@ +/****************************************************************************** + * + * Module Name: uttrack - Memory allocation tracking routines (debug only) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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. + */ + +/* + * These procedures are used for tracking memory leaks in the subsystem, and + * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. + * + * Each memory allocation is tracked via a doubly linked list. Each + * element contains the caller's component, module name, function name, and + * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call + * acpi_ut_track_allocation to add an element to the list; deletion + * occurs in the body of acpi_ut_free. + */ + +#include +#include "accommon.h" + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("uttrack") + +/* Local prototypes */ +static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation); + +static acpi_status +acpi_ut_track_allocation(struct acpi_debug_mem_block *address, + acpi_size size, + u8 alloc_type, + u32 component, const char *module, u32 line); + +static acpi_status +acpi_ut_remove_allocation(struct acpi_debug_mem_block *address, + u32 component, const char *module, u32 line); + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_list + * + * PARAMETERS: cache_name - Ascii name for the cache + * object_size - Size of each cached object + * return_cache - Where the new cache object is returned + * + * RETURN: Status + * + * DESCRIPTION: Create a local memory list for tracking purposed + * + ******************************************************************************/ + +acpi_status +acpi_ut_create_list(char *list_name, + u16 object_size, struct acpi_memory_list **return_cache) +{ + struct acpi_memory_list *cache; + + cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); + if (!cache) { + return (AE_NO_MEMORY); + } + + ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + + cache->list_name = list_name; + cache->object_size = object_size; + + *return_cache = cache; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate_and_track + * + * PARAMETERS: size - Size of the allocation + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void *acpi_ut_allocate_and_track(acpi_size size, + u32 component, const char *module, u32 line) +{ + struct acpi_debug_mem_block *allocation; + acpi_status status; + + allocation = + acpi_ut_allocate(size + sizeof(struct acpi_debug_mem_header), + component, module, line); + if (!allocation) { + return (NULL); + } + + status = acpi_ut_track_allocation(allocation, size, + ACPI_MEM_MALLOC, component, module, + line); + if (ACPI_FAILURE(status)) { + acpi_os_free(allocation); + return (NULL); + } + + 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 = + acpi_gbl_global_list->current_total_size; + } + + return ((void *)&allocation->user_space); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate_zeroed_and_track + * + * PARAMETERS: size - Size of the allocation + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void *acpi_ut_allocate_zeroed_and_track(acpi_size size, + u32 component, + const char *module, u32 line) +{ + struct acpi_debug_mem_block *allocation; + acpi_status status; + + allocation = + acpi_ut_allocate_zeroed(size + sizeof(struct acpi_debug_mem_header), + component, module, line); + if (!allocation) { + + /* Report allocation error */ + + ACPI_ERROR((module, line, + "Could not allocate size %u", (u32)size)); + return (NULL); + } + + status = acpi_ut_track_allocation(allocation, size, + ACPI_MEM_CALLOC, component, module, + line); + if (ACPI_FAILURE(status)) { + acpi_os_free(allocation); + return (NULL); + } + + 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 = + acpi_gbl_global_list->current_total_size; + } + + return ((void *)&allocation->user_space); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_free_and_track + * + * PARAMETERS: allocation - Address of the memory to deallocate + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: None + * + * DESCRIPTION: Frees the memory at Allocation + * + ******************************************************************************/ + +void +acpi_ut_free_and_track(void *allocation, + u32 component, const char *module, u32 line) +{ + struct acpi_debug_mem_block *debug_block; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ut_free, allocation); + + if (NULL == allocation) { + ACPI_ERROR((module, line, "Attempt to delete a NULL address")); + + return_VOID; + } + + debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block, + (((char *)allocation) - + sizeof(struct acpi_debug_mem_header))); + + 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); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Could not free memory")); + } + + acpi_os_free(debug_block); + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation)); + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_find_allocation + * + * PARAMETERS: allocation - Address of allocated memory + * + * RETURN: A list element if found; NULL otherwise. + * + * DESCRIPTION: Searches for an element in the global allocation tracking list. + * + ******************************************************************************/ + +static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation) +{ + struct acpi_debug_mem_block *element; + + ACPI_FUNCTION_ENTRY(); + + element = acpi_gbl_global_list->list_head; + + /* Search for the address. */ + + while (element) { + if (element == allocation) { + return (element); + } + + element = element->next; + } + + return (NULL); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_track_allocation + * + * PARAMETERS: allocation - Address of allocated memory + * size - Size of the allocation + * alloc_type - MEM_MALLOC or MEM_CALLOC + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: None. + * + * DESCRIPTION: Inserts an element into the global allocation tracking list. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, + acpi_size size, + u8 alloc_type, + u32 component, const char *module, u32 line) +{ + struct acpi_memory_list *mem_list; + struct acpi_debug_mem_block *element; + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation); + + if (acpi_gbl_disable_mem_tracking) { + return_ACPI_STATUS(AE_OK); + } + + mem_list = acpi_gbl_global_list; + status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * Search list for this address to make sure it is not already on the list. + * This will catch several kinds of problems. + */ + element = acpi_ut_find_allocation(allocation); + if (element) { + ACPI_ERROR((AE_INFO, + "UtTrackAllocation: Allocation already present in list! (%p)", + allocation)); + + ACPI_ERROR((AE_INFO, "Element %p Address %p", + element, allocation)); + + goto unlock_and_exit; + } + + /* Fill in the instance data. */ + + allocation->size = (u32)size; + allocation->alloc_type = alloc_type; + allocation->component = component; + allocation->line = line; + + ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME); + allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; + + /* Insert at list head */ + + if (mem_list->list_head) { + ((struct acpi_debug_mem_block *)(mem_list->list_head))-> + previous = allocation; + } + + allocation->next = mem_list->list_head; + allocation->previous = NULL; + + mem_list->list_head = allocation; + + unlock_and_exit: + status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_allocation + * + * PARAMETERS: allocation - Address of allocated memory + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: + * + * DESCRIPTION: Deletes an element from the global allocation tracking list. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, + u32 component, const char *module, u32 line) +{ + struct acpi_memory_list *mem_list; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_remove_allocation); + + if (acpi_gbl_disable_mem_tracking) { + return_ACPI_STATUS(AE_OK); + } + + mem_list = acpi_gbl_global_list; + if (NULL == mem_list->list_head) { + + /* No allocations! */ + + ACPI_ERROR((module, line, + "Empty allocation list, nothing to free!")); + + return_ACPI_STATUS(AE_OK); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Unlink */ + + if (allocation->previous) { + (allocation->previous)->next = allocation->next; + } else { + mem_list->list_head = allocation->next; + } + + if (allocation->next) { + (allocation->next)->previous = allocation->previous; + } + + /* Mark the segment as deleted */ + + ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size); + + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", + allocation->size)); + + status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_allocation_info + * + * PARAMETERS: + * + * RETURN: None + * + * DESCRIPTION: Print some info about the outstanding allocations. + * + ******************************************************************************/ + +void acpi_ut_dump_allocation_info(void) +{ +/* + struct acpi_memory_list *mem_list; +*/ + + ACPI_FUNCTION_TRACE(ut_dump_allocation_info); + +/* + 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))); + + 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))); + + 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))); + + 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))); + + 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))); + + 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))))); +*/ + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_allocations + * + * PARAMETERS: component - Component(s) to dump info for. + * module - Module to dump info for. NULL means all. + * + * RETURN: None + * + * DESCRIPTION: Print a list of all outstanding allocations. + * + ******************************************************************************/ + +void acpi_ut_dump_allocations(u32 component, const char *module) +{ + struct acpi_debug_mem_block *element; + union acpi_descriptor *descriptor; + u32 num_outstanding = 0; + u8 descriptor_type; + + ACPI_FUNCTION_TRACE(ut_dump_allocations); + + if (acpi_gbl_disable_mem_tracking) { + return; + } + + /* + * Walk the allocation list. + */ + if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) { + return; + } + + element = acpi_gbl_global_list->list_head; + while (element) { + if ((element->component & component) && + ((module == NULL) + || (0 == ACPI_STRCMP(module, element->module)))) { + descriptor = + ACPI_CAST_PTR(union acpi_descriptor, + &element->user_space); + + if (element->size < + sizeof(struct acpi_common_descriptor)) { + acpi_os_printf("%p Length 0x%04X %9.9s-%u " + "[Not a Descriptor - too small]\n", + descriptor, element->size, + element->module, element->line); + } else { + /* Ignore allocated objects that are in a cache */ + + if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) != + ACPI_DESC_TYPE_CACHED) { + acpi_os_printf + ("%p Length 0x%04X %9.9s-%u [%s] ", + descriptor, element->size, + element->module, element->line, + acpi_ut_get_descriptor_name + (descriptor)); + + /* Validate the descriptor type using Type field and length */ + + descriptor_type = 0; /* Not a valid descriptor type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE + (descriptor)) { + case ACPI_DESC_TYPE_OPERAND: + if (element->size == + sizeof(union + acpi_operand_object)) + { + descriptor_type = + ACPI_DESC_TYPE_OPERAND; + } + break; + + case ACPI_DESC_TYPE_PARSER: + if (element->size == + sizeof(union + acpi_parse_object)) { + descriptor_type = + ACPI_DESC_TYPE_PARSER; + } + break; + + case ACPI_DESC_TYPE_NAMED: + if (element->size == + sizeof(struct + acpi_namespace_node)) + { + descriptor_type = + ACPI_DESC_TYPE_NAMED; + } + break; + + default: + break; + } + + /* Display additional info for the major descriptor types */ + + switch (descriptor_type) { + case ACPI_DESC_TYPE_OPERAND: + acpi_os_printf + ("%12.12s RefCount 0x%04X\n", + acpi_ut_get_type_name + (descriptor->object.common. + type), + descriptor->object.common. + reference_count); + break; + + case ACPI_DESC_TYPE_PARSER: + acpi_os_printf + ("AmlOpcode 0x%04hX\n", + descriptor->op.asl. + aml_opcode); + break; + + case ACPI_DESC_TYPE_NAMED: + acpi_os_printf("%4.4s\n", + acpi_ut_get_node_name + (&descriptor-> + node)); + break; + + default: + acpi_os_printf("\n"); + break; + } + } + } + + num_outstanding++; + } + + element = element->next; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY); + + /* Print summary */ + + if (!num_outstanding) { + ACPI_INFO((AE_INFO, "No outstanding allocations")); + } else { + ACPI_ERROR((AE_INFO, "%u(0x%X) Outstanding allocations", + num_outstanding, num_outstanding)); + } + + return_VOID; +} + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ -- cgit v1.2.3 From f540fadf29a6987efbfa7daf10976935fd59ae7c Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 31 Oct 2012 02:25:15 +0000 Subject: ACPICA: Fix unmerged debugger divergences. Debugger improvements in ACPICA are always ignored by ACPICA Linux release. This will lead to divergences between Linux and ACPICA. This patch fixes such unmerged debugger updates. Following patches are included: 1. Fixed a couple compiler warnings for extra extern Wed, 14 Mar 2007 21:12:19 +0000 2. Cleanup for internal Reference Object. Wed, 27 Aug 2008 10:11:30 -0700 3. Debugger: Lock method args for multithread command. Fri, 24 Apr 2009 12:28:49 -0700 4. Debugger: Add max count argument for Batch command. Tue, 29 Sep 2009 12:31:58 -0700 5. Add new host interfaces for _OSI support. Thu, 5 Aug 2010 14:18:28 -0700 6. Increase debugger buffer size for method return objects. Wed, 17 Nov 2010 13:48:30 -0800 7. Debugger: Add command to display status of global handlers. Tue, 25 Jan 2011 13:47:58 -0800 8. Debugger: Split large dbcmds.c file. Wed, 26 Jan 2011 13:03:41 -0800 9. Debugger/AcpiExec: Add support to pass complex args to methods. Tue, 17 May 2011 13:33:39 -0700 10.Debugger: Add Template command to dump resource templates. Fri, 28 Oct 2011 14:18:51 -0700 11.Support for custom ACPICA build for ACPI 5.0 reduced hardware. Wed, 1 Feb 2012 13:18:17 -0800 12.Debugger: Improve command help support. Wed, 15 Feb 2012 07:59:26 -0800 13.Update ACPI_HW_DEPENDENT* macro invocations. Wed, 15 Feb 2012 08:14:08 -0800 14.Debugger: Rename function to simplify source code conversion. Wed, 13 Jun 2012 14:23:06 -0700 15.Debugger: Enhance "Tables" and "Unload" commands. Fri, 29 Jun 2012 13:10:58 -0700 16.Debugger: update prototype for AcpiDbSleep function. Fri, 17 Aug 2012 13:43:02 -0700 This patch will not affect the generated vmlinx binary. This will decrease 264 lines of 20120913 divergence.diff. Signed-off-by: Robert Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 94 ++++++++++++++++++++++++++++-------------- drivers/acpi/acpica/acglobal.h | 69 ++++++++++++++++--------------- drivers/acpi/acpica/aclocal.h | 2 + include/acpi/acconfig.h | 1 + 4 files changed, 101 insertions(+), 65 deletions(-) diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 5e8abb07724..432a318c9ed 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -44,17 +44,28 @@ #ifndef __ACDEBUG_H__ #define __ACDEBUG_H__ -#define ACPI_DEBUG_BUFFER_SIZE 4196 +#define ACPI_DEBUG_BUFFER_SIZE 0x4000 /* 16K buffer for return objects */ -struct command_info { +struct acpi_db_command_info { char *name; /* Command Name */ u8 min_args; /* Minimum arguments required */ }; -struct argument_info { +struct acpi_db_command_help { + u8 line_count; /* Number of help lines */ + char *invocation; /* Command Invocation */ + char *description; /* Command Description */ +}; + +struct acpi_db_argument_info { char *name; /* Argument Name */ }; +struct acpi_db_execute_walk { + u32 count; + u32 max_count; +}; + #define PARAM_LIST(pl) pl #define DBTEST_OUTPUT_LEVEL(lvl) if (acpi_gbl_db_opt_verbose) #define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\ @@ -77,59 +88,71 @@ acpi_db_single_step(struct acpi_walk_state *walk_state, /* * dbcmds - debug commands and output routines */ -acpi_status acpi_db_disassemble_method(char *name); +struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string); void acpi_db_display_table_info(char *table_arg); -void acpi_db_unload_acpi_table(char *table_arg, char *instance_arg); +void acpi_db_display_template(char *buffer_arg); -void -acpi_db_set_method_breakpoint(char *location, - struct acpi_walk_state *walk_state, - union acpi_parse_object *op); +void acpi_db_unload_acpi_table(char *name); -void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op); +void acpi_db_send_notify(char *name, u32 value); -void acpi_db_get_bus_info(void); +void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); -void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op); +acpi_status acpi_db_sleep(char *object_arg); -void acpi_db_dump_namespace(char *start_arg, char *depth_arg); +void acpi_db_display_locks(void); -void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg); +void acpi_db_display_resources(char *object_arg); -void acpi_db_send_notify(char *name, u32 value); +ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_display_gpes(void)) + +void acpi_db_display_handlers(void); + +ACPI_HW_DEPENDENT_RETURN_VOID(void + acpi_db_generate_gpe(char *gpe_arg, + char *block_arg)) + +/* + * dbmethod - control method commands + */ +void +acpi_db_set_method_breakpoint(char *location, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op); void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg); -acpi_status -acpi_db_display_objects(char *obj_type_arg, char *display_count_arg); +acpi_status acpi_db_disassemble_method(char *name); -void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); +void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op); -acpi_status acpi_db_find_name_in_namespace(char *name_arg); +void acpi_db_batch_execute(char *count_arg); +/* + * dbnames - namespace commands + */ void acpi_db_set_scope(char *name); -ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_db_sleep(char *object_arg)) +void acpi_db_dump_namespace(char *start_arg, char *depth_arg); -void acpi_db_find_references(char *object_arg); +void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg); -void acpi_db_display_locks(void); +acpi_status acpi_db_find_name_in_namespace(char *name_arg); -void acpi_db_display_resources(char *object_arg); +void acpi_db_check_predefined_names(void); -ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_display_gpes(void)) +acpi_status +acpi_db_display_objects(char *obj_type_arg, char *display_count_arg); void acpi_db_check_integrity(void); -ACPI_HW_DEPENDENT_RETURN_VOID(void - acpi_db_generate_gpe(char *gpe_arg, - char *block_arg)) - -void acpi_db_check_predefined_names(void); +void acpi_db_find_references(char *object_arg); -void acpi_db_batch_execute(void); +void acpi_db_get_bus_info(void); /* * dbdisply - debug display commands @@ -161,7 +184,8 @@ acpi_db_display_argument_object(union acpi_operand_object *obj_desc, /* * dbexec - debugger control method execution */ -void acpi_db_execute(char *name, char **args, u32 flags); +void +acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags); void acpi_db_create_execution_threads(char *num_threads_arg, @@ -175,7 +199,8 @@ u32 acpi_db_get_cache_info(struct acpi_memory_list *cache); * dbfileio - Debugger file I/O commands */ acpi_object_type -acpi_db_match_argument(char *user_argument, struct argument_info *arguments); +acpi_db_match_argument(char *user_argument, + struct acpi_db_argument_info *arguments); void acpi_db_close_debug_file(void); @@ -208,6 +233,11 @@ 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); + +char *acpi_db_get_next_token(char *string, + char **next, acpi_object_type * return_type); + /* * dbstats - Generation and display of ACPI table statistics */ diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index ce79100fb5e..fe20e186ca1 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -153,26 +153,6 @@ u8 acpi_gbl_reduced_hardware; ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE); -/***************************************************************************** - * - * Debug support - * - ****************************************************************************/ - -/* Procedure nesting level for debug output */ - -extern u32 acpi_gbl_nesting_level; - -ACPI_EXTERN u32 acpi_gpe_count; -ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]; - -/* Support for dynamic control method tracing mechanism */ - -ACPI_EXTERN u32 acpi_gbl_original_dbg_level; -ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; -ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; -ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; - /***************************************************************************** * * ACPI Table globals @@ -259,15 +239,6 @@ ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE reg * ****************************************************************************/ -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - -/* Lists for tracking memory allocations */ - -ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list; -ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; -ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats; -#endif - /* Object caches */ ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache; @@ -326,6 +297,15 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; #endif +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +/* Lists for tracking memory allocations */ + +ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list; +ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; +ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats; +#endif + /***************************************************************************** * * Namespace globals @@ -401,6 +381,28 @@ ACPI_EXTERN void *acpi_gbl_global_event_handler_context; #endif /* !ACPI_REDUCED_HARDWARE */ +/***************************************************************************** + * + * Debug support + * + ****************************************************************************/ + +/* Procedure nesting level for debug output */ + +extern u32 acpi_gbl_nesting_level; + +/* Event counters */ + +ACPI_EXTERN u32 acpi_gpe_count; +ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]; + +/* Support for dynamic control method tracing mechanism */ + +ACPI_EXTERN u32 acpi_gbl_original_dbg_level; +ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; + /***************************************************************************** * * Debugger globals @@ -426,10 +428,11 @@ ACPI_EXTERN u8 acpi_gbl_db_opt_stats; ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]; -ACPI_EXTERN char acpi_gbl_db_line_buf[80]; -ACPI_EXTERN char acpi_gbl_db_parsed_buf[80]; -ACPI_EXTERN char acpi_gbl_db_scope_buf[40]; -ACPI_EXTERN char acpi_gbl_db_debug_filename[40]; +ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]; +ACPI_EXTERN char acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]; +ACPI_EXTERN char acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]; +ACPI_EXTERN char acpi_gbl_db_scope_buf[80]; +ACPI_EXTERN char acpi_gbl_db_debug_filename[80]; ACPI_EXTERN u8 acpi_gbl_db_output_to_file; ACPI_EXTERN char *acpi_gbl_db_buffer; ACPI_EXTERN char *acpi_gbl_db_filename; diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index c816ee67509..b5a4651cf2b 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1031,6 +1031,7 @@ struct acpi_db_method_info { acpi_handle method; acpi_handle main_thread_gate; acpi_handle thread_complete_gate; + acpi_handle info_gate; acpi_thread_id *threads; u32 num_threads; u32 num_created; @@ -1041,6 +1042,7 @@ struct acpi_db_method_info { u32 num_loops; char pathname[128]; char **args; + acpi_object_type *types; /* * Arguments to be passed to method for the command diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 03f14856bd0..0943457e0fa 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -241,6 +241,7 @@ *****************************************************************************/ #define ACPI_DEBUGGER_MAX_ARGS 8 /* Must be max method args + 1 */ +#define ACPI_DB_LINE_BUFFER_SIZE 512 #define ACPI_DEBUGGER_COMMAND_PROMPT '-' #define ACPI_DEBUGGER_EXECUTE_PROMPT '%' -- cgit v1.2.3 From 78e25fef2751434f38c7f711ecbf8762f79f7318 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 31 Oct 2012 02:25:24 +0000 Subject: ACPICA: Fix divergences of definition conflicts. There are conflicts in the "acpi_device_id*" definitions between the Linux and the ACPICA. The definitions of acpi_device_id* in ACPICA have been changed to the "acpi_pnp_device_id*". This patch changes the corresponding "acpica_device_id*" definitiions in the Linux. This patch will not affect the generated vmlinx binary. This will decrease 298 lines of 20120913 divergence.diff. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 6 +++--- drivers/acpi/acpica/evrgnini.c | 4 ++-- drivers/acpi/acpica/nsxfeval.c | 4 ++-- drivers/acpi/acpica/nsxfname.c | 28 ++++++++++++++-------------- drivers/acpi/acpica/utids.c | 37 ++++++++++++++++++++----------------- drivers/acpi/scan.c | 2 +- include/acpi/actypes.h | 12 ++++++------ 7 files changed, 48 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 82d6025332e..d94b4177657 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -355,15 +355,15 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, */ acpi_status acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id ** return_id); + struct acpi_pnp_device_id ** return_id); acpi_status acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id ** return_id); + struct acpi_pnp_device_id ** return_id); acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, - struct acpica_device_id_list ** return_cid_list); + struct acpi_pnp_device_id_list ** return_cid_list); /* * utlock - reader/writer locks diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 4c1c8261166..6786f00042c 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -350,8 +350,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) { acpi_status status; - struct acpica_device_id *hid; - struct acpica_device_id_list *cid; + struct acpi_pnp_device_id *hid; + struct acpi_pnp_device_id_list *cid; u32 i; u8 match; diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 9692e670233..494f2ebd623 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -542,8 +542,8 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, acpi_status status; struct acpi_namespace_node *node; u32 flags; - struct acpica_device_id *hid; - struct acpica_device_id_list *cid; + struct acpi_pnp_device_id *hid; + struct acpi_pnp_device_id_list *cid; u32 i; u8 found; int no_match; diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 08e9610b34c..7bc4985146f 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -53,8 +53,8 @@ ACPI_MODULE_NAME("nsxfname") /* Local prototypes */ -static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, - struct acpica_device_id *source, +static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, + struct acpi_pnp_device_id *source, char *string_area); /****************************************************************************** @@ -219,20 +219,20 @@ ACPI_EXPORT_SYMBOL(acpi_get_name) * * FUNCTION: acpi_ns_copy_device_id * - * PARAMETERS: dest - Pointer to the destination DEVICE_ID - * source - Pointer to the source DEVICE_ID + * PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID + * source - Pointer to the source PNP_DEVICE_ID * string_area - Pointer to where to copy the dest string * * RETURN: Pointer to the next string area * - * DESCRIPTION: Copy a single DEVICE_ID, including the string data. + * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. * ******************************************************************************/ -static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, - struct acpica_device_id *source, +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 DEVICE_ID */ + /* Create the destination PNP_DEVICE_ID */ dest->string = string_area; dest->length = source->length; @@ -269,9 +269,9 @@ acpi_get_object_info(acpi_handle handle, { struct acpi_namespace_node *node; struct acpi_device_info *info; - struct acpica_device_id_list *cid_list = NULL; - struct acpica_device_id *hid = NULL; - struct acpica_device_id *uid = NULL; + struct acpi_pnp_device_id_list *cid_list = NULL; + struct acpi_pnp_device_id *hid = NULL; + struct acpi_pnp_device_id *uid = NULL; char *next_id_string; acpi_object_type type; acpi_name name; @@ -348,7 +348,7 @@ acpi_get_object_info(acpi_handle handle, info_size += (cid_list->list_size - - sizeof(struct acpica_device_id_list)); + sizeof(struct acpi_pnp_device_id_list)); valid |= ACPI_VALID_CID; } } @@ -418,11 +418,11 @@ acpi_get_object_info(acpi_handle handle, next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); if (cid_list) { - /* Point past the CID DEVICE_ID array */ + /* Point past the CID PNP_DEVICE_ID array */ next_id_string += ((acpi_size) cid_list->count * - sizeof(struct acpica_device_id)); + sizeof(struct acpi_pnp_device_id)); } /* diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 5d84e195457..f18ac81c839 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -67,10 +67,10 @@ ACPI_MODULE_NAME("utids") ******************************************************************************/ acpi_status acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id) + struct acpi_pnp_device_id **return_id) { union acpi_operand_object *obj_desc; - struct acpica_device_id *hid; + struct acpi_pnp_device_id *hid; u32 length; acpi_status status; @@ -94,16 +94,17 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node, /* Allocate a buffer for the HID */ hid = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + (acpi_size) length); if (!hid) { status = AE_NO_MEMORY; goto cleanup; } - /* Area for the string starts after DEVICE_ID struct */ + /* Area for the string starts after PNP_DEVICE_ID struct */ - hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id)); + hid->string = + ACPI_ADD_PTR(char, hid, sizeof(struct acpi_pnp_device_id)); /* Convert EISAID to a string or simply copy existing string */ @@ -144,10 +145,10 @@ cleanup: acpi_status acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id) + struct acpi_pnp_device_id **return_id) { union acpi_operand_object *obj_desc; - struct acpica_device_id *uid; + struct acpi_pnp_device_id *uid; u32 length; acpi_status status; @@ -171,16 +172,17 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, /* Allocate a buffer for the UID */ uid = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + (acpi_size) length); if (!uid) { status = AE_NO_MEMORY; goto cleanup; } - /* Area for the string starts after DEVICE_ID struct */ + /* Area for the string starts after PNP_DEVICE_ID struct */ - uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id)); + uid->string = + ACPI_ADD_PTR(char, uid, sizeof(struct acpi_pnp_device_id)); /* Convert an Integer to string, or just copy an existing string */ @@ -226,11 +228,11 @@ cleanup: acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, - struct acpica_device_id_list **return_cid_list) + struct acpi_pnp_device_id_list **return_cid_list) { union acpi_operand_object **cid_objects; union acpi_operand_object *obj_desc; - struct acpica_device_id_list *cid_list; + struct acpi_pnp_device_id_list *cid_list; char *next_id_string; u32 string_area_size; u32 length; @@ -288,11 +290,12 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node, /* * Now that we know the length of the CIDs, allocate return buffer: * 1) Size of the base structure + - * 2) Size of the CID DEVICE_ID array + + * 2) Size of the CID PNP_DEVICE_ID array + * 3) Size of the actual CID strings */ - cid_list_size = sizeof(struct acpica_device_id_list) + - ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size; + cid_list_size = sizeof(struct acpi_pnp_device_id_list) + + ((count - 1) * sizeof(struct acpi_pnp_device_id)) + + string_area_size; cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size); if (!cid_list) { @@ -300,10 +303,10 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node, goto cleanup; } - /* Area for CID strings starts after the CID DEVICE_ID array */ + /* Area for CID strings starts after the CID PNP_DEVICE_ID array */ next_id_string = ACPI_CAST_PTR(char, cid_list->ids) + - ((acpi_size) count * sizeof(struct acpica_device_id)); + ((acpi_size) count * sizeof(struct acpi_pnp_device_id)); /* Copy/convert the CIDs to the return buffer */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1fcb8678665..db127100bd9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1185,7 +1185,7 @@ static void acpi_device_set_id(struct acpi_device *device) { acpi_status status; struct acpi_device_info *info; - struct acpica_device_id_list *cid_list; + struct acpi_pnp_device_id_list *cid_list; int i; switch (device->device_type) { diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index a85bae96826..7520f420e4e 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1020,15 +1020,15 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); /* Structures used for device/processor HID, UID, CID */ -struct acpica_device_id { +struct acpi_pnp_device_id { u32 length; /* Length of string + null */ char *string; }; -struct acpica_device_id_list { +struct acpi_pnp_device_id_list { u32 count; /* Number of IDs in Ids array */ u32 list_size; /* Size of list, including ID strings */ - struct acpica_device_id ids[1]; /* ID array */ + struct acpi_pnp_device_id ids[1]; /* ID array */ }; /* @@ -1046,9 +1046,9 @@ struct acpi_device_info { u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */ u32 current_status; /* _STA value */ u64 address; /* _ADR value */ - struct acpica_device_id hardware_id; /* _HID value */ - struct acpica_device_id unique_id; /* _UID value */ - struct acpica_device_id_list compatible_id_list; /* _CID list */ + struct acpi_pnp_device_id hardware_id; /* _HID value */ + struct acpi_pnp_device_id unique_id; /* _UID value */ + struct acpi_pnp_device_id_list compatible_id_list; /* _CID list */ }; /* Values for Flags field above (acpi_get_object_info) */ -- cgit v1.2.3 From 644ef74e6d187ca2e8a23ff41a513964de36f93e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 31 Oct 2012 02:25:36 +0000 Subject: ACPICA: Fix AcpiSrc caused divergences. There are definitions that can been converted into new styles by the recent AcpiSrc while they remain the old styles in the Linux. This patch fixes those definitions that will be converted by the AcpiSrc. This patch will not affect the generated vmlinux binary. This will decrease 97 lines of 20120913 divergence.diff. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/aclocal.h | 4 ++-- drivers/acpi/acpica/acobject.h | 2 +- drivers/acpi/acpica/dswexec.c | 2 +- drivers/acpi/acpica/evxface.c | 2 +- drivers/acpi/sysfs.c | 4 ++-- include/acpi/acpixf.h | 2 +- include/acpi/actypes.h | 8 ++++---- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index fe20e186ca1..35006d193d5 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -376,7 +376,7 @@ ACPI_EXTERN struct acpi_gpe_block_info #if (!ACPI_REDUCED_HARDWARE) ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized; -ACPI_EXTERN ACPI_GBL_EVENT_HANDLER acpi_gbl_global_event_handler; +ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler; ACPI_EXTERN void *acpi_gbl_global_event_handler_context; #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index b5a4651cf2b..564f2abf590 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -262,7 +262,7 @@ struct acpi_create_field_info { }; typedef -acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state); +acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state); /* * Bitmapped ACPI types. Used internally only @@ -645,7 +645,7 @@ union acpi_generic_state { * ****************************************************************************/ -typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state); +typedef acpi_status(*acpi_execute_op) (struct acpi_walk_state * walk_state); /* Address Range info block */ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 364a1303fb8..ac4269fb1a3 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -179,7 +179,7 @@ struct acpi_object_method { union acpi_operand_object *mutex; u8 *aml_start; union { - ACPI_INTERNAL_METHOD implementation; + acpi_internal_method implementation; union acpi_operand_object *handler; } dispatch; diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 642f3c053e8..fa44609aba3 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -57,7 +57,7 @@ ACPI_MODULE_NAME("dswexec") /* * Dispatch table for opcode classes */ -static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch[] = { +static acpi_execute_op acpi_gbl_op_type_dispatch[] = { acpi_ex_opcode_0A_0T_1R, acpi_ex_opcode_1A_0T_0R, acpi_ex_opcode_1A_0T_1R, diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 7587eb6c958..ae668f32cf1 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -398,7 +398,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_exception_handler) * ******************************************************************************/ acpi_status -acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context) +acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) { acpi_status status; diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 7c3f98ba4af..ea61ca9129c 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -476,7 +476,7 @@ static void fixed_event_count(u32 event_number) return; } -static void acpi_gbl_event_handler(u32 event_type, acpi_handle device, +static void acpi_global_event_handler(u32 event_type, acpi_handle device, u32 event_number, void *context) { if (event_type == ACPI_EVENT_TYPE_GPE) @@ -638,7 +638,7 @@ void acpi_irq_stats_init(void) if (all_counters == NULL) goto fail; - status = acpi_install_global_event_handler(acpi_gbl_event_handler, NULL); + status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); if (ACPI_FAILURE(status)) goto fail; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 8b891dbead6..352fd1a3832 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -274,7 +274,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function); ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_install_global_event_handler - (ACPI_GBL_EVENT_HANDLER handler, void *context)) + (acpi_gbl_event_handler handler, void *context)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_install_fixed_event_handler(u32 diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 7520f420e4e..ea50a314e55 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -796,11 +796,11 @@ typedef u8 acpi_adr_space_type; /* Sleep function dispatch */ -typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state); +typedef acpi_status(*acpi_sleep_function) (u8 sleep_state); struct acpi_sleep_functions { - ACPI_SLEEP_FUNCTION legacy_function; - ACPI_SLEEP_FUNCTION extended_function; + acpi_sleep_function legacy_function; + acpi_sleep_function extended_function; }; /* @@ -931,7 +931,7 @@ typedef void * Various handlers and callback procedures */ typedef -void (*ACPI_GBL_EVENT_HANDLER) (u32 event_type, +void (*acpi_gbl_event_handler) (u32 event_type, acpi_handle device, u32 event_number, void *context); -- cgit v1.2.3 From 1f86e8c1c9f129d450fd75e42d25ddba69a522ac Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 31 Oct 2012 02:25:45 +0000 Subject: ACPICA: Fix indent caused divergences. New version of "indent" program will generate different outputs that will lead to the divergences between the Linux and the ACPICA. This patch fixes such divergences caused by the "indent" program. The version of the "indent" used for this patch is "GNU indent 2.2.11". This patch will not affect the generated vmlinux binary. This will decrease 581 lines of 20120913 divergence.diff. Signed-off-by: Robert Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdispat.h | 11 +++++++---- drivers/acpi/acpica/acevents.h | 6 ++++-- drivers/acpi/acpica/aclocal.h | 6 ++++-- drivers/acpi/acpica/acparser.h | 3 +-- drivers/acpi/acpica/acpredef.h | 11 ++++++----- drivers/acpi/acpica/dsopcode.c | 3 ++- drivers/acpi/acpica/dsutils.c | 3 ++- drivers/acpi/acpica/dswstate.c | 14 +++++++++----- drivers/acpi/acpica/evgpe.c | 20 ++++++++++++-------- drivers/acpi/acpica/evgpeblk.c | 3 ++- drivers/acpi/acpica/evgpeutil.c | 3 ++- drivers/acpi/acpica/evrgnini.c | 3 +-- drivers/acpi/acpica/evxfgpe.c | 9 +++++---- drivers/acpi/acpica/exconvrt.c | 4 ++-- drivers/acpi/acpica/excreate.c | 3 +-- drivers/acpi/acpica/exdump.c | 9 ++++++--- drivers/acpi/acpica/exfldio.c | 3 +-- drivers/acpi/acpica/exnames.c | 6 +++--- drivers/acpi/acpica/exresop.c | 3 ++- drivers/acpi/acpica/hwgpe.c | 3 ++- drivers/acpi/acpica/hwtimer.c | 3 +-- drivers/acpi/acpica/hwxfsleep.c | 12 ++++-------- drivers/acpi/acpica/nsaccess.c | 3 +-- drivers/acpi/acpica/nsinit.c | 4 ++-- drivers/acpi/acpica/psopcode.c | 23 ++++++++++++++--------- drivers/acpi/acpica/psparse.c | 5 +++-- drivers/acpi/acpica/rscalc.c | 3 +-- include/acpi/acpixf.h | 13 +++++-------- include/acpi/actypes.h | 6 ++++-- 29 files changed, 109 insertions(+), 89 deletions(-) diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 5935ba6707e..ed33ebcdaeb 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -309,10 +309,13 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state); acpi_status acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state); -struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object - *origin, union acpi_operand_object - *mth_desc, struct acpi_thread_state - *thread); +struct acpi_walk_state * acpi_ds_create_walk_state(acpi_owner_id owner_id, + union acpi_parse_object + *origin, + union acpi_operand_object + *mth_desc, + struct acpi_thread_state + *thread); acpi_status acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index c0a43b38c6a..e975c672044 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -84,9 +84,11 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); +acpi_status +acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); +acpi_status +acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, u32 gpe_number); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 564f2abf590..5b5be40a199 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -486,8 +486,10 @@ struct acpi_gpe_device_info { struct acpi_namespace_node *gpe_device; }; -typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context); +typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info * + gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, + void *context); /* Information about each particular fixed event */ diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index b725d780d34..eefcf47a61a 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -150,8 +150,7 @@ u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state); void acpi_ps_pop_scope(struct acpi_parse_state *parser_state, - union acpi_parse_object **op, - u32 * arg_list, u32 * arg_count); + union acpi_parse_object **op, u32 *arg_list, u32 *arg_count); acpi_status acpi_ps_push_scope(struct acpi_parse_state *parser_state, diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 3080c017f5b..9dfa1c83bd4 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -150,8 +150,7 @@ enum acpi_return_package_types { * is saved here (rather than in a separate table) in order to minimize the * overall size of the stored data. */ -static const union acpi_predefined_info predefined_names[] = -{ +static const union acpi_predefined_info predefined_names[] = { {{"_AC0", 0, ACPI_RTYPE_INTEGER}}, {{"_AC1", 0, ACPI_RTYPE_INTEGER}}, {{"_AC2", 0, ACPI_RTYPE_INTEGER}}, @@ -538,7 +537,8 @@ static const union acpi_predefined_info predefined_names[] = /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ - {{"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, + {{"_WAK", 1, + ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */ /* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */ @@ -551,11 +551,12 @@ static const union acpi_predefined_info predefined_names[] = }; #if 0 + /* This is an internally implemented control method, no need to check */ - {{"_OSI", 1, ACPI_RTYPE_INTEGER}}, +{ { +"_OSI", 1, ACPI_RTYPE_INTEGER}}, /* TBD: */ - _PRT - currently ignore reversed entries. attempt to fix here? think about possibly fixing package elements like _BIF, etc. #endif diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index aa34d8984d3..0df024e5fb6 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -649,7 +649,8 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && (op->common.parent->common.aml_opcode != AML_VAR_PACKAGE_OP) - && (op->common.parent->common.aml_opcode != AML_NAME_OP))) { + && (op->common.parent->common.aml_opcode != + AML_NAME_OP))) { walk_state->result_obj = obj_desc; } } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 73a5447475f..4bbdd6c7a3d 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -560,7 +560,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, * indicate this to the interpreter, set the * object to the root */ - obj_desc = ACPI_CAST_PTR(union + obj_desc = + ACPI_CAST_PTR(union acpi_operand_object, acpi_gbl_root_node); status = AE_OK; diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index d0e6555061e..9bb7fa45e24 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -51,8 +51,9 @@ ACPI_MODULE_NAME("dswstate") /* Local prototypes */ -static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws); -static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws); +static acpi_status +acpi_ds_result_stack_push(struct acpi_walk_state *walk_state); +static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state); /******************************************************************************* * @@ -536,9 +537,12 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) * ******************************************************************************/ -struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object - *origin, union acpi_operand_object - *method_desc, struct acpi_thread_state +struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, + union acpi_parse_object + *origin, + union acpi_operand_object + *method_desc, + struct acpi_thread_state *thread) { struct acpi_walk_state *walk_state; diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index ef0193d74b5..36d12057442 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -89,7 +89,8 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) /* Set the mask bit only if there are references to this GPE */ if (gpe_event_info->runtime_count) { - ACPI_SET_BIT(gpe_register_info->enable_for_run, (u8)register_bit); + ACPI_SET_BIT(gpe_register_info->enable_for_run, + (u8)register_bit); } return_ACPI_STATUS(AE_OK); @@ -106,8 +107,7 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) * DESCRIPTION: Clear a GPE of stale events and enable it. * ******************************************************************************/ -acpi_status -acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) +acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status; @@ -131,8 +131,8 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) } /* Enable the requested GPE */ - status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); return_ACPI_STATUS(status); } @@ -150,7 +150,8 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) +acpi_status +acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status = AE_OK; @@ -191,7 +192,8 @@ acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info * ******************************************************************************/ -acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) +acpi_status +acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status = AE_OK; @@ -208,7 +210,8 @@ acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_i status = acpi_ev_update_gpe_enable_mask(gpe_event_info); if (ACPI_SUCCESS(status)) { - status = acpi_hw_low_set_gpe(gpe_event_info, + status = + acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); } @@ -306,7 +309,8 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, /* A Non-NULL gpe_device means this is a GPE Block Device */ - obj_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *) + obj_desc = + acpi_ns_get_attached_object((struct acpi_namespace_node *) gpe_device); if (!obj_desc || !obj_desc->device.gpe_block) { return (NULL); diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 8cf4c104c7b..1571a61a783 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -486,7 +486,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not enable GPE 0x%02X", - gpe_index + gpe_block->block_base_number)); + gpe_index + + gpe_block->block_base_number)); continue; } diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index cb50dd91bc1..228a0c3b1d4 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -374,7 +374,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; - } else if ((gpe_event_info-> + } else + if ((gpe_event_info-> flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NOTIFY) { diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 6786f00042c..1474241bfc7 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -227,8 +227,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, /* Install a handler for this PCI root bridge */ - status = - acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); + status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 87c5f233226..d36f9973937 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -221,7 +221,8 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, if (wake_device == ACPI_ROOT_OBJECT) { device_node = acpi_gbl_root_node; } else { - device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); + device_node = + ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); } /* Validate WakeDevice is of type Device */ @@ -324,7 +325,8 @@ ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) * ******************************************************************************/ -acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) +acpi_status +acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; @@ -694,8 +696,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) * the FADT-defined gpe blocks. Otherwise, the GPE block device. * ******************************************************************************/ -acpi_status -acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) +acpi_status acpi_get_gpe_device(u32 index, acpi_handle * gpe_device) { struct acpi_gpe_device_info info; acpi_status status; diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index bfb062e4c4b..4492a4e0302 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -516,8 +516,8 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc, string_length--; } - return_desc = acpi_ut_create_string_object((acpi_size) - string_length); + return_desc = + acpi_ut_create_string_object((acpi_size) string_length); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 691d4763102..9f152701bc0 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -243,8 +243,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) /* Init object and attach to NS node */ - obj_desc->mutex.sync_level = - (u8) walk_state->operands[1]->integer.value; + obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value; obj_desc->mutex.node = (struct acpi_namespace_node *)walk_state->operands[0]; diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 213c081776f..40608b3e28f 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -464,7 +464,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) ACPI_FUNCTION_NAME(ex_dump_operand) - if (!((ACPI_LV_EXEC & acpi_dbg_level) + if (! + ((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } @@ -810,7 +811,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags) ACPI_FUNCTION_ENTRY(); if (!flags) { - if (!((ACPI_LV_OBJECTS & acpi_dbg_level) + if (! + ((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } @@ -996,7 +998,8 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) } if (!flags) { - if (!((ACPI_LV_OBJECTS & acpi_dbg_level) + if (! + ((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return_VOID; } diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index a7784152ed3..419148a66e7 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -54,8 +54,7 @@ ACPI_MODULE_NAME("exfldio") /* Local prototypes */ static acpi_status acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, - u32 field_datum_byte_offset, - u64 *value, u32 read_write); + u32 field_datum_byte_offset, u64 *value, u32 read_write); static u8 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value); diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index fcc75fa27d3..6d19bd42d29 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -53,8 +53,7 @@ ACPI_MODULE_NAME("exnames") /* Local prototypes */ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs); -static acpi_status -acpi_ex_name_segment(u8 ** in_aml_address, char *name_string); +static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string); /******************************************************************************* * @@ -178,7 +177,8 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n")); - for (index = 0; (index < ACPI_NAME_SIZE) + for (index = 0; + (index < ACPI_NAME_SIZE) && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) { char_buf[index] = *aml_address++; ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index])); diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index f232fbabdea..17dc218cd39 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -337,7 +337,8 @@ acpi_ex_resolve_operands(u16 opcode, if ((opcode == AML_STORE_OP) && ((*stack_ptr)->common.type == ACPI_TYPE_LOCAL_REFERENCE) - && ((*stack_ptr)->reference.class == ACPI_REFCLASS_INDEX)) { + && ((*stack_ptr)->reference.class == + ACPI_REFCLASS_INDEX)) { goto next_operand; } break; diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index db4076580e2..3b3b5e45847 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -339,7 +339,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_status acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context) + struct acpi_gpe_block_info * gpe_block, + void *context) { u32 i; acpi_status status; diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index b6411f16832..438004a1dd8 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -101,8 +101,7 @@ acpi_status acpi_get_timer(u32 * ticks) return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = - acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); + status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 0ff1ecea5c3..ae443fe2ebf 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -49,8 +49,7 @@ ACPI_MODULE_NAME("hwxfsleep") /* Local prototypes */ -static acpi_status -acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); +static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); /* * Dispatch table used to efficiently branch to the various sleep @@ -234,8 +233,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) * function. * ******************************************************************************/ -static acpi_status -acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) +static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) { acpi_status status; struct acpi_sleep_functions *sleep_functions = @@ -369,8 +367,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } - status = - acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); + status = acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); return_ACPI_STATUS(status); } @@ -396,8 +393,7 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); status = - acpi_hw_sleep_dispatch(sleep_state, - ACPI_WAKE_PREP_FUNCTION_ID); + acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 23db53ce229..fc168e62c1c 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -179,8 +179,7 @@ acpi_status acpi_ns_root_initialize(void) /* Build an object around the static string */ - obj_desc->string.length = - (u32) ACPI_STRLEN(val); + obj_desc->string.length = (u32)ACPI_STRLEN(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 95ffe8dfa1f..4328e2adfeb 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -96,8 +96,8 @@ acpi_status acpi_ns_initialize_objects(void) /* Walk entire namespace from the supplied root */ status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, acpi_ns_init_one_object, NULL, - &info, NULL); + ACPI_UINT32_MAX, acpi_ns_init_one_object, + NULL, &info, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index ed1d457bd5c..e5572a78bdb 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -392,10 +392,12 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { 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_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), + 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_CONSTANT), + 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), @@ -495,7 +497,8 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { 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_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_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, @@ -519,12 +522,13 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 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 | AML_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, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD | - AML_DEFER), + ACPI_TYPE_LOCAL_BANK_FIELD, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_FIELD | AML_DEFER), /* Internal opcodes that map to invalid AML opcodes */ @@ -632,7 +636,8 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 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 | AML_NSNODE), + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE), /* ACPI 3.0 opcodes */ diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 01985703bb9..dfdda00c6ff 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -459,8 +459,9 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) /* Executing a control method - additional cleanup */ - acpi_ds_terminate_control_method( - walk_state->method_desc, walk_state); + acpi_ds_terminate_control_method(walk_state-> + method_desc, + walk_state); } acpi_ds_delete_walk_state(walk_state); diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index de12469d1c9..42745676ecd 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -664,8 +664,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, (*sub_object_list)->string. length + 1); } else { - temp_size_needed += - acpi_ns_get_pathname_length((*sub_object_list)->reference.node); + temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); } } else { /* diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 352fd1a3832..fe84aee5df4 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -178,8 +178,7 @@ acpi_status acpi_unload_table_id(acpi_owner_id id); acpi_status acpi_get_table_header(acpi_string signature, - u32 instance, - struct acpi_table_header *out_table_header); + u32 instance, struct acpi_table_header *out_table_header); acpi_status acpi_get_table_with_size(acpi_string signature, @@ -190,8 +189,7 @@ acpi_get_table(acpi_string signature, u32 instance, struct acpi_table_header **out_table); acpi_status -acpi_get_table_by_index(u32 table_index, - struct acpi_table_header **out_table); +acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table); acpi_status acpi_install_table_handler(acpi_tbl_handler handler, void *context); @@ -300,10 +298,9 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status u32 gpe_number, acpi_gpe_handler address)) -acpi_status -acpi_install_notify_handler(acpi_handle device, - u32 handler_type, - acpi_notify_handler handler, void *context); +acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, + acpi_notify_handler handler, + void *context); acpi_status acpi_remove_notify_handler(acpi_handle device, diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index ea50a314e55..1fa6ba12307 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -922,7 +922,8 @@ struct acpi_system_info { /* * Types specific to the OS service interfaces */ -typedef u32(ACPI_SYSTEM_XFACE * acpi_osd_handler) (void *context); +typedef u32 + (ACPI_SYSTEM_XFACE * acpi_osd_handler) (void *context); typedef void (ACPI_SYSTEM_XFACE * acpi_osd_exec_callback) (void *context); @@ -938,7 +939,8 @@ void (*acpi_gbl_event_handler) (u32 event_type, #define ACPI_EVENT_TYPE_GPE 0 #define ACPI_EVENT_TYPE_FIXED 1 -typedef u32(*acpi_event_handler) (void *context); +typedef +u32(*acpi_event_handler) (void *context); typedef u32 (*acpi_gpe_handler) (acpi_handle gpe_device, u32 gpe_number, void *context); -- cgit v1.2.3 From 86ff0e508f88eda6e479a897476026055831d2d8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 31 Oct 2012 02:25:52 +0000 Subject: ACPICA: Fix unmerged acmacros.h divergences. The 20121018 release depends on some unmerged acmaros.h fixes. This patch includes the fixes made on acmaros.h that will not affect the generated vmlinux binary. This patch will not affect the generated vmlinux binary. This will decrease 157 lines of 20120913 divergence.diff. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acmacros.h | 161 +++++++++++++++-------------------------- drivers/acpi/acpica/psloop.c | 2 - 2 files changed, 57 insertions(+), 106 deletions(-) diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index a7f68c47f51..da8062d91ee 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -84,29 +84,29 @@ /* These macros reverse the bytes during the move, converting little-endian to big endian */ - /* Big Endian <== Little Endian */ - /* Hi...Lo Lo...Hi */ + /* Big Endian <== Little Endian */ + /* Hi...Lo Lo...Hi */ /* 16-bit source, 16/32/64 destination */ #define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\ - (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];} + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];} #define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d))=0;\ - ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ - ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} + ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} #define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ - ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ - ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} + ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} /* 32-bit source, 16/32/64 destination */ #define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ #define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\ - (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\ - (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ - (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} #define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ ((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ @@ -196,24 +196,12 @@ #endif #endif -/* Macros based on machine integer width */ - -#if ACPI_MACHINE_WIDTH == 32 -#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_32_TO_16(d, s) - -#elif ACPI_MACHINE_WIDTH == 64 -#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_64_TO_16(d, s) - -#else -#error unknown ACPI_MACHINE_WIDTH -#endif - /* * Fast power-of-two math macros for non-optimized compilers */ -#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2))) -#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2))) -#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1))) +#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2))) +#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2))) +#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1))) #define ACPI_DIV_2(a) _ACPI_DIV(a, 1) #define ACPI_MUL_2(a) _ACPI_MUL(a, 1) @@ -238,12 +226,12 @@ /* * Rounding macros (Power of two boundaries only) */ -#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \ - (~(((acpi_size) boundary)-1))) +#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \ + (~(((acpi_size) boundary)-1))) -#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \ - (((acpi_size) boundary)-1)) & \ - (~(((acpi_size) boundary)-1))) +#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \ + (((acpi_size) boundary)-1)) & \ + (~(((acpi_size) boundary)-1))) /* Note: sizeof(acpi_size) evaluates to either 4 or 8 (32- vs 64-bit mode) */ @@ -264,7 +252,7 @@ #define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary)) -#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) +#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) /* * Bitmask creation @@ -355,7 +343,6 @@ * Ascii error messages can be configured out */ #ifndef ACPI_NO_ERROR_MESSAGES - /* * Error reporting. Callers module and line number are inserted by AE_INFO, * the plist contains a set of parens to allow variable-length lists. @@ -375,18 +362,15 @@ #define ACPI_WARN_PREDEFINED(plist) #define ACPI_INFO_PREDEFINED(plist) -#endif /* ACPI_NO_ERROR_MESSAGES */ +#endif /* ACPI_NO_ERROR_MESSAGES */ /* * Debug macros that are conditionally compiled */ #ifdef ACPI_DEBUG_OUTPUT - /* * Function entry tracing */ -#ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE - #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ acpi_ut_trace(ACPI_DEBUG_PARAMETERS) #define ACPI_FUNCTION_TRACE_PTR(a, b) ACPI_FUNCTION_NAME(a) \ @@ -464,44 +448,18 @@ #endif /* ACPI_SIMPLE_RETURN_MACROS */ -#else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */ - -#define ACPI_FUNCTION_TRACE(a) -#define ACPI_FUNCTION_TRACE_PTR(a,b) -#define ACPI_FUNCTION_TRACE_U32(a,b) -#define ACPI_FUNCTION_TRACE_STR(a,b) -#define ACPI_FUNCTION_EXIT -#define ACPI_FUNCTION_STATUS_EXIT(s) -#define ACPI_FUNCTION_VALUE_EXIT(s) -#define ACPI_FUNCTION_TRACE(a) -#define ACPI_FUNCTION_ENTRY() - -#define return_VOID return -#define return_ACPI_STATUS(s) return(s) -#define return_VALUE(s) return(s) -#define return_UINT8(s) return(s) -#define return_UINT32(s) return(s) -#define return_PTR(s) return(s) - -#endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */ - /* Conditional execution */ #define ACPI_DEBUG_EXEC(a) a -#define ACPI_NORMAL_EXEC(a) - -#define ACPI_DEBUG_DEFINE(a) a; #define ACPI_DEBUG_ONLY_MEMBERS(a) a; #define _VERBOSE_STRUCTURES -/* Stack and buffer dumping */ +/* Various object display routines for debug */ #define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a), 0) -#define ACPI_DUMP_OPERANDS(a, b, c) acpi_ex_dump_operands(a, b, c) - +#define ACPI_DUMP_OPERANDS(a, b ,c) acpi_ex_dump_operands(a, b, c) #define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b) #define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) -#define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) #define ACPI_DUMP_BUFFER(a, b) acpi_ut_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) #else @@ -510,25 +468,23 @@ * leaving no executable debug code! */ #define ACPI_DEBUG_EXEC(a) -#define ACPI_NORMAL_EXEC(a) a; - -#define ACPI_DEBUG_DEFINE(a) do { } while(0) -#define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0) -#define ACPI_FUNCTION_TRACE(a) do { } while(0) -#define ACPI_FUNCTION_TRACE_PTR(a, b) do { } while(0) -#define ACPI_FUNCTION_TRACE_U32(a, b) do { } while(0) -#define ACPI_FUNCTION_TRACE_STR(a, b) do { } while(0) -#define ACPI_FUNCTION_EXIT do { } while(0) -#define ACPI_FUNCTION_STATUS_EXIT(s) do { } while(0) -#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0) -#define ACPI_FUNCTION_ENTRY() do { } while(0) -#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0) -#define ACPI_DUMP_OPERANDS(a, b, c) do { } while(0) -#define ACPI_DUMP_ENTRY(a, b) do { } while(0) -#define ACPI_DUMP_TABLES(a, b) do { } while(0) -#define ACPI_DUMP_PATHNAME(a, b, c, d) do { } while(0) -#define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0) -#define ACPI_DUMP_BUFFER(a, b) do { } while(0) +#define ACPI_DEBUG_ONLY_MEMBERS(a) +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_TRACE_PTR(a, b) +#define ACPI_FUNCTION_TRACE_U32(a, b) +#define ACPI_FUNCTION_TRACE_STR(a, b) +#define ACPI_FUNCTION_EXIT +#define ACPI_FUNCTION_STATUS_EXIT(s) +#define ACPI_FUNCTION_VALUE_EXIT(s) +#define ACPI_FUNCTION_ENTRY() +#define ACPI_DUMP_STACK_ENTRY(a) +#define ACPI_DUMP_OPERANDS(a, b, c) +#define ACPI_DUMP_ENTRY(a, b) +#define ACPI_DUMP_TABLES(a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) +#define ACPI_DUMP_BUFFER(a, b) +#define ACPI_DEBUG_PRINT(pl) +#define ACPI_DEBUG_PRINT_RAW(pl) #define return_VOID return #define return_ACPI_STATUS(s) return(s) @@ -556,18 +512,6 @@ #define ACPI_DEBUGGER_EXEC(a) #endif -#ifdef ACPI_DEBUG_OUTPUT -/* - * 1) Set name to blanks - * 2) Copy the object name - */ -#define ACPI_ADD_OBJECT_NAME(a,b) ACPI_MEMSET (a->common.name, ' ', sizeof (a->common.name));\ - ACPI_STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) -#else - -#define ACPI_ADD_OBJECT_NAME(a,b) -#endif - /* * Memory allocation tracking (DEBUG ONLY) */ @@ -578,13 +522,13 @@ /* Memory allocation */ #ifndef ACPI_ALLOCATE -#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size) (a), ACPI_MEM_PARAMETERS) #endif #ifndef ACPI_ALLOCATE_ZEROED -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size) (a), ACPI_MEM_PARAMETERS) #endif #ifndef ACPI_FREE -#define ACPI_FREE(a) acpio_os_free(a) +#define ACPI_FREE(a) acpi_os_free(a) #endif #define ACPI_MEM_TRACKING(a) @@ -592,16 +536,25 @@ /* Memory allocation */ -#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS) -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size) (a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size) (a), ACPI_MEM_PARAMETERS) #define ACPI_FREE(a) acpi_ut_free_and_track(a, ACPI_MEM_PARAMETERS) #define ACPI_MEM_TRACKING(a) a #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ -/* Preemption point */ -#ifndef ACPI_PREEMPTION_POINT -#define ACPI_PREEMPTION_POINT() /* no preemption */ -#endif +/* + * Macros used for ACPICA utilities only + */ + +/* Generate a UUID */ + +#define ACPI_INIT_UUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + (a) & 0xFF, ((a) >> 8) & 0xFF, ((a) >> 16) & 0xFF, ((a) >> 24) & 0xFF, \ + (b) & 0xFF, ((b) >> 8) & 0xFF, \ + (c) & 0xFF, ((c) >> 8) & 0xFF, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) + +#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) #endif /* ACMACROS_H */ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 799162c1b6d..31e2e9fb2de 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -843,8 +843,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, *op = NULL; } - ACPI_PREEMPTION_POINT(); - return_ACPI_STATUS(AE_OK); } -- cgit v1.2.3 From 68aafc35161dcc9d365a32c2f9f077aedc61754d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:26:01 +0000 Subject: ACPICA: Audit/update for ACPICA return macros and debug depth counter 1) Ensure that all functions that use the various TRACE macros also use the appropriate ACPICA return macros. 2) Ensure that all normal return statements surround the return expression (value) with parens. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dswload2.c | 4 ++-- drivers/acpi/acpica/dswstate.c | 4 ++-- drivers/acpi/acpica/evxfgpe.c | 4 ++-- drivers/acpi/acpica/exdebug.c | 2 +- drivers/acpi/acpica/exmutex.c | 2 +- drivers/acpi/acpica/exoparg6.c | 2 +- drivers/acpi/acpica/hwpci.c | 4 ++-- drivers/acpi/acpica/nsnames.c | 2 +- drivers/acpi/acpica/nsxfeval.c | 2 +- drivers/acpi/acpica/rslist.c | 4 ++-- drivers/acpi/acpica/tbinstal.c | 2 ++ drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 4 ++-- drivers/acpi/acpica/tbxfroot.c | 1 - drivers/acpi/acpica/utdebug.c | 1 + drivers/acpi/acpica/utmutex.c | 2 ++ drivers/acpi/acpica/uttrack.c | 4 ++-- drivers/acpi/acpica/utxface.c | 3 ++- 18 files changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 89c0114210c..37983574835 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -254,7 +254,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, acpi_ut_get_type_name(node->type), acpi_ut_get_node_name(node))); - return (AE_AML_OPERAND_TYPE); + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } break; @@ -602,7 +602,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) region_space, walk_state); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } acpi_ex_exit_interpreter(); diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 9bb7fa45e24..8e6267980aa 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -708,13 +708,13 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state); if (!walk_state) { - return; + return_VOID; } if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) { ACPI_ERROR((AE_INFO, "%p is not a valid walk state", walk_state)); - return; + return_VOID; } /* There should not be any open scopes */ diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index d36f9973937..3f30e753b65 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -569,7 +569,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } node = acpi_ns_validate_handle(gpe_device); @@ -652,7 +652,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } node = acpi_ns_validate_handle(gpe_device); diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index bc5b9a6a131..e0c905095ed 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -190,7 +190,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, acpi_os_printf("Table Index 0x%X\n", source_desc->reference.value); - return; + return_VOID; default: break; diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index bcceda5be9e..9099783eb85 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -305,7 +305,7 @@ acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) ACPI_FUNCTION_TRACE(ex_release_mutex_object); if (obj_desc->mutex.acquisition_depth == 0) { - return (AE_NOT_ACQUIRED); + return_ACPI_STATUS(AE_NOT_ACQUIRED); } /* Match multiple Acquires with multiple Releases */ diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 0786b865906..ab68dc532c7 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -198,7 +198,7 @@ acpi_ex_do_match(u32 match_op, return (FALSE); } - return logical_result; + return (logical_result); } /******************************************************************************* diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 1455ddcdc32..65bc3453a29 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -259,7 +259,7 @@ acpi_hw_process_pci_list(struct acpi_pci_id *pci_id, status = acpi_hw_get_pci_device_info(pci_id, info->device, &bus_number, &is_bridge); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + return (status); } info = info->next; @@ -271,7 +271,7 @@ acpi_hw_process_pci_list(struct acpi_pci_id *pci_id, pci_id->segment, pci_id->bus, pci_id->device, pci_id->function, status, bus_number, is_bridge)); - return_ACPI_STATUS(AE_OK); + return (AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 96e0eb609bb..55a175eadcc 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -195,7 +195,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) ACPI_ERROR((AE_INFO, "Invalid Namespace Node (%p) while traversing namespace", next_node)); - return 0; + return (0); } size += ACPI_PATH_SEGMENT_LENGTH; next_node = next_node->parent; diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 494f2ebd623..ee4d873f9f0 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -550,7 +550,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } node = acpi_ns_validate_handle(obj_handle); diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 46b5324b22d..8b64db9a3fd 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -109,7 +109,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, ACPI_ERROR((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", resource_index)); - return (AE_AML_INVALID_RESOURCE_TYPE); + return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } /* Convert the AML byte stream resource to a local resource struct */ @@ -200,7 +200,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, ACPI_ERROR((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", resource->type)); - return (AE_AML_INVALID_RESOURCE_TYPE); + return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } status = acpi_rs_convert_resource_to_aml(resource, diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 70f9d787c82..f540ae46292 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -526,6 +526,8 @@ void acpi_tb_terminate(void) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index b6cea30da63..285e24b9738 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -354,7 +354,7 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length) sum = (u8) (sum + *(buffer++)); } - return sum; + return (sum); } /******************************************************************************* diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 21101262e47..f5632780421 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -236,7 +236,7 @@ acpi_get_table_header(char *signature, sizeof(struct acpi_table_header)); if (!header) { - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } ACPI_MEMCPY(out_table_header, header, sizeof(struct acpi_table_header)); @@ -244,7 +244,7 @@ acpi_get_table_header(char *signature, sizeof(struct acpi_table_header)); } else { - return AE_NOT_FOUND; + return (AE_NOT_FOUND); } } else { ACPI_MEMCPY(out_table_header, diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 74e72080003..f8ee9b35b99 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -67,7 +67,6 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) { - ACPI_FUNCTION_ENTRY(); /* * The signature and checksum must both be correct diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 6e3ae6a23f0..2c217991764 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -300,6 +300,7 @@ acpi_ut_trace_ptr(u32 line_number, const char *function_name, const char *module_name, u32 component_id, void *pointer) { + acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 296baa676bc..93a11919933 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -193,6 +193,8 @@ static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) acpi_gbl_mutex_info[mutex_id].mutex = NULL; acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; + + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 73ca27d40f9..e79c49d44d0 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -517,14 +517,14 @@ void acpi_ut_dump_allocations(u32 component, const char *module) ACPI_FUNCTION_TRACE(ut_dump_allocations); if (acpi_gbl_disable_mem_tracking) { - return; + return_VOID; } /* * Walk the allocation list. */ if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) { - return; + return_VOID; } element = acpi_gbl_global_list->list_head; diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index b09632b4f5b..0c98d42fb2f 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -238,7 +238,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function) } acpi_gbl_init_handler = handler; - return AE_OK; + return (AE_OK); } ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler) @@ -263,6 +263,7 @@ acpi_status acpi_purge_cached_objects(void) (void)acpi_os_purge_cache(acpi_gbl_operand_cache); (void)acpi_os_purge_cache(acpi_gbl_ps_node_cache); (void)acpi_os_purge_cache(acpi_gbl_ps_node_ext_cache); + return_ACPI_STATUS(AE_OK); } -- cgit v1.2.3 From 4f3ca640e97ba54df42789a7c3085c75630e863c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:26:11 +0000 Subject: ACPICA: ACPICA core: Cleanup empty lines at file start and end Maintenance for source code consistency. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acobject.h | 1 - drivers/acpi/acpica/amlresrc.h | 1 - drivers/acpi/acpica/exmisc.c | 1 - drivers/acpi/acpica/exmutex.c | 1 - drivers/acpi/acpica/exnames.c | 1 - drivers/acpi/acpica/exoparg1.c | 1 - drivers/acpi/acpica/exoparg3.c | 1 - drivers/acpi/acpica/exoparg6.c | 1 - drivers/acpi/acpica/exprep.c | 1 - drivers/acpi/acpica/exregion.c | 1 - drivers/acpi/acpica/exresnte.c | 1 - drivers/acpi/acpica/exresolv.c | 1 - drivers/acpi/acpica/exresop.c | 1 - drivers/acpi/acpica/exstoren.c | 1 - drivers/acpi/acpica/exstorob.c | 1 - drivers/acpi/acpica/exsystem.c | 1 - drivers/acpi/acpica/exutils.c | 1 - drivers/acpi/acpica/hwacpi.c | 1 - drivers/acpi/acpica/hwgpe.c | 1 - drivers/acpi/acpica/hwregs.c | 1 - drivers/acpi/acpica/hwtimer.c | 1 - drivers/acpi/acpica/hwvalid.c | 1 - drivers/acpi/acpica/hwxface.c | 1 - include/acpi/acpiosxf.h | 1 - include/acpi/acpixf.h | 1 - 25 files changed, 25 deletions(-) diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index ac4269fb1a3..b83e46aebb1 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -1,4 +1,3 @@ - /****************************************************************************** * * Name: acobject.h - Definition of union acpi_operand_object (Internal object only) diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index af4947956ec..968449685e0 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: amlresrc.h - AML resource descriptors diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 271c0c57ea1..15e1abd1913 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 9099783eb85..4723974a4cf 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exmutex - ASL Mutex Acquire/Release functions diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 6d19bd42d29..a41c82fe2d3 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exnames - interpreter/scanner name load/execute diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 9ba8c73cea1..c6490d60919 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exoparg1 - AML execution - opcodes with 1 argument diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 71fcc65c9ff..00b19bfe5b5 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exoparg3 - AML execution - opcodes with 3 arguments diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index ab68dc532c7..98188555e78 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exoparg6 - AML execution - opcodes with 6 arguments diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 81eca60d274..95892480876 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 1f1ce0c3d2f..b41e333eb8f 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exregion - ACPI default op_region (address space) handlers diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index fa50e77e64a..1cb057fe817 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exresnte - AML Interpreter object resolution diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index bbf40ac2758..ae199e7cdfb 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exresolv - AML Interpreter object resolution diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 17dc218cd39..04b70b38ebd 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exresop - AML Interpreter operand/object resolution diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index b35bed52e06..6fe6eacb372 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exstoren - AML Interpreter object store support, diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 53c24847354..b9ac30c11b5 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exstorob - AML Interpreter object store support, store to object diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index b760641e2fc..2d6d8bc12ed 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exsystem - Interface to OS services diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index d1ab7917eed..ff291e626ec 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exutils - interpreter/scanner utilities diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index a1e71d0ef57..bcf931ca192 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 3b3b5e45847..64560045052 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwgpe - Low level GPE enable/disable/clear functions diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 4af6d20ef07..f4e57503576 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -1,4 +1,3 @@ - /******************************************************************************* * * Module Name: hwregs - Read/write access functions for the various ACPI diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 438004a1dd8..19f6cce95f1 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Name: hwtimer.c - ACPI Power Management Timer Interface diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index c99d546b217..b6aae58299d 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwvalid - I/O request validation diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 7bfd649d199..05a154c3c9a 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwxface - Public ACPICA hardware interfaces diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 1222ba93d80..64e2c8b830a 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -1,4 +1,3 @@ - /****************************************************************************** * * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index fe84aee5df4..2596de109ff 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -1,4 +1,3 @@ - /****************************************************************************** * * Name: acpixf.h - External interfaces to the ACPI subsystem -- cgit v1.2.3 From 691fda505822e46e2a8106e33b408a12e11732bc Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:26:23 +0000 Subject: ACPICA: Fix some typos in comments No functional changes. Some small fixes within commments. Colin Ian King. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbxfload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index f87cc63e69a..a5e1e4e4709 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -211,7 +211,7 @@ static acpi_status acpi_tb_load_namespace(void) * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must * be a valid ACPI table with a valid ACPI table header. * Note1: Mainly intended to support hotplug addition of SSDTs. - * Note2: Does not copy the incoming table. User is reponsible + * Note2: Does not copy the incoming table. User is responsible * to ensure that the table is not deleted or unmapped. * ******************************************************************************/ -- cgit v1.2.3 From 267d672ab3e2b171230b3edb5711794fab0afb02 Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Wed, 31 Oct 2012 02:26:36 +0000 Subject: ACPICA: Fix for predefined name loop during ACPICA initialization If a name cannot be created, simply continue on to the next name. Do not attempt to use the name, do not abort. With assistance from Colin Ian King. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsaccess.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index fc168e62c1c..d70eaf39dfd 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -110,11 +110,11 @@ acpi_status acpi_ns_root_initialize(void) status = acpi_ns_lookup(NULL, init_val->name, init_val->type, ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); - - if (ACPI_FAILURE(status) || (!new_node)) { /* Must be on same line for code converter */ + if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not create predefined name %s", init_val->name)); + continue; } /* -- cgit v1.2.3 From b9e17693576e4739cd267f59cbdfdd33c5eefe76 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:26:47 +0000 Subject: ACPICA: Update local C library module comments for ASCII table Improve the commenting of the table. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utclib.c | 261 ++++++++++++++++++++++--------------------- 1 file changed, 131 insertions(+), 130 deletions(-) diff --git a/drivers/acpi/acpica/utclib.c b/drivers/acpi/acpica/utclib.c index f887f93e56a..19ea4755aa7 100644 --- a/drivers/acpi/acpica/utclib.c +++ b/drivers/acpi/acpica/utclib.c @@ -46,7 +46,7 @@ /* * These implementations of standard C Library routines can optionally be - * used if a C library is not available. In general, they are less efficient + * used if a C library is not available. In general, they are less efficient * than an inline or assembly implementation */ @@ -606,134 +606,134 @@ int acpi_ut_to_lower(int c) ******************************************************************************/ const u8 _acpi_ctype[257] = { - _ACPI_CN, /* 0x0 0. */ - _ACPI_CN, /* 0x1 1. */ - _ACPI_CN, /* 0x2 2. */ - _ACPI_CN, /* 0x3 3. */ - _ACPI_CN, /* 0x4 4. */ - _ACPI_CN, /* 0x5 5. */ - _ACPI_CN, /* 0x6 6. */ - _ACPI_CN, /* 0x7 7. */ - _ACPI_CN, /* 0x8 8. */ - _ACPI_CN | _ACPI_SP, /* 0x9 9. */ - _ACPI_CN | _ACPI_SP, /* 0xA 10. */ - _ACPI_CN | _ACPI_SP, /* 0xB 11. */ - _ACPI_CN | _ACPI_SP, /* 0xC 12. */ - _ACPI_CN | _ACPI_SP, /* 0xD 13. */ - _ACPI_CN, /* 0xE 14. */ - _ACPI_CN, /* 0xF 15. */ - _ACPI_CN, /* 0x10 16. */ - _ACPI_CN, /* 0x11 17. */ - _ACPI_CN, /* 0x12 18. */ - _ACPI_CN, /* 0x13 19. */ - _ACPI_CN, /* 0x14 20. */ - _ACPI_CN, /* 0x15 21. */ - _ACPI_CN, /* 0x16 22. */ - _ACPI_CN, /* 0x17 23. */ - _ACPI_CN, /* 0x18 24. */ - _ACPI_CN, /* 0x19 25. */ - _ACPI_CN, /* 0x1A 26. */ - _ACPI_CN, /* 0x1B 27. */ - _ACPI_CN, /* 0x1C 28. */ - _ACPI_CN, /* 0x1D 29. */ - _ACPI_CN, /* 0x1E 30. */ - _ACPI_CN, /* 0x1F 31. */ - _ACPI_XS | _ACPI_SP, /* 0x20 32. ' ' */ - _ACPI_PU, /* 0x21 33. '!' */ - _ACPI_PU, /* 0x22 34. '"' */ - _ACPI_PU, /* 0x23 35. '#' */ - _ACPI_PU, /* 0x24 36. '$' */ - _ACPI_PU, /* 0x25 37. '%' */ - _ACPI_PU, /* 0x26 38. '&' */ - _ACPI_PU, /* 0x27 39. ''' */ - _ACPI_PU, /* 0x28 40. '(' */ - _ACPI_PU, /* 0x29 41. ')' */ - _ACPI_PU, /* 0x2A 42. '*' */ - _ACPI_PU, /* 0x2B 43. '+' */ - _ACPI_PU, /* 0x2C 44. ',' */ - _ACPI_PU, /* 0x2D 45. '-' */ - _ACPI_PU, /* 0x2E 46. '.' */ - _ACPI_PU, /* 0x2F 47. '/' */ - _ACPI_XD | _ACPI_DI, /* 0x30 48. '0' */ - _ACPI_XD | _ACPI_DI, /* 0x31 49. '1' */ - _ACPI_XD | _ACPI_DI, /* 0x32 50. '2' */ - _ACPI_XD | _ACPI_DI, /* 0x33 51. '3' */ - _ACPI_XD | _ACPI_DI, /* 0x34 52. '4' */ - _ACPI_XD | _ACPI_DI, /* 0x35 53. '5' */ - _ACPI_XD | _ACPI_DI, /* 0x36 54. '6' */ - _ACPI_XD | _ACPI_DI, /* 0x37 55. '7' */ - _ACPI_XD | _ACPI_DI, /* 0x38 56. '8' */ - _ACPI_XD | _ACPI_DI, /* 0x39 57. '9' */ - _ACPI_PU, /* 0x3A 58. ':' */ - _ACPI_PU, /* 0x3B 59. ';' */ - _ACPI_PU, /* 0x3C 60. '<' */ - _ACPI_PU, /* 0x3D 61. '=' */ - _ACPI_PU, /* 0x3E 62. '>' */ - _ACPI_PU, /* 0x3F 63. '?' */ - _ACPI_PU, /* 0x40 64. '@' */ - _ACPI_XD | _ACPI_UP, /* 0x41 65. 'A' */ - _ACPI_XD | _ACPI_UP, /* 0x42 66. 'B' */ - _ACPI_XD | _ACPI_UP, /* 0x43 67. 'C' */ - _ACPI_XD | _ACPI_UP, /* 0x44 68. 'D' */ - _ACPI_XD | _ACPI_UP, /* 0x45 69. 'E' */ - _ACPI_XD | _ACPI_UP, /* 0x46 70. 'F' */ - _ACPI_UP, /* 0x47 71. 'G' */ - _ACPI_UP, /* 0x48 72. 'H' */ - _ACPI_UP, /* 0x49 73. 'I' */ - _ACPI_UP, /* 0x4A 74. 'J' */ - _ACPI_UP, /* 0x4B 75. 'K' */ - _ACPI_UP, /* 0x4C 76. 'L' */ - _ACPI_UP, /* 0x4D 77. 'M' */ - _ACPI_UP, /* 0x4E 78. 'N' */ - _ACPI_UP, /* 0x4F 79. 'O' */ - _ACPI_UP, /* 0x50 80. 'P' */ - _ACPI_UP, /* 0x51 81. 'Q' */ - _ACPI_UP, /* 0x52 82. 'R' */ - _ACPI_UP, /* 0x53 83. 'S' */ - _ACPI_UP, /* 0x54 84. 'T' */ - _ACPI_UP, /* 0x55 85. 'U' */ - _ACPI_UP, /* 0x56 86. 'V' */ - _ACPI_UP, /* 0x57 87. 'W' */ - _ACPI_UP, /* 0x58 88. 'X' */ - _ACPI_UP, /* 0x59 89. 'Y' */ - _ACPI_UP, /* 0x5A 90. 'Z' */ - _ACPI_PU, /* 0x5B 91. '[' */ - _ACPI_PU, /* 0x5C 92. '\' */ - _ACPI_PU, /* 0x5D 93. ']' */ - _ACPI_PU, /* 0x5E 94. '^' */ - _ACPI_PU, /* 0x5F 95. '_' */ - _ACPI_PU, /* 0x60 96. '`' */ - _ACPI_XD | _ACPI_LO, /* 0x61 97. 'a' */ - _ACPI_XD | _ACPI_LO, /* 0x62 98. 'b' */ - _ACPI_XD | _ACPI_LO, /* 0x63 99. 'c' */ - _ACPI_XD | _ACPI_LO, /* 0x64 100. 'd' */ - _ACPI_XD | _ACPI_LO, /* 0x65 101. 'e' */ - _ACPI_XD | _ACPI_LO, /* 0x66 102. 'f' */ - _ACPI_LO, /* 0x67 103. 'g' */ - _ACPI_LO, /* 0x68 104. 'h' */ - _ACPI_LO, /* 0x69 105. 'i' */ - _ACPI_LO, /* 0x6A 106. 'j' */ - _ACPI_LO, /* 0x6B 107. 'k' */ - _ACPI_LO, /* 0x6C 108. 'l' */ - _ACPI_LO, /* 0x6D 109. 'm' */ - _ACPI_LO, /* 0x6E 110. 'n' */ - _ACPI_LO, /* 0x6F 111. 'o' */ - _ACPI_LO, /* 0x70 112. 'p' */ - _ACPI_LO, /* 0x71 113. 'q' */ - _ACPI_LO, /* 0x72 114. 'r' */ - _ACPI_LO, /* 0x73 115. 's' */ - _ACPI_LO, /* 0x74 116. 't' */ - _ACPI_LO, /* 0x75 117. 'u' */ - _ACPI_LO, /* 0x76 118. 'v' */ - _ACPI_LO, /* 0x77 119. 'w' */ - _ACPI_LO, /* 0x78 120. 'x' */ - _ACPI_LO, /* 0x79 121. 'y' */ - _ACPI_LO, /* 0x7A 122. 'z' */ - _ACPI_PU, /* 0x7B 123. '{' */ - _ACPI_PU, /* 0x7C 124. '|' */ - _ACPI_PU, /* 0x7D 125. '}' */ - _ACPI_PU, /* 0x7E 126. '~' */ - _ACPI_CN, /* 0x7F 127. */ + _ACPI_CN, /* 0x00 0 NUL */ + _ACPI_CN, /* 0x01 1 SOH */ + _ACPI_CN, /* 0x02 2 STX */ + _ACPI_CN, /* 0x03 3 ETX */ + _ACPI_CN, /* 0x04 4 EOT */ + _ACPI_CN, /* 0x05 5 ENQ */ + _ACPI_CN, /* 0x06 6 ACK */ + _ACPI_CN, /* 0x07 7 BEL */ + _ACPI_CN, /* 0x08 8 BS */ + _ACPI_CN | _ACPI_SP, /* 0x09 9 TAB */ + _ACPI_CN | _ACPI_SP, /* 0x0A 10 LF */ + _ACPI_CN | _ACPI_SP, /* 0x0B 11 VT */ + _ACPI_CN | _ACPI_SP, /* 0x0C 12 FF */ + _ACPI_CN | _ACPI_SP, /* 0x0D 13 CR */ + _ACPI_CN, /* 0x0E 14 SO */ + _ACPI_CN, /* 0x0F 15 SI */ + _ACPI_CN, /* 0x10 16 DLE */ + _ACPI_CN, /* 0x11 17 DC1 */ + _ACPI_CN, /* 0x12 18 DC2 */ + _ACPI_CN, /* 0x13 19 DC3 */ + _ACPI_CN, /* 0x14 20 DC4 */ + _ACPI_CN, /* 0x15 21 NAK */ + _ACPI_CN, /* 0x16 22 SYN */ + _ACPI_CN, /* 0x17 23 ETB */ + _ACPI_CN, /* 0x18 24 CAN */ + _ACPI_CN, /* 0x19 25 EM */ + _ACPI_CN, /* 0x1A 26 SUB */ + _ACPI_CN, /* 0x1B 27 ESC */ + _ACPI_CN, /* 0x1C 28 FS */ + _ACPI_CN, /* 0x1D 29 GS */ + _ACPI_CN, /* 0x1E 30 RS */ + _ACPI_CN, /* 0x1F 31 US */ + _ACPI_XS | _ACPI_SP, /* 0x20 32 ' ' */ + _ACPI_PU, /* 0x21 33 '!' */ + _ACPI_PU, /* 0x22 34 '"' */ + _ACPI_PU, /* 0x23 35 '#' */ + _ACPI_PU, /* 0x24 36 '$' */ + _ACPI_PU, /* 0x25 37 '%' */ + _ACPI_PU, /* 0x26 38 '&' */ + _ACPI_PU, /* 0x27 39 ''' */ + _ACPI_PU, /* 0x28 40 '(' */ + _ACPI_PU, /* 0x29 41 ')' */ + _ACPI_PU, /* 0x2A 42 '*' */ + _ACPI_PU, /* 0x2B 43 '+' */ + _ACPI_PU, /* 0x2C 44 ',' */ + _ACPI_PU, /* 0x2D 45 '-' */ + _ACPI_PU, /* 0x2E 46 '.' */ + _ACPI_PU, /* 0x2F 47 '/' */ + _ACPI_XD | _ACPI_DI, /* 0x30 48 '0' */ + _ACPI_XD | _ACPI_DI, /* 0x31 49 '1' */ + _ACPI_XD | _ACPI_DI, /* 0x32 50 '2' */ + _ACPI_XD | _ACPI_DI, /* 0x33 51 '3' */ + _ACPI_XD | _ACPI_DI, /* 0x34 52 '4' */ + _ACPI_XD | _ACPI_DI, /* 0x35 53 '5' */ + _ACPI_XD | _ACPI_DI, /* 0x36 54 '6' */ + _ACPI_XD | _ACPI_DI, /* 0x37 55 '7' */ + _ACPI_XD | _ACPI_DI, /* 0x38 56 '8' */ + _ACPI_XD | _ACPI_DI, /* 0x39 57 '9' */ + _ACPI_PU, /* 0x3A 58 ':' */ + _ACPI_PU, /* 0x3B 59 ';' */ + _ACPI_PU, /* 0x3C 60 '<' */ + _ACPI_PU, /* 0x3D 61 '=' */ + _ACPI_PU, /* 0x3E 62 '>' */ + _ACPI_PU, /* 0x3F 63 '?' */ + _ACPI_PU, /* 0x40 64 '@' */ + _ACPI_XD | _ACPI_UP, /* 0x41 65 'A' */ + _ACPI_XD | _ACPI_UP, /* 0x42 66 'B' */ + _ACPI_XD | _ACPI_UP, /* 0x43 67 'C' */ + _ACPI_XD | _ACPI_UP, /* 0x44 68 'D' */ + _ACPI_XD | _ACPI_UP, /* 0x45 69 'E' */ + _ACPI_XD | _ACPI_UP, /* 0x46 70 'F' */ + _ACPI_UP, /* 0x47 71 'G' */ + _ACPI_UP, /* 0x48 72 'H' */ + _ACPI_UP, /* 0x49 73 'I' */ + _ACPI_UP, /* 0x4A 74 'J' */ + _ACPI_UP, /* 0x4B 75 'K' */ + _ACPI_UP, /* 0x4C 76 'L' */ + _ACPI_UP, /* 0x4D 77 'M' */ + _ACPI_UP, /* 0x4E 78 'N' */ + _ACPI_UP, /* 0x4F 79 'O' */ + _ACPI_UP, /* 0x50 80 'P' */ + _ACPI_UP, /* 0x51 81 'Q' */ + _ACPI_UP, /* 0x52 82 'R' */ + _ACPI_UP, /* 0x53 83 'S' */ + _ACPI_UP, /* 0x54 84 'T' */ + _ACPI_UP, /* 0x55 85 'U' */ + _ACPI_UP, /* 0x56 86 'V' */ + _ACPI_UP, /* 0x57 87 'W' */ + _ACPI_UP, /* 0x58 88 'X' */ + _ACPI_UP, /* 0x59 89 'Y' */ + _ACPI_UP, /* 0x5A 90 'Z' */ + _ACPI_PU, /* 0x5B 91 '[' */ + _ACPI_PU, /* 0x5C 92 '\' */ + _ACPI_PU, /* 0x5D 93 ']' */ + _ACPI_PU, /* 0x5E 94 '^' */ + _ACPI_PU, /* 0x5F 95 '_' */ + _ACPI_PU, /* 0x60 96 '`' */ + _ACPI_XD | _ACPI_LO, /* 0x61 97 'a' */ + _ACPI_XD | _ACPI_LO, /* 0x62 98 'b' */ + _ACPI_XD | _ACPI_LO, /* 0x63 99 'c' */ + _ACPI_XD | _ACPI_LO, /* 0x64 100 'd' */ + _ACPI_XD | _ACPI_LO, /* 0x65 101 'e' */ + _ACPI_XD | _ACPI_LO, /* 0x66 102 'f' */ + _ACPI_LO, /* 0x67 103 'g' */ + _ACPI_LO, /* 0x68 104 'h' */ + _ACPI_LO, /* 0x69 105 'i' */ + _ACPI_LO, /* 0x6A 106 'j' */ + _ACPI_LO, /* 0x6B 107 'k' */ + _ACPI_LO, /* 0x6C 108 'l' */ + _ACPI_LO, /* 0x6D 109 'm' */ + _ACPI_LO, /* 0x6E 110 'n' */ + _ACPI_LO, /* 0x6F 111 'o' */ + _ACPI_LO, /* 0x70 112 'p' */ + _ACPI_LO, /* 0x71 113 'q' */ + _ACPI_LO, /* 0x72 114 'r' */ + _ACPI_LO, /* 0x73 115 's' */ + _ACPI_LO, /* 0x74 116 't' */ + _ACPI_LO, /* 0x75 117 'u' */ + _ACPI_LO, /* 0x76 118 'v' */ + _ACPI_LO, /* 0x77 119 'w' */ + _ACPI_LO, /* 0x78 120 'x' */ + _ACPI_LO, /* 0x79 121 'y' */ + _ACPI_LO, /* 0x7A 122 'z' */ + _ACPI_PU, /* 0x7B 123 '{' */ + _ACPI_PU, /* 0x7C 124 '|' */ + _ACPI_PU, /* 0x7D 125 '}' */ + _ACPI_PU, /* 0x7E 126 '~' */ + _ACPI_CN, /* 0x7F 127 DEL */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 to 0x8F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 to 0x9F */ @@ -742,7 +742,8 @@ const u8 _acpi_ctype[257] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 to 0xCF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 to 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 to 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0 to 0x100 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 to 0xFF */ + 0 /* 0x100 */ }; #endif /* ACPI_USE_SYSTEM_CLIBRARY */ -- cgit v1.2.3 From 73a3090a2160fb01317f5a44af6ee5a064a29625 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:26:55 +0000 Subject: ACPICA: Remove extra spaces after periods within comments This makes all comments consistent. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/aclocal.h | 4 ++-- drivers/acpi/acpica/acobject.h | 4 ++-- drivers/acpi/acpica/acopcode.h | 6 +++--- drivers/acpi/acpica/acstruct.h | 2 +- drivers/acpi/acpica/dscontrol.c | 2 +- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dsmethod.c | 6 +++--- drivers/acpi/acpica/dsmthdat.c | 14 +++++++------- drivers/acpi/acpica/dsobject.c | 6 +++--- drivers/acpi/acpica/dsutils.c | 30 +++++++++++++++--------------- drivers/acpi/acpica/dswexec.c | 8 ++++---- drivers/acpi/acpica/dswstate.c | 8 ++++---- drivers/acpi/acpica/excreate.c | 6 +++--- drivers/acpi/acpica/exdump.c | 2 +- drivers/acpi/acpica/exfield.c | 4 ++-- drivers/acpi/acpica/exfldio.c | 12 ++++++------ drivers/acpi/acpica/exmisc.c | 4 ++-- drivers/acpi/acpica/exnames.c | 2 +- drivers/acpi/acpica/exoparg1.c | 10 +++++----- drivers/acpi/acpica/exoparg2.c | 2 +- drivers/acpi/acpica/exoparg3.c | 2 +- drivers/acpi/acpica/exoparg6.c | 2 +- drivers/acpi/acpica/exprep.c | 12 ++++++------ drivers/acpi/acpica/exregion.c | 2 +- drivers/acpi/acpica/exresnte.c | 8 ++++---- drivers/acpi/acpica/exresolv.c | 2 +- drivers/acpi/acpica/exresop.c | 4 ++-- drivers/acpi/acpica/exstore.c | 4 ++-- drivers/acpi/acpica/exstoren.c | 10 +++++----- drivers/acpi/acpica/exstorob.c | 4 ++-- drivers/acpi/acpica/exsystem.c | 8 ++++---- drivers/acpi/acpica/exutils.c | 4 ++-- drivers/acpi/acpica/hwacpi.c | 2 +- drivers/acpi/acpica/hwtimer.c | 2 +- drivers/acpi/acpica/nsalloc.c | 4 ++-- drivers/acpi/acpica/nsdump.c | 2 +- drivers/acpi/acpica/nsload.c | 10 +++++----- drivers/acpi/acpica/nsobject.c | 8 ++++---- drivers/acpi/acpica/nsparse.c | 8 ++++---- drivers/acpi/acpica/nsutils.c | 6 +++--- drivers/acpi/acpica/nswalk.c | 10 +++++----- drivers/acpi/acpica/nsxfeval.c | 14 +++++++------- drivers/acpi/acpica/nsxfname.c | 6 +++--- drivers/acpi/acpica/nsxfobj.c | 4 ++-- drivers/acpi/acpica/psargs.c | 8 ++++---- drivers/acpi/acpica/psopcode.c | 6 +++--- drivers/acpi/acpica/psparse.c | 8 ++++---- drivers/acpi/acpica/psutils.c | 4 ++-- drivers/acpi/acpica/rscalc.c | 2 +- drivers/acpi/acpica/tbxfroot.c | 2 +- drivers/acpi/acpica/utcache.c | 6 +++--- drivers/acpi/acpica/utdebug.c | 18 +++++++++--------- drivers/acpi/acpica/utmath.c | 2 +- drivers/acpi/acpica/utmisc.c | 14 +++++++------- drivers/acpi/acpica/utmutex.c | 12 ++++++------ drivers/acpi/acpica/utobject.c | 8 ++++---- drivers/acpi/acpica/utstate.c | 2 +- drivers/acpi/acpica/uttrack.c | 6 +++--- drivers/acpi/acpica/utxface.c | 2 +- include/acpi/acexcep.h | 2 +- 61 files changed, 188 insertions(+), 188 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 35006d193d5..64472e4ec32 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -70,7 +70,7 @@ /* * Enable "slack" in the AML interpreter? Default is FALSE, and the - * interpreter strictly follows the ACPI specification. Setting to TRUE + * interpreter strictly follows the ACPI specification. Setting to TRUE * allows the interpreter to ignore certain errors and/or bad AML constructs. * * Currently, these features are enabled by this flag: diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 5b5be40a199..ff8bd0061e8 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -265,7 +265,7 @@ typedef acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state); /* - * Bitmapped ACPI types. Used internally only + * Bitmapped ACPI types. Used internally only */ #define ACPI_BTYPE_ANY 0x00000000 #define ACPI_BTYPE_INTEGER 0x00000001 @@ -584,7 +584,7 @@ struct acpi_pscope_state { }; /* - * Thread state - one per thread across multiple walk states. Multiple walk + * Thread state - one per thread across multiple walk states. Multiple walk * states are created when there are nested control methods executing. */ struct acpi_thread_state { diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index b83e46aebb1..24eb9eac951 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -197,7 +197,7 @@ struct acpi_object_method { /****************************************************************************** * - * Objects that can be notified. All share a common notify_info area. + * Objects that can be notified. All share a common notify_info area. * *****************************************************************************/ @@ -234,7 +234,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; /****************************************************************************** * - * Fields. All share a common header/info field. + * Fields. All share a common header/info field. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index 9440d053fbb..d786a5128b7 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -54,7 +54,7 @@ #define _UNK 0x6B /* - * Reserved ASCII characters. Do not use any of these for + * Reserved ASCII characters. Do not use any of these for * internal opcodes, since they are used to differentiate * name strings from AML opcodes */ @@ -63,7 +63,7 @@ #define _PFX 0x6D /* - * All AML opcodes and the parse-time arguments for each. Used by the AML + * All AML opcodes and the parse-time arguments for each. Used by the AML * parser Each list is compressed into a 32-bit number and stored in the * master opcode table (in psopcode.c). */ @@ -193,7 +193,7 @@ #define ARGP_ZERO_OP ARG_NONE /* - * All AML opcodes and the runtime arguments for each. Used by the AML + * All AML opcodes and the runtime arguments for each. Used by the AML * interpreter Each list is compressed into a 32-bit number and stored * in the master opcode table (in psopcode.c). * diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index f196e2c9a71..937e66c65d1 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -53,7 +53,7 @@ ****************************************************************************/ /* - * Walk state - current state of a parse tree walk. Used for both a leisurely + * Walk state - current state of a parse tree walk. Used for both a leisurely * stroll through the tree (for whatever reason), and for control method * execution. */ diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 465f02134b8..57895db3231 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -280,7 +280,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, /* * Get the return value and save as the last result - * value. This is the only place where walk_state->return_desc + * value. This is the only place where walk_state->return_desc * is set to anything other than zero! */ walk_state->return_desc = walk_state->operands[0]; diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 3da6fd8530c..b5b904ee815 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -277,7 +277,7 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, * * RETURN: Status * - * DESCRIPTION: Process all named fields in a field declaration. Names are + * DESCRIPTION: Process all named fields in a field declaration. Names are * entered into the namespace. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index aa9a5d4e405..52eb4e01622 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -170,7 +170,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc) * * RETURN: Status * - * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, + * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, * increments the thread count, and waits at the method semaphore * for clearance to execute. * @@ -444,7 +444,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, * RETURN: Status * * DESCRIPTION: Restart a method that was preempted by another (nested) method - * invocation. Handle the return value (if any) from the callee. + * invocation. Handle the return value (if any) from the callee. * ******************************************************************************/ @@ -530,7 +530,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, * * RETURN: None * - * DESCRIPTION: Terminate a control method. Delete everything that the method + * DESCRIPTION: Terminate a control method. Delete everything that the method * created, delete all locals and arguments, and delete the parse * tree if requested. * diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 8d55cebaa65..9a83b7e0f3b 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -76,7 +76,7 @@ acpi_ds_method_data_get_type(u16 opcode, * RETURN: Status * * DESCRIPTION: Initialize the data structures that hold the method's arguments - * and locals. The data struct is an array of namespace nodes for + * and locals. The data struct is an array of namespace nodes for * each - this allows ref_of and de_ref_of to work properly for these * special data types. * @@ -129,7 +129,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) * * RETURN: None * - * DESCRIPTION: Delete method locals and arguments. Arguments are only + * DESCRIPTION: Delete method locals and arguments. Arguments are only * deleted if this method was called from another method. * ******************************************************************************/ @@ -183,7 +183,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state) * * RETURN: Status * - * DESCRIPTION: Initialize arguments for a method. The parameter list is a list + * DESCRIPTION: Initialize arguments for a method. The parameter list is a list * of ACPI operand objects, either null terminated or whose length * is defined by max_param_count. * @@ -401,7 +401,7 @@ acpi_ds_method_data_get_value(u8 type, * This means that either 1) The expected argument was * not passed to the method, or 2) A local variable * was referenced by the method (via the ASL) - * before it was initialized. Either case is an error. + * before it was initialized. Either case is an error. */ /* If slack enabled, init the local_x/arg_x to an Integer of value zero */ @@ -465,7 +465,7 @@ acpi_ds_method_data_get_value(u8 type, * * RETURN: None * - * DESCRIPTION: Delete the entry at Opcode:Index. Inserts + * DESCRIPTION: Delete the entry at Opcode:Index. Inserts * a null into the stack slot after the object is deleted. * ******************************************************************************/ @@ -523,7 +523,7 @@ acpi_ds_method_data_delete_value(u8 type, * * RETURN: Status * - * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed + * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed * as the new value for the Arg or Local and the reference count * for obj_desc is incremented. * @@ -566,7 +566,7 @@ acpi_ds_store_object_to_local(u8 type, /* * If the reference count on the object is more than one, we must - * take a copy of the object before we store. A reference count + * take a copy of the object before we store. A reference count * of exactly 1 means that the object was just created during the * evaluation of an expression, and we can safely use it since it * is not used anywhere else. diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 68592dd3496..c9f15d3a368 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -293,7 +293,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, /* * Second arg is the buffer data (optional) byte_list can be either - * individual bytes or a string initializer. In either case, a + * individual bytes or a string initializer. In either case, a * byte_list appears in the AML. */ arg = op->common.value.arg; /* skip first arg */ @@ -568,7 +568,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, /* * Because of the execution pass through the non-control-method - * parts of the table, we can arrive here twice. Only init + * parts of the table, we can arrive here twice. Only init * the named object node the first time through */ if (acpi_ns_get_attached_object(node)) { @@ -618,7 +618,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Initialize a namespace object from a parser Op and its - * associated arguments. The namespace object is a more compact + * associated arguments. The namespace object is a more compact * representation of the Op and its arguments. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 4bbdd6c7a3d..afeb99f4948 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -61,7 +61,7 @@ ACPI_MODULE_NAME("dsutils") * * RETURN: None. * - * DESCRIPTION: Clear and remove a reference on an implicit return value. Used + * DESCRIPTION: Clear and remove a reference on an implicit return value. Used * to delete "stale" return values (if enabled, the return value * from every operator is saved at least momentarily, in case the * parent method exits.) @@ -107,7 +107,7 @@ void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state) * * DESCRIPTION: Implements the optional "implicit return". We save the result * of every ASL operator and control method invocation in case the - * parent method exit. Before storing a new return value, we + * parent method exit. Before storing a new return value, we * delete the previous return value. * ******************************************************************************/ @@ -198,7 +198,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, * * If there is no parent, or the parent is a scope_op, we are executing * at the method level. An executing method typically has no parent, - * since each method is parsed separately. A method invoked externally + * since each method is parsed separately. A method invoked externally * via execute_control_method has a scope_op as the parent. */ if ((!op->common.parent) || @@ -223,7 +223,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, } /* - * Decide what to do with the result based on the parent. If + * Decide what to do with the result based on the parent. If * the parent opcode will not use the result, delete the object. * Otherwise leave it as is, it will be deleted when it is used * as an operand later. @@ -266,7 +266,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, /* * These opcodes allow term_arg(s) as operands and therefore - * the operands can be method calls. The result is used. + * the operands can be method calls. The result is used. */ goto result_used; @@ -284,7 +284,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, AML_BANK_FIELD_OP)) { /* * These opcodes allow term_arg(s) as operands and therefore - * the operands can be method calls. The result is used. + * the operands can be method calls. The result is used. */ goto result_used; } @@ -329,9 +329,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op, * * RETURN: Status * - * DESCRIPTION: Used after interpretation of an opcode. If there is an internal + * DESCRIPTION: Used after interpretation of an opcode. If there is an internal * result descriptor, check if the parent opcode will actually use - * this result. If not, delete the result now so that it will + * this result. If not, delete the result now so that it will * not become orphaned. * ******************************************************************************/ @@ -376,7 +376,7 @@ acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, * * RETURN: Status * - * DESCRIPTION: Resolve all operands to their values. Used to prepare + * DESCRIPTION: Resolve all operands to their values. Used to prepare * arguments to a control method invocation (a call from one * method to another.) * @@ -391,7 +391,7 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state) /* * Attempt to resolve each of the valid operands - * Method arguments are passed by reference, not by value. This means + * Method arguments are passed by reference, not by value. This means * that the actual objects are passed, not copies of the objects. */ for (i = 0; i < walk_state->num_operands; i++) { @@ -451,7 +451,7 @@ void acpi_ds_clear_operands(struct acpi_walk_state *walk_state) * RETURN: Status * * DESCRIPTION: Translate a parse tree object that is an argument to an AML - * opcode to the equivalent interpreter object. This may include + * opcode to the equivalent interpreter object. This may include * looking up a name or entering a new name into the internal * namespace. * @@ -496,9 +496,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* * Special handling for buffer_field declarations. This is a deferred * opcode that unfortunately defines the field name as the last - * parameter instead of the first. We get here when we are performing + * parameter instead of the first. We get here when we are performing * the deferred execution, so the actual name of the field is already - * in the namespace. We don't want to attempt to look it up again + * in the namespace. We don't want to attempt to look it up again * because we may be executing in a different scope than where the * actual opcode exists. */ @@ -605,8 +605,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* * If the name is null, this means that this is an * optional result parameter that was not specified - * in the original ASL. Create a Zero Constant for a - * placeholder. (Store to a constant is a Noop.) + * in the original ASL. Create a Zero Constant for a + * placeholder. (Store to a constant is a Noop.) */ opcode = AML_ZERO_OP; /* Has no arguments! */ diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index fa44609aba3..58593931be9 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -204,7 +204,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Descending callback used during the execution of control - * methods. This is where most operators and operands are + * methods. This is where most operators and operands are * dispatched to the interpreter. * ****************************************************************************/ @@ -297,7 +297,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, if (walk_state->walk_type & ACPI_WALK_METHOD) { /* * Found a named object declaration during method execution; - * we must enter this object into the namespace. The created + * we must enter this object into the namespace. The created * object is temporary and will be deleted upon completion of * the execution of this method. * @@ -348,7 +348,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Ascending callback used during the execution of control - * methods. The only thing we really need to do here is to + * methods. The only thing we really need to do here is to * notice the beginning of IF, ELSE, and WHILE blocks. * ****************************************************************************/ @@ -432,7 +432,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) if (ACPI_SUCCESS(status)) { /* * Dispatch the request to the appropriate interpreter handler - * routine. There is one routine per opcode "type" based upon the + * routine. There is one routine per opcode "type" based upon the * number of opcode arguments and return type. */ status = diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 8e6267980aa..3e65a15a735 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -348,7 +348,7 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state) * * RETURN: Status * - * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT * deleted by this routine. * ******************************************************************************/ @@ -492,7 +492,7 @@ acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, * RETURN: A walk_state object popped from the thread's stack * * DESCRIPTION: Remove and return the walkstate object that is at the head of - * the walk stack for the given walk list. NULL indicates that + * the walk stack for the given walk list. NULL indicates that * the list is empty. * ******************************************************************************/ @@ -532,7 +532,7 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) * * RETURN: Pointer to the new walk state. * - * DESCRIPTION: Allocate and initialize a new walk state. The current walk + * DESCRIPTION: Allocate and initialize a new walk state. The current walk * state is set to this new state. * ******************************************************************************/ @@ -657,7 +657,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, /* * Setup the current scope. * Find a Named Op that has a namespace node associated with it. - * search upwards from this Op. Current scope is the first + * search upwards from this Op. Current scope is the first * Op with a namespace node. */ extra_op = parser_state->start_op; diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 9f152701bc0..66554bc6f9a 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -78,7 +78,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { /* * Dereference an existing alias so that we don't create a chain - * of aliases. With this code, we guarantee that an alias is + * of aliases. With this code, we guarantee that an alias is * always exactly one level of indirection away from the * actual aliased name. */ @@ -90,7 +90,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) /* * For objects that can never change (i.e., the NS node will * permanently point to the same object), we can simply attach - * the object to the new NS node. For other objects (such as + * the object to the new NS node. For other objects (such as * Integers, buffers, etc.), we have to point the Alias node * to the original Node. */ @@ -139,7 +139,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) /* * The new alias assumes the type of the target, and it points - * to the same object. The reference count of the object has an + * to the same object. The reference count of the object has an * additional reference to prevent deletion out from under either the * target node or the alias Node */ diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 40608b3e28f..3157f3bb8de 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -778,7 +778,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands, * PARAMETERS: title - Descriptive text * value - Value to be displayed * - * DESCRIPTION: Object dump output formatting functions. These functions + * DESCRIPTION: Object dump output formatting functions. These functions * reduce the number of format strings required and keeps them * all in one place for easy modification. * diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index dc092f5b35d..ebc55fbf3ff 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -59,7 +59,7 @@ ACPI_MODULE_NAME("exfield") * * RETURN: Status * - * DESCRIPTION: Read from a named field. Returns either an Integer or a + * DESCRIPTION: Read from a named field. Returns either an Integer or a * Buffer, depending on the size of the field. * ******************************************************************************/ @@ -149,7 +149,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, * Allocate a buffer for the contents of the field. * * If the field is larger than the current integer width, create - * a BUFFER to hold it. Otherwise, use an INTEGER. This allows + * a BUFFER to hold it. Otherwise, use an INTEGER. This allows * the use of arithmetic operators on the returned value if the * field size is equal or smaller than an Integer. * diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 419148a66e7..aa2ccfb7cb6 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -154,7 +154,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, #endif /* - * Validate the request. The entire request from the byte offset for a + * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ @@ -182,7 +182,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider - * than the region itself. For example, a region of length one + * than the region itself. For example, a region of length one * byte, and a field with Dword access specified. */ ACPI_ERROR((AE_INFO, @@ -320,7 +320,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, * * DESCRIPTION: Check if a value is out of range of the field being written. * Used to check if the values written to Index and Bank registers - * are out of range. Normally, the value is simply truncated + * are out of range. Normally, the value is simply truncated * to fit the field, but this case is most likely a serious * coding error in the ASL. * @@ -369,7 +369,7 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) * * RETURN: Status * - * DESCRIPTION: Read or Write a single datum of a field. The field_type is + * DESCRIPTION: Read or Write a single datum of a field. The field_type is * demultiplexed here to handle the different types of fields * (buffer_field, region_field, index_field, bank_field) * @@ -859,7 +859,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, 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 + * we are writing to. This is because individual fields are * indivisible and partial writes are not supported -- as per * the ACPI specification. */ @@ -874,7 +874,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* * Copy the original data to the new buffer, starting - * at Byte zero. All unused (upper) bytes of the + * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length); diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 15e1abd1913..84058705ed1 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -253,7 +253,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, ACPI_FUNCTION_TRACE(ex_do_concatenate); /* - * Convert the second operand if necessary. The first operand + * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand @@ -572,7 +572,7 @@ acpi_ex_do_logical_op(u16 opcode, ACPI_FUNCTION_TRACE(ex_do_logical_op); /* - * Convert the second operand if necessary. The first operand + * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI 3.0+ specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index a41c82fe2d3..2ff578a16ad 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -62,7 +62,7 @@ static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string); * (-1)==root, 0==none * num_name_segs - count of 4-character name segments * - * RETURN: A pointer to the allocated string segment. This segment must + * RETURN: A pointer to the allocated string segment. This segment must * be deleted by the caller. * * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index c6490d60919..bbf01e9bf05 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -605,7 +605,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) } /* - * Set result to ONES (TRUE) if Value == 0. Note: + * Set result to ONES (TRUE) if Value == 0. Note: * return_desc->Integer.Value is initially == 0 (FALSE) from above. */ if (!operand[0]->integer.value) { @@ -617,7 +617,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) case AML_INCREMENT_OP: /* Increment (Operand) */ /* - * Create a new integer. Can't just get the base integer and + * Create a new integer. Can't just get the base integer and * increment it because it may be an Arg or Field. */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); @@ -685,7 +685,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* * 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 + * get the associated object, not its value. For example, we don't * want to resolve a field_unit to its value, we want the actual * field_unit object. */ @@ -726,7 +726,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* * The type of the base object must be integer, buffer, string, or - * package. All others are not supported. + * package. All others are not supported. * * NOTE: Integer is not specifically supported by the ACPI spec, * but is supported implicitly via implicit operand conversion. @@ -964,7 +964,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) case ACPI_TYPE_PACKAGE: /* - * Return the referenced element of the package. We must + * Return the referenced element of the package. We must * add another reference to the referenced object, however. */ return_desc = diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 879e8a277b9..ee5634a074c 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -123,7 +123,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) /* * Dispatch the notify to the appropriate handler * NOTE: the request is queued for execution after this method - * completes. The notify handlers are NOT invoked synchronously + * completes. The notify handlers are NOT invoked synchronously * from this thread -- because handlers may in turn run other * control methods. */ diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 00b19bfe5b5..2c89b4651f0 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -157,7 +157,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ /* - * Create the return object. The Source operand is guaranteed to be + * Create the return object. The Source operand is guaranteed to be * either a String or a Buffer, so just use its type. */ return_desc = acpi_ut_create_internal_object((operand[0])-> diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 98188555e78..3e08695c3b3 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -268,7 +268,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) * and the next should be examined. * * Upon finding a match, the loop will terminate via "break" at - * the bottom. If it terminates "normally", match_value will be + * the bottom. If it terminates "normally", match_value will be * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no * match was found. */ diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 95892480876..ba9db4de7c8 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -77,8 +77,8 @@ acpi_ex_generate_access(u32 field_bit_offset, * any_acc keyword. * * NOTE: Need to have the region_length in order to check for boundary - * conditions (end-of-region). However, the region_length is a deferred - * operation. Therefore, to complete this implementation, the generation + * conditions (end-of-region). However, the region_length is a deferred + * operation. Therefore, to complete this implementation, the generation * of this access width must be deferred until the region length has * been evaluated. * @@ -307,7 +307,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, * RETURN: Status * * DESCRIPTION: Initialize the areas of the field object that are common - * to the various types of fields. Note: This is very "sensitive" + * to the various types of fields. Note: This is very "sensitive" * code because we are solving the general case for field * alignment. * @@ -335,13 +335,13 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, obj_desc->common_field.bit_length = field_bit_length; /* - * Decode the access type so we can compute offsets. The access type gives + * Decode the access type so we can compute offsets. The access type gives * two pieces of information - the width of each field access and the * necessary byte_alignment (address granularity) of the access. * * For any_acc, the access_bit_width is the largest width that is both * necessary and possible in an attempt to access the whole field in one - * I/O operation. However, for any_acc, the byte_alignment is always one + * I/O operation. However, for any_acc, the byte_alignment is always one * byte. * * For all Buffer Fields, the byte_alignment is always one byte. @@ -362,7 +362,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, /* * base_byte_offset is the address of the start of the field within the - * region. It is the byte address of the first *datum* (field-width data + * region. It is the byte address of the first *datum* (field-width data * unit) of the field. (i.e., the first datum that contains at least the * first *bit* of the field.) * diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index b41e333eb8f..1db2c0bfde0 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -201,7 +201,7 @@ acpi_ex_system_memory_space_handler(u32 function, * Perform the memory read or write * * Note: For machines that do not support non-aligned transfers, the target - * address was checked for alignment above. We do not attempt to break the + * address was checked for alignment above. We do not attempt to break the * transfer up into smaller (byte-size) chunks because the AML specifically * asked for a transfer width that the hardware may require. */ diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 1cb057fe817..6239956786e 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -57,8 +57,8 @@ ACPI_MODULE_NAME("exresnte") * PARAMETERS: object_ptr - Pointer to a location that contains * a pointer to a NS node, and will receive a * pointer to the resolved object. - * walk_state - Current state. Valid only if executing AML - * code. NULL if simply resolving an object + * walk_state - Current state. Valid only if executing AML + * code. NULL if simply resolving an object * * RETURN: Status * @@ -66,7 +66,7 @@ ACPI_MODULE_NAME("exresnte") * * Note: for some of the data types, the pointer attached to the Node * can be either a pointer to an actual internal object or a pointer into the - * AML stream itself. These types are currently: + * AML stream itself. These types are currently: * * ACPI_TYPE_INTEGER * ACPI_TYPE_STRING @@ -88,7 +88,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, ACPI_FUNCTION_TRACE(ex_resolve_node_to_value); /* - * The stack pointer points to a struct acpi_namespace_node (Node). Get the + * The stack pointer points to a struct acpi_namespace_node (Node). Get the * object that is attached to the Node. */ node = *object_ptr; diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index ae199e7cdfb..cc176b245e2 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -326,7 +326,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, * * RETURN: Status * - * DESCRIPTION: Return the base object and type. Traverse a reference list if + * DESCRIPTION: Return the base object and type. Traverse a reference list if * necessary to get to the base object. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 04b70b38ebd..b9ebff2f6a0 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -86,7 +86,7 @@ acpi_ex_check_object_type(acpi_object_type type_needed, if (type_needed == ACPI_TYPE_LOCAL_REFERENCE) { /* * Allow the AML "Constant" opcodes (Zero, One, etc.) to be reference - * objects and thus allow them to be targets. (As per the ACPI + * objects and thus allow them to be targets. (As per the ACPI * specification, a store to a constant is a noop.) */ if ((this_type == ACPI_TYPE_INTEGER) && @@ -638,7 +638,7 @@ 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 + * objects as the source operand. The ACPI spec does not * allow this, however. */ break; diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 5fffe7ab5ec..90431f12f83 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -374,7 +374,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, * with the input value. * * When storing into an object the data is converted to the - * target object type then stored in the object. This means + * target object type then stored in the object. This means * that the target object type (for an initialized target) will * not be changed by a store operation. * @@ -491,7 +491,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, acpi_ut_get_object_type_name(source_desc), source_desc, node)); - /* No conversions for all other types. Just attach the source object */ + /* No conversions for all other types. Just attach the source object */ status = acpi_ns_attach_object(node, source_desc, source_desc->common.type); diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 6fe6eacb372..87153bbc4b4 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -60,7 +60,7 @@ ACPI_MODULE_NAME("exstoren") * * RETURN: Status, resolved object in source_desc_ptr. * - * DESCRIPTION: Resolve an object. If the object is a reference, dereference + * DESCRIPTION: Resolve an object. If the object is a reference, dereference * it and return the actual object in the source_desc_ptr. * ******************************************************************************/ @@ -92,7 +92,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, /* * Stores into a Field/Region or into a Integer/Buffer/String - * are all essentially the same. This case handles the + * are all essentially the same. This case handles the * "interchangeable" types Integer, String, and Buffer. */ if (source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) { @@ -166,7 +166,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, * * RETURN: Status * - * DESCRIPTION: "Store" an object to another object. This may include + * DESCRIPTION: "Store" an object to another object. This may include * converting the source type to the target type (implicit * conversion), and a copy of the value of the source to * the target. @@ -177,14 +177,14 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, * with the input value. * * When storing into an object the data is converted to the - * target object type then stored in the object. This means + * target object type then stored in the object. This means * that the target object type (for an initialized target) will * not be changed by a store operation. * * This module allows destination types of Number, String, * Buffer, and Package. * - * Assumes parameters are already validated. NOTE: source_desc + * Assumes parameters are already validated. NOTE: source_desc * resolution (from a reference object) must be performed by * the caller if necessary. * diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index b9ac30c11b5..b5f339cb130 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -107,7 +107,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, #ifdef ACPI_OBSOLETE_BEHAVIOR /* * NOTE: ACPI versions up to 3.0 specified that the buffer must be - * truncated if the string is smaller than the buffer. However, "other" + * truncated if the string is smaller than the buffer. However, "other" * implementations of ACPI never did this and thus became the defacto * standard. ACPI 3.0A changes this behavior such that the buffer * is no longer truncated. @@ -116,7 +116,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, /* * OBSOLETE BEHAVIOR: * If the original source was a string, we must truncate the buffer, - * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer + * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer * copy must not truncate the original buffer. */ if (original_src_type == ACPI_TYPE_STRING) { diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index 2d6d8bc12ed..c8a0ad5c1f5 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -58,7 +58,7 @@ ACPI_MODULE_NAME("exsystem") * RETURN: Status * * DESCRIPTION: Implements a semaphore wait with a check to see if the - * semaphore is available immediately. If it is not, the + * semaphore is available immediately. If it is not, the * interpreter is released before waiting. * ******************************************************************************/ @@ -103,7 +103,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) * RETURN: Status * * DESCRIPTION: Implements a mutex wait with a check to see if the - * mutex is available immediately. If it is not, the + * mutex is available immediately. If it is not, the * interpreter is released before waiting. * ******************************************************************************/ @@ -151,7 +151,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) * DESCRIPTION: Suspend running thread for specified amount of time. * Note: ACPI specification requires that Stall() does not * relinquish the processor, and delays longer than 100 usec - * should use Sleep() instead. We allow stalls up to 255 usec + * should use Sleep() instead. We allow stalls up to 255 usec * for compatibility with other interpreters and existing BIOSs. * ******************************************************************************/ @@ -253,7 +253,7 @@ acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc) * RETURN: Status * * DESCRIPTION: Provides an access point to perform synchronization operations - * within the AML. This operation is a request to wait for an + * within the AML. This operation is a request to wait for an * event. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index ff291e626ec..264d22d8018 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -44,12 +44,12 @@ /* * DEFINE_AML_GLOBALS is tested in amlcode.h * to determine whether certain global names should be "defined" or only - * "declared" in the current compilation. This enhances maintainability + * "declared" in the current compilation. This enhances maintainability * by enabling a single header file to embody all knowledge of the names * in question. * * Exactly one module of any executable should #define DEFINE_GLOBALS - * before #including the header files which use this convention. The + * before #including the header files which use this convention. The * names in question will be defined and initialized in that module, * and declared as extern in all other modules which #include those * header files. diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index bcf931ca192..90a9aea1cee 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -135,7 +135,7 @@ acpi_status acpi_hw_set_mode(u32 mode) * * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY * - * DESCRIPTION: Return current operating state of system. Determined by + * DESCRIPTION: Return current operating state of system. Determined by * querying the SCI_EN bit. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 19f6cce95f1..bfdce22f379 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -127,7 +127,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_timer) * a versatile and accurate timer. * * Note that this function accommodates only a single timer - * rollover. Thus for 24-bit timers, this function should only + * rollover. Thus for 24-bit timers, this function should only * be used for calculating durations less than ~4.6 seconds * (~20 minutes for 32-bit timers) -- calculations below: * diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index ac389e5bb59..15143c44f5e 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -332,7 +332,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) * * RETURN: None. * - * DESCRIPTION: Delete a subtree of the namespace. This includes all objects + * DESCRIPTION: Delete a subtree of the namespace. This includes all objects * stored within the subtree. * ******************************************************************************/ @@ -418,7 +418,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) * RETURN: Status * * DESCRIPTION: Delete entries within the namespace that are owned by a - * specific ID. Used to delete entire ACPI tables. All + * specific ID. Used to delete entire ACPI tables. All * reference counts are updated. * * MUTEX: Locks namespace during deletion walk. diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 993b12417e7..924b3c71473 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -692,7 +692,7 @@ void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level) * * PARAMETERS: search_base - Root of subtree to be dumped, or * NS_ALL to dump the entire namespace - * max_depth - Maximum depth of dump. Use INT_MAX + * max_depth - Maximum depth of dump. Use INT_MAX * for an effectively unlimited depth. * * RETURN: None diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 76935ff2928..911f99127b9 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -80,8 +80,8 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) /* * Parse the table and load the namespace with all named - * objects found within. Control methods are NOT parsed - * at this time. In fact, the control methods cannot be + * objects found within. Control methods are NOT parsed + * at this time. In fact, the control methods cannot be * parsed until the entire namespace is loaded, because * if a control method makes a forward reference (call) * to another control method, we can't continue parsing @@ -122,7 +122,7 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) } /* - * Now we can parse the control methods. We always parse + * Now we can parse the control methods. We always parse * them here for a sanity check, and if configured for * just-in-time parsing, we delete the control method * parse trees. @@ -166,7 +166,7 @@ acpi_status acpi_ns_load_namespace(void) } /* - * Load the namespace. The DSDT is required, + * Load the namespace. The DSDT is required, * but the SSDT and PSDT tables are optional. */ status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT); @@ -283,7 +283,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) * RETURN: Status * * DESCRIPTION: Shrinks the namespace, typically in response to an undocking - * event. Deletes an entire subtree starting from (and + * event. Deletes an entire subtree starting from (and * including) the given handle. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index d6c9a3cc671..e69f7fa2579 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -61,7 +61,7 @@ ACPI_MODULE_NAME("nsobject") * RETURN: Status * * DESCRIPTION: Record the given object as the value associated with the - * name whose acpi_handle is passed. If Object is NULL + * name whose acpi_handle is passed. If Object is NULL * and Type is ACPI_TYPE_ANY, set the name as having no value. * Note: Future may require that the Node->Flags field be passed * as a parameter. @@ -133,7 +133,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, ((struct acpi_namespace_node *)object)->object) { /* * Value passed is a name handle and that name has a - * non-null value. Use that name's value and type. + * non-null value. Use that name's value and type. */ obj_desc = ((struct acpi_namespace_node *)object)->object; object_type = ((struct acpi_namespace_node *)object)->type; @@ -321,7 +321,7 @@ union acpi_operand_object *acpi_ns_get_secondary_object(union * * RETURN: Status * - * DESCRIPTION: Low-level attach data. Create and attach a Data object. + * DESCRIPTION: Low-level attach data. Create and attach a Data object. * ******************************************************************************/ @@ -377,7 +377,7 @@ acpi_ns_attach_data(struct acpi_namespace_node *node, * * RETURN: Status * - * DESCRIPTION: Low-level detach data. Delete the data node, but the caller + * DESCRIPTION: Low-level detach data. Delete the data node, but the caller * is responsible for the actual data. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index ec7ba2d3463..233f756d5cf 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -168,11 +168,11 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) /* * AML Parse, pass 1 * - * In this pass, we load most of the namespace. Control methods - * are not parsed until later. A parse tree is not created. Instead, - * each Parser Op subtree is deleted when it is finished. This saves + * In this pass, we load most of the namespace. Control methods + * are not parsed until later. A parse tree is not created. Instead, + * each Parser Op subtree is deleted when it is finished. This saves * a great deal of memory, and allows a small cache of parse objects - * to service the entire parse. The second pass of the parse then + * to service the entire parse. The second pass of the parse then * performs another complete parse of the AML. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index ef753a41e08..16b3da80b92 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -530,7 +530,7 @@ acpi_ns_externalize_name(u32 internal_name_length, ((num_segments > 0) ? (num_segments - 1) : 0) + 1; /* - * Check to see if we're still in bounds. If not, there's a problem + * Check to see if we're still in bounds. If not, there's a problem * with internal_name (invalid format). */ if (required_length > internal_name_length) { @@ -681,7 +681,7 @@ u32 acpi_ns_opens_scope(acpi_object_type type) * \ (backslash) and ^ (carat) prefixes, and the * . (period) to separate segments are supported. * prefix_node - Root of subtree to be searched, or NS_ALL for the - * root of the name space. If Name is fully + * root of the name space. If Name is fully * qualified (first s8 is '\'), the passed value * of Scope will not be accessed. * flags - Used to indicate whether to perform upsearch or @@ -689,7 +689,7 @@ u32 acpi_ns_opens_scope(acpi_object_type type) * return_node - Where the Node is returned * * DESCRIPTION: Look up a name relative to a given scope and return the - * corresponding Node. NOTE: Scope can be null. + * corresponding Node. NOTE: Scope can be null. * * MUTEX: Locks namespace * diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 730bccc5e7f..0483877f26b 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -60,8 +60,8 @@ ACPI_MODULE_NAME("nswalk") * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if * none is found. * - * DESCRIPTION: Return the next peer node within the namespace. If Handle - * is valid, Scope is ignored. Otherwise, the first node + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node * within Scope is returned. * ******************************************************************************/ @@ -97,8 +97,8 @@ struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if * none is found. * - * DESCRIPTION: Return the next peer node within the namespace. If Handle - * is valid, Scope is ignored. Otherwise, the first node + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node * within Scope is returned. * ******************************************************************************/ @@ -305,7 +305,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* * Depth first search: Attempt to go down another level in the - * namespace if we are allowed to. Don't go any further if we have + * namespace if we are allowed to. Don't go any further if we have * reached the caller specified maximum depth or if the user * function has specified that the maximum depth has been reached. */ diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index ee4d873f9f0..d6a9f77972b 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -61,16 +61,16 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) * external_params - List of parameters to pass to method, - * terminated by NULL. May be NULL + * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if - * any). If NULL, no value is returned. + * any). If NULL, no value is returned. * return_type - Expected type of return object * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given - * parameters if necessary. One of "Handle" or "Pathname" must + * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ @@ -155,15 +155,15 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) * external_params - List of parameters to pass to method, - * terminated by NULL. May be NULL + * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if - * any). If NULL, no value is returned. + * any). If NULL, no value is returned. * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given - * parameters if necessary. One of "Handle" or "Pathname" must + * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ @@ -656,7 +656,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, * starting (and ending) at the object specified by start_handle. * The user_function is called whenever an object of type - * Device is found. If the user function returns + * Device is found. If the user function returns * a non-zero value, the search is terminated immediately and this * value is returned to the caller. * diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 7bc4985146f..ce878977117 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -69,8 +69,8 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, * RETURN: Status * * DESCRIPTION: This routine will search for a caller specified name in the - * name space. The caller can restrict the search region by - * specifying a non NULL parent. The parent value is itself a + * name space. The caller can restrict the search region by + * specifying a non NULL parent. The parent value is itself a * namespace handle. * ******************************************************************************/ @@ -149,7 +149,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_handle) * RETURN: Pointer to a string containing the fully qualified Name. * * DESCRIPTION: This routine returns the fully qualified name associated with - * the Handle parameter. This and the acpi_pathname_to_handle are + * the Handle parameter. This and the acpi_pathname_to_handle are * complementary functions. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 6766fc4f088..9d029dac6b6 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -220,8 +220,8 @@ ACPI_EXPORT_SYMBOL(acpi_get_parent) * * RETURN: Status * - * DESCRIPTION: Return the next peer object within the namespace. If Handle is - * valid, Scope is ignored. Otherwise, the first object within + * DESCRIPTION: Return the next peer object within the namespace. If Handle is + * valid, Scope is ignored. Otherwise, the first object within * Scope is returned. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 844464c4f90..cb79e2d4d74 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -120,7 +120,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state) * RETURN: Pointer to end-of-package +1 * * DESCRIPTION: Get next package length and return a pointer past the end of - * the package. Consumes the package length field + * the package. Consumes the package length field * ******************************************************************************/ @@ -147,8 +147,8 @@ u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state) * RETURN: Pointer to the start of the name string (pointer points into * the AML. * - * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name - * prefix characters. Set parser state to point past the string. + * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name + * prefix characters. Set parser state to point past the string. * (Name is consumed from the AML.) * ******************************************************************************/ @@ -220,7 +220,7 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state) * * DESCRIPTION: Get next name (if method call, return # of required args). * Names are looked up in the internal namespace to determine - * if the name represents a control method. If a method + * if the name represents a control method. If a method * is found, the number of arguments to the method is returned. * This information is critical for parsing to continue correctly. * diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index e5572a78bdb..1793d934aa3 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -59,7 +59,7 @@ static const u8 acpi_gbl_argument_count[] = * * DESCRIPTION: Opcode table. Each entry contains * The name is a simple ascii string, the operand specifier is an - * ascii string with one letter per operand. The letter specifies + * ascii string with one letter per operand. The letter specifies * the operand type. * ******************************************************************************/ @@ -183,7 +183,7 @@ static const u8 acpi_gbl_argument_count[] = ******************************************************************************/ /* - * Master Opcode information table. A summary of everything we know about each + * Master Opcode information table. A summary of everything we know about each * opcode, all in one place. */ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { @@ -700,7 +700,7 @@ static const u8 acpi_gbl_short_op_index[256] = { /* * This table is indexed by the second opcode of the extended opcode - * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info) + * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info) */ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = { /* 0 1 2 3 4 5 6 7 */ diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index dfdda00c6ff..2494caf4775 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -43,9 +43,9 @@ /* * Parse the AML and build an operation tree as most interpreters, - * like Perl, do. Parsing is done by hand rather than with a YACC + * like Perl, do. Parsing is done by hand rather than with a YACC * generated parser to tightly constrain stack and dynamic memory - * usage. At the same time, parsing is kept flexible and the code + * usage. At the same time, parsing is kept flexible and the code * fairly compact by parsing based on a list of AML opcode * templates in aml_op_info[] */ @@ -379,7 +379,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, case AE_CTRL_FALSE: /* * Either an IF/WHILE Predicate was false or we encountered a BREAK - * opcode. In both cases, we do not execute the rest of the + * opcode. In both cases, we do not execute the rest of the * package; We simply close out the parent (finishing the walk of * this branch of the tree) and continue execution at the parent * level. @@ -488,7 +488,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) acpi_gbl_current_walk_list = thread; /* - * Execute the walk loop as long as there is a valid Walk State. This + * Execute the walk loop as long as there is a valid Walk State. This * handles nested control method invocations without recursion. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state)); diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 8736ad5f04d..4137dcb352d 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -108,7 +108,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) * RETURN: Pointer to the new Op, null on failure * * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on - * opcode. A cache of opcodes is available for the pure + * opcode. A cache of opcodes is available for the pure * GENERIC_OP, since this is by far the most commonly used. * ******************************************************************************/ @@ -164,7 +164,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) * * RETURN: None. * - * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list + * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list * or actually free it. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 42745676ecd..68517798550 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -601,7 +601,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, /* * Calculate the size of the return buffer. * The base size is the number of elements * the sizes of the - * structures. Additional space for the strings is added below. + * structures. Additional space for the strings is added below. * The minus one is to subtract the size of the u8 Source[1] * member because it is added below. * diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index f8ee9b35b99..28f330230f9 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -107,7 +107,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) * RETURN: Status, RSDP physical address * * DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor - * pointer structure. If it is found, set *RSDP to point to it. + * pointer structure. If it is found, set *RSDP to point to it. * * NOTE1: The RSDP must be either in the first 1K of the Extended * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index eacb9ba2b9e..e1d40ed2639 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -183,7 +183,7 @@ acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) * * RETURN: None * - * DESCRIPTION: Release an object to the specified cache. If cache is full, + * DESCRIPTION: Release an object to the specified cache. If cache is full, * the object is deleted. * ******************************************************************************/ @@ -240,9 +240,9 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object) * * PARAMETERS: cache - Handle to cache object * - * RETURN: the acquired object. NULL on error + * RETURN: the acquired object. NULL on error * - * DESCRIPTION: Get an object from the specified cache. If cache is empty, + * DESCRIPTION: Get an object from the specified cache. If cache is empty, * the object is allocated. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 2c217991764..7a3327067f2 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -223,7 +223,7 @@ ACPI_EXPORT_SYMBOL(acpi_debug_print) * * RETURN: None * - * DESCRIPTION: Print message with no headers. Has same interface as + * DESCRIPTION: Print message with no headers. Has same interface as * debug_print so that the same macros can be used. * ******************************************************************************/ @@ -259,7 +259,7 @@ ACPI_EXPORT_SYMBOL(acpi_debug_print_raw) * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -291,7 +291,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_trace) * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -321,7 +321,7 @@ acpi_ut_trace_ptr(u32 line_number, * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -352,7 +352,7 @@ acpi_ut_trace_str(u32 line_number, * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -382,7 +382,7 @@ acpi_ut_trace_u32(u32 line_number, * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -414,7 +414,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_exit) * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit status also. * ******************************************************************************/ @@ -455,7 +455,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_status_exit) * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * ******************************************************************************/ @@ -487,7 +487,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_value_exit) * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index d88a8aaab2a..49563674833 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -81,7 +81,7 @@ typedef union uint64_overlay { * RETURN: Status (Checks for divide-by-zero) * * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) - * divide and modulo. The result is a 64-bit quotient and a + * divide and modulo. The result is a 64-bit quotient and a * 32-bit remainder. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 0fed4bcc84b..7ba197298ef 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -250,7 +250,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) * control method or unloading a table. Either way, we would * ignore any error anyway. * - * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 + * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 * ******************************************************************************/ @@ -534,8 +534,8 @@ u32 acpi_ut_dword_byte_swap(u32 value) * RETURN: None * * DESCRIPTION: Set the global integer bit width based upon the revision - * of the DSDT. For Revision 1 and 0, Integers are 32 bits. - * For Revision 2 and above, Integers are 64 bits. Yes, this + * of the DSDT. For Revision 1 and 0, Integers are 32 bits. + * For Revision 2 and above, Integers are 64 bits. Yes, this * makes a difference. * ******************************************************************************/ @@ -671,7 +671,7 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position) * * RETURN: TRUE if the name is valid, FALSE otherwise * - * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: + * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: * 1) Upper case alpha * 2) numeric * 3) underscore @@ -1010,10 +1010,10 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, /* * Check for: - * 1) An uninitialized package element. It is completely + * 1) An uninitialized package element. It is completely * legal to declare a package and leave it uninitialized * 2) Not an internal object - can be a namespace node instead - * 3) Any type other than a package. Packages are handled in else + * 3) Any type other than a package. Packages are handled in else * case below. */ if ((!this_source_obj) || @@ -1032,7 +1032,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, state->pkg.source_object->package.count) { /* * We've handled all of the objects at this level, This means - * that we have just completed a package. That package may + * that we have just completed a package. That package may * have contained one or more packages itself. * * Delete this state and pop the previous state (package). diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 93a11919933..5ccf57c0d87 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -228,9 +228,9 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) /* * Mutex debug code, for internal debugging only. * - * Deadlock prevention. Check if this thread owns any mutexes of value - * greater than or equal to this one. If so, the thread has violated - * the mutex ordering rule. This indicates a coding error somewhere in + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than or equal to this one. If so, the thread has violated + * the mutex ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { @@ -321,9 +321,9 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) /* * Mutex debug code, for internal debugging only. * - * Deadlock prevention. Check if this thread owns any mutexes of value - * greater than this one. If so, the thread has violated the mutex - * ordering rule. This indicates a coding error somewhere in + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than this one. If so, the thread has violated the mutex + * ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 655f0799a39..5c52ca78f6f 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -77,7 +77,7 @@ acpi_ut_get_element_length(u8 object_type, * * NOTE: We always allocate the worst-case object descriptor because * these objects are cached, and we want them to be - * one-size-satisifies-any-request. This in itself may not be + * one-size-satisifies-any-request. This in itself may not be * the most memory efficient, but the efficiency of the object * cache should more than make up for this! * @@ -370,9 +370,9 @@ u8 acpi_ut_valid_internal_object(void *object) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) * - * RETURN: Pointer to newly allocated object descriptor. Null on error + * RETURN: Pointer to newly allocated object descriptor. Null on error * - * DESCRIPTION: Allocate a new object descriptor. Gracefully handle + * DESCRIPTION: Allocate a new object descriptor. Gracefully handle * error conditions. * ******************************************************************************/ @@ -554,7 +554,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, /* * Account for the space required by the object rounded up to the next - * multiple of the machine word size. This keeps each object aligned + * multiple of the machine word size. This keeps each object aligned * on a machine word boundary. (preventing alignment faults on some * machines.) */ diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index a1c98826007..cee0473ba81 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -147,7 +147,7 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state * * RETURN: The new state object. NULL on failure. * - * DESCRIPTION: Create a generic state object. Attempt to obtain one from + * DESCRIPTION: Create a generic state object. Attempt to obtain one from * the global state cache; If none available, create a new one. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index e79c49d44d0..79f311c3d1c 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -45,9 +45,9 @@ * These procedures are used for tracking memory leaks in the subsystem, and * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. * - * Each memory allocation is tracked via a doubly linked list. Each + * Each memory allocation is tracked via a doubly linked list. Each * element contains the caller's component, module name, function name, and - * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call + * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call * acpi_ut_track_allocation to add an element to the list; deletion * occurs in the body of acpi_ut_free. */ @@ -499,7 +499,7 @@ void acpi_ut_dump_allocation_info(void) * FUNCTION: acpi_ut_dump_allocations * * PARAMETERS: component - Component(s) to dump info for. - * module - Module to dump info for. NULL means all. + * module - Module to dump info for. NULL means all. * * RETURN: None * diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 0c98d42fb2f..390db0ca5e2 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -147,7 +147,7 @@ ACPI_EXPORT_SYMBOL(acpi_subsystem_status) * RETURN: status - the status of the call * * DESCRIPTION: This function is called to get information about the current - * state of the ACPI subsystem. It will return system information + * state of the ACPI subsystem. It will return system information * in the out_buffer. * * If the function fails an appropriate status will be returned diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 19503449814..6c3890e0214 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -122,7 +122,7 @@ #define AE_CODE_TBL_MAX 0x0005 /* - * AML exceptions. These are caused by problems with + * AML exceptions. These are caused by problems with * the actual AML byte stream */ #define AE_AML_BAD_OPCODE (acpi_status) (0x0001 | AE_CODE_AML) -- cgit v1.2.3 From abf95c362929ce0af7dd413f981597c5386f749d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:27:04 +0000 Subject: ACPICA: Remove extra spaces after periods in the Intel license For consistency with the rest of the source code. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpiosxf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 64e2c8b830a..43152742b46 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These + * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These * interfaces must be implemented by OSL to interface the * ACPI components to the host operating system. * -- cgit v1.2.3 From bee6dc39cfa4be083e8c11cee0867eb7dc56895b Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 31 Oct 2012 02:27:15 +0000 Subject: ACPICA: Resource Mgr: Small fix for buffer size calculation Fixes a one byte error in the output buffer calculation. Feng Tang - ACPICA BZ 849: https://www.acpica.org/bugzilla/show_bug.cgi?id=849 Signed-off-by: Feng Tang Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/rscalc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 68517798550..147feb6aa2a 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -457,6 +457,15 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Get the number of vendor data bytes */ extra_struct_bytes = resource_length; + + /* + * There is already one byte included in the minimum + * descriptor size. If there are extra struct bytes, + * subtract one from the count. + */ + if (extra_struct_bytes) { + extra_struct_bytes--; + } break; case ACPI_RESOURCE_NAME_END_TAG: -- cgit v1.2.3 From 2489ef01849d3d7f62f53b47c245017406f02d32 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:27:24 +0000 Subject: ACPICA: Add debug print message for mutex objects that are force-released At control method termination, any currently acquired mutex objects are force-released. Add a new message for each one that is released. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exmutex.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 4723974a4cf..d1f449d93dc 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -461,7 +461,7 @@ 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_ENTRY(); + ACPI_FUNCTION_NAME(ex_release_all_mutexes); /* Traverse the list of owned mutexes, releasing each one */ @@ -473,6 +473,10 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) 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)); + /* Release the mutex, special case for Global Lock */ if (obj_desc == acpi_gbl_global_lock_mutex) { -- cgit v1.2.3 From d8da9151bb7e2d18624fdd8dbb066419186f0ec1 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:27:32 +0000 Subject: ACPICA: AcpiExec: Improve algorithm for tracking memory leaks Add some intelligence to the code that maintains the global list of allocated memory. The list is now ordered by allocated memory address, significantly improving performance. When running AcpiExec on the ASLTS test suite, speed improvements of 3X to 5X are seen, depending on the platform and/or the environment. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/uttrack.c | 100 ++++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 79f311c3d1c..a424a9e3fea 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -61,7 +61,9 @@ ACPI_MODULE_NAME("uttrack") /* Local prototypes */ -static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation); +static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct + acpi_debug_mem_block + *allocation); static acpi_status acpi_ut_track_allocation(struct acpi_debug_mem_block *address, @@ -263,31 +265,61 @@ acpi_ut_free_and_track(void *allocation, * * PARAMETERS: allocation - Address of allocated memory * - * RETURN: A list element if found; NULL otherwise. + * RETURN: Three cases: + * 1) List is empty, NULL is returned. + * 2) Element was found. Returns Allocation parameter. + * 3) Element was not found. Returns position where it should be + * inserted into the list. * * DESCRIPTION: Searches for an element in the global allocation tracking list. + * If the element is not found, returns the location within the + * list where the element should be inserted. + * + * Note: The list is ordered by larger-to-smaller addresses. + * + * This global list is used to detect memory leaks in ACPICA as + * well as other issues such as an attempt to release the same + * internal object more than once. Although expensive as far + * as cpu time, this list is much more helpful for finding these + * types of issues than using memory leak detectors outside of + * the ACPICA code. * ******************************************************************************/ -static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation) +static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct + acpi_debug_mem_block + *allocation) { struct acpi_debug_mem_block *element; - ACPI_FUNCTION_ENTRY(); - element = acpi_gbl_global_list->list_head; + if (!element) { + return (NULL); + } + + /* + * Search for the address. + * + * Note: List is ordered by larger-to-smaller addresses, on the + * assumption that a new allocation usually has a larger address + * than previous allocations. + */ + while (element > allocation) { - /* Search for the address. */ + /* Check for end-of-list */ - while (element) { - if (element == allocation) { + if (!element->next) { return (element); } element = element->next; } - return (NULL); + if (element == allocation) { + return (element); + } + + return (element->previous); } /******************************************************************************* @@ -301,7 +333,7 @@ static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation) * module - Source file name of caller * line - Line number of caller * - * RETURN: None. + * RETURN: Status * * DESCRIPTION: Inserts an element into the global allocation tracking list. * @@ -330,22 +362,18 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, } /* - * Search list for this address to make sure it is not already on the list. - * This will catch several kinds of problems. + * Search the global list for this address to make sure it is not + * already present. This will catch several kinds of problems. */ element = acpi_ut_find_allocation(allocation); - if (element) { + if (element == allocation) { ACPI_ERROR((AE_INFO, - "UtTrackAllocation: Allocation already present in list! (%p)", + "UtTrackAllocation: Allocation (%p) already present in global list!", allocation)); - - ACPI_ERROR((AE_INFO, "Element %p Address %p", - element, allocation)); - goto unlock_and_exit; } - /* Fill in the instance data. */ + /* Fill in the instance data */ allocation->size = (u32)size; allocation->alloc_type = alloc_type; @@ -355,17 +383,31 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME); allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; - /* Insert at list head */ + if (!element) { - if (mem_list->list_head) { - ((struct acpi_debug_mem_block *)(mem_list->list_head))-> - previous = allocation; - } + /* Insert at list head */ + + if (mem_list->list_head) { + ((struct acpi_debug_mem_block *)(mem_list->list_head))-> + previous = allocation; + } + + allocation->next = mem_list->list_head; + allocation->previous = NULL; - allocation->next = mem_list->list_head; - allocation->previous = NULL; + mem_list->list_head = allocation; + } else { + /* Insert after element */ + + allocation->next = element->next; + allocation->previous = element; + + if (element->next) { + (element->next)->previous = allocation; + } - mem_list->list_head = allocation; + element->next = allocation; + } unlock_and_exit: status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); @@ -381,7 +423,7 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, * module - Source file name of caller * line - Line number of caller * - * RETURN: + * RETURN: Status * * DESCRIPTION: Deletes an element from the global allocation tracking list. * @@ -443,7 +485,7 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, * * FUNCTION: acpi_ut_dump_allocation_info * - * PARAMETERS: + * PARAMETERS: None * * RETURN: None * -- cgit v1.2.3 From ff60027174cf94bab6d4f45ab5c5da1de63b7d1b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:27:40 +0000 Subject: ACPICA: Add ACPI_MOVE_NAME macro to optimize 4-byte ACPI_NAME copies Resolves to a 32-bit move for the normal case, strncpy on machines that do not support misaligned transfers. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actypes.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 1fa6ba12307..d1fb674fd39 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -453,10 +453,14 @@ typedef u64 acpi_integer; #define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) #define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) +/* Optimizations for 4-character (32-bit) acpi_name manipulation */ + #ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED #define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32, (a)) == *ACPI_CAST_PTR (u32, (b))) +#define ACPI_MOVE_NAME(dest,src) (*ACPI_CAST_PTR (u32, (dest)) = *ACPI_CAST_PTR (u32, (src))) #else #define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) +#define ACPI_MOVE_NAME(dest,src) (ACPI_STRNCPY (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) #endif /******************************************************************************* -- cgit v1.2.3 From 00eb32550f59a15796e936418b46b5134bd23a55 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:27:48 +0000 Subject: ACPICA: Enhance error reporting for invalid opcodes and bad ACPI_NAMEs For disassembler, dump the 48 bytes surrounding the invalid opcode. Fix incorrect table offset reported for invalid opcodes. Report original 32-bit value for bad ACPI_NAMEs. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsutils.c | 9 ++++---- drivers/acpi/acpica/psloop.c | 51 ++++++++++++++++++++++++++++++++--------- drivers/acpi/acpica/utmisc.c | 3 +++ drivers/acpi/acpica/utxferror.c | 2 +- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 16b3da80b92..0d3d481ce58 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -557,10 +557,11 @@ acpi_ns_externalize_name(u32 internal_name_length, (*converted_name)[j++] = '.'; } - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; + ACPI_MOVE_NAME(*converted_name, internal_name); + acpi_ut_repair_name(*converted_name); + + j += ACPI_NAME_SIZE; + names_index += ACPI_NAME_SIZE; } } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 31e2e9fb2de..e8b6dc0c51c 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -135,16 +135,38 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) /* The opcode is unrecognized. Just skip unknown opcodes */ - ACPI_ERROR((AE_INFO, - "Found unknown opcode 0x%X at AML address %p offset 0x%X, ignoring", - walk_state->opcode, walk_state->parser_state.aml, - walk_state->aml_offset)); + if (walk_state->pass_number == 2) { + ACPI_ERROR((AE_INFO, + "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", + walk_state->opcode, + walk_state->aml_offset + + sizeof(struct acpi_table_header))); - ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); + ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); - /* Assume one-byte bad opcode */ +#ifdef ACPI_ASL_COMPILER + + acpi_os_printf + ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", + walk_state->opcode, + walk_state->aml_offset + + sizeof(struct acpi_table_header)); + + /* TBD: Pass current offset to dump_buffer */ + + acpi_ut_dump_buffer2(((u8 *)walk_state->parser_state. + aml - 16), 48, DB_BYTE_DISPLAY); + acpi_os_printf(" */\n"); +#endif + } + + /* Increment past one or two-byte opcode */ walk_state->parser_state.aml++; + if (walk_state->opcode > 0xFF) { + walk_state->parser_state.aml++; + } + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); default: @@ -519,11 +541,18 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, if ((op_info->class == AML_CLASS_EXECUTE) && (!arg)) { ACPI_WARNING((AE_INFO, - "Detected an unsupported executable opcode " - "at module-level: [0x%.4X] at table offset 0x%.4X", - op->common.aml_opcode, - (u32)((aml_op_start - walk_state->parser_state.aml_start) - + sizeof(struct acpi_table_header)))); + "Unsupported module-level executable opcode " + "0x%.2X at table offset 0x%.4X", + op->common. + aml_opcode, + (u32) + (ACPI_PTR_DIFF + (aml_op_start, + walk_state-> + parser_state. + aml_start) + + sizeof(struct + acpi_table_header)))); } } break; diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 7ba197298ef..9286a69eb9a 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -720,9 +720,12 @@ void acpi_ut_repair_name(char *name) { u32 i; u8 found_bad_char = FALSE; + u32 original_name; ACPI_FUNCTION_NAME(ut_repair_name); + ACPI_MOVE_NAME(&original_name, name); + /* Check each character in the name */ for (i = 0; i < ACPI_NAME_SIZE; i++) { diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 6d63cc39b9a..d4d3826140d 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -408,7 +408,7 @@ acpi_ut_namespace_error(const char *module_name, ACPI_MOVE_32_TO_32(&bad_name, ACPI_CAST_PTR(u32, internal_name)); - acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name); + acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name); } else { /* Convert path to external format */ -- cgit v1.2.3 From 2d2dd50880d018e42076252f9fff16e11c567de0 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:27:56 +0000 Subject: ACPICA: Update support for ACPI 5 MPST table Fixes some problems introduced by late changes to the table as it was added to the ACPI 5.0 specification. Both the table compiler and the disassembler and the main header support for the table. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl3.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index 8c61b5fe42a..6585141e4b9 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -277,10 +277,10 @@ struct acpi_table_gtdt { ******************************************************************************/ #define ACPI_MPST_CHANNEL_INFO \ - u16 reserved1; \ u8 channel_id; \ - u8 reserved2; \ - u16 power_node_count; + u8 reserved1[3]; \ + u16 power_node_count; \ + u16 reserved2; /* Main table */ @@ -304,9 +304,8 @@ struct acpi_mpst_power_node { u32 length; u64 range_address; u64 range_length; - u8 num_power_states; - u8 num_physical_components; - u16 reserved2; + u32 num_power_states; + u32 num_physical_components; }; /* Values for Flags field above */ @@ -332,10 +331,11 @@ struct acpi_mpst_component { struct acpi_mpst_data_hdr { u16 characteristics_count; + u16 reserved; }; struct acpi_mpst_power_data { - u8 revision; + u8 structure_id; u8 flags; u16 reserved1; u32 average_power; @@ -356,10 +356,10 @@ struct acpi_mpst_shared { u32 signature; u16 pcc_command; u16 pcc_status; - u16 command_register; - u16 status_register; - u16 power_state_id; - u16 power_node_id; + u32 command_register; + u32 status_register; + u32 power_state_id; + u32 power_node_id; u64 energy_consumed; u64 average_power; }; -- cgit v1.2.3 From eed9525ac445f446a5dabd70d32938044f04fad5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:28:03 +0000 Subject: ACPICA: Deploy ACPI_MOVE_NAME across ACPICA source base Replaces instances of strncpy(...,4) for ACPI_NAMEs. ACPI_MOVE_NAME optimizes these to a single 32-bit copy on machines that support misaligned transfers. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsxfname.c | 3 +-- drivers/acpi/acpica/tbfind.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index ce878977117..2d10df2ef66 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -202,8 +202,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) /* Just copy the ACPI name from the Node and zero terminate it */ - ACPI_STRNCPY(buffer->pointer, acpi_ut_get_node_name(node), - ACPI_NAME_SIZE); + ACPI_MOVE_NAME(buffer->pointer, acpi_ut_get_node_name(node)); ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; status = AE_OK; diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 57deae16657..77d1db29a72 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -77,7 +77,7 @@ acpi_tb_find_table(char *signature, /* Normalize the input strings */ ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header)); - ACPI_STRNCPY(header.signature, signature, ACPI_NAME_SIZE); + ACPI_MOVE_NAME(header.signature, signature); ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); -- cgit v1.2.3 From 97171c6be3088a68b403c7285d34c151f7dbfb18 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:28:11 +0000 Subject: ACPICA: Add starting offset parameter to common dump buffer routine Rename the dump buffer routines. Offset parameter can specify the buffer starting offset that is used when displaying each line of the buffer. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acmacros.h | 2 +- drivers/acpi/acpica/acutils.h | 5 +++-- drivers/acpi/acpica/exdebug.c | 8 ++++---- drivers/acpi/acpica/exdump.c | 9 +++++---- drivers/acpi/acpica/psloop.c | 22 ++++++++++++++-------- drivers/acpi/acpica/utdebug.c | 13 +++++++------ 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index da8062d91ee..5efad99f216 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -460,7 +460,7 @@ #define ACPI_DUMP_OPERANDS(a, b ,c) acpi_ex_dump_operands(a, b, c) #define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b) #define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) -#define ACPI_DUMP_BUFFER(a, b) acpi_ut_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) +#define ACPI_DUMP_BUFFER(a, b) acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) #else /* diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index d94b4177657..5a6aa581e24 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -305,9 +305,10 @@ acpi_ut_ptr_exit(u32 line_number, const char *function_name, const char *module_name, u32 component_id, u8 *ptr); -void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id); +void +acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id); -void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display); +void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 offset); void acpi_ut_report_error(char *module_name, u32 line_number); diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index e0c905095ed..d7c9f51608a 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -145,10 +145,10 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_TYPE_BUFFER: acpi_os_printf("[0x%.2X]\n", (u32)source_desc->buffer.length); - acpi_ut_dump_buffer2(source_desc->buffer.pointer, - (source_desc->buffer.length < 256) ? - source_desc->buffer.length : 256, - DB_BYTE_DISPLAY); + acpi_ut_dump_buffer(source_desc->buffer.pointer, + (source_desc->buffer.length < 256) ? + source_desc->buffer.length : 256, + DB_BYTE_DISPLAY, 0); break; case ACPI_TYPE_STRING: diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 3157f3bb8de..858b43a7dcf 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -942,10 +942,11 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, acpi_os_printf("[Buffer] Length %.2X = ", obj_desc->buffer.length); if (obj_desc->buffer.length) { - acpi_ut_dump_buffer(ACPI_CAST_PTR - (u8, obj_desc->buffer.pointer), - obj_desc->buffer.length, - DB_DWORD_DISPLAY, _COMPONENT); + acpi_ut_debug_dump_buffer(ACPI_CAST_PTR + (u8, + obj_desc->buffer.pointer), + obj_desc->buffer.length, + DB_DWORD_DISPLAY, _COMPONENT); } else { acpi_os_printf("\n"); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index e8b6dc0c51c..d48c8fc0e72 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -133,7 +133,7 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) case AML_CLASS_UNKNOWN: - /* The opcode is unrecognized. Just skip unknown opcodes */ + /* The opcode is unrecognized. Complain and skip unknown opcodes */ if (walk_state->pass_number == 2) { ACPI_ERROR((AE_INFO, @@ -142,28 +142,34 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) walk_state->aml_offset + sizeof(struct acpi_table_header))); - ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); + ACPI_DUMP_BUFFER(walk_state->parser_state.aml - 16, 48); #ifdef ACPI_ASL_COMPILER - + /* + * This is executed for the disassembler only. Output goes + * to the disassembled ASL output file. + */ acpi_os_printf ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", walk_state->opcode, walk_state->aml_offset + sizeof(struct acpi_table_header)); - /* TBD: Pass current offset to dump_buffer */ + /* Dump the context surrounding the invalid opcode */ - acpi_ut_dump_buffer2(((u8 *)walk_state->parser_state. - aml - 16), 48, DB_BYTE_DISPLAY); + acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. + aml - 16), 48, DB_BYTE_DISPLAY, + walk_state->aml_offset + + sizeof(struct acpi_table_header) - + 16); acpi_os_printf(" */\n"); #endif } - /* Increment past one or two-byte opcode */ + /* Increment past one-byte or two-byte opcode */ walk_state->parser_state.aml++; - if (walk_state->opcode > 0xFF) { + if (walk_state->opcode > 0xFF) { /* Can only happen if first byte is 0x5B */ walk_state->parser_state.aml++; } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 7a3327067f2..5d95166245a 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -513,7 +513,7 @@ acpi_ut_ptr_exit(u32 line_number, * PARAMETERS: buffer - Buffer to dump * count - Amount to dump, in bytes * display - BYTE, WORD, DWORD, or QWORD display - * component_ID - Caller's component ID + * offset - Beginning buffer offset (display only) * * RETURN: None * @@ -521,7 +521,7 @@ acpi_ut_ptr_exit(u32 line_number, * ******************************************************************************/ -void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display) +void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) { u32 i = 0; u32 j; @@ -543,7 +543,7 @@ void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display) /* Print current offset */ - acpi_os_printf("%6.4X: ", i); + acpi_os_printf("%6.4X: ", (base_offset + i)); /* Print 16 hex chars */ @@ -625,7 +625,7 @@ void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display) /******************************************************************************* * - * FUNCTION: acpi_ut_dump_buffer + * FUNCTION: acpi_ut_debug_dump_buffer * * PARAMETERS: buffer - Buffer to dump * count - Amount to dump, in bytes @@ -638,7 +638,8 @@ void acpi_ut_dump_buffer2(u8 *buffer, u32 count, u32 display) * ******************************************************************************/ -void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) +void +acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) { /* Only dump the buffer if tracing is enabled */ @@ -648,5 +649,5 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) return; } - acpi_ut_dump_buffer2(buffer, count, display); + acpi_ut_dump_buffer(buffer, count, display, 0); } -- cgit v1.2.3 From 47abd13ccfa140ad34620b343bf0e6eca15ed8e8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:28:19 +0000 Subject: ACPICA: Fix externalize name to complete migration to ACPI_MOVE_NAME Fix for name segment copy and validation. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsutils.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 0d3d481ce58..b5b4cb72a8a 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -557,8 +557,11 @@ acpi_ns_externalize_name(u32 internal_name_length, (*converted_name)[j++] = '.'; } - ACPI_MOVE_NAME(*converted_name, internal_name); - acpi_ut_repair_name(*converted_name); + /* Copy and validate the 4-char name segment */ + + ACPI_MOVE_NAME(&(*converted_name)[j], + &internal_name[names_index]); + acpi_ut_repair_name(&(*converted_name)[j]); j += ACPI_NAME_SIZE; names_index += ACPI_NAME_SIZE; -- cgit v1.2.3 From 17b1f45a68ebd7944904a801d81a5c4206f9f76b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:28:27 +0000 Subject: ACPICA: Update for 64-bit generation of recent error message changes Fix for errors on printf changes on 64-bit platforms and gcc. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psloop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index d48c8fc0e72..5607805aab2 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -139,8 +139,8 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) ACPI_ERROR((AE_INFO, "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", walk_state->opcode, - walk_state->aml_offset + - sizeof(struct acpi_table_header))); + (u32)(walk_state->aml_offset + + sizeof(struct acpi_table_header)))); ACPI_DUMP_BUFFER(walk_state->parser_state.aml - 16, 48); @@ -152,8 +152,8 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) acpi_os_printf ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", walk_state->opcode, - walk_state->aml_offset + - sizeof(struct acpi_table_header)); + (u32)(walk_state->aml_offset + + sizeof(struct acpi_table_header))); /* Dump the context surrounding the invalid opcode */ -- cgit v1.2.3 From 413fc3f592c65977858f8adce2e7af0e82aa1191 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:28:38 +0000 Subject: ACPICA: AcpiGetObjectInfo: Add support for ACPI 5 _SUB method Now calls _SUB in addition to the other ID methods: _HID, _CID, and _UID. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 4 +++ drivers/acpi/acpica/nsxfname.c | 29 ++++++++++++++---- drivers/acpi/acpica/utids.c | 67 ++++++++++++++++++++++++++++++++++++++++++ include/acpi/acnames.h | 1 + include/acpi/actypes.h | 12 ++++---- 5 files changed, 103 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 5a6aa581e24..b0f5f92b674 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -362,6 +362,10 @@ acpi_status 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/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 2d10df2ef66..811c6f13f47 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -231,6 +231,7 @@ 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; @@ -255,8 +256,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, _STA, - * _ADR, _sx_w, and _sx_d methods. + * For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, + * _STA, _ADR, _sx_w, and _sx_d methods. * * Note: Allocates the return buffer, must be freed by the caller. * @@ -271,6 +272,7 @@ 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; char *next_id_string; acpi_object_type type; acpi_name name; @@ -315,7 +317,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, and _CID methods. + * Run the Device _HID, _UID, _SUB, 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 @@ -338,6 +340,14 @@ 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); @@ -425,8 +435,9 @@ acpi_get_object_info(acpi_handle handle, } /* - * 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. + * 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. * * For HID and CID, check if the ID is a PCI Root Bridge. */ @@ -444,6 +455,11 @@ 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; @@ -480,6 +496,9 @@ acpi_get_object_info(acpi_handle handle, 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 f18ac81c839..774c3aefbf5 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -125,6 +125,73 @@ cleanup: return_ACPI_STATUS(status); } +/******************************************************************************* + * + * 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 */ + + ACPI_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 diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 745dd24e3cb..7665df66328 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -50,6 +50,7 @@ #define METHOD_NAME__HID "_HID" #define METHOD_NAME__CID "_CID" #define METHOD_NAME__UID "_UID" +#define METHOD_NAME__SUB "_SUB" #define METHOD_NAME__ADR "_ADR" #define METHOD_NAME__INI "_INI" #define METHOD_NAME__STA "_STA" diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index d1fb674fd39..4f43f1fba13 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1024,7 +1024,7 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); #define ACPI_UUID_LENGTH 16 -/* Structures used for device/processor HID, UID, CID */ +/* Structures used for device/processor HID, UID, CID, and SUB */ struct acpi_pnp_device_id { u32 length; /* Length of string + null */ @@ -1054,6 +1054,7 @@ 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_list compatible_id_list; /* _CID list */ }; @@ -1067,11 +1068,12 @@ struct acpi_device_info { #define ACPI_VALID_ADR 0x02 #define ACPI_VALID_HID 0x04 #define ACPI_VALID_UID 0x08 -#define ACPI_VALID_CID 0x10 -#define ACPI_VALID_SXDS 0x20 -#define ACPI_VALID_SXWS 0x40 +#define ACPI_VALID_SUB 0x10 +#define ACPI_VALID_CID 0x20 +#define ACPI_VALID_SXDS 0x40 +#define ACPI_VALID_SXWS 0x80 -/* Flags for _STA method */ +/* Flags for _STA return value (current_status above) */ #define ACPI_STA_DEVICE_PRESENT 0x01 #define ACPI_STA_DEVICE_ENABLED 0x02 -- cgit v1.2.3 From a19ec8a607f82885aa150836a72dec12d3c9aca5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 31 Oct 2012 02:28:46 +0000 Subject: ACPICA: Update version to 20121018 Version 20121018. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 2596de109ff..3d88395d4d6 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 0x20120913 +#define ACPI_CA_VERSION 0x20121018 #include #include -- cgit v1.2.3 From 8bf1ac723639c4260f76df0e45ee23aa35a23067 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Tue, 23 Oct 2012 01:23:33 +0200 Subject: cpufreq / core: Fix typo in comment describing show_bios_limit() show_bios_limit is mistakenly written as show_scaling_driver in a comment describing purpose of show_bios_limit() routine. Fix it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index fb8a5279c5d..021973b7dc5 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -581,7 +581,7 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) } /** - * show_scaling_driver - show the current cpufreq HW/BIOS limitation + * show_bios_limit - show the current cpufreq HW/BIOS limitation */ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) { -- cgit v1.2.3 From 4b972f0b04eaae645b22d99479b9aea43c3d64e7 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Tue, 23 Oct 2012 01:23:43 +0200 Subject: cpufreq / core: Fix printing of governor and driver name Arrays for governer and driver name are of size CPUFREQ_NAME_LEN or 16. i.e. 15 bytes for name and 1 for trailing '\0'. When cpufreq driver print these names (for sysfs), it includes '\n' or ' ' in the fmt string and still passes length as CPUFREQ_NAME_LEN. If the driver or governor names are using all 15 fields allocated to them, then the trailing '\n' or ' ' will never be printed. And so commands like: root@linaro-developer# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver will print something like: cpufreq_foodrvroot@linaro-developer# Fix this by increasing print length by one character. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 6 +++--- include/linux/cpufreq.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 021973b7dc5..db6e337ad33 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -445,7 +445,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) return sprintf(buf, "performance\n"); else if (policy->governor) - return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", + return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", policy->governor->name); return -EINVAL; } @@ -491,7 +491,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, */ static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) { - return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name); + return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name); } /** @@ -512,7 +512,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2))) goto out; - i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name); + i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name); } out: i += sprintf(&buf[i], "\n"); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index b60f6ba01d0..fc4b7851015 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -22,6 +22,8 @@ #include #define CPUFREQ_NAME_LEN 16 +/* Print length for names. Extra 1 space for accomodating '\n' in prints */ +#define CPUFREQ_NAME_PLEN (CPUFREQ_NAME_LEN + 1) /********************************************************************* -- cgit v1.2.3 From 2aacdfff9c6958723aa5076003247933cefc32ea Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Tue, 23 Oct 2012 01:28:05 +0200 Subject: cpufreq: Move common part from governors to separate file, v2 Multiple cpufreq governers have defined similar get_cpu_idle_time_***() routines. These routines must be moved to some common place, so that all governors can use them. So moving them to cpufreq_governor.c, which seems to be a better place for keeping these routines. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Makefile | 4 +-- drivers/cpufreq/cpufreq_conservative.c | 34 ---------------------- drivers/cpufreq/cpufreq_governor.c | 52 ++++++++++++++++++++++++++++++++++ drivers/cpufreq/cpufreq_ondemand.c | 34 ---------------------- include/linux/cpufreq.h | 5 ++++ 5 files changed, 59 insertions(+), 70 deletions(-) create mode 100644 drivers/cpufreq/cpufreq_governor.c diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 1bc90e1306d..5b1413e4721 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -7,8 +7,8 @@ obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o -obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o -obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o +obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o cpufreq_governor.o +obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o cpufreq_governor.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index a152af7e199..181abad0726 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -95,40 +95,6 @@ static struct dbs_tuners { .freq_step = 5, }; -static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) -{ - u64 idle_time; - u64 cur_wall_time; - u64 busy_time; - - cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); - - busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; - - idle_time = cur_wall_time - busy_time; - if (wall) - *wall = jiffies_to_usecs(cur_wall_time); - - return jiffies_to_usecs(idle_time); -} - -static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) -{ - u64 idle_time = get_cpu_idle_time_us(cpu, NULL); - - if (idle_time == -1ULL) - return get_cpu_idle_time_jiffy(cpu, wall); - else - idle_time += get_cpu_iowait_time_us(cpu, wall); - - return idle_time; -} - /* keep track of frequency transitions */ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c new file mode 100644 index 00000000000..0001071cdcd --- /dev/null +++ b/drivers/cpufreq/cpufreq_governor.c @@ -0,0 +1,52 @@ +/* + * drivers/cpufreq/cpufreq_governor.c + * + * CPUFREQ governors common code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +/* + * Code picked from earlier governer implementations + */ +static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) +{ + u64 idle_time; + u64 cur_wall_time; + u64 busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = jiffies_to_usecs(cur_wall_time); + + return jiffies_to_usecs(idle_time); +} + +cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, NULL); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + else + idle_time += get_cpu_iowait_time_us(cpu, wall); + + return idle_time; +} +EXPORT_SYMBOL_GPL(get_cpu_idle_time); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 396322f2a83..d7f774bb49d 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -119,40 +119,6 @@ static struct dbs_tuners { .powersave_bias = 0, }; -static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) -{ - u64 idle_time; - u64 cur_wall_time; - u64 busy_time; - - cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); - - busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; - - idle_time = cur_wall_time - busy_time; - if (wall) - *wall = jiffies_to_usecs(cur_wall_time); - - return jiffies_to_usecs(idle_time); -} - -static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) -{ - u64 idle_time = get_cpu_idle_time_us(cpu, NULL); - - if (idle_time == -1ULL) - return get_cpu_idle_time_jiffy(cpu, wall); - else - idle_time += get_cpu_iowait_time_us(cpu, wall); - - return idle_time; -} - static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) { u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index fc4b7851015..d03c2199305 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -11,6 +11,7 @@ #ifndef _LINUX_CPUFREQ_H #define _LINUX_CPUFREQ_H +#include #include #include #include @@ -407,5 +408,9 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, void cpufreq_frequency_table_put_attr(unsigned int cpu); +/********************************************************************* + * Governor Helpers * + *********************************************************************/ +cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall); #endif /* _LINUX_CPUFREQ_H */ -- cgit v1.2.3 From db7011516cbfc3d867b77721f77258d36cfbf705 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 23 Oct 2012 01:29:03 +0200 Subject: cpufreq: Improve debug prints With debug options on, it is difficult to locate cpufreq core's debug prints. Fix this by prefixing debug prints with KBUILD_MODNAME. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 ++ drivers/cpufreq/cpufreq_performance.c | 2 ++ drivers/cpufreq/cpufreq_powersave.c | 2 ++ drivers/cpufreq/cpufreq_userspace.c | 2 ++ drivers/cpufreq/freq_table.c | 2 ++ 5 files changed, 10 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index db6e337ad33..85df5387bc6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -15,6 +15,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index f13a8a9af6a..ceee06849b9 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -10,6 +10,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 4c2eb512f2b..2d948a17115 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -10,6 +10,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index bedac1aa9be..c8c3d293cc5 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -11,6 +11,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 90431cb9280..49cda256efb 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -9,6 +9,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include -- cgit v1.2.3 From 8636fd280e970696be62c8495a5aacb5f3b6237d Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Wed, 24 Oct 2012 22:16:34 +0200 Subject: cpufreq: fix jiffies/cputime mixup in conservative/ondemand governors The function get_cpu_idle_time_jiffy in both the conservative and ondemand governors use jiffies_to_usecs to convert a cputime value to usecs which gives the wrong value on architectures where cputime and jiffies use different units. Only matters if NO_HZ is disabled, since otherwise get_cpu_idle_time_us should already return a valid value, and get_cpu_idle_time_jiffy isn't actually called. Signed-off-by: Andreas Schwab Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 0001071cdcd..679842a8d34 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -33,9 +33,9 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) idle_time = cur_wall_time - busy_time; if (wall) - *wall = jiffies_to_usecs(cur_wall_time); + *wall = cputime_to_usecs(cur_wall_time); - return jiffies_to_usecs(idle_time); + return cputime_to_usecs(idle_time); } cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) -- cgit v1.2.3 From 0676f7f2e7d2adec11f40320ca43a8897b8ef906 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 24 Oct 2012 23:39:48 +0200 Subject: cpufreq: return early from __cpufreq_driver_getavg() There is no need to do cpufreq_get_cpu() and cpufreq_put_cpu() for drivers that don't support getavg() routine. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 85df5387bc6..f552d5fe0f8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1511,12 +1511,14 @@ int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) { int ret = 0; + if (!(cpu_online(cpu) && cpufreq_driver->getavg)) + return 0; + policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - if (cpu_online(cpu) && cpufreq_driver->getavg) - ret = cpufreq_driver->getavg(policy, cpu); + ret = cpufreq_driver->getavg(policy, cpu); cpufreq_cpu_put(policy); return ret; -- cgit v1.2.3 From 4471a34f9a1f2da220272e823bdb8e8fa83a7661 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 26 Oct 2012 00:47:42 +0200 Subject: cpufreq: governors: remove redundant code Initially ondemand governor was written and then using its code conservative governor is written. It used a lot of code from ondemand governor, but copy of code was created instead of using the same routines from both governors. Which increased code redundancy, which is difficult to manage. This patch is an attempt to move common part of both the governors to cpufreq_governor.c file to come over above mentioned issues. This shouldn't change anything from functionality point of view. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 548 ++++++++------------------ drivers/cpufreq/cpufreq_governor.c | 276 ++++++++++++- drivers/cpufreq/cpufreq_governor.h | 177 +++++++++ drivers/cpufreq/cpufreq_ondemand.c | 698 +++++++++++---------------------- include/linux/cpufreq.h | 6 - 5 files changed, 832 insertions(+), 873 deletions(-) create mode 100644 drivers/cpufreq/cpufreq_governor.h diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 181abad0726..64ef737e7e7 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -11,83 +11,30 @@ * published by the Free Software Foundation. */ -#include -#include -#include #include -#include -#include +#include +#include #include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include -/* - * dbs is used in this file as a shortform for demandbased switching - * It helps to keep variable names smaller, simpler - */ +#include "cpufreq_governor.h" +/* Conservative governor macors */ #define DEF_FREQUENCY_UP_THRESHOLD (80) #define DEF_FREQUENCY_DOWN_THRESHOLD (20) - -/* - * The polling frequency of this governor depends on the capability of - * the processor. Default polling frequency is 1000 times the transition - * latency of the processor. The governor will work on any processor with - * transition latency <= 10mS, using appropriate sampling - * rate. - * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) - * this governor will not work. - * All times here are in uS. - */ -#define MIN_SAMPLING_RATE_RATIO (2) - -static unsigned int min_sampling_rate; - -#define LATENCY_MULTIPLIER (1000) -#define MIN_LATENCY_MULTIPLIER (100) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) -#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) - -static void do_dbs_timer(struct work_struct *work); - -struct cpu_dbs_info_s { - cputime64_t prev_cpu_idle; - cputime64_t prev_cpu_wall; - cputime64_t prev_cpu_nice; - struct cpufreq_policy *cur_policy; - struct delayed_work work; - unsigned int down_skip; - unsigned int requested_freq; - int cpu; - unsigned int enable:1; - /* - * percpu mutex that serializes governor limit change with - * do_dbs_timer invocation. We do not want do_dbs_timer to run - * when user is changing the governor or limits. - */ - struct mutex timer_mutex; -}; -static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info); -static unsigned int dbs_enable; /* number of CPUs using this policy */ +static struct dbs_data cs_dbs_data; +static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info); -/* - * dbs_mutex protects dbs_enable in governor start/stop. - */ -static DEFINE_MUTEX(dbs_mutex); - -static struct dbs_tuners { - unsigned int sampling_rate; - unsigned int sampling_down_factor; - unsigned int up_threshold; - unsigned int down_threshold; - unsigned int ignore_nice; - unsigned int freq_step; -} dbs_tuners_ins = { +static struct cs_dbs_tuners cs_tuners = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, @@ -95,61 +42,121 @@ static struct dbs_tuners { .freq_step = 5, }; -/* keep track of frequency transitions */ -static int -dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, - void *data) +/* + * Every sampling_rate, we check, if current idle time is less than 20% + * (default), then we try to increase frequency Every sampling_rate * + * sampling_down_factor, we check, if current idle time is more than 80%, then + * we try to decrease frequency + * + * Any frequency increase takes it to the maximum frequency. Frequency reduction + * happens at minimum steps of 5% (default) of maximum frequency + */ +static void cs_check_cpu(int cpu, unsigned int load) { - struct cpufreq_freqs *freq = data; - struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cs_cpu_dbs_info, - freq->cpu); + struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); + struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + unsigned int freq_target; + + /* + * break out if we 'cannot' reduce the speed as the user might + * want freq_step to be zero + */ + if (cs_tuners.freq_step == 0) + return; + + /* Check for frequency increase */ + if (load > cs_tuners.up_threshold) { + dbs_info->down_skip = 0; + + /* if we are already at full speed then break out early */ + if (dbs_info->requested_freq == policy->max) + return; + + freq_target = (cs_tuners.freq_step * policy->max) / 100; + + /* max freq cannot be less than 100. But who knows.... */ + if (unlikely(freq_target == 0)) + freq_target = 5; + + dbs_info->requested_freq += freq_target; + if (dbs_info->requested_freq > policy->max) + dbs_info->requested_freq = policy->max; + __cpufreq_driver_target(policy, dbs_info->requested_freq, + CPUFREQ_RELATION_H); + return; + } + + /* + * The optimal frequency is the frequency that is the lowest that can + * support the current CPU usage without triggering the up policy. To be + * safe, we focus 10 points under the threshold. + */ + if (load < (cs_tuners.down_threshold - 10)) { + freq_target = (cs_tuners.freq_step * policy->max) / 100; + + dbs_info->requested_freq -= freq_target; + if (dbs_info->requested_freq < policy->min) + dbs_info->requested_freq = policy->min; + + /* + * if we cannot reduce the frequency anymore, break out early + */ + if (policy->cur == policy->min) + return; + + __cpufreq_driver_target(policy, dbs_info->requested_freq, + CPUFREQ_RELATION_H); + return; + } +} + +static void cs_dbs_timer(struct work_struct *work) +{ + struct cs_cpu_dbs_info_s *dbs_info = container_of(work, + struct cs_cpu_dbs_info_s, cdbs.work.work); + unsigned int cpu = dbs_info->cdbs.cpu; + int delay = delay_for_sampling_rate(cs_tuners.sampling_rate); + + mutex_lock(&dbs_info->cdbs.timer_mutex); + + dbs_check_cpu(&cs_dbs_data, cpu); + + schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay); + mutex_unlock(&dbs_info->cdbs.timer_mutex); +} + +static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freq = data; + struct cs_cpu_dbs_info_s *dbs_info = + &per_cpu(cs_cpu_dbs_info, freq->cpu); struct cpufreq_policy *policy; - if (!this_dbs_info->enable) + if (!dbs_info->enable) return 0; - policy = this_dbs_info->cur_policy; + policy = dbs_info->cdbs.cur_policy; /* - * we only care if our internally tracked freq moves outside - * the 'valid' ranges of freqency available to us otherwise - * we do not change it + * we only care if our internally tracked freq moves outside the 'valid' + * ranges of freqency available to us otherwise we do not change it */ - if (this_dbs_info->requested_freq > policy->max - || this_dbs_info->requested_freq < policy->min) - this_dbs_info->requested_freq = freq->new; + if (dbs_info->requested_freq > policy->max + || dbs_info->requested_freq < policy->min) + dbs_info->requested_freq = freq->new; return 0; } -static struct notifier_block dbs_cpufreq_notifier_block = { - .notifier_call = dbs_cpufreq_notifier -}; - /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_min(struct kobject *kobj, struct attribute *attr, char *buf) { - return sprintf(buf, "%u\n", min_sampling_rate); + return sprintf(buf, "%u\n", cs_dbs_data.min_sampling_rate); } -define_one_global_ro(sampling_rate_min); - -/* cpufreq_conservative Governor Tunables */ -#define show_one(file_name, object) \ -static ssize_t show_##file_name \ -(struct kobject *kobj, struct attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ -} -show_one(sampling_rate, sampling_rate); -show_one(sampling_down_factor, sampling_down_factor); -show_one(up_threshold, up_threshold); -show_one(down_threshold, down_threshold); -show_one(ignore_nice_load, ignore_nice); -show_one(freq_step, freq_step); - static ssize_t store_sampling_down_factor(struct kobject *a, struct attribute *b, const char *buf, size_t count) @@ -161,7 +168,7 @@ static ssize_t store_sampling_down_factor(struct kobject *a, if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) return -EINVAL; - dbs_tuners_ins.sampling_down_factor = input; + cs_tuners.sampling_down_factor = input; return count; } @@ -175,7 +182,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, if (ret != 1) return -EINVAL; - dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); + cs_tuners.sampling_rate = max(input, cs_dbs_data.min_sampling_rate); return count; } @@ -186,11 +193,10 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, int ret; ret = sscanf(buf, "%u", &input); - if (ret != 1 || input > 100 || - input <= dbs_tuners_ins.down_threshold) + if (ret != 1 || input > 100 || input <= cs_tuners.down_threshold) return -EINVAL; - dbs_tuners_ins.up_threshold = input; + cs_tuners.up_threshold = input; return count; } @@ -203,21 +209,19 @@ static ssize_t store_down_threshold(struct kobject *a, struct attribute *b, /* cannot be lower than 11 otherwise freq will not fall */ if (ret != 1 || input < 11 || input > 100 || - input >= dbs_tuners_ins.up_threshold) + input >= cs_tuners.up_threshold) return -EINVAL; - dbs_tuners_ins.down_threshold = input; + cs_tuners.down_threshold = input; return count; } static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, const char *buf, size_t count) { - unsigned int input; + unsigned int input, j; int ret; - unsigned int j; - ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; @@ -225,19 +229,20 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, if (input > 1) input = 1; - if (input == dbs_tuners_ins.ignore_nice) /* nothing to do */ + if (input == cs_tuners.ignore_nice) /* nothing to do */ return count; - dbs_tuners_ins.ignore_nice = input; + cs_tuners.ignore_nice = input; /* we need to re-evaluate prev_cpu_idle */ for_each_online_cpu(j) { - struct cpu_dbs_info_s *dbs_info; + struct cs_cpu_dbs_info_s *dbs_info; dbs_info = &per_cpu(cs_cpu_dbs_info, j); - dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->cdbs.prev_cpu_wall); + if (cs_tuners.ignore_nice) + dbs_info->cdbs.prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; } return count; } @@ -255,18 +260,28 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b, if (input > 100) input = 100; - /* no need to test here if freq_step is zero as the user might actually - * want this, they would be crazy though :) */ - dbs_tuners_ins.freq_step = input; + /* + * no need to test here if freq_step is zero as the user might actually + * want this, they would be crazy though :) + */ + cs_tuners.freq_step = input; return count; } +show_one(cs, sampling_rate, sampling_rate); +show_one(cs, sampling_down_factor, sampling_down_factor); +show_one(cs, up_threshold, up_threshold); +show_one(cs, down_threshold, down_threshold); +show_one(cs, ignore_nice_load, ignore_nice); +show_one(cs, freq_step, freq_step); + define_one_global_rw(sampling_rate); define_one_global_rw(sampling_down_factor); define_one_global_rw(up_threshold); define_one_global_rw(down_threshold); define_one_global_rw(ignore_nice_load); define_one_global_rw(freq_step); +define_one_global_ro(sampling_rate_min); static struct attribute *dbs_attributes[] = { &sampling_rate_min.attr, @@ -279,283 +294,38 @@ static struct attribute *dbs_attributes[] = { NULL }; -static struct attribute_group dbs_attr_group = { +static struct attribute_group cs_attr_group = { .attrs = dbs_attributes, .name = "conservative", }; /************************** sysfs end ************************/ -static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) -{ - unsigned int load = 0; - unsigned int max_load = 0; - unsigned int freq_target; - - struct cpufreq_policy *policy; - unsigned int j; - - policy = this_dbs_info->cur_policy; - - /* - * Every sampling_rate, we check, if current idle time is less - * than 20% (default), then we try to increase frequency - * Every sampling_rate*sampling_down_factor, we check, if current - * idle time is more than 80%, then we try to decrease frequency - * - * Any frequency increase takes it to the maximum frequency. - * Frequency reduction happens at minimum steps of - * 5% (default) of maximum frequency - */ - - /* Get Absolute Load */ - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - cputime64_t cur_wall_time, cur_idle_time; - unsigned int idle_time, wall_time; - - j_dbs_info = &per_cpu(cs_cpu_dbs_info, j); - - cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); - - wall_time = (unsigned int) - (cur_wall_time - j_dbs_info->prev_cpu_wall); - j_dbs_info->prev_cpu_wall = cur_wall_time; - - idle_time = (unsigned int) - (cur_idle_time - j_dbs_info->prev_cpu_idle); - j_dbs_info->prev_cpu_idle = cur_idle_time; - - if (dbs_tuners_ins.ignore_nice) { - u64 cur_nice; - unsigned long cur_nice_jiffies; - - cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - - j_dbs_info->prev_cpu_nice; - /* - * Assumption: nice time between sampling periods will - * be less than 2^32 jiffies for 32 bit sys - */ - cur_nice_jiffies = (unsigned long) - cputime64_to_jiffies64(cur_nice); - - j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - idle_time += jiffies_to_usecs(cur_nice_jiffies); - } - - if (unlikely(!wall_time || wall_time < idle_time)) - continue; - - load = 100 * (wall_time - idle_time) / wall_time; - - if (load > max_load) - max_load = load; - } +define_get_cpu_dbs_routines(cs_cpu_dbs_info); - /* - * break out if we 'cannot' reduce the speed as the user might - * want freq_step to be zero - */ - if (dbs_tuners_ins.freq_step == 0) - return; - - /* Check for frequency increase */ - if (max_load > dbs_tuners_ins.up_threshold) { - this_dbs_info->down_skip = 0; - - /* if we are already at full speed then break out early */ - if (this_dbs_info->requested_freq == policy->max) - return; - - freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; - - /* max freq cannot be less than 100. But who knows.... */ - if (unlikely(freq_target == 0)) - freq_target = 5; - - this_dbs_info->requested_freq += freq_target; - if (this_dbs_info->requested_freq > policy->max) - this_dbs_info->requested_freq = policy->max; - - __cpufreq_driver_target(policy, this_dbs_info->requested_freq, - CPUFREQ_RELATION_H); - return; - } - - /* - * The optimal frequency is the frequency that is the lowest that - * can support the current CPU usage without triggering the up - * policy. To be safe, we focus 10 points under the threshold. - */ - if (max_load < (dbs_tuners_ins.down_threshold - 10)) { - freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; - - this_dbs_info->requested_freq -= freq_target; - if (this_dbs_info->requested_freq < policy->min) - this_dbs_info->requested_freq = policy->min; - - /* - * if we cannot reduce the frequency anymore, break out early - */ - if (policy->cur == policy->min) - return; - - __cpufreq_driver_target(policy, this_dbs_info->requested_freq, - CPUFREQ_RELATION_H); - return; - } -} - -static void do_dbs_timer(struct work_struct *work) -{ - struct cpu_dbs_info_s *dbs_info = - container_of(work, struct cpu_dbs_info_s, work.work); - unsigned int cpu = dbs_info->cpu; - - /* We want all CPUs to do sampling nearly on same jiffy */ - int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - - delay -= jiffies % delay; - - mutex_lock(&dbs_info->timer_mutex); - - dbs_check_cpu(dbs_info); - - schedule_delayed_work_on(cpu, &dbs_info->work, delay); - mutex_unlock(&dbs_info->timer_mutex); -} - -static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) -{ - /* We want all CPUs to do sampling nearly on same jiffy */ - int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - delay -= jiffies % delay; +static struct notifier_block cs_cpufreq_notifier_block = { + .notifier_call = dbs_cpufreq_notifier, +}; - dbs_info->enable = 1; - INIT_DEFERRABLE_WORK(&dbs_info->work, do_dbs_timer); - schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); -} +static struct cs_ops cs_ops = { + .notifier_block = &cs_cpufreq_notifier_block, +}; -static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) -{ - dbs_info->enable = 0; - cancel_delayed_work_sync(&dbs_info->work); -} +static struct dbs_data cs_dbs_data = { + .governor = GOV_CONSERVATIVE, + .attr_group = &cs_attr_group, + .tuners = &cs_tuners, + .get_cpu_cdbs = get_cpu_cdbs, + .get_cpu_dbs_info_s = get_cpu_dbs_info_s, + .gov_dbs_timer = cs_dbs_timer, + .gov_check_cpu = cs_check_cpu, + .gov_ops = &cs_ops, +}; -static int cpufreq_governor_dbs(struct cpufreq_policy *policy, +static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event) { - unsigned int cpu = policy->cpu; - struct cpu_dbs_info_s *this_dbs_info; - unsigned int j; - int rc; - - this_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - - switch (event) { - case CPUFREQ_GOV_START: - if ((!cpu_online(cpu)) || (!policy->cur)) - return -EINVAL; - - mutex_lock(&dbs_mutex); - - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - j_dbs_info = &per_cpu(cs_cpu_dbs_info, j); - j_dbs_info->cur_policy = policy; - - j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &j_dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - j_dbs_info->prev_cpu_nice = - kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - } - this_dbs_info->cpu = cpu; - this_dbs_info->down_skip = 0; - this_dbs_info->requested_freq = policy->cur; - - mutex_init(&this_dbs_info->timer_mutex); - dbs_enable++; - /* - * Start the timerschedule work, when this governor - * is used for first time - */ - if (dbs_enable == 1) { - unsigned int latency; - /* policy latency is in nS. Convert it to uS first */ - latency = policy->cpuinfo.transition_latency / 1000; - if (latency == 0) - latency = 1; - - rc = sysfs_create_group(cpufreq_global_kobject, - &dbs_attr_group); - if (rc) { - mutex_unlock(&dbs_mutex); - return rc; - } - - /* - * conservative does not implement micro like ondemand - * governor, thus we are bound to jiffes/HZ - */ - min_sampling_rate = - MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); - /* Bring kernel and HW constraints together */ - min_sampling_rate = max(min_sampling_rate, - MIN_LATENCY_MULTIPLIER * latency); - dbs_tuners_ins.sampling_rate = - max(min_sampling_rate, - latency * LATENCY_MULTIPLIER); - - cpufreq_register_notifier( - &dbs_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - } - mutex_unlock(&dbs_mutex); - - dbs_timer_init(this_dbs_info); - - break; - - case CPUFREQ_GOV_STOP: - dbs_timer_exit(this_dbs_info); - - mutex_lock(&dbs_mutex); - dbs_enable--; - mutex_destroy(&this_dbs_info->timer_mutex); - - /* - * Stop the timerschedule work, when this governor - * is used for first time - */ - if (dbs_enable == 0) - cpufreq_unregister_notifier( - &dbs_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - - mutex_unlock(&dbs_mutex); - if (!dbs_enable) - sysfs_remove_group(cpufreq_global_kobject, - &dbs_attr_group); - - break; - - case CPUFREQ_GOV_LIMITS: - mutex_lock(&this_dbs_info->timer_mutex); - if (policy->max < this_dbs_info->cur_policy->cur) - __cpufreq_driver_target( - this_dbs_info->cur_policy, - policy->max, CPUFREQ_RELATION_H); - else if (policy->min > this_dbs_info->cur_policy->cur) - __cpufreq_driver_target( - this_dbs_info->cur_policy, - policy->min, CPUFREQ_RELATION_L); - dbs_check_cpu(this_dbs_info); - mutex_unlock(&this_dbs_info->timer_mutex); - - break; - } - return 0; + return cpufreq_governor_dbs(&cs_dbs_data, policy, event); } #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE @@ -563,13 +333,14 @@ static #endif struct cpufreq_governor cpufreq_gov_conservative = { .name = "conservative", - .governor = cpufreq_governor_dbs, + .governor = cs_cpufreq_governor_dbs, .max_transition_latency = TRANSITION_LATENCY_LIMIT, .owner = THIS_MODULE, }; static int __init cpufreq_gov_dbs_init(void) { + mutex_init(&cs_dbs_data.mutex); return cpufreq_register_governor(&cpufreq_gov_conservative); } @@ -578,7 +349,6 @@ static void __exit cpufreq_gov_dbs_exit(void) cpufreq_unregister_governor(&cpufreq_gov_conservative); } - MODULE_AUTHOR("Alexander Clouter "); MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for " "Low Latency Frequency Transition capable processors " diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 679842a8d34..5ea2c829a79 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -3,19 +3,31 @@ * * CPUFREQ governors common code * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * (C) 2003 Jun Nakajima + * (C) 2009 Alexander Clouter + * (c) 2012 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 #include #include -/* - * Code picked from earlier governer implementations - */ +#include + +#include "cpufreq_governor.h" + static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) { u64 idle_time; @@ -33,9 +45,9 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) idle_time = cur_wall_time - busy_time; if (wall) - *wall = cputime_to_usecs(cur_wall_time); + *wall = jiffies_to_usecs(cur_wall_time); - return cputime_to_usecs(idle_time); + return jiffies_to_usecs(idle_time); } cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) @@ -50,3 +62,257 @@ cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) return idle_time; } EXPORT_SYMBOL_GPL(get_cpu_idle_time); + +void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) +{ + struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu); + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cpufreq_policy *policy; + unsigned int max_load = 0; + unsigned int ignore_nice; + unsigned int j; + + if (dbs_data->governor == GOV_ONDEMAND) + ignore_nice = od_tuners->ignore_nice; + else + ignore_nice = cs_tuners->ignore_nice; + + policy = cdbs->cur_policy; + + /* Get Absolute Load (in terms of freq for ondemand gov) */ + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_common_info *j_cdbs; + cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int load; + + j_cdbs = dbs_data->get_cpu_cdbs(j); + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_cdbs->prev_cpu_wall); + j_cdbs->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_cdbs->prev_cpu_idle); + j_cdbs->prev_cpu_idle = cur_idle_time; + + if (ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + cdbs->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + cdbs->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + if (dbs_data->governor == GOV_ONDEMAND) { + struct od_cpu_dbs_info_s *od_j_dbs_info = + dbs_data->get_cpu_dbs_info_s(cpu); + + cur_iowait_time = get_cpu_iowait_time_us(j, + &cur_wall_time); + if (cur_iowait_time == -1ULL) + cur_iowait_time = 0; + + iowait_time = (unsigned int) (cur_iowait_time - + od_j_dbs_info->prev_cpu_iowait); + od_j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + /* + * For the purpose of ondemand, waiting for disk IO is + * an indication that you're performance critical, and + * not that the system is actually idle. So subtract the + * iowait time from the cpu idle time. + */ + if (od_tuners->io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + } + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + load = 100 * (wall_time - idle_time) / wall_time; + + if (dbs_data->governor == GOV_ONDEMAND) { + int freq_avg = __cpufreq_driver_getavg(policy, j); + if (freq_avg <= 0) + freq_avg = policy->cur; + + load *= freq_avg; + } + + if (load > max_load) + max_load = load; + } + + dbs_data->gov_check_cpu(cpu, max_load); +} +EXPORT_SYMBOL_GPL(dbs_check_cpu); + +static inline void dbs_timer_init(struct dbs_data *dbs_data, + struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate) +{ + int delay = delay_for_sampling_rate(sampling_rate); + + INIT_DEFERRABLE_WORK(&cdbs->work, dbs_data->gov_dbs_timer); + schedule_delayed_work_on(cdbs->cpu, &cdbs->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_common_info *cdbs) +{ + cancel_delayed_work_sync(&cdbs->work); +} + +int cpufreq_governor_dbs(struct dbs_data *dbs_data, + struct cpufreq_policy *policy, unsigned int event) +{ + struct od_cpu_dbs_info_s *od_dbs_info = NULL; + struct cs_cpu_dbs_info_s *cs_dbs_info = NULL; + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cpu_dbs_common_info *cpu_cdbs; + unsigned int *sampling_rate, latency, ignore_nice, j, cpu = policy->cpu; + int rc; + + cpu_cdbs = dbs_data->get_cpu_cdbs(cpu); + + if (dbs_data->governor == GOV_CONSERVATIVE) { + cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu); + sampling_rate = &cs_tuners->sampling_rate; + ignore_nice = cs_tuners->ignore_nice; + } else { + od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu); + sampling_rate = &od_tuners->sampling_rate; + ignore_nice = od_tuners->ignore_nice; + } + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_data->mutex); + + dbs_data->enable++; + cpu_cdbs->cpu = cpu; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_common_info *j_cdbs; + j_cdbs = dbs_data->get_cpu_cdbs(j); + + j_cdbs->cur_policy = policy; + j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, + &j_cdbs->prev_cpu_wall); + if (ignore_nice) + j_cdbs->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + + /* + * Start the timerschedule work, when this governor is used for + * first time + */ + if (dbs_data->enable != 1) + goto second_time; + + rc = sysfs_create_group(cpufreq_global_kobject, + dbs_data->attr_group); + if (rc) { + mutex_unlock(&dbs_data->mutex); + return rc; + } + + /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + + /* + * conservative does not implement micro like ondemand + * governor, thus we are bound to jiffes/HZ + */ + if (dbs_data->governor == GOV_CONSERVATIVE) { + struct cs_ops *ops = dbs_data->gov_ops; + + cpufreq_register_notifier(ops->notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + + dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * + jiffies_to_usecs(10); + } else { + struct od_ops *ops = dbs_data->gov_ops; + + od_tuners->io_is_busy = ops->io_busy(); + } + + /* Bring kernel and HW constraints together */ + dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + *sampling_rate = max(dbs_data->min_sampling_rate, latency * + LATENCY_MULTIPLIER); + +second_time: + if (dbs_data->governor == GOV_CONSERVATIVE) { + cs_dbs_info->down_skip = 0; + cs_dbs_info->enable = 1; + cs_dbs_info->requested_freq = policy->cur; + } else { + struct od_ops *ops = dbs_data->gov_ops; + od_dbs_info->rate_mult = 1; + od_dbs_info->sample_type = OD_NORMAL_SAMPLE; + ops->powersave_bias_init_cpu(cpu); + } + mutex_unlock(&dbs_data->mutex); + + mutex_init(&cpu_cdbs->timer_mutex); + dbs_timer_init(dbs_data, cpu_cdbs, *sampling_rate); + break; + + case CPUFREQ_GOV_STOP: + if (dbs_data->governor == GOV_CONSERVATIVE) + cs_dbs_info->enable = 0; + + dbs_timer_exit(cpu_cdbs); + + mutex_lock(&dbs_data->mutex); + mutex_destroy(&cpu_cdbs->timer_mutex); + dbs_data->enable--; + if (!dbs_data->enable) { + struct cs_ops *ops = dbs_data->gov_ops; + + sysfs_remove_group(cpufreq_global_kobject, + dbs_data->attr_group); + if (dbs_data->governor == GOV_CONSERVATIVE) + cpufreq_unregister_notifier(ops->notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + mutex_unlock(&dbs_data->mutex); + + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&cpu_cdbs->timer_mutex); + if (policy->max < cpu_cdbs->cur_policy->cur) + __cpufreq_driver_target(cpu_cdbs->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > cpu_cdbs->cur_policy->cur) + __cpufreq_driver_target(cpu_cdbs->cur_policy, + policy->min, CPUFREQ_RELATION_L); + dbs_check_cpu(dbs_data, cpu); + mutex_unlock(&cpu_cdbs->timer_mutex); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_governor_dbs); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h new file mode 100644 index 00000000000..34e14adfc3f --- /dev/null +++ b/drivers/cpufreq/cpufreq_governor.h @@ -0,0 +1,177 @@ +/* + * drivers/cpufreq/cpufreq_governor.h + * + * Header file for CPUFreq governors common code + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * (C) 2003 Jun Nakajima + * (C) 2009 Alexander Clouter + * (c) 2012 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. + */ + +#ifndef _CPUFREQ_GOVERNER_H +#define _CPUFREQ_GOVERNER_H + +#include +#include +#include +#include +#include +#include + +/* + * The polling frequency depends on the capability of the processor. Default + * polling frequency is 1000 times the transition latency of the processor. The + * governor will work on any processor with transition latency <= 10mS, using + * appropriate sampling rate. + * + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. All times here are in uS. + */ +#define MIN_SAMPLING_RATE_RATIO (2) +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +/* Ondemand Sampling types */ +enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE}; + +/* Macro creating sysfs show routines */ +#define show_one(_gov, file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", _gov##_tuners.object); \ +} + +#define define_get_cpu_dbs_routines(_dbs_info) \ +static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \ +{ \ + return &per_cpu(_dbs_info, cpu).cdbs; \ +} \ + \ +static void *get_cpu_dbs_info_s(int cpu) \ +{ \ + return &per_cpu(_dbs_info, cpu); \ +} + +/* + * Abbreviations: + * dbs: used as a shortform for demand based switching It helps to keep variable + * names smaller, simpler + * cdbs: common dbs + * on_*: On-demand governor + * cs_*: Conservative governor + */ + +/* Per cpu structures */ +struct cpu_dbs_common_info { + int cpu; + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_wall; + cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + /* + * percpu mutex that serializes governor limit change with gov_dbs_timer + * invocation. We do not want gov_dbs_timer to run when user is changing + * the governor or limits. + */ + struct mutex timer_mutex; +}; + +struct od_cpu_dbs_info_s { + struct cpu_dbs_common_info cdbs; + cputime64_t prev_cpu_iowait; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_lo; + unsigned int freq_lo_jiffies; + unsigned int freq_hi_jiffies; + unsigned int rate_mult; + unsigned int sample_type:1; +}; + +struct cs_cpu_dbs_info_s { + struct cpu_dbs_common_info cdbs; + unsigned int down_skip; + unsigned int requested_freq; + unsigned int enable:1; +}; + +/* Governers sysfs tunables */ +struct od_dbs_tuners { + unsigned int ignore_nice; + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_differential; + unsigned int powersave_bias; + unsigned int io_is_busy; +}; + +struct cs_dbs_tuners { + unsigned int ignore_nice; + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_threshold; + unsigned int freq_step; +}; + +/* Per Governer data */ +struct dbs_data { + /* Common across governors */ + #define GOV_ONDEMAND 0 + #define GOV_CONSERVATIVE 1 + int governor; + unsigned int min_sampling_rate; + unsigned int enable; /* number of CPUs using this policy */ + struct attribute_group *attr_group; + void *tuners; + + /* dbs_mutex protects dbs_enable in governor start/stop */ + struct mutex mutex; + + struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); + void *(*get_cpu_dbs_info_s)(int cpu); + void (*gov_dbs_timer)(struct work_struct *work); + void (*gov_check_cpu)(int cpu, unsigned int load); + + /* Governor specific ops, see below */ + void *gov_ops; +}; + +/* Governor specific ops, will be passed to dbs_data->gov_ops */ +struct od_ops { + int (*io_busy)(void); + void (*powersave_bias_init_cpu)(int cpu); + unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy, + unsigned int freq_next, unsigned int relation); + void (*freq_increase)(struct cpufreq_policy *p, unsigned int freq); +}; + +struct cs_ops { + struct notifier_block *notifier_block; +}; + +static inline int delay_for_sampling_rate(unsigned int sampling_rate) +{ + int delay = usecs_to_jiffies(sampling_rate); + + /* We want all CPUs to do sampling nearly on same jiffy */ + if (num_online_cpus() > 1) + delay -= jiffies % delay; + + return delay; +} + +cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall); +void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); +int cpufreq_governor_dbs(struct dbs_data *dbs_data, + struct cpufreq_policy *policy, unsigned int event); +#endif /* _CPUFREQ_GOVERNER_H */ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index d7f774bb49d..bdaab920630 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -10,24 +10,23 @@ * published by the Free Software Foundation. */ -#include -#include -#include +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include -#include -#include +#include +#include #include +#include +#include #include -#include +#include +#include #include -#include -#include +#include -/* - * dbs is used in this file as a shortform for demandbased switching - * It helps to keep variable names smaller, simpler - */ +#include "cpufreq_governor.h" +/* On-demand governor macors */ #define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) #define DEF_FREQUENCY_UP_THRESHOLD (80) #define DEF_SAMPLING_DOWN_FACTOR (1) @@ -38,80 +37,10 @@ #define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) -/* - * The polling frequency of this governor depends on the capability of - * the processor. Default polling frequency is 1000 times the transition - * latency of the processor. The governor will work on any processor with - * transition latency <= 10mS, using appropriate sampling - * rate. - * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) - * this governor will not work. - * All times here are in uS. - */ -#define MIN_SAMPLING_RATE_RATIO (2) - -static unsigned int min_sampling_rate; - -#define LATENCY_MULTIPLIER (1000) -#define MIN_LATENCY_MULTIPLIER (100) -#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) - -static void do_dbs_timer(struct work_struct *work); -static int cpufreq_governor_dbs(struct cpufreq_policy *policy, - unsigned int event); - -#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND -static -#endif -struct cpufreq_governor cpufreq_gov_ondemand = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .max_transition_latency = TRANSITION_LATENCY_LIMIT, - .owner = THIS_MODULE, -}; - -/* Sampling types */ -enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; - -struct cpu_dbs_info_s { - cputime64_t prev_cpu_idle; - cputime64_t prev_cpu_iowait; - cputime64_t prev_cpu_wall; - cputime64_t prev_cpu_nice; - struct cpufreq_policy *cur_policy; - struct delayed_work work; - struct cpufreq_frequency_table *freq_table; - unsigned int freq_lo; - unsigned int freq_lo_jiffies; - unsigned int freq_hi_jiffies; - unsigned int rate_mult; - int cpu; - unsigned int sample_type:1; - /* - * percpu mutex that serializes governor limit change with - * do_dbs_timer invocation. We do not want do_dbs_timer to run - * when user is changing the governor or limits. - */ - struct mutex timer_mutex; -}; -static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info); - -static unsigned int dbs_enable; /* number of CPUs using this policy */ +static struct dbs_data od_dbs_data; +static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info); -/* - * dbs_mutex protects dbs_enable in governor start/stop. - */ -static DEFINE_MUTEX(dbs_mutex); - -static struct dbs_tuners { - unsigned int sampling_rate; - unsigned int up_threshold; - unsigned int down_differential; - unsigned int ignore_nice; - unsigned int sampling_down_factor; - unsigned int powersave_bias; - unsigned int io_is_busy; -} dbs_tuners_ins = { +static struct od_dbs_tuners od_tuners = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, @@ -119,14 +48,35 @@ static struct dbs_tuners { .powersave_bias = 0, }; -static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) +static void ondemand_powersave_bias_init_cpu(int cpu) { - u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - if (iowait_time == -1ULL) - return 0; + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); + dbs_info->freq_lo = 0; +} - return iowait_time; +/* + * Not all CPUs want IO time to be accounted as busy; this depends on how + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. + * Mike Chan (androidlcom) calis this is also not true for ARM. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +static int should_io_be_busy(void) +{ +#if defined(CONFIG_X86) + /* + * For Intel, Core 2 (model 15) andl later have an efficient idle. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; +#endif + return 0; } /* @@ -135,14 +85,13 @@ static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wal * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. */ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, - unsigned int freq_next, - unsigned int relation) + unsigned int freq_next, unsigned int relation) { unsigned int freq_req, freq_reduc, freq_avg; unsigned int freq_hi, freq_lo; unsigned int index = 0; unsigned int jiffies_total, jiffies_hi, jiffies_lo; - struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); if (!dbs_info->freq_table) { @@ -154,7 +103,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, relation, &index); freq_req = dbs_info->freq_table[index].frequency; - freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; + freq_reduc = freq_req * od_tuners.powersave_bias / 1000; freq_avg = freq_req - freq_reduc; /* Find freq bounds for freq_avg in freq_table */ @@ -173,7 +122,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, dbs_info->freq_lo_jiffies = 0; return freq_lo; } - jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + jiffies_total = usecs_to_jiffies(od_tuners.sampling_rate); jiffies_hi = (freq_avg - freq_lo) * jiffies_total; jiffies_hi += ((freq_hi - freq_lo) / 2); jiffies_hi /= (freq_hi - freq_lo); @@ -184,13 +133,6 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, return freq_hi; } -static void ondemand_powersave_bias_init_cpu(int cpu) -{ - struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - dbs_info->freq_table = cpufreq_frequency_get_table(cpu); - dbs_info->freq_lo = 0; -} - static void ondemand_powersave_bias_init(void) { int i; @@ -199,53 +141,138 @@ static void ondemand_powersave_bias_init(void) } } -/************************** sysfs interface ************************/ +static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ + if (od_tuners.powersave_bias) + freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); + else if (p->cur == p->max) + return; -static ssize_t show_sampling_rate_min(struct kobject *kobj, - struct attribute *attr, char *buf) + __cpufreq_driver_target(p, freq, od_tuners.powersave_bias ? + CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); +} + +/* + * Every sampling_rate, we check, if current idle time is less than 20% + * (default), then we try to increase frequency Every sampling_rate, we look for + * a the lowest frequency which can sustain the load while keeping idle time + * over 30%. If such a frequency exist, we try to decrease to this frequency. + * + * Any frequency increase takes it to the maximum frequency. Frequency reduction + * happens at minimum steps of 5% (default) of current frequency + */ +static void od_check_cpu(int cpu, unsigned int load_freq) { - return sprintf(buf, "%u\n", min_sampling_rate); + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + + dbs_info->freq_lo = 0; + + /* Check for frequency increase */ + if (load_freq > od_tuners.up_threshold * policy->cur) { + /* If switching to max speed, apply sampling_down_factor */ + if (policy->cur < policy->max) + dbs_info->rate_mult = + od_tuners.sampling_down_factor; + dbs_freq_increase(policy, policy->max); + return; + } + + /* Check for frequency decrease */ + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) + return; + + /* + * The optimal frequency is the frequency that is the lowest that can + * support the current CPU usage without triggering the up policy. To be + * safe, we focus 10 points under the threshold. + */ + if (load_freq < (od_tuners.up_threshold - od_tuners.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = load_freq / (od_tuners.up_threshold - + od_tuners.down_differential); + + /* No longer fully busy, reset rate_mult */ + dbs_info->rate_mult = 1; + + if (freq_next < policy->min) + freq_next = policy->min; + + if (!od_tuners.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } else { + int freq = powersave_bias_target(policy, freq_next, + CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, freq, + CPUFREQ_RELATION_L); + } + } } -define_one_global_ro(sampling_rate_min); +static void od_dbs_timer(struct work_struct *work) +{ + struct od_cpu_dbs_info_s *dbs_info = + container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); + unsigned int cpu = dbs_info->cdbs.cpu; + int delay, sample_type = dbs_info->sample_type; -/* cpufreq_ondemand Governor Tunables */ -#define show_one(file_name, object) \ -static ssize_t show_##file_name \ -(struct kobject *kobj, struct attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ + mutex_lock(&dbs_info->cdbs.timer_mutex); + + /* Common NORMAL_SAMPLE setup */ + dbs_info->sample_type = OD_NORMAL_SAMPLE; + if (sample_type == OD_SUB_SAMPLE) { + delay = dbs_info->freq_lo_jiffies; + __cpufreq_driver_target(dbs_info->cdbs.cur_policy, + dbs_info->freq_lo, CPUFREQ_RELATION_H); + } else { + dbs_check_cpu(&od_dbs_data, cpu); + if (dbs_info->freq_lo) { + /* Setup timer for SUB_SAMPLE */ + dbs_info->sample_type = OD_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; + } else { + delay = delay_for_sampling_rate(dbs_info->rate_mult); + } + } + + schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay); + mutex_unlock(&dbs_info->cdbs.timer_mutex); +} + +/************************** sysfs interface ************************/ + +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", od_dbs_data.min_sampling_rate); } -show_one(sampling_rate, sampling_rate); -show_one(io_is_busy, io_is_busy); -show_one(up_threshold, up_threshold); -show_one(sampling_down_factor, sampling_down_factor); -show_one(ignore_nice_load, ignore_nice); -show_one(powersave_bias, powersave_bias); /** * update_sampling_rate - update sampling rate effective immediately if needed. * @new_rate: new sampling rate * * If new rate is smaller than the old, simply updaing - * dbs_tuners_int.sampling_rate might not be appropriate. For example, - * if the original sampling_rate was 1 second and the requested new sampling - * rate is 10 ms because the user needs immediate reaction from ondemand - * governor, but not sure if higher frequency will be required or not, - * then, the governor may change the sampling rate too late; up to 1 second - * later. Thus, if we are reducing the sampling rate, we need to make the - * new value effective immediately. + * dbs_tuners_int.sampling_rate might not be appropriate. For example, if the + * original sampling_rate was 1 second and the requested new sampling rate is 10 + * ms because the user needs immediate reaction from ondemand governor, but not + * sure if higher frequency will be required or not, then, the governor may + * change the sampling rate too late; up to 1 second later. Thus, if we are + * reducing the sampling rate, we need to make the new value effective + * immediately. */ static void update_sampling_rate(unsigned int new_rate) { int cpu; - dbs_tuners_ins.sampling_rate = new_rate - = max(new_rate, min_sampling_rate); + od_tuners.sampling_rate = new_rate = max(new_rate, + od_dbs_data.min_sampling_rate); for_each_online_cpu(cpu) { struct cpufreq_policy *policy; - struct cpu_dbs_info_s *dbs_info; + struct od_cpu_dbs_info_s *dbs_info; unsigned long next_sampling, appointed_at; policy = cpufreq_cpu_get(cpu); @@ -254,28 +281,28 @@ static void update_sampling_rate(unsigned int new_rate) dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); cpufreq_cpu_put(policy); - mutex_lock(&dbs_info->timer_mutex); + mutex_lock(&dbs_info->cdbs.timer_mutex); - if (!delayed_work_pending(&dbs_info->work)) { - mutex_unlock(&dbs_info->timer_mutex); + if (!delayed_work_pending(&dbs_info->cdbs.work)) { + mutex_unlock(&dbs_info->cdbs.timer_mutex); continue; } - next_sampling = jiffies + usecs_to_jiffies(new_rate); - appointed_at = dbs_info->work.timer.expires; - + next_sampling = jiffies + usecs_to_jiffies(new_rate); + appointed_at = dbs_info->cdbs.work.timer.expires; if (time_before(next_sampling, appointed_at)) { - mutex_unlock(&dbs_info->timer_mutex); - cancel_delayed_work_sync(&dbs_info->work); - mutex_lock(&dbs_info->timer_mutex); + mutex_unlock(&dbs_info->cdbs.timer_mutex); + cancel_delayed_work_sync(&dbs_info->cdbs.work); + mutex_lock(&dbs_info->cdbs.timer_mutex); - schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, - usecs_to_jiffies(new_rate)); + schedule_delayed_work_on(dbs_info->cdbs.cpu, + &dbs_info->cdbs.work, + usecs_to_jiffies(new_rate)); } - mutex_unlock(&dbs_info->timer_mutex); + mutex_unlock(&dbs_info->cdbs.timer_mutex); } } @@ -300,7 +327,7 @@ static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; - dbs_tuners_ins.io_is_busy = !!input; + od_tuners.io_is_busy = !!input; return count; } @@ -315,7 +342,7 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, input < MIN_FREQUENCY_UP_THRESHOLD) { return -EINVAL; } - dbs_tuners_ins.up_threshold = input; + od_tuners.up_threshold = input; return count; } @@ -328,12 +355,12 @@ static ssize_t store_sampling_down_factor(struct kobject *a, if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) return -EINVAL; - dbs_tuners_ins.sampling_down_factor = input; + od_tuners.sampling_down_factor = input; /* Reset down sampling multiplier in case it was active */ for_each_online_cpu(j) { - struct cpu_dbs_info_s *dbs_info; - dbs_info = &per_cpu(od_cpu_dbs_info, j); + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, + j); dbs_info->rate_mult = 1; } return count; @@ -354,19 +381,20 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, if (input > 1) input = 1; - if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ + if (input == od_tuners.ignore_nice) { /* nothing to do */ return count; } - dbs_tuners_ins.ignore_nice = input; + od_tuners.ignore_nice = input; /* we need to re-evaluate prev_cpu_idle */ for_each_online_cpu(j) { - struct cpu_dbs_info_s *dbs_info; + struct od_cpu_dbs_info_s *dbs_info; dbs_info = &per_cpu(od_cpu_dbs_info, j); - dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->cdbs.prev_cpu_wall); + if (od_tuners.ignore_nice) + dbs_info->cdbs.prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; } return count; @@ -385,17 +413,25 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b, if (input > 1000) input = 1000; - dbs_tuners_ins.powersave_bias = input; + od_tuners.powersave_bias = input; ondemand_powersave_bias_init(); return count; } +show_one(od, sampling_rate, sampling_rate); +show_one(od, io_is_busy, io_is_busy); +show_one(od, up_threshold, up_threshold); +show_one(od, sampling_down_factor, sampling_down_factor); +show_one(od, ignore_nice_load, ignore_nice); +show_one(od, powersave_bias, powersave_bias); + define_one_global_rw(sampling_rate); define_one_global_rw(io_is_busy); define_one_global_rw(up_threshold); define_one_global_rw(sampling_down_factor); define_one_global_rw(ignore_nice_load); define_one_global_rw(powersave_bias); +define_one_global_ro(sampling_rate_min); static struct attribute *dbs_attributes[] = { &sampling_rate_min.attr, @@ -408,354 +444,71 @@ static struct attribute *dbs_attributes[] = { NULL }; -static struct attribute_group dbs_attr_group = { +static struct attribute_group od_attr_group = { .attrs = dbs_attributes, .name = "ondemand", }; /************************** sysfs end ************************/ -static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) -{ - if (dbs_tuners_ins.powersave_bias) - freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); - else if (p->cur == p->max) - return; - - __cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ? - CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); -} - -static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) -{ - unsigned int max_load_freq; - - struct cpufreq_policy *policy; - unsigned int j; - - this_dbs_info->freq_lo = 0; - policy = this_dbs_info->cur_policy; - - /* - * Every sampling_rate, we check, if current idle time is less - * than 20% (default), then we try to increase frequency - * Every sampling_rate, we look for a the lowest - * frequency which can sustain the load while keeping idle time over - * 30%. If such a frequency exist, we try to decrease to this frequency. - * - * Any frequency increase takes it to the maximum frequency. - * Frequency reduction happens at minimum steps of - * 5% (default) of current frequency - */ - - /* Get Absolute Load - in terms of freq */ - max_load_freq = 0; - - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; - unsigned int idle_time, wall_time, iowait_time; - unsigned int load, load_freq; - int freq_avg; - - j_dbs_info = &per_cpu(od_cpu_dbs_info, j); - - cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); - cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); - - wall_time = (unsigned int) - (cur_wall_time - j_dbs_info->prev_cpu_wall); - j_dbs_info->prev_cpu_wall = cur_wall_time; - - idle_time = (unsigned int) - (cur_idle_time - j_dbs_info->prev_cpu_idle); - j_dbs_info->prev_cpu_idle = cur_idle_time; - - iowait_time = (unsigned int) - (cur_iowait_time - j_dbs_info->prev_cpu_iowait); - j_dbs_info->prev_cpu_iowait = cur_iowait_time; - - if (dbs_tuners_ins.ignore_nice) { - u64 cur_nice; - unsigned long cur_nice_jiffies; - - cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - - j_dbs_info->prev_cpu_nice; - /* - * Assumption: nice time between sampling periods will - * be less than 2^32 jiffies for 32 bit sys - */ - cur_nice_jiffies = (unsigned long) - cputime64_to_jiffies64(cur_nice); - - j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - idle_time += jiffies_to_usecs(cur_nice_jiffies); - } - - /* - * For the purpose of ondemand, waiting for disk IO is an - * indication that you're performance critical, and not that - * the system is actually idle. So subtract the iowait time - * from the cpu idle time. - */ - - if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) - idle_time -= iowait_time; +define_get_cpu_dbs_routines(od_cpu_dbs_info); - if (unlikely(!wall_time || wall_time < idle_time)) - continue; - - load = 100 * (wall_time - idle_time) / wall_time; - - freq_avg = __cpufreq_driver_getavg(policy, j); - if (freq_avg <= 0) - freq_avg = policy->cur; - - load_freq = load * freq_avg; - if (load_freq > max_load_freq) - max_load_freq = load_freq; - } - - /* Check for frequency increase */ - if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) { - /* If switching to max speed, apply sampling_down_factor */ - if (policy->cur < policy->max) - this_dbs_info->rate_mult = - dbs_tuners_ins.sampling_down_factor; - dbs_freq_increase(policy, policy->max); - return; - } - - /* Check for frequency decrease */ - /* if we cannot reduce the frequency anymore, break out early */ - if (policy->cur == policy->min) - return; - - /* - * The optimal frequency is the frequency that is the lowest that - * can support the current CPU usage without triggering the up - * policy. To be safe, we focus 10 points under the threshold. - */ - if (max_load_freq < - (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * - policy->cur) { - unsigned int freq_next; - freq_next = max_load_freq / - (dbs_tuners_ins.up_threshold - - dbs_tuners_ins.down_differential); - - /* No longer fully busy, reset rate_mult */ - this_dbs_info->rate_mult = 1; - - if (freq_next < policy->min) - freq_next = policy->min; - - if (!dbs_tuners_ins.powersave_bias) { - __cpufreq_driver_target(policy, freq_next, - CPUFREQ_RELATION_L); - } else { - int freq = powersave_bias_target(policy, freq_next, - CPUFREQ_RELATION_L); - __cpufreq_driver_target(policy, freq, - CPUFREQ_RELATION_L); - } - } -} - -static void do_dbs_timer(struct work_struct *work) -{ - struct cpu_dbs_info_s *dbs_info = - container_of(work, struct cpu_dbs_info_s, work.work); - unsigned int cpu = dbs_info->cpu; - int sample_type = dbs_info->sample_type; - - int delay; - - mutex_lock(&dbs_info->timer_mutex); - - /* Common NORMAL_SAMPLE setup */ - dbs_info->sample_type = DBS_NORMAL_SAMPLE; - if (!dbs_tuners_ins.powersave_bias || - sample_type == DBS_NORMAL_SAMPLE) { - dbs_check_cpu(dbs_info); - if (dbs_info->freq_lo) { - /* Setup timer for SUB_SAMPLE */ - dbs_info->sample_type = DBS_SUB_SAMPLE; - delay = dbs_info->freq_hi_jiffies; - } else { - /* We want all CPUs to do sampling nearly on - * same jiffy - */ - delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate - * dbs_info->rate_mult); - - if (num_online_cpus() > 1) - delay -= jiffies % delay; - } - } else { - __cpufreq_driver_target(dbs_info->cur_policy, - dbs_info->freq_lo, CPUFREQ_RELATION_H); - delay = dbs_info->freq_lo_jiffies; - } - schedule_delayed_work_on(cpu, &dbs_info->work, delay); - mutex_unlock(&dbs_info->timer_mutex); -} - -static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) -{ - /* We want all CPUs to do sampling nearly on same jiffy */ - int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - - if (num_online_cpus() > 1) - delay -= jiffies % delay; +static struct od_ops od_ops = { + .io_busy = should_io_be_busy, + .powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu, + .powersave_bias_target = powersave_bias_target, + .freq_increase = dbs_freq_increase, +}; - dbs_info->sample_type = DBS_NORMAL_SAMPLE; - INIT_DEFERRABLE_WORK(&dbs_info->work, do_dbs_timer); - schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); -} +static struct dbs_data od_dbs_data = { + .governor = GOV_ONDEMAND, + .attr_group = &od_attr_group, + .tuners = &od_tuners, + .get_cpu_cdbs = get_cpu_cdbs, + .get_cpu_dbs_info_s = get_cpu_dbs_info_s, + .gov_dbs_timer = od_dbs_timer, + .gov_check_cpu = od_check_cpu, + .gov_ops = &od_ops, +}; -static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) { - cancel_delayed_work_sync(&dbs_info->work); + return cpufreq_governor_dbs(&od_dbs_data, policy, event); } -/* - * Not all CPUs want IO time to be accounted as busy; this dependson how - * efficient idling at a higher frequency/voltage is. - * Pavel Machek says this is not so for various generations of AMD and old - * Intel systems. - * Mike Chan (androidlcom) calis this is also not true for ARM. - * Because of this, whitelist specific known (series) of CPUs by default, and - * leave all others up to the user. - */ -static int should_io_be_busy(void) -{ -#if defined(CONFIG_X86) - /* - * For Intel, Core 2 (model 15) andl later have an efficient idle. - */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_data.x86 == 6 && - boot_cpu_data.x86_model >= 15) - return 1; +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND +static #endif - return 0; -} - -static int cpufreq_governor_dbs(struct cpufreq_policy *policy, - unsigned int event) -{ - unsigned int cpu = policy->cpu; - struct cpu_dbs_info_s *this_dbs_info; - unsigned int j; - int rc; - - this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - - switch (event) { - case CPUFREQ_GOV_START: - if ((!cpu_online(cpu)) || (!policy->cur)) - return -EINVAL; - - mutex_lock(&dbs_mutex); - - dbs_enable++; - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - j_dbs_info = &per_cpu(od_cpu_dbs_info, j); - j_dbs_info->cur_policy = policy; - - j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &j_dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - j_dbs_info->prev_cpu_nice = - kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - } - this_dbs_info->cpu = cpu; - this_dbs_info->rate_mult = 1; - ondemand_powersave_bias_init_cpu(cpu); - /* - * Start the timerschedule work, when this governor - * is used for first time - */ - if (dbs_enable == 1) { - unsigned int latency; - - rc = sysfs_create_group(cpufreq_global_kobject, - &dbs_attr_group); - if (rc) { - mutex_unlock(&dbs_mutex); - return rc; - } - - /* policy latency is in nS. Convert it to uS first */ - latency = policy->cpuinfo.transition_latency / 1000; - if (latency == 0) - latency = 1; - /* Bring kernel and HW constraints together */ - min_sampling_rate = max(min_sampling_rate, - MIN_LATENCY_MULTIPLIER * latency); - dbs_tuners_ins.sampling_rate = - max(min_sampling_rate, - latency * LATENCY_MULTIPLIER); - dbs_tuners_ins.io_is_busy = should_io_be_busy(); - } - mutex_unlock(&dbs_mutex); - - mutex_init(&this_dbs_info->timer_mutex); - dbs_timer_init(this_dbs_info); - break; - - case CPUFREQ_GOV_STOP: - dbs_timer_exit(this_dbs_info); - - mutex_lock(&dbs_mutex); - mutex_destroy(&this_dbs_info->timer_mutex); - dbs_enable--; - mutex_unlock(&dbs_mutex); - if (!dbs_enable) - sysfs_remove_group(cpufreq_global_kobject, - &dbs_attr_group); - - break; - - case CPUFREQ_GOV_LIMITS: - mutex_lock(&this_dbs_info->timer_mutex); - if (policy->max < this_dbs_info->cur_policy->cur) - __cpufreq_driver_target(this_dbs_info->cur_policy, - policy->max, CPUFREQ_RELATION_H); - else if (policy->min > this_dbs_info->cur_policy->cur) - __cpufreq_driver_target(this_dbs_info->cur_policy, - policy->min, CPUFREQ_RELATION_L); - dbs_check_cpu(this_dbs_info); - mutex_unlock(&this_dbs_info->timer_mutex); - break; - } - return 0; -} +struct cpufreq_governor cpufreq_gov_ondemand = { + .name = "ondemand", + .governor = od_cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; static int __init cpufreq_gov_dbs_init(void) { u64 idle_time; int cpu = get_cpu(); + mutex_init(&od_dbs_data.mutex); idle_time = get_cpu_idle_time_us(cpu, NULL); put_cpu(); if (idle_time != -1ULL) { /* Idle micro accounting is supported. Use finer thresholds */ - dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; - dbs_tuners_ins.down_differential = - MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + od_tuners.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + od_tuners.down_differential = MICRO_FREQUENCY_DOWN_DIFFERENTIAL; /* * In nohz/micro accounting case we set the minimum frequency * not depending on HZ, but fixed (very low). The deferred * timer might skip some samples if idle/sleeping as needed. */ - min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + od_dbs_data.min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; } else { /* For correct statistics, we need 10 ticks for each measure */ - min_sampling_rate = - MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + od_dbs_data.min_sampling_rate = MIN_SAMPLING_RATE_RATIO * + jiffies_to_usecs(10); } return cpufreq_register_governor(&cpufreq_gov_ondemand); @@ -766,7 +519,6 @@ static void __exit cpufreq_gov_dbs_exit(void) cpufreq_unregister_governor(&cpufreq_gov_ondemand); } - MODULE_AUTHOR("Venkatesh Pallipadi "); MODULE_AUTHOR("Alexey Starikovskiy "); MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for " diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index d03c2199305..a55b88eaf96 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -407,10 +407,4 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, unsigned int cpu); void cpufreq_frequency_table_put_attr(unsigned int cpu); - -/********************************************************************* - * Governor Helpers * - *********************************************************************/ -cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall); - #endif /* _LINUX_CPUFREQ_H */ -- cgit v1.2.3 From 1e7586a18a2ab69a160837c0a4be31f7147cfb5e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 26 Oct 2012 00:51:21 +0200 Subject: cpufreq: Fix sparse warnings by updating cputime64_t to u64 There were few sparse warnings due to mismatch of type on function arguments. Two types were used u64 and cputime64_t. Both are actually u64, so use u64 only. Reported-by: Fengguang Wu Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 4 ++-- drivers/cpufreq/cpufreq_governor.h | 11 +++++------ drivers/cpufreq/cpufreq_stats.c | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 5ea2c829a79..be9d255e292 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -50,7 +50,7 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) return jiffies_to_usecs(idle_time); } -cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall) { u64 idle_time = get_cpu_idle_time_us(cpu, NULL); @@ -83,7 +83,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) /* Get Absolute Load (in terms of freq for ondemand gov) */ for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs; - cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; + u64 cur_wall_time, cur_idle_time, cur_iowait_time; unsigned int idle_time, wall_time, iowait_time; unsigned int load; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 34e14adfc3f..f6616540c53 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -17,7 +17,6 @@ #ifndef _CPUFREQ_GOVERNER_H #define _CPUFREQ_GOVERNER_H -#include #include #include #include @@ -72,9 +71,9 @@ static void *get_cpu_dbs_info_s(int cpu) \ /* Per cpu structures */ struct cpu_dbs_common_info { int cpu; - cputime64_t prev_cpu_idle; - cputime64_t prev_cpu_wall; - cputime64_t prev_cpu_nice; + u64 prev_cpu_idle; + u64 prev_cpu_wall; + u64 prev_cpu_nice; struct cpufreq_policy *cur_policy; struct delayed_work work; /* @@ -87,7 +86,7 @@ struct cpu_dbs_common_info { struct od_cpu_dbs_info_s { struct cpu_dbs_common_info cdbs; - cputime64_t prev_cpu_iowait; + u64 prev_cpu_iowait; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; unsigned int freq_lo_jiffies; @@ -170,7 +169,7 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate) return delay; } -cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall); +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall); void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); int cpufreq_governor_dbs(struct dbs_data *dbs_data, struct cpufreq_policy *policy, unsigned int event); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 399831690fe..e40e5080964 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -37,7 +37,7 @@ struct cpufreq_stats { unsigned int max_state; unsigned int state_num; unsigned int last_index; - cputime64_t *time_in_state; + u64 *time_in_state; unsigned int *freq_table; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS unsigned int *trans_table; @@ -223,7 +223,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, count++; } - alloc_size = count * sizeof(int) + count * sizeof(cputime64_t); + alloc_size = count * sizeof(int) + count * sizeof(u64); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); -- cgit v1.2.3 From da58445570326ac2a342770a9c9a2646276e1721 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 26 Oct 2012 00:51:32 +0200 Subject: cpufreq: Fix sparse warning by making local function static cpufreq_disabled() is a local function, so should be marked static. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f552d5fe0f8..261ef654a35 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -129,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void) pure_initcall(init_cpufreq_transition_notifier_list); static int off __read_mostly; -int cpufreq_disabled(void) +static int cpufreq_disabled(void) { return off; } -- cgit v1.2.3 From 5a1c022850ea5d64c2997bf9b89f5ae112d5ee4d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 31 Oct 2012 01:28:15 +0100 Subject: cpufreq: Avoid calling cpufreq driver's target() routine if target_freq == policy->cur Avoid calling cpufreq driver's target() routine if new frequency is same as policies current frequency. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 261ef654a35..28dc134cec3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1476,6 +1476,10 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu, target_freq, relation); + + if (target_freq == policy->cur) + return 0; + if (cpu_online(policy->cpu) && cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); -- cgit v1.2.3 From 7249924e537816368c4a35afd97ab311f75a6368 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 31 Oct 2012 01:28:21 +0100 Subject: cpufreq: Make sure target freq is within limits __cpufreq_driver_target() must not pass target frequency beyond the limits of current policy. Today most of cpufreq platform drivers are doing this check in their target routines. Why not move it to __cpufreq_driver_target()? Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 28dc134cec3..2f5ac2dcfda 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1470,12 +1470,19 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation) { int retval = -EINVAL; + unsigned int old_target_freq = target_freq; if (cpufreq_disabled()) return -ENODEV; - pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu, - target_freq, relation); + /* Make sure that target_freq is within supported range */ + if (target_freq > policy->max) + target_freq = policy->max; + if (target_freq < policy->min) + target_freq = policy->min; + + pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", + policy->cpu, target_freq, relation, old_target_freq); if (target_freq == policy->cur) return 0; -- cgit v1.2.3 From f55c9c26278b0fcfa3336eccbba3d8a782da8aed Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 31 Oct 2012 05:49:13 +0000 Subject: cpufreq: Remove unnecessary initialization of a local variable Remove an unnecessary initializer for the 'ret' variable in __cpufreq_set_policy(). [rjw: Modified the subject and changelog slightly.] Signed-off-by: Jingoo Han Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f5ac2dcfda..1f93dbd7235 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -404,7 +404,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, static ssize_t store_##file_name \ (struct cpufreq_policy *policy, const char *buf, size_t count) \ { \ - unsigned int ret = -EINVAL; \ + unsigned int ret; \ struct cpufreq_policy new_policy; \ \ ret = cpufreq_get_policy(&new_policy, policy->cpu); \ @@ -459,7 +459,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) static ssize_t store_scaling_governor(struct cpufreq_policy *policy, const char *buf, size_t count) { - unsigned int ret = -EINVAL; + unsigned int ret; char str_governor[16]; struct cpufreq_policy new_policy; -- cgit v1.2.3 From 1aef40e288acfb3cc28ff77528b34ef66683bed6 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 26 Oct 2012 12:26:24 +0200 Subject: cpuidle / sysfs: change function parameter The function needs the cpuidle_device which is initially passed to the caller. The current code gets the struct device from the struct cpuidle_device, pass it the cpuidle_add_sysfs function. This function calls per_cpu(cpuidle_devices, cpu) to get the cpuidle_device. This patch pass the cpuidle_device instead and simplify the code. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 8 +++----- drivers/cpuidle/cpuidle.h | 4 ++-- drivers/cpuidle/sysfs.c | 12 +++--------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 7f15b8514a1..b511ac39cc8 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -394,7 +394,6 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device); static int __cpuidle_register_device(struct cpuidle_device *dev) { int ret; - struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); if (!try_module_get(cpuidle_driver->owner)) @@ -404,7 +403,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); - ret = cpuidle_add_sysfs(cpu_dev); + ret = cpuidle_add_sysfs(dev); if (ret) goto err_sysfs; @@ -416,7 +415,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) return 0; err_coupled: - cpuidle_remove_sysfs(cpu_dev); + cpuidle_remove_sysfs(dev); wait_for_completion(&dev->kobj_unregister); err_sysfs: list_del(&dev->device_list); @@ -460,7 +459,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device); */ void cpuidle_unregister_device(struct cpuidle_device *dev) { - struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); if (dev->registered == 0) @@ -470,7 +468,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) cpuidle_disable_device(dev); - cpuidle_remove_sysfs(cpu_dev); + cpuidle_remove_sysfs(dev); list_del(&dev->device_list); wait_for_completion(&dev->kobj_unregister); per_cpu(cpuidle_devices, dev->cpu) = NULL; diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 76e7f696ad8..2120d9e937c 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -29,8 +29,8 @@ extern int cpuidle_add_interface(struct device *dev); extern void cpuidle_remove_interface(struct device *dev); extern int cpuidle_add_state_sysfs(struct cpuidle_device *device); extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device); -extern int cpuidle_add_sysfs(struct device *dev); -extern void cpuidle_remove_sysfs(struct device *dev); +extern int cpuidle_add_sysfs(struct cpuidle_device *dev); +extern void cpuidle_remove_sysfs(struct cpuidle_device *dev); #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED bool cpuidle_state_is_coupled(struct cpuidle_device *dev, diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 5f809e337b8..84e62852e50 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -408,13 +408,11 @@ void cpuidle_remove_state_sysfs(struct cpuidle_device *device) * cpuidle_add_sysfs - creates a sysfs instance for the target device * @dev: the target device */ -int cpuidle_add_sysfs(struct device *cpu_dev) +int cpuidle_add_sysfs(struct cpuidle_device *dev) { - int cpu = cpu_dev->id; - struct cpuidle_device *dev; + struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; - dev = per_cpu(cpuidle_devices, cpu); error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, "cpuidle"); if (!error) @@ -426,11 +424,7 @@ int cpuidle_add_sysfs(struct device *cpu_dev) * cpuidle_remove_sysfs - deletes a sysfs instance on the target device * @dev: the target device */ -void cpuidle_remove_sysfs(struct device *cpu_dev) +void cpuidle_remove_sysfs(struct cpuidle_device *dev) { - int cpu = cpu_dev->id; - struct cpuidle_device *dev; - - dev = per_cpu(cpuidle_devices, cpu); kobject_put(&dev->kobj); } -- cgit v1.2.3 From e45a00d679a788217f35ee4214a32d6d1924160b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 26 Oct 2012 12:26:32 +0200 Subject: cpuidle / sysfs: move kobj initialization in the syfs file Move the kobj initialization and completion in the sysfs.c and encapsulate the code more. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 4 ---- drivers/cpuidle/sysfs.c | 7 +++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index b511ac39cc8..f4b8fc50c0f 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -399,8 +399,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) if (!try_module_get(cpuidle_driver->owner)) return -EINVAL; - init_completion(&dev->kobj_unregister); - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); ret = cpuidle_add_sysfs(dev); @@ -416,7 +414,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) err_coupled: cpuidle_remove_sysfs(dev); - wait_for_completion(&dev->kobj_unregister); err_sysfs: list_del(&dev->device_list); per_cpu(cpuidle_devices, dev->cpu) = NULL; @@ -470,7 +467,6 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) cpuidle_remove_sysfs(dev); list_del(&dev->device_list); - wait_for_completion(&dev->kobj_unregister); per_cpu(cpuidle_devices, dev->cpu) = NULL; cpuidle_coupled_unregister_device(dev); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 84e62852e50..ed87399bb02 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -374,8 +374,8 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) kobj->state_usage = &device->states_usage[i]; init_completion(&kobj->kobj_unregister); - ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, - "state%d", i); + ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, + &device->kobj, "state%d", i); if (ret) { kfree(kobj); goto error_state; @@ -413,6 +413,8 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; + init_completion(&dev->kobj_unregister); + error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, "cpuidle"); if (!error) @@ -427,4 +429,5 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) void cpuidle_remove_sysfs(struct cpuidle_device *dev) { kobject_put(&dev->kobj); + wait_for_completion(&dev->kobj_unregister); } -- cgit v1.2.3 From 69a37beabf1f0a6705c08e879bdd5d82ff6486c4 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Fri, 26 Oct 2012 12:26:41 +0200 Subject: cpuidle: Quickly notice prediction failure for repeat mode The prediction for future is difficult and when the cpuidle governor prediction fails and govenor possibly choose the shallower C-state than it should. How to quickly notice and find the failure becomes important for power saving. cpuidle menu governor has a method to predict the repeat pattern if there are 8 C-states residency which are continuous and the same or very close, so it will predict the next C-states residency will keep same residency time. There is a real case that turbostat utility (tools/power/x86/turbostat) at kernel 3.3 or early. turbostat utility will read 10 registers one by one at Sandybridge, so it will generate 10 IPIs to wake up idle CPUs. So cpuidle menu governor will predict it is repeat mode and there is another IPI wake up idle CPU soon, so it keeps idle CPU stay at C1 state even though CPU is totally idle. However, in the turbostat, following 10 registers reading is sleep 5 seconds by default, so the idle CPU will keep at C1 for a long time though it is idle until break event occurs. In a idle Sandybridge system, run "./turbostat -v", we will notice that deep C-state dangles between "70% ~ 99%". After patched the kernel, we will notice deep C-state stays at >99.98%. In the patch, a timer is added when menu governor detects a repeat mode and choose a shallow C-state. The timer is set to a time out value that greater than predicted time, and we conclude repeat mode prediction failure if timer is triggered. When repeat mode happens as expected, the timer is not triggered and CPU waken up from C-states and it will cancel the timer initiatively. When repeat mode does not happen, the timer will be time out and menu governor will quickly notice that the repeat mode prediction fails and then re-evaluates deeper C-states possibility. Below is another case which will clearly show the patch much benefit: #include #include #include #include #include #include #include volatile int * shutdown; volatile long * count; int delay = 20; int loop = 8; void usage(void) { fprintf(stderr, "Usage: idle_predict [options]\n" " --help -h Print this help\n" " --thread -n Thread number\n" " --loop -l Loop times in shallow Cstate\n" " --delay -t Sleep time (uS)in shallow Cstate\n"); } void *simple_loop() { int idle_num = 1; while (!(*shutdown)) { *count = *count + 1; if (idle_num % loop) usleep(delay); else { /* sleep 1 second */ usleep(1000000); idle_num = 0; } idle_num++; } } static void sighand(int sig) { *shutdown = 1; } int main(int argc, char *argv[]) { sigset_t sigset; int signum = SIGALRM; int i, c, er = 0, thread_num = 8; pthread_t pt[1024]; static char optstr[] = "n:l:t:h:"; while ((c = getopt(argc, argv, optstr)) != EOF) switch (c) { case 'n': thread_num = atoi(optarg); break; case 'l': loop = atoi(optarg); break; case 't': delay = atoi(optarg); break; case 'h': default: usage(); exit(1); } printf("thread=%d,loop=%d,delay=%d\n",thread_num,loop,delay); count = malloc(sizeof(long)); shutdown = malloc(sizeof(int)); *count = 0; *shutdown = 0; sigemptyset(&sigset); sigaddset(&sigset, signum); sigprocmask (SIG_BLOCK, &sigset, NULL); signal(SIGINT, sighand); signal(SIGTERM, sighand); for(i = 0; i < thread_num ; i++) pthread_create(&pt[i], NULL, simple_loop, NULL); for (i = 0; i < thread_num; i++) pthread_join(pt[i], NULL); exit(0); } Get powertop V2 from git://github.com/fenrus75/powertop, build powertop. After build the above test application, then run it. Test plaform can be Intel Sandybridge or other recent platforms. #./idle_predict -l 10 & #./powertop We will find that deep C-state will dangle between 40%~100% and much time spent on C1 state. It is because menu governor wrongly predict that repeat mode is kept, so it will choose the C1 shallow C-state even though it has chance to sleep 1 second in deep C-state. While after patched the kernel, we find that deep C-state will keep >99.6%. Signed-off-by: Rik van Riel Signed-off-by: Youquan Song Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 75 +++++++++++++++++++++++++++++++++++++--- include/linux/tick.h | 6 ++++ kernel/time/tick-sched.c | 4 +++ 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 5b1f2c372c1..37c0ff6c805 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -28,6 +28,13 @@ #define MAX_INTERESTING 50000 #define STDDEV_THRESH 400 +/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */ +#define MAX_DEVIATION 60 + +static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer); +static DEFINE_PER_CPU(int, hrtimer_status); +/* menu hrtimer mode */ +enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT}; /* * Concepts and ideas behind the menu governor @@ -191,17 +198,42 @@ static u64 div_round64(u64 dividend, u32 divisor) return div_u64(dividend + (divisor / 2), divisor); } +/* Cancel the hrtimer if it is not triggered yet */ +void menu_hrtimer_cancel(void) +{ + int cpu = smp_processor_id(); + struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu); + + /* The timer is still not time out*/ + if (per_cpu(hrtimer_status, cpu)) { + hrtimer_cancel(hrtmr); + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; + } +} +EXPORT_SYMBOL_GPL(menu_hrtimer_cancel); + +/* Call back for hrtimer is triggered */ +static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer) +{ + int cpu = smp_processor_id(); + + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; + + return HRTIMER_NORESTART; +} + /* * Try detecting repeating patterns by keeping track of the last 8 * intervals, and checking if the standard deviation of that set * of points is below a threshold. If it is... then use the * average of these 8 points as the estimated value. */ -static void detect_repeating_patterns(struct menu_device *data) +static int detect_repeating_patterns(struct menu_device *data) { int i; uint64_t avg = 0; uint64_t stddev = 0; /* contains the square of the std deviation */ + int ret = 0; /* first calculate average and standard deviation of the past */ for (i = 0; i < INTERVALS; i++) @@ -210,7 +242,7 @@ static void detect_repeating_patterns(struct menu_device *data) /* if the avg is beyond the known next tick, it's worthless */ if (avg > data->expected_us) - return; + return 0; for (i = 0; i < INTERVALS; i++) stddev += (data->intervals[i] - avg) * @@ -223,8 +255,12 @@ static void detect_repeating_patterns(struct menu_device *data) * repeating pattern and predict we keep doing this. */ - if (avg && stddev < STDDEV_THRESH) + if (avg && stddev < STDDEV_THRESH) { data->predicted_us = avg; + ret = 1; + } + + return ret; } /** @@ -240,6 +276,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) int i; int multiplier; struct timespec t; + int repeat = 0, low_predicted = 0; + int cpu = smp_processor_id(); + struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu); if (data->needs_update) { menu_update(drv, dev); @@ -274,7 +313,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); - detect_repeating_patterns(data); + repeat = detect_repeating_patterns(data); /* * We want to default to C1 (hlt), not to busy polling @@ -295,8 +334,10 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (s->disabled || su->disable) continue; - if (s->target_residency > data->predicted_us) + if (s->target_residency > data->predicted_us) { + low_predicted = 1; continue; + } if (s->exit_latency > latency_req) continue; if (s->exit_latency * multiplier > data->predicted_us) @@ -309,6 +350,27 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) } } + /* not deepest C-state chosen for low predicted residency */ + if (low_predicted) { + unsigned int timer_us = 0; + + /* + * Set a timer to detect whether this sleep is much + * longer than repeat mode predicted. If the timer + * triggers, the code will evaluate whether to put + * the CPU into a deeper C-state. + * The timer is cancelled on CPU wakeup. + */ + timer_us = 2 * (data->predicted_us + MAX_DEVIATION); + + if (repeat && (4 * timer_us < data->expected_us)) { + hrtimer_start(hrtmr, ns_to_ktime(1000 * timer_us), + HRTIMER_MODE_REL_PINNED); + /* In repeat case, menu hrtimer is started */ + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT; + } + } + return data->last_state_idx; } @@ -399,6 +461,9 @@ static int menu_enable_device(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); + struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu); + hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + t->function = menu_hrtimer_notify; memset(data, 0, sizeof(struct menu_device)); diff --git a/include/linux/tick.h b/include/linux/tick.h index f37fceb69b7..1a6567b4849 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -142,4 +142,10 @@ static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; } # endif /* !NO_HZ */ +# ifdef CONFIG_CPU_IDLE_GOV_MENU +extern void menu_hrtimer_cancel(void); +# else +static inline void menu_hrtimer_cancel(void) {} +# endif /* CONFIG_CPU_IDLE_GOV_MENU */ + #endif diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index a4026088526..6f337068dc4 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -526,6 +526,8 @@ void tick_nohz_irq_exit(void) if (!ts->inidle) return; + /* Cancel the timer because CPU already waken up from the C-states*/ + menu_hrtimer_cancel(); __tick_nohz_idle_enter(ts); } @@ -621,6 +623,8 @@ void tick_nohz_idle_exit(void) ts->inidle = 0; + /* Cancel the timer because CPU already waken up from the C-states*/ + menu_hrtimer_cancel(); if (ts->idle_active || ts->tick_stopped) now = ktime_get(); -- cgit v1.2.3 From e11538d1f03914eb92af5a1a378375c05ae8520c Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Fri, 26 Oct 2012 12:26:50 +0200 Subject: cpuidle: Quickly notice prediction failure in general case The prediction for future is difficult and when the cpuidle governor prediction fails and govenor possibly choose the shallower C-state than it should. How to quickly notice and find the failure becomes important for power saving. The patch extends to general case that prediction logic get a small predicted residency, so it choose a shallow C-state though the expected residency is large . Once the prediction will be fail, the CPU will keep staying at shallow C-state for a long time. Acutally, the CPU has change enter into deep C-state. So when the expected residency is long enough but governor choose a shallow C-state, an timer will be added in order to monitor if the prediction failure. When C-state is waken up prior to the adding timer, the timer will be cancelled initiatively. When the timer is triggered and menu governor will quickly notice prediction failure and re-evaluates deeper C-states possibility. Signed-off-by: Rik van Riel Signed-off-by: Youquan Song Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 37c0ff6c805..43a54fd6bfa 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -34,7 +34,7 @@ static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer); static DEFINE_PER_CPU(int, hrtimer_status); /* menu hrtimer mode */ -enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT}; +enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL}; /* * Concepts and ideas behind the menu governor @@ -116,6 +116,13 @@ enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT}; * */ +/* + * The C-state residency is so long that is is worthwhile to exit + * from the shallow C-state and re-enter into a deeper C-state. + */ +static unsigned int perfect_cstate_ms __read_mostly = 30; +module_param(perfect_cstate_ms, uint, 0000); + struct menu_device { int last_state_idx; int needs_update; @@ -216,6 +223,16 @@ EXPORT_SYMBOL_GPL(menu_hrtimer_cancel); static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer) { int cpu = smp_processor_id(); + struct menu_device *data = &per_cpu(menu_devices, cpu); + + /* In general case, the expected residency is much larger than + * deepest C-state target residency, but prediction logic still + * predicts a small predicted residency, so the prediction + * history is totally broken if the timer is triggered. + * So reset the correction factor. + */ + if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL) + data->correction_factor[data->bucket] = RESOLUTION * DECAY; per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; @@ -353,6 +370,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) /* not deepest C-state chosen for low predicted residency */ if (low_predicted) { unsigned int timer_us = 0; + unsigned int perfect_us = 0; /* * Set a timer to detect whether this sleep is much @@ -363,12 +381,26 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) */ timer_us = 2 * (data->predicted_us + MAX_DEVIATION); + perfect_us = perfect_cstate_ms * 1000; + if (repeat && (4 * timer_us < data->expected_us)) { hrtimer_start(hrtmr, ns_to_ktime(1000 * timer_us), HRTIMER_MODE_REL_PINNED); /* In repeat case, menu hrtimer is started */ per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT; + } else if (perfect_us < data->expected_us) { + /* + * The next timer is long. This could be because + * we did not make a useful prediction. + * In that case, it makes sense to re-enter + * into a deeper C-state after some time. + */ + hrtimer_start(hrtmr, ns_to_ktime(1000 * timer_us), + HRTIMER_MODE_REL_PINNED); + /* In general case, menu hrtimer is started */ + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL; } + } return data->last_state_idx; -- cgit v1.2.3 From d73d68dc49e09143e8e3bef10670a021c26ec4a5 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Fri, 26 Oct 2012 12:26:59 +0200 Subject: cpuidle: Set residency to 0 if target Cstate not enter When cpuidle governor choose a C-state to enter for idle CPU, but it notice that there is tasks request to be executed. So the idle CPU will not really enter the target C-state and go to run task. In this situation, it will use the residency of previous really entered target C-states. Obviously, it is not reasonable. So, this patch fix it by set the target C-state residency to 0. Signed-off-by: Rik van Riel Signed-off-by: Youquan Song Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index f4b8fc50c0f..ce4cac706dd 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -144,6 +144,10 @@ int cpuidle_idle_call(void) /* ask the governor for the next state */ next_state = cpuidle_curr_governor->select(drv, dev); if (need_resched()) { + dev->last_residency = 0; + /* give the governor an opportunity to reflect on the outcome */ + if (cpuidle_curr_governor->reflect) + cpuidle_curr_governor->reflect(dev, next_state); local_irq_enable(); return 0; } -- cgit v1.2.3 From c96ca4fb76b711279be063da083f09b8d65af5c5 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Fri, 26 Oct 2012 12:27:07 +0200 Subject: cpuidle: Get typical recent sleep interval The function detect_repeating_patterns was not very useful for workloads with alternating long and short pauses, for example virtual machines handling network requests for each other (say a web and database server). Instead, try to find a recent sleep interval that is somewhere between the median and the mode sleep time, by discarding outliers to the up side and recalculating the average and standard deviation until that is no longer required. This should do something sane with a sleep interval series like: 200 180 210 10000 30 1000 170 200 The current code would simply discard such a series, while the new code will guess a typical sleep interval just shy of 200. The original patch come from Rik van Riel . Signed-off-by: Rik van Riel Signed-off-by: Youquan Song Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 69 ++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 43a54fd6bfa..2efee27714a 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -245,36 +245,59 @@ static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer) * of points is below a threshold. If it is... then use the * average of these 8 points as the estimated value. */ -static int detect_repeating_patterns(struct menu_device *data) +static u32 get_typical_interval(struct menu_device *data) { - int i; - uint64_t avg = 0; - uint64_t stddev = 0; /* contains the square of the std deviation */ - int ret = 0; - - /* first calculate average and standard deviation of the past */ - for (i = 0; i < INTERVALS; i++) - avg += data->intervals[i]; - avg = avg / INTERVALS; + int i = 0, divisor = 0; + uint64_t max = 0, avg = 0, stddev = 0; + int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ + unsigned int ret = 0; - /* if the avg is beyond the known next tick, it's worthless */ - if (avg > data->expected_us) - return 0; - - for (i = 0; i < INTERVALS; i++) - stddev += (data->intervals[i] - avg) * - (data->intervals[i] - avg); +again: - stddev = stddev / INTERVALS; + /* first calculate average and standard deviation of the past */ + max = avg = divisor = stddev = 0; + for (i = 0; i < INTERVALS; i++) { + int64_t value = data->intervals[i]; + if (value <= thresh) { + avg += value; + divisor++; + if (value > max) + max = value; + } + } + do_div(avg, divisor); + for (i = 0; i < INTERVALS; i++) { + int64_t value = data->intervals[i]; + if (value <= thresh) { + int64_t diff = value - avg; + stddev += diff * diff; + } + } + do_div(stddev, divisor); + stddev = int_sqrt(stddev); /* - * now.. if stddev is small.. then assume we have a - * repeating pattern and predict we keep doing this. + * If we have outliers to the upside in our distribution, discard + * those by setting the threshold to exclude these outliers, then + * calculate the average and standard deviation again. Once we get + * down to the bottom 3/4 of our samples, stop excluding samples. + * + * This can deal with workloads that have long pauses interspersed + * with sporadic activity with a bunch of short pauses. + * + * The typical interval is obtained when standard deviation is small + * or standard deviation is small compared to the average interval. */ - - if (avg && stddev < STDDEV_THRESH) { + if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) + || stddev <= 20) { data->predicted_us = avg; ret = 1; + return ret; + + } else if ((divisor * 4) > INTERVALS * 3) { + /* Exclude the max interval */ + thresh = max - 1; + goto again; } return ret; @@ -330,7 +353,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); - repeat = detect_repeating_patterns(data); + repeat = get_typical_interval(data); /* * We want to default to C1 (hlt), not to busy polling -- cgit v1.2.3 From 349631e0e411fefa2fed7e0a30b97704562dbd6b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 31 Oct 2012 01:05:16 +0100 Subject: cpuidle / sysfs: move structure declaration into the sysfs.c file The structure cpuidle_state_kobj is not used anywhere except in the sysfs.c file. The definition of this structure is not needed in the cpuidle header file. This patch moves it to the sysfs.c file in order to encapsulate the code a bit more. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/sysfs.c | 7 +++++++ include/linux/cpuidle.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index ed87399bb02..f15c1e56e16 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -297,6 +297,13 @@ static struct attribute *cpuidle_state_default_attrs[] = { NULL }; +struct cpuidle_state_kobj { + struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; + struct completion kobj_unregister; + struct kobject kobj; +}; + #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) #define kobj_to_state(k) (kobj_to_state_obj(k)->state) #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 279b1eaa8b7..7daf0e3b93b 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -82,13 +82,6 @@ cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data) st_usage->driver_data = data; } -struct cpuidle_state_kobj { - struct cpuidle_state *state; - struct cpuidle_state_usage *state_usage; - struct completion kobj_unregister; - struct kobject kobj; -}; - struct cpuidle_device { unsigned int registered:1; unsigned int enabled:1; -- cgit v1.2.3 From 8f3e9953e1e4ae5c11e2e880e7d85c03c0180613 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 31 Oct 2012 01:09:02 +0100 Subject: cpuidle: fixup device.h header in cpuidle.h The "struct device" is only used in sysfs.c. The other .c files including the private header "cpuidle.h" do not need to pull the entire headers tree from there as they don't manipulate the "struct device". This patch fixes this by moving the header inclusion to sysfs.c and adding a forward declaration for the struct device. The number of lines generated by the preprocesor: Without this patch : 17269 loc With this patch : 16446 loc Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.h | 5 +++-- drivers/cpuidle/sysfs.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 2120d9e937c..f6b0923c225 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -5,8 +5,6 @@ #ifndef __DRIVER_CPUIDLE_H #define __DRIVER_CPUIDLE_H -#include - /* For internal use only */ extern struct cpuidle_governor *cpuidle_curr_governor; extern struct list_head cpuidle_governors; @@ -25,6 +23,9 @@ extern void cpuidle_uninstall_idle_handler(void); extern int cpuidle_switch_governor(struct cpuidle_governor *gov); /* sysfs */ + +struct device; + extern int cpuidle_add_interface(struct device *dev); extern void cpuidle_remove_interface(struct device *dev); extern int cpuidle_add_state_sysfs(struct cpuidle_device *device); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index f15c1e56e16..49b1f4bcc1b 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "cpuidle.h" -- cgit v1.2.3 From 42f67f2acab2b7179c0d1ab234869e391448dfa6 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 31 Oct 2012 16:44:45 +0000 Subject: cpuidle: move driver's refcount to cpuidle We want to support different cpuidle drivers co-existing together. In this case we should move the refcount to the cpuidle_driver structure to handle several drivers at a time. Signed-off-by: Daniel Lezcano Acked-by: Peter De Schrijver Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/driver.c | 13 ++++++++----- include/linux/cpuidle.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 87db3877fea..39ba8e181e9 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -16,7 +16,6 @@ static struct cpuidle_driver *cpuidle_curr_driver; DEFINE_SPINLOCK(cpuidle_driver_lock); -int cpuidle_driver_refcount; static void set_power_states(struct cpuidle_driver *drv) { @@ -61,6 +60,8 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) if (!drv->power_specified) set_power_states(drv); + drv->refcnt = 0; + cpuidle_curr_driver = drv; spin_unlock(&cpuidle_driver_lock); @@ -92,7 +93,7 @@ void cpuidle_unregister_driver(struct cpuidle_driver *drv) spin_lock(&cpuidle_driver_lock); - if (!WARN_ON(cpuidle_driver_refcount > 0)) + if (!WARN_ON(drv->refcnt > 0)) cpuidle_curr_driver = NULL; spin_unlock(&cpuidle_driver_lock); @@ -106,7 +107,7 @@ struct cpuidle_driver *cpuidle_driver_ref(void) spin_lock(&cpuidle_driver_lock); drv = cpuidle_curr_driver; - cpuidle_driver_refcount++; + drv->refcnt++; spin_unlock(&cpuidle_driver_lock); return drv; @@ -114,10 +115,12 @@ struct cpuidle_driver *cpuidle_driver_ref(void) void cpuidle_driver_unref(void) { + struct cpuidle_driver *drv = cpuidle_curr_driver; + spin_lock(&cpuidle_driver_lock); - if (!WARN_ON(cpuidle_driver_refcount <= 0)) - cpuidle_driver_refcount--; + if (drv && !WARN_ON(drv->refcnt <= 0)) + drv->refcnt--; spin_unlock(&cpuidle_driver_lock); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 7daf0e3b93b..d08e1afa491 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -124,6 +124,7 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev) struct cpuidle_driver { const char *name; struct module *owner; + int refcnt; unsigned int power_specified:1; /* set to 1 to use the core cpuidle time keeping (for all states). */ -- cgit v1.2.3 From 41682032715c2c969357c81391a442a24dd1c2c2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 31 Oct 2012 16:44:46 +0000 Subject: cpuidle: move driver checking within the lock section The code is racy and the check with cpuidle_curr_driver should be done under the lock. I don't find a path in the different drivers where that could happen because the arch specific drivers are written in such way it is not possible to register a driver while it is unregistered, except maybe in a very improbable case when "intel_idle" and "processor_idle" are competing. One could unregister a driver, while the other one is registering. Signed-off-by: Daniel Lezcano Acked-by: Peter De Schrijver Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/driver.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 39ba8e181e9..3e590756923 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -85,17 +85,9 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver); */ void cpuidle_unregister_driver(struct cpuidle_driver *drv) { - if (drv != cpuidle_curr_driver) { - WARN(1, "invalid cpuidle_unregister_driver(%s)\n", - drv->name); - return; - } - spin_lock(&cpuidle_driver_lock); - - if (!WARN_ON(drv->refcnt > 0)) + if (drv == cpuidle_curr_driver && !WARN_ON(drv->refcnt > 0)) cpuidle_curr_driver = NULL; - spin_unlock(&cpuidle_driver_lock); } EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); -- cgit v1.2.3 From 13dd52f11a04e616900f565d6a1e5138e58d579f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 31 Oct 2012 16:44:47 +0000 Subject: cpuidle: prepare the cpuidle core to handle multiple drivers This patch is a preparation for the multiple cpuidle drivers support. As the next patch will introduce the multiple drivers with the Kconfig option and we want to keep the code clean and understandable, this patch defines a set of functions for encapsulating some common parts and splits what should be done under a lock from the rest. [rjw: Modified the subject and changelog slightly.] Signed-off-by: Daniel Lezcano Acked-by: Peter De Schrijver Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/driver.c | 60 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 3e590756923..8246662f594 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -39,11 +39,20 @@ static void set_power_states(struct cpuidle_driver *drv) drv->states[i].power_usage = -1 - i; } -/** - * cpuidle_register_driver - registers a driver - * @drv: the driver - */ -int cpuidle_register_driver(struct cpuidle_driver *drv) +static void __cpuidle_driver_init(struct cpuidle_driver *drv) +{ + drv->refcnt = 0; + + if (!drv->power_specified) + set_power_states(drv); +} + +static void cpuidle_set_driver(struct cpuidle_driver *drv) +{ + cpuidle_curr_driver = drv; +} + +static int __cpuidle_register_driver(struct cpuidle_driver *drv) { if (!drv || !drv->state_count) return -EINVAL; @@ -51,22 +60,38 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) if (cpuidle_disabled()) return -ENODEV; - spin_lock(&cpuidle_driver_lock); - if (cpuidle_curr_driver) { - spin_unlock(&cpuidle_driver_lock); + if (cpuidle_get_driver()) return -EBUSY; - } - if (!drv->power_specified) - set_power_states(drv); + __cpuidle_driver_init(drv); - drv->refcnt = 0; + cpuidle_set_driver(drv); - cpuidle_curr_driver = drv; + return 0; +} + +static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) +{ + if (drv != cpuidle_get_driver()) + return; + + if (!WARN_ON(drv->refcnt > 0)) + cpuidle_set_driver(NULL); +} +/** + * cpuidle_register_driver - registers a driver + * @drv: the driver + */ +int cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int ret; + + spin_lock(&cpuidle_driver_lock); + ret = __cpuidle_register_driver(drv); spin_unlock(&cpuidle_driver_lock); - return 0; + return ret; } EXPORT_SYMBOL_GPL(cpuidle_register_driver); @@ -86,8 +111,7 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver); void cpuidle_unregister_driver(struct cpuidle_driver *drv) { spin_lock(&cpuidle_driver_lock); - if (drv == cpuidle_curr_driver && !WARN_ON(drv->refcnt > 0)) - cpuidle_curr_driver = NULL; + __cpuidle_unregister_driver(drv); spin_unlock(&cpuidle_driver_lock); } EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); @@ -98,7 +122,7 @@ struct cpuidle_driver *cpuidle_driver_ref(void) spin_lock(&cpuidle_driver_lock); - drv = cpuidle_curr_driver; + drv = cpuidle_get_driver(); drv->refcnt++; spin_unlock(&cpuidle_driver_lock); @@ -107,7 +131,7 @@ struct cpuidle_driver *cpuidle_driver_ref(void) void cpuidle_driver_unref(void) { - struct cpuidle_driver *drv = cpuidle_curr_driver; + struct cpuidle_driver *drv = cpuidle_get_driver(); spin_lock(&cpuidle_driver_lock); -- cgit v1.2.3 From bf4d1b5ddb78f86078ac6ae0415802d5f0c68f92 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 31 Oct 2012 16:44:48 +0000 Subject: cpuidle: support multiple drivers With the tegra3 and the big.LITTLE [1] new architectures, several cpus with different characteristics (latencies and states) can co-exists on the system. The cpuidle framework has the limitation of handling only identical cpus. This patch removes this limitation by introducing the multiple driver support for cpuidle. This option is configurable at compile time and should be enabled for the architectures mentioned above. So there is no impact for the other platforms if the option is disabled. The option defaults to 'n'. Note the multiple drivers support is also compatible with the existing drivers, even if just one driver is needed, all the cpu will be tied to this driver using an extra small chunk of processor memory. The multiple driver support use a per-cpu driver pointer instead of a global variable and the accessor to this variable are done from a cpu context. In order to keep the compatibility with the existing drivers, the function 'cpuidle_register_driver' and 'cpuidle_unregister_driver' will register the specified driver for all the cpus. The semantic for the output of /sys/devices/system/cpu/cpuidle/current_driver remains the same except the driver name will be related to the current cpu. The /sys/devices/system/cpu/cpu[0-9]/cpuidle/driver/name files are added allowing to read the per cpu driver name. [1] http://lwn.net/Articles/481055/ Signed-off-by: Daniel Lezcano Acked-by: Peter De Schrijver Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/Kconfig | 9 +++ drivers/cpuidle/cpuidle.c | 36 ++++++---- drivers/cpuidle/cpuidle.h | 4 +- drivers/cpuidle/driver.c | 166 ++++++++++++++++++++++++++++++++++++++----- drivers/cpuidle/sysfs.c | 174 ++++++++++++++++++++++++++++++++++++++++++++-- include/linux/cpuidle.h | 7 +- 6 files changed, 356 insertions(+), 40 deletions(-) diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index a76b689e553..234ae651b38 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -9,6 +9,15 @@ config CPU_IDLE If you're using an ACPI-enabled platform, you should say Y here. +config CPU_IDLE_MULTIPLE_DRIVERS + bool "Support multiple cpuidle drivers" + depends on CPU_IDLE + default n + help + Allows the cpuidle framework to use different drivers for each CPU. + This is useful if you have a system with different CPU latencies and + states. If unsure say N. + config CPU_IDLE_GOV_LADDER bool depends on CPU_IDLE diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index ce4cac706dd..711dd83fd3b 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -68,7 +68,7 @@ static cpuidle_enter_t cpuidle_enter_ops; int cpuidle_play_dead(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); int i, dead_state = -1; int power_usage = -1; @@ -128,7 +128,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv; int next_state, entered_state; if (off) @@ -141,6 +141,8 @@ int cpuidle_idle_call(void) if (!dev || !dev->enabled) return -EBUSY; + drv = cpuidle_get_cpu_driver(dev); + /* ask the governor for the next state */ next_state = cpuidle_curr_governor->select(drv, dev); if (need_resched()) { @@ -312,15 +314,19 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} int cpuidle_enable_device(struct cpuidle_device *dev) { int ret, i; - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv; if (!dev) return -EINVAL; if (dev->enabled) return 0; + + drv = cpuidle_get_cpu_driver(dev); + if (!drv || !cpuidle_curr_governor) return -EIO; + if (!dev->state_count) dev->state_count = drv->state_count; @@ -335,7 +341,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev) poll_idle_init(drv); - if ((ret = cpuidle_add_state_sysfs(dev))) + ret = cpuidle_add_device_sysfs(dev); + if (ret) return ret; if (cpuidle_curr_governor->enable && @@ -356,7 +363,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return 0; fail_sysfs: - cpuidle_remove_state_sysfs(dev); + cpuidle_remove_device_sysfs(dev); return ret; } @@ -372,17 +379,20 @@ EXPORT_SYMBOL_GPL(cpuidle_enable_device); */ void cpuidle_disable_device(struct cpuidle_device *dev) { + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + if (!dev || !dev->enabled) return; - if (!cpuidle_get_driver() || !cpuidle_curr_governor) + + if (!drv || !cpuidle_curr_governor) return; dev->enabled = 0; if (cpuidle_curr_governor->disable) - cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); + cpuidle_curr_governor->disable(drv, dev); - cpuidle_remove_state_sysfs(dev); + cpuidle_remove_device_sysfs(dev); enabled_devices--; } @@ -398,9 +408,9 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device); static int __cpuidle_register_device(struct cpuidle_device *dev) { int ret; - struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - if (!try_module_get(cpuidle_driver->owner)) + if (!try_module_get(drv->owner)) return -EINVAL; per_cpu(cpuidle_devices, dev->cpu) = dev; @@ -421,7 +431,7 @@ err_coupled: err_sysfs: list_del(&dev->device_list); per_cpu(cpuidle_devices, dev->cpu) = NULL; - module_put(cpuidle_driver->owner); + module_put(drv->owner); return ret; } @@ -460,7 +470,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device); */ void cpuidle_unregister_device(struct cpuidle_device *dev) { - struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); if (dev->registered == 0) return; @@ -477,7 +487,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) cpuidle_resume_and_unlock(); - module_put(cpuidle_driver->owner); + module_put(drv->owner); } EXPORT_SYMBOL_GPL(cpuidle_unregister_device); diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index f6b0923c225..ee97e9672ec 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -28,8 +28,8 @@ struct device; extern int cpuidle_add_interface(struct device *dev); extern void cpuidle_remove_interface(struct device *dev); -extern int cpuidle_add_state_sysfs(struct cpuidle_device *device); -extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device); +extern int cpuidle_add_device_sysfs(struct cpuidle_device *device); +extern void cpuidle_remove_device_sysfs(struct cpuidle_device *device); extern int cpuidle_add_sysfs(struct cpuidle_device *dev); extern void cpuidle_remove_sysfs(struct cpuidle_device *dev); diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 8246662f594..3af841fb397 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -14,9 +14,11 @@ #include "cpuidle.h" -static struct cpuidle_driver *cpuidle_curr_driver; DEFINE_SPINLOCK(cpuidle_driver_lock); +static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); +static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); + static void set_power_states(struct cpuidle_driver *drv) { int i; @@ -47,12 +49,7 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv) set_power_states(drv); } -static void cpuidle_set_driver(struct cpuidle_driver *drv) -{ - cpuidle_curr_driver = drv; -} - -static int __cpuidle_register_driver(struct cpuidle_driver *drv) +static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) { if (!drv || !drv->state_count) return -EINVAL; @@ -60,23 +57,84 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv) if (cpuidle_disabled()) return -ENODEV; - if (cpuidle_get_driver()) + if (__cpuidle_get_cpu_driver(cpu)) return -EBUSY; __cpuidle_driver_init(drv); - cpuidle_set_driver(drv); + __cpuidle_set_cpu_driver(drv, cpu); return 0; } -static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) +static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu) { - if (drv != cpuidle_get_driver()) + if (drv != __cpuidle_get_cpu_driver(cpu)) return; if (!WARN_ON(drv->refcnt > 0)) - cpuidle_set_driver(NULL); + __cpuidle_set_cpu_driver(NULL, cpu); +} + +#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS + +static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers); + +static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + per_cpu(cpuidle_drivers, cpu) = drv; +} + +static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu) +{ + return per_cpu(cpuidle_drivers, cpu); +} + +static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv) +{ + int cpu; + for_each_present_cpu(cpu) + __cpuidle_unregister_driver(drv, cpu); +} + +static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv) +{ + int ret = 0; + int i, cpu; + + for_each_present_cpu(cpu) { + ret = __cpuidle_register_driver(drv, cpu); + if (ret) + break; + } + + if (ret) + for_each_present_cpu(i) { + if (i == cpu) + break; + __cpuidle_unregister_driver(drv, i); + } + + + return ret; +} + +int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + int ret; + + spin_lock(&cpuidle_driver_lock); + ret = __cpuidle_register_driver(drv, cpu); + spin_unlock(&cpuidle_driver_lock); + + return ret; +} + +void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + spin_lock(&cpuidle_driver_lock); + __cpuidle_unregister_driver(drv, cpu); + spin_unlock(&cpuidle_driver_lock); } /** @@ -88,7 +146,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) int ret; spin_lock(&cpuidle_driver_lock); - ret = __cpuidle_register_driver(drv); + ret = __cpuidle_register_all_cpu_driver(drv); spin_unlock(&cpuidle_driver_lock); return ret; @@ -96,13 +154,48 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) EXPORT_SYMBOL_GPL(cpuidle_register_driver); /** - * cpuidle_get_driver - return the current driver + * cpuidle_unregister_driver - unregisters a driver + * @drv: the driver */ -struct cpuidle_driver *cpuidle_get_driver(void) +void cpuidle_unregister_driver(struct cpuidle_driver *drv) +{ + spin_lock(&cpuidle_driver_lock); + __cpuidle_unregister_all_cpu_driver(drv); + spin_unlock(&cpuidle_driver_lock); +} +EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); + +#else + +static struct cpuidle_driver *cpuidle_curr_driver; + +static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + cpuidle_curr_driver = drv; +} + +static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu) { return cpuidle_curr_driver; } -EXPORT_SYMBOL_GPL(cpuidle_get_driver); + +/** + * cpuidle_register_driver - registers a driver + * @drv: the driver + */ +int cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int ret, cpu; + + cpu = get_cpu(); + spin_lock(&cpuidle_driver_lock); + ret = __cpuidle_register_driver(drv, cpu); + spin_unlock(&cpuidle_driver_lock); + put_cpu(); + + return ret; +} +EXPORT_SYMBOL_GPL(cpuidle_register_driver); /** * cpuidle_unregister_driver - unregisters a driver @@ -110,11 +203,50 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver); */ void cpuidle_unregister_driver(struct cpuidle_driver *drv) { + int cpu; + + cpu = get_cpu(); spin_lock(&cpuidle_driver_lock); - __cpuidle_unregister_driver(drv); + __cpuidle_unregister_driver(drv, cpu); spin_unlock(&cpuidle_driver_lock); + put_cpu(); } EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); +#endif + +/** + * cpuidle_get_driver - return the current driver + */ +struct cpuidle_driver *cpuidle_get_driver(void) +{ + struct cpuidle_driver *drv; + int cpu; + + cpu = get_cpu(); + drv = __cpuidle_get_cpu_driver(cpu); + put_cpu(); + + return drv; +} +EXPORT_SYMBOL_GPL(cpuidle_get_driver); + +/** + * cpuidle_get_cpu_driver - return the driver tied with a cpu + */ +struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev) +{ + struct cpuidle_driver *drv; + + if (!dev) + return NULL; + + spin_lock(&cpuidle_driver_lock); + drv = __cpuidle_get_cpu_driver(dev->cpu); + spin_unlock(&cpuidle_driver_lock); + + return drv; +} +EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver); struct cpuidle_driver *cpuidle_driver_ref(void) { diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 49b1f4bcc1b..34094294610 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -364,17 +364,17 @@ static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i) } /** - * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes + * cpuidle_add_state_sysfs - adds cpuidle states sysfs attributes * @device: the target device */ -int cpuidle_add_state_sysfs(struct cpuidle_device *device) +static int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); /* state statistics */ - for (i = 0; i < device->state_count; i++) { + for (i = 0; i < drv->state_count; i++) { kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); if (!kobj) goto error_state; @@ -401,10 +401,10 @@ error_state: } /** - * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes + * cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes * @device: the target device */ -void cpuidle_remove_state_sysfs(struct cpuidle_device *device) +static void cpuidle_remove_state_sysfs(struct cpuidle_device *device) { int i; @@ -412,6 +412,168 @@ void cpuidle_remove_state_sysfs(struct cpuidle_device *device) cpuidle_free_state_kobj(device, i); } +#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS +#define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj) +#define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr) + +#define define_one_driver_ro(_name, show) \ + static struct cpuidle_driver_attr attr_driver_##_name = \ + __ATTR(_name, 0644, show, NULL) + +struct cpuidle_driver_kobj { + struct cpuidle_driver *drv; + struct completion kobj_unregister; + struct kobject kobj; +}; + +struct cpuidle_driver_attr { + struct attribute attr; + ssize_t (*show)(struct cpuidle_driver *, char *); + ssize_t (*store)(struct cpuidle_driver *, const char *, size_t); +}; + +static ssize_t show_driver_name(struct cpuidle_driver *drv, char *buf) +{ + ssize_t ret; + + spin_lock(&cpuidle_driver_lock); + ret = sprintf(buf, "%s\n", drv ? drv->name : "none"); + spin_unlock(&cpuidle_driver_lock); + + return ret; +} + +static void cpuidle_driver_sysfs_release(struct kobject *kobj) +{ + struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); + complete(&driver_kobj->kobj_unregister); +} + +static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr, + char * buf) +{ + int ret = -EIO; + struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); + struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr); + + if (dattr->show) + ret = dattr->show(driver_kobj->drv, buf); + + return ret; +} + +static ssize_t cpuidle_driver_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + int ret = -EIO; + struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); + struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr); + + if (dattr->store) + ret = dattr->store(driver_kobj->drv, buf, size); + + return ret; +} + +define_one_driver_ro(name, show_driver_name); + +static const struct sysfs_ops cpuidle_driver_sysfs_ops = { + .show = cpuidle_driver_show, + .store = cpuidle_driver_store, +}; + +static struct attribute *cpuidle_driver_default_attrs[] = { + &attr_driver_name.attr, + NULL +}; + +static struct kobj_type ktype_driver_cpuidle = { + .sysfs_ops = &cpuidle_driver_sysfs_ops, + .default_attrs = cpuidle_driver_default_attrs, + .release = cpuidle_driver_sysfs_release, +}; + +/** + * cpuidle_add_driver_sysfs - adds the driver name sysfs attribute + * @device: the target device + */ +static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) +{ + struct cpuidle_driver_kobj *kdrv; + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + int ret; + + kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL); + if (!kdrv) + return -ENOMEM; + + kdrv->drv = drv; + init_completion(&kdrv->kobj_unregister); + + ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, + &dev->kobj, "driver"); + if (ret) { + kfree(kdrv); + return ret; + } + + kobject_uevent(&kdrv->kobj, KOBJ_ADD); + dev->kobj_driver = kdrv; + + return ret; +} + +/** + * cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute + * @device: the target device + */ +static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev) +{ + struct cpuidle_driver_kobj *kdrv = dev->kobj_driver; + kobject_put(&kdrv->kobj); + wait_for_completion(&kdrv->kobj_unregister); + kfree(kdrv); +} +#else +static inline int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) +{ + return 0; +} + +static inline void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev) +{ + ; +} +#endif + +/** + * cpuidle_add_device_sysfs - adds device specific sysfs attributes + * @device: the target device + */ +int cpuidle_add_device_sysfs(struct cpuidle_device *device) +{ + int ret; + + ret = cpuidle_add_state_sysfs(device); + if (ret) + return ret; + + ret = cpuidle_add_driver_sysfs(device); + if (ret) + cpuidle_remove_state_sysfs(device); + return ret; +} + +/** + * cpuidle_remove_device_sysfs : removes device specific sysfs attributes + * @device : the target device + */ +void cpuidle_remove_device_sysfs(struct cpuidle_device *device) +{ + cpuidle_remove_driver_sysfs(device); + cpuidle_remove_state_sysfs(device); +} + /** * cpuidle_add_sysfs - creates a sysfs instance for the target device * @dev: the target device diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index d08e1afa491..3711b34dc4f 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -91,7 +91,7 @@ struct cpuidle_device { int state_count; struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; - + struct cpuidle_driver_kobj *kobj_driver; struct list_head device_list; struct kobject kobj; struct completion kobj_unregister; @@ -157,6 +157,10 @@ extern int cpuidle_wrap_enter(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)); extern int cpuidle_play_dead(void); +extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); +extern int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu); +extern void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu); + #else static inline void disable_cpuidle(void) { } static inline int cpuidle_idle_call(void) { return -ENODEV; } @@ -183,7 +187,6 @@ static inline int cpuidle_wrap_enter(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)) { return -ENODEV; } static inline int cpuidle_play_dead(void) {return -ENODEV; } - #endif #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED -- cgit v1.2.3 From 7e6fdd4bad033fa2d73716377b184fa975b0d985 Mon Sep 17 00:00:00 2001 From: Rajagopal Venkat Date: Fri, 26 Oct 2012 01:50:09 +0200 Subject: PM / devfreq: Core updates to support devices which can idle Prepare devfreq core framework to support devices which can idle. When device idleness is detected perhaps through runtime-pm, need some mechanism to suspend devfreq load monitoring and resume back when device is online. Present code continues monitoring unless device is removed from devfreq core. This patch introduces following design changes, - use per device work instead of global work to monitor device load. This enables suspend/resume of device devfreq and reduces monitoring code complexity. - decouple delayed work based load monitoring logic from core by introducing helpers functions to be used by governors. This provides flexibility for governors either to use delayed work based monitoring functions or to implement their own mechanism. - devfreq core interacts with governors via events to perform specific actions. These events include start/stop devfreq. This sets ground for adding suspend/resume events. The devfreq apis are not modified and are kept intact. Signed-off-by: Rajagopal Venkat Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-class-devfreq | 8 - drivers/devfreq/devfreq.c | 442 +++++++++++--------------- drivers/devfreq/governor.h | 11 + drivers/devfreq/governor_performance.c | 16 +- drivers/devfreq/governor_powersave.c | 16 +- drivers/devfreq/governor_simpleondemand.c | 24 ++ drivers/devfreq/governor_userspace.c | 23 +- include/linux/devfreq.h | 34 +- 8 files changed, 278 insertions(+), 296 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index 23d78b5aab1..89283b1b024 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -21,14 +21,6 @@ Description: The /sys/class/devfreq/.../cur_freq shows the current frequency of the corresponding devfreq object. -What: /sys/class/devfreq/.../central_polling -Date: September 2011 -Contact: MyungJoo Ham -Description: - The /sys/class/devfreq/.../central_polling shows whether - the devfreq ojbect is using devfreq-provided central - polling mechanism or not. - What: /sys/class/devfreq/.../polling_interval Date: September 2011 Contact: MyungJoo Ham diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index b146d76f04c..1aaf1aeb1f1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -30,17 +30,11 @@ struct class *devfreq_class; /* - * devfreq_work periodically monitors every registered device. - * The minimum polling interval is one jiffy. The polling interval is - * determined by the minimum polling period among all polling devfreq - * devices. The resolution of polling interval is one jiffy. + * devfreq core provides delayed work based load monitoring helper + * functions. Governors can use these or can implement their own + * monitoring mechanism. */ -static bool polling; static struct workqueue_struct *devfreq_wq; -static struct delayed_work devfreq_work; - -/* wait removing if this is to be removed */ -static struct devfreq *wait_remove_device; /* The list of all device-devfreq */ static LIST_HEAD(devfreq_list); @@ -72,6 +66,8 @@ static struct devfreq *find_device_devfreq(struct device *dev) return ERR_PTR(-ENODEV); } +/* Load monitoring helper functions for governors use */ + /** * update_devfreq() - Reevaluate the device and configure frequency. * @devfreq: the devfreq instance. @@ -120,6 +116,152 @@ int update_devfreq(struct devfreq *devfreq) return err; } +/** + * devfreq_monitor() - Periodically poll devfreq objects. + * @work: the work struct used to run devfreq_monitor periodically. + * + */ +static void devfreq_monitor(struct work_struct *work) +{ + int err; + struct devfreq *devfreq = container_of(work, + struct devfreq, work.work); + + mutex_lock(&devfreq->lock); + err = update_devfreq(devfreq); + if (err) + dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err); + + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + mutex_unlock(&devfreq->lock); +} + +/** + * devfreq_monitor_start() - Start load monitoring of devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function for starting devfreq device load monitoing. By + * default delayed work based monitoring is supported. Function + * to be called from governor in response to DEVFREQ_GOV_START + * event when device is added to devfreq framework. + */ +void devfreq_monitor_start(struct devfreq *devfreq) +{ + INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor); + if (devfreq->profile->polling_ms) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); +} + +/** + * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function to stop devfreq device load monitoing. Function + * to be called from governor in response to DEVFREQ_GOV_STOP + * event when device is removed from devfreq framework. + */ +void devfreq_monitor_stop(struct devfreq *devfreq) +{ + cancel_delayed_work_sync(&devfreq->work); +} + +/** + * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function to suspend devfreq device load monitoing. Function + * to be called from governor in response to DEVFREQ_GOV_SUSPEND + * event or when polling interval is set to zero. + * + * Note: Though this function is same as devfreq_monitor_stop(), + * intentionally kept separate to provide hooks for collecting + * transition statistics. + */ +void devfreq_monitor_suspend(struct devfreq *devfreq) +{ + mutex_lock(&devfreq->lock); + if (devfreq->stop_polling) { + mutex_unlock(&devfreq->lock); + return; + } + + devfreq->stop_polling = true; + mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); +} + +/** + * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function to resume devfreq device load monitoing. Function + * to be called from governor in response to DEVFREQ_GOV_RESUME + * event or when polling interval is set to non-zero. + */ +void devfreq_monitor_resume(struct devfreq *devfreq) +{ + mutex_lock(&devfreq->lock); + if (!devfreq->stop_polling) + goto out; + + if (!delayed_work_pending(&devfreq->work) && + devfreq->profile->polling_ms) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + devfreq->stop_polling = false; + +out: + mutex_unlock(&devfreq->lock); +} + +/** + * devfreq_interval_update() - Update device devfreq monitoring interval + * @devfreq: the devfreq instance. + * @delay: new polling interval to be set. + * + * Helper function to set new load monitoring polling interval. Function + * to be called from governor in response to DEVFREQ_GOV_INTERVAL event. + */ +void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay) +{ + unsigned int cur_delay = devfreq->profile->polling_ms; + unsigned int new_delay = *delay; + + mutex_lock(&devfreq->lock); + devfreq->profile->polling_ms = new_delay; + + if (devfreq->stop_polling) + goto out; + + /* if new delay is zero, stop polling */ + if (!new_delay) { + mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); + return; + } + + /* if current delay is zero, start polling with new delay */ + if (!cur_delay) { + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + goto out; + } + + /* if current delay is greater than new delay, restart polling */ + if (cur_delay > new_delay) { + mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); + mutex_lock(&devfreq->lock); + if (!devfreq->stop_polling) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + } +out: + mutex_unlock(&devfreq->lock); +} + /** * devfreq_notifier_call() - Notify that the device frequency requirements * has been changed out of devfreq framework. @@ -143,59 +285,32 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, } /** - * _remove_devfreq() - Remove devfreq from the device. + * _remove_devfreq() - Remove devfreq from the list and release its resources. * @devfreq: the devfreq struct * @skip: skip calling device_unregister(). - * - * Note that the caller should lock devfreq->lock before calling - * this. _remove_devfreq() will unlock it and free devfreq - * internally. devfreq_list_lock should be locked by the caller - * as well (not relased at return) - * - * Lock usage: - * devfreq->lock: locked before call. - * unlocked at return (and freed) - * devfreq_list_lock: locked before call. - * kept locked at return. - * if devfreq is centrally polled. - * - * Freed memory: - * devfreq */ static void _remove_devfreq(struct devfreq *devfreq, bool skip) { - if (!mutex_is_locked(&devfreq->lock)) { - WARN(true, "devfreq->lock must be locked by the caller.\n"); - return; - } - if (!devfreq->governor->no_central_polling && - !mutex_is_locked(&devfreq_list_lock)) { - WARN(true, "devfreq_list_lock must be locked by the caller.\n"); + mutex_lock(&devfreq_list_lock); + if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { + mutex_unlock(&devfreq_list_lock); + dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n"); return; } + list_del(&devfreq->node); + mutex_unlock(&devfreq_list_lock); - if (devfreq->being_removed) - return; - - devfreq->being_removed = true; + devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL); if (devfreq->profile->exit) devfreq->profile->exit(devfreq->dev.parent); - if (devfreq->governor->exit) - devfreq->governor->exit(devfreq); - if (!skip && get_device(&devfreq->dev)) { device_unregister(&devfreq->dev); put_device(&devfreq->dev); } - if (!devfreq->governor->no_central_polling) - list_del(&devfreq->node); - - mutex_unlock(&devfreq->lock); mutex_destroy(&devfreq->lock); - kfree(devfreq); } @@ -210,130 +325,8 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip) static void devfreq_dev_release(struct device *dev) { struct devfreq *devfreq = to_devfreq(dev); - bool central_polling = !devfreq->governor->no_central_polling; - - /* - * If devfreq_dev_release() was called by device_unregister() of - * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and - * being_removed is already set. This also partially checks the case - * where devfreq_dev_release() is called from a thread other than - * the one called _remove_devfreq(); however, this case is - * dealt completely with another following being_removed check. - * - * Because being_removed is never being - * unset, we do not need to worry about race conditions on - * being_removed. - */ - if (devfreq->being_removed) - return; - if (central_polling) - mutex_lock(&devfreq_list_lock); - - mutex_lock(&devfreq->lock); - - /* - * Check being_removed flag again for the case where - * devfreq_dev_release() was called in a thread other than the one - * possibly called _remove_devfreq(). - */ - if (devfreq->being_removed) { - mutex_unlock(&devfreq->lock); - goto out; - } - - /* devfreq->lock is unlocked and removed in _removed_devfreq() */ _remove_devfreq(devfreq, true); - -out: - if (central_polling) - mutex_unlock(&devfreq_list_lock); -} - -/** - * devfreq_monitor() - Periodically poll devfreq objects. - * @work: the work struct used to run devfreq_monitor periodically. - * - */ -static void devfreq_monitor(struct work_struct *work) -{ - static unsigned long last_polled_at; - struct devfreq *devfreq, *tmp; - int error; - unsigned long jiffies_passed; - unsigned long next_jiffies = ULONG_MAX, now = jiffies; - struct device *dev; - - /* Initially last_polled_at = 0, polling every device at bootup */ - jiffies_passed = now - last_polled_at; - last_polled_at = now; - if (jiffies_passed == 0) - jiffies_passed = 1; - - mutex_lock(&devfreq_list_lock); - list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) { - mutex_lock(&devfreq->lock); - dev = devfreq->dev.parent; - - /* Do not remove tmp for a while */ - wait_remove_device = tmp; - - if (devfreq->governor->no_central_polling || - devfreq->next_polling == 0) { - mutex_unlock(&devfreq->lock); - continue; - } - mutex_unlock(&devfreq_list_lock); - - /* - * Reduce more next_polling if devfreq_wq took an extra - * delay. (i.e., CPU has been idled.) - */ - if (devfreq->next_polling <= jiffies_passed) { - error = update_devfreq(devfreq); - - /* Remove a devfreq with an error. */ - if (error && error != -EAGAIN) { - - dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n", - error, devfreq->governor->name); - - /* - * Unlock devfreq before locking the list - * in order to avoid deadlock with - * find_device_devfreq or others - */ - mutex_unlock(&devfreq->lock); - mutex_lock(&devfreq_list_lock); - /* Check if devfreq is already removed */ - if (IS_ERR(find_device_devfreq(dev))) - continue; - mutex_lock(&devfreq->lock); - /* This unlocks devfreq->lock and free it */ - _remove_devfreq(devfreq, false); - continue; - } - devfreq->next_polling = devfreq->polling_jiffies; - } else { - devfreq->next_polling -= jiffies_passed; - } - - if (devfreq->next_polling) - next_jiffies = (next_jiffies > devfreq->next_polling) ? - devfreq->next_polling : next_jiffies; - - mutex_unlock(&devfreq->lock); - mutex_lock(&devfreq_list_lock); - } - wait_remove_device = NULL; - mutex_unlock(&devfreq_list_lock); - - if (next_jiffies > 0 && next_jiffies < ULONG_MAX) { - polling = true; - queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies); - } else { - polling = false; - } } /** @@ -357,16 +350,13 @@ struct devfreq *devfreq_add_device(struct device *dev, return ERR_PTR(-EINVAL); } - - if (!governor->no_central_polling) { - mutex_lock(&devfreq_list_lock); - devfreq = find_device_devfreq(dev); - mutex_unlock(&devfreq_list_lock); - if (!IS_ERR(devfreq)) { - dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__); - err = -EINVAL; - goto err_out; - } + mutex_lock(&devfreq_list_lock); + devfreq = find_device_devfreq(dev); + mutex_unlock(&devfreq_list_lock); + if (!IS_ERR(devfreq)) { + dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__); + err = -EINVAL; + goto err_out; } devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL); @@ -386,48 +376,41 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->governor = governor; devfreq->previous_freq = profile->initial_freq; devfreq->data = data; - devfreq->next_polling = devfreq->polling_jiffies - = msecs_to_jiffies(devfreq->profile->polling_ms); devfreq->nb.notifier_call = devfreq_notifier_call; dev_set_name(&devfreq->dev, dev_name(dev)); err = device_register(&devfreq->dev); if (err) { put_device(&devfreq->dev); + mutex_unlock(&devfreq->lock); goto err_dev; } - if (governor->init) - err = governor->init(devfreq); - if (err) - goto err_init; - mutex_unlock(&devfreq->lock); - if (governor->no_central_polling) - goto out; - mutex_lock(&devfreq_list_lock); - list_add(&devfreq->node, &devfreq_list); + mutex_unlock(&devfreq_list_lock); - if (devfreq_wq && devfreq->next_polling && !polling) { - polling = true; - queue_delayed_work(devfreq_wq, &devfreq_work, - devfreq->next_polling); + err = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_START, NULL); + if (err) { + dev_err(dev, "%s: Unable to start governor for the device\n", + __func__); + goto err_init; } - mutex_unlock(&devfreq_list_lock); -out: + return devfreq; err_init: + list_del(&devfreq->node); device_unregister(&devfreq->dev); err_dev: - mutex_unlock(&devfreq->lock); kfree(devfreq); err_out: return ERR_PTR(err); } +EXPORT_SYMBOL(devfreq_add_device); /** * devfreq_remove_device() - Remove devfreq feature from a device. @@ -435,30 +418,14 @@ err_out: */ int devfreq_remove_device(struct devfreq *devfreq) { - bool central_polling; - if (!devfreq) return -EINVAL; - central_polling = !devfreq->governor->no_central_polling; - - if (central_polling) { - mutex_lock(&devfreq_list_lock); - while (wait_remove_device == devfreq) { - mutex_unlock(&devfreq_list_lock); - schedule(); - mutex_lock(&devfreq_list_lock); - } - } - - mutex_lock(&devfreq->lock); - _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */ - - if (central_polling) - mutex_unlock(&devfreq_list_lock); + _remove_devfreq(devfreq, false); return 0; } +EXPORT_SYMBOL(devfreq_remove_device); static ssize_t show_governor(struct device *dev, struct device_attribute *attr, char *buf) @@ -490,35 +457,13 @@ static ssize_t store_polling_interval(struct device *dev, if (ret != 1) goto out; - mutex_lock(&df->lock); - df->profile->polling_ms = value; - df->next_polling = df->polling_jiffies - = msecs_to_jiffies(value); - mutex_unlock(&df->lock); - + df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value); ret = count; - if (df->governor->no_central_polling) - goto out; - - mutex_lock(&devfreq_list_lock); - if (df->next_polling > 0 && !polling) { - polling = true; - queue_delayed_work(devfreq_wq, &devfreq_work, - df->next_polling); - } - mutex_unlock(&devfreq_list_lock); out: return ret; } -static ssize_t show_central_polling(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", - !to_devfreq(dev)->governor->no_central_polling); -} - static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -590,7 +535,6 @@ static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr, static struct device_attribute devfreq_attrs[] = { __ATTR(governor, S_IRUGO, show_governor, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), - __ATTR(central_polling, S_IRUGO, show_central_polling, NULL), __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, store_polling_interval), __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), @@ -598,23 +542,6 @@ static struct device_attribute devfreq_attrs[] = { { }, }; -/** - * devfreq_start_polling() - Initialize data structure for devfreq framework and - * start polling registered devfreq devices. - */ -static int __init devfreq_start_polling(void) -{ - mutex_lock(&devfreq_list_lock); - polling = false; - devfreq_wq = create_freezable_workqueue("devfreq_wq"); - INIT_DEFERRABLE_WORK(&devfreq_work, devfreq_monitor); - mutex_unlock(&devfreq_list_lock); - - devfreq_monitor(&devfreq_work.work); - return 0; -} -late_initcall(devfreq_start_polling); - static int __init devfreq_init(void) { devfreq_class = class_create(THIS_MODULE, "devfreq"); @@ -622,7 +549,15 @@ static int __init devfreq_init(void) pr_err("%s: couldn't create class\n", __FILE__); return PTR_ERR(devfreq_class); } + + devfreq_wq = create_freezable_workqueue("devfreq_wq"); + if (IS_ERR(devfreq_wq)) { + class_destroy(devfreq_class); + pr_err("%s: couldn't create workqueue\n", __FILE__); + return PTR_ERR(devfreq_wq); + } devfreq_class->dev_attrs = devfreq_attrs; + return 0; } subsys_initcall(devfreq_init); @@ -630,6 +565,7 @@ subsys_initcall(devfreq_init); static void __exit devfreq_exit(void) { class_destroy(devfreq_class); + destroy_workqueue(devfreq_wq); } module_exit(devfreq_exit); diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index ea7f13c58de..bb3aff32d62 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -18,7 +18,18 @@ #define to_devfreq(DEV) container_of((DEV), struct devfreq, dev) +/* Devfreq events */ +#define DEVFREQ_GOV_START 0x1 +#define DEVFREQ_GOV_STOP 0x2 +#define DEVFREQ_GOV_INTERVAL 0x3 + /* Caution: devfreq->lock must be locked before calling update_devfreq */ extern int update_devfreq(struct devfreq *devfreq); +extern void devfreq_monitor_start(struct devfreq *devfreq); +extern void devfreq_monitor_stop(struct devfreq *devfreq); +extern void devfreq_monitor_suspend(struct devfreq *devfreq); +extern void devfreq_monitor_resume(struct devfreq *devfreq); +extern void devfreq_interval_update(struct devfreq *devfreq, + unsigned int *delay); #endif /* _GOVERNOR_H */ diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index af75ddd4f15..eea3f9bd789 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -26,14 +26,22 @@ static int devfreq_performance_func(struct devfreq *df, return 0; } -static int performance_init(struct devfreq *devfreq) +static int devfreq_performance_handler(struct devfreq *devfreq, + unsigned int event, void *data) { - return update_devfreq(devfreq); + int ret = 0; + + if (event == DEVFREQ_GOV_START) { + mutex_lock(&devfreq->lock); + ret = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + } + + return ret; } const struct devfreq_governor devfreq_performance = { .name = "performance", - .init = performance_init, .get_target_freq = devfreq_performance_func, - .no_central_polling = true, + .event_handler = devfreq_performance_handler, }; diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index fec0cdbd247..2868d98ed3e 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -23,14 +23,22 @@ static int devfreq_powersave_func(struct devfreq *df, return 0; } -static int powersave_init(struct devfreq *devfreq) +static int devfreq_powersave_handler(struct devfreq *devfreq, + unsigned int event, void *data) { - return update_devfreq(devfreq); + int ret = 0; + + if (event == DEVFREQ_GOV_START) { + mutex_lock(&devfreq->lock); + ret = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + } + + return ret; } const struct devfreq_governor devfreq_powersave = { .name = "powersave", - .init = powersave_init, .get_target_freq = devfreq_powersave_func, - .no_central_polling = true, + .event_handler = devfreq_powersave_handler, }; diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index a2e3eae7901..3716a659122 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -12,6 +12,7 @@ #include #include #include +#include "governor.h" /* Default constants for DevFreq-Simple-Ondemand (DFSO) */ #define DFSO_UPTHRESHOLD (90) @@ -88,7 +89,30 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, return 0; } +static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + switch (event) { + case DEVFREQ_GOV_START: + devfreq_monitor_start(devfreq); + break; + + case DEVFREQ_GOV_STOP: + devfreq_monitor_stop(devfreq); + break; + + case DEVFREQ_GOV_INTERVAL: + devfreq_interval_update(devfreq, (unsigned int *)data); + break; + default: + break; + } + + return 0; +} + const struct devfreq_governor devfreq_simple_ondemand = { .name = "simple_ondemand", .get_target_freq = devfreq_simple_ondemand_func, + .event_handler = devfreq_simple_ondemand_handler, }; diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 0681246fc89..7067555bd44 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -116,10 +116,27 @@ static void userspace_exit(struct devfreq *devfreq) devfreq->data = NULL; } +static int devfreq_userspace_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + int ret = 0; + + switch (event) { + case DEVFREQ_GOV_START: + ret = userspace_init(devfreq); + break; + case DEVFREQ_GOV_STOP: + userspace_exit(devfreq); + break; + default: + break; + } + + return ret; +} + const struct devfreq_governor devfreq_userspace = { .name = "userspace", .get_target_freq = devfreq_userspace_func, - .init = userspace_init, - .exit = userspace_exit, - .no_central_polling = true, + .event_handler = devfreq_userspace_handler, }; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 281c72a3b9d..9cdffde74bb 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -91,25 +91,18 @@ struct devfreq_dev_profile { * status of the device (load = busy_time / total_time). * If no_central_polling is set, this callback is called * only with update_devfreq() notified by OPP. - * @init Called when the devfreq is being attached to a device - * @exit Called when the devfreq is being removed from a - * device. Governor should stop any internal routines - * before return because related data may be - * freed after exit(). - * @no_central_polling Do not use devfreq's central polling mechanism. - * When this is set, devfreq will not call - * get_target_freq with devfreq_monitor(). However, - * devfreq will call get_target_freq with - * devfreq_update() notified by OPP framework. + * @event_handler Callback for devfreq core framework to notify events + * to governors. Events include per device governor + * init and exit, opp changes out of devfreq, suspend + * and resume of per device devfreq during device idle. * * Note that the callbacks are called with devfreq->lock locked by devfreq. */ struct devfreq_governor { const char name[DEVFREQ_NAME_LEN]; int (*get_target_freq)(struct devfreq *this, unsigned long *freq); - int (*init)(struct devfreq *this); - void (*exit)(struct devfreq *this); - const bool no_central_polling; + int (*event_handler)(struct devfreq *devfreq, + unsigned int event, void *data); }; /** @@ -124,18 +117,13 @@ struct devfreq_governor { * @nb notifier block used to notify devfreq object that it should * reevaluate operable frequencies. Devfreq users may use * devfreq.nb to the corresponding register notifier call chain. - * @polling_jiffies interval in jiffies. + * @work delayed work for load monitoring. * @previous_freq previously configured frequency value. - * @next_polling the number of remaining jiffies to poll with - * "devfreq_monitor" executions to reevaluate - * frequency/voltage of the device. Set by - * profile's polling_ms interval. * @data Private data of the governor. The devfreq framework does not * touch this. - * @being_removed a flag to mark that this object is being removed in - * order to prevent trying to remove the object multiple times. * @min_freq Limit minimum frequency requested by user (0: none) * @max_freq Limit maximum frequency requested by user (0: none) + * @stop_polling devfreq polling status of a device. * * This structure stores the devfreq information for a give device. * @@ -153,17 +141,15 @@ struct devfreq { struct devfreq_dev_profile *profile; const struct devfreq_governor *governor; struct notifier_block nb; + struct delayed_work work; - unsigned long polling_jiffies; unsigned long previous_freq; - unsigned int next_polling; void *data; /* private data for governors */ - bool being_removed; - unsigned long min_freq; unsigned long max_freq; + bool stop_polling; }; #if defined(CONFIG_PM_DEVFREQ) -- cgit v1.2.3 From 206c30cfeb7c05dfb9fdfd81b1deb933627e43c1 Mon Sep 17 00:00:00 2001 From: Rajagopal Venkat Date: Fri, 26 Oct 2012 01:50:18 +0200 Subject: PM / devfreq: Add suspend and resume apis Add devfreq suspend/resume apis for devfreq users. This patch supports suspend and resume of devfreq load monitoring, required for devices which can idle. Signed-off-by: Rajagopal Venkat Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 28 ++++++++++++++++++++++++++++ drivers/devfreq/governor.h | 2 ++ drivers/devfreq/governor_simpleondemand.c | 9 +++++++++ include/linux/devfreq.h | 12 ++++++++++++ 4 files changed, 51 insertions(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 1aaf1aeb1f1..999600da21c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -427,6 +427,34 @@ int devfreq_remove_device(struct devfreq *devfreq) } EXPORT_SYMBOL(devfreq_remove_device); +/** + * devfreq_suspend_device() - Suspend devfreq of a device. + * @devfreq: the devfreq instance to be suspended + */ +int devfreq_suspend_device(struct devfreq *devfreq) +{ + if (!devfreq) + return -EINVAL; + + return devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_SUSPEND, NULL); +} +EXPORT_SYMBOL(devfreq_suspend_device); + +/** + * devfreq_resume_device() - Resume devfreq of a device. + * @devfreq: the devfreq instance to be resumed + */ +int devfreq_resume_device(struct devfreq *devfreq) +{ + if (!devfreq) + return -EINVAL; + + return devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_RESUME, NULL); +} +EXPORT_SYMBOL(devfreq_resume_device); + static ssize_t show_governor(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index bb3aff32d62..26432ac0a39 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -22,6 +22,8 @@ #define DEVFREQ_GOV_START 0x1 #define DEVFREQ_GOV_STOP 0x2 #define DEVFREQ_GOV_INTERVAL 0x3 +#define DEVFREQ_GOV_SUSPEND 0x4 +#define DEVFREQ_GOV_RESUME 0x5 /* Caution: devfreq->lock must be locked before calling update_devfreq */ extern int update_devfreq(struct devfreq *devfreq); diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 3716a659122..b5cf0fb24ef 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -104,6 +104,15 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, case DEVFREQ_GOV_INTERVAL: devfreq_interval_update(devfreq, (unsigned int *)data); break; + + case DEVFREQ_GOV_SUSPEND: + devfreq_monitor_suspend(devfreq); + break; + + case DEVFREQ_GOV_RESUME: + devfreq_monitor_resume(devfreq); + break; + default: break; } diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 9cdffde74bb..ee243a3229b 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -158,6 +158,8 @@ extern struct devfreq *devfreq_add_device(struct device *dev, const struct devfreq_governor *governor, void *data); extern int devfreq_remove_device(struct devfreq *devfreq); +extern int devfreq_suspend_device(struct devfreq *devfreq); +extern int devfreq_resume_device(struct devfreq *devfreq); /* Helper functions for devfreq user device driver with OPP. */ extern struct opp *devfreq_recommended_opp(struct device *dev, @@ -211,6 +213,16 @@ static int devfreq_remove_device(struct devfreq *devfreq) return 0; } +static int devfreq_suspend_device(struct devfreq *devfreq) +{ + return 0; +} + +static int devfreq_resume_device(struct devfreq *devfreq) +{ + return 0; +} + static struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags) { -- cgit v1.2.3 From 7f98a905dca6e4f144cdd4462edeac00c2bdc379 Mon Sep 17 00:00:00 2001 From: Rajagopal Venkat Date: Fri, 26 Oct 2012 01:50:26 +0200 Subject: PM / devfreq: Add current freq callback in device profile Devfreq returns governor predicted frequency as current frequency via sysfs interface. But device may not support all frequencies that governor predicts. So add a callback in device profile to get current freq from driver. Also add a new sysfs node to expose governor predicted next target frequency. Signed-off-by: Rajagopal Venkat Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-class-devfreq | 11 ++++++++++- drivers/devfreq/devfreq.c | 14 ++++++++++++++ include/linux/devfreq.h | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index 89283b1b024..e6cf08e6734 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -19,7 +19,16 @@ Date: September 2011 Contact: MyungJoo Ham Description: The /sys/class/devfreq/.../cur_freq shows the current - frequency of the corresponding devfreq object. + frequency of the corresponding devfreq object. Same as + target_freq when get_cur_freq() is not implemented by + devfreq driver. + +What: /sys/class/devfreq/.../target_freq +Date: September 2012 +Contact: Rajagopal Venkat +Description: + The /sys/class/devfreq/.../target_freq shows the next governor + predicted target frequency of the corresponding devfreq object. What: /sys/class/devfreq/.../polling_interval Date: September 2011 diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 999600da21c..f2f8a976c46 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -463,6 +463,19 @@ static ssize_t show_governor(struct device *dev, static ssize_t show_freq(struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned long freq; + struct devfreq *devfreq = to_devfreq(dev); + + if (devfreq->profile->get_cur_freq && + !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) + return sprintf(buf, "%lu\n", freq); + + return sprintf(buf, "%lu\n", devfreq->previous_freq); +} + +static ssize_t show_target_freq(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq); } @@ -563,6 +576,7 @@ static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr, static struct device_attribute devfreq_attrs[] = { __ATTR(governor, S_IRUGO, show_governor, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), + __ATTR(target_freq, S_IRUGO, show_target_freq, NULL), __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, store_polling_interval), __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index ee243a3229b..7e2e2ea4a70 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -66,6 +66,8 @@ struct devfreq_dev_status { * explained above with "DEVFREQ_FLAG_*" macros. * @get_dev_status The device should provide the current performance * status to devfreq, which is used by governors. + * @get_cur_freq The device should provide the current frequency + * at which it is operating. * @exit An optional callback that is called when devfreq * is removing the devfreq object due to error or * from devfreq_remove_device() call. If the user @@ -79,6 +81,7 @@ struct devfreq_dev_profile { int (*target)(struct device *dev, unsigned long *freq, u32 flags); int (*get_dev_status)(struct device *dev, struct devfreq_dev_status *stat); + int (*get_cur_freq)(struct device *dev, unsigned long *freq); void (*exit)(struct device *dev); }; -- cgit v1.2.3 From c5b4a1c15da3e6f472c6ff1a085a1134d18a1464 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 26 Oct 2012 01:50:35 +0200 Subject: PM / devfreq: kernel-doc typo corrections Parameter documentation needs a ':' for scripts/kernel-doc to parse properly. Minor fixes for ones warned by: ./scripts/kernel-doc -text drivers/devfreq/devfreq.c>/dev/null Signed-off-by: Nishanth Menon Acked-by: Randy Dunlap Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index f2f8a976c46..a42f69b34eb 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -265,9 +265,9 @@ out: /** * devfreq_notifier_call() - Notify that the device frequency requirements * has been changed out of devfreq framework. - * @nb the notifier_block (supposed to be devfreq->nb) - * @type not used - * @devp not used + * @nb: the notifier_block (supposed to be devfreq->nb) + * @type: not used + * @devp: not used * * Called by a notifier that uses devfreq->nb. */ @@ -414,7 +414,7 @@ EXPORT_SYMBOL(devfreq_add_device); /** * devfreq_remove_device() - Remove devfreq feature from a device. - * @devfreq the devfreq instance to be removed + * @devfreq: the devfreq instance to be removed */ int devfreq_remove_device(struct devfreq *devfreq) { @@ -619,9 +619,9 @@ module_exit(devfreq_exit); /** * devfreq_recommended_opp() - Helper function to get proper OPP for the * freq value given to target callback. - * @dev The devfreq user device. (parent of devfreq) - * @freq The frequency given to target function - * @flags Flags handed from devfreq framework. + * @dev: The devfreq user device. (parent of devfreq) + * @freq: The frequency given to target function + * @flags: Flags handed from devfreq framework. * */ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, @@ -652,8 +652,8 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, * devfreq_register_opp_notifier() - Helper function to get devfreq notified * for any changes in the OPP availability * changes - * @dev The devfreq user device. (parent of devfreq) - * @devfreq The devfreq object. + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. */ int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { @@ -668,8 +668,8 @@ int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq * notified for any changes in the OPP * availability changes anymore. - * @dev The devfreq user device. (parent of devfreq) - * @devfreq The devfreq object. + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. * * At exit() callback of devfreq_dev_profile, this must be included if * devfreq_recommended_opp is used. -- cgit v1.2.3 From 12e26265e6225bf93b2fdc70399774b31e2dd980 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 26 Oct 2012 01:50:43 +0200 Subject: PM / devfreq: fix sscanf handling for writable sysfs entries sscanf returns 0 when an invalid parameter like: echo -n "a">min_freq is attempted. Returning back the return result(0) will cause the command not to return back to command prompt. Instead, just return -EINVAL when sscanf does not return 1. This is done for min_freq, max_freq and polling_interval Signed-off-by: Nishanth Menon Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index a42f69b34eb..79a7343c28a 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -496,12 +496,11 @@ static ssize_t store_polling_interval(struct device *dev, ret = sscanf(buf, "%u", &value); if (ret != 1) - goto out; + return -EINVAL; df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value); ret = count; -out: return ret; } @@ -515,7 +514,7 @@ static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, ret = sscanf(buf, "%lu", &value); if (ret != 1) - goto out; + return -EINVAL; mutex_lock(&df->lock); max = df->max_freq; @@ -529,7 +528,6 @@ static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); -out: return ret; } @@ -549,7 +547,7 @@ static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr, ret = sscanf(buf, "%lu", &value); if (ret != 1) - goto out; + return -EINVAL; mutex_lock(&df->lock); min = df->min_freq; @@ -563,7 +561,6 @@ static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); -out: return ret; } -- cgit v1.2.3 From 1a1357ea176670867f347419c3345e2becc07338 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 26 Oct 2012 01:50:53 +0200 Subject: PM / devfreq: make devfreq_class static devfreq_class is used internally by devfreq and has no need to be globally available. This also fixes the following sparse warning: drivers/devfreq/devfreq.c:30:14: warning: symbol 'devfreq_class' was not declared. Should it be static? Signed-off-by: Nishanth Menon Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 79a7343c28a..789af4ff5c9 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -27,7 +27,7 @@ #include #include "governor.h" -struct class *devfreq_class; +static struct class *devfreq_class; /* * devfreq core provides delayed work based load monitoring helper -- cgit v1.2.3 From dde8437d06560366d8988c92b5774039ec703864 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Tue, 23 Oct 2012 01:21:49 +0200 Subject: PM / OPP: RCU reclaim synchronize_rcu() blocks the caller of opp_enable/disbale for a complete grace period. This blocking duration prevents any intensive use of the functions. Replace synchronize_rcu() by call_rcu() which will call our function for freeing the old opp element. The duration of opp_enable() and opp_disable() will be no more dependant of the grace period. Signed-off-by: Vincent Guittot Reviewed-by: Paul E. McKenney Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index d9468642fc4..1211210b15b 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -65,6 +65,7 @@ struct opp { unsigned long u_volt; struct device_opp *dev_opp; + struct rcu_head head; }; /** @@ -441,6 +442,17 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) return 0; } +/** + * opp_free_rcu() - helper to clear the struct opp when grace period has + * elapsed without blocking the the caller of opp_set_availability + */ +static void opp_free_rcu(struct rcu_head *head) +{ + struct opp *opp = container_of(head, struct opp, head); + + kfree(opp); +} + /** * opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation @@ -512,7 +524,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, list_replace_rcu(&opp->node, &new_opp->node); mutex_unlock(&dev_opp_list_lock); - synchronize_rcu(); + call_rcu(&opp->head, opp_free_rcu); /* Notify the change of the OPP availability */ if (availability_req) @@ -522,13 +534,10 @@ static int opp_set_availability(struct device *dev, unsigned long freq, srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, new_opp); - /* clean up old opp */ - new_opp = opp; - goto out; + return 0; unlock: mutex_unlock(&dev_opp_list_lock); -out: kfree(new_opp); return r; } -- cgit v1.2.3 From 80126ce7aeb4e187429681ef8a7785b7dcd7a348 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 23 Oct 2012 01:27:44 +0200 Subject: PM / OPP: Export symbols for module usage. Export the OPP functions for use by driver modules. Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org [nm@ti.com: expansion of functions exported] Signed-off-by: Nishanth Menon Signed-off-by: Liam Girdwood Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 1211210b15b..66888861f9e 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -23,6 +23,7 @@ #include #include #include +#include /* * Internal data structure organization with the OPP layer library is as @@ -161,6 +162,7 @@ unsigned long opp_get_voltage(struct opp *opp) return v; } +EXPORT_SYMBOL(opp_get_voltage); /** * opp_get_freq() - Gets the frequency corresponding to an available opp @@ -190,6 +192,7 @@ unsigned long opp_get_freq(struct opp *opp) return f; } +EXPORT_SYMBOL(opp_get_freq); /** * opp_get_opp_count() - Get number of opps available in the opp list @@ -222,6 +225,7 @@ int opp_get_opp_count(struct device *dev) return count; } +EXPORT_SYMBOL(opp_get_opp_count); /** * opp_find_freq_exact() - search for an exact frequency @@ -269,6 +273,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, return opp; } +EXPORT_SYMBOL(opp_find_freq_exact); /** * opp_find_freq_ceil() - Search for an rounded ceil freq @@ -311,6 +316,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) return opp; } +EXPORT_SYMBOL(opp_find_freq_ceil); /** * opp_find_freq_floor() - Search for a rounded floor freq @@ -357,6 +363,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) return opp; } +EXPORT_SYMBOL(opp_find_freq_floor); /** * opp_add() - Add an OPP table from a table definitions @@ -561,6 +568,7 @@ int opp_enable(struct device *dev, unsigned long freq) { return opp_set_availability(dev, freq, true); } +EXPORT_SYMBOL(opp_enable); /** * opp_disable() - Disable a specific OPP @@ -582,6 +590,7 @@ int opp_disable(struct device *dev, unsigned long freq) { return opp_set_availability(dev, freq, false); } +EXPORT_SYMBOL(opp_disable); #ifdef CONFIG_CPU_FREQ /** -- cgit v1.2.3 From 0779726cc265805d0f7c7dd1d791fa4076b31a9a Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Oct 2012 22:00:12 +0200 Subject: PM / OPP: predictable fail results for opp_find* functions, v2 Currently the opp_find* functions return -ENODEV when: a) it cant find a device (e.g. request for an OPP search on device which was not registered) b) When it cant find a match for the search strategy used This makes life a little in-efficient for users such as devfreq to make reasonable judgement before switching search strategies. So, standardize the return results as following: -EINVAL for bad pointer parameters -ENODEV when device cannot be found -ERANGE when search fails This has the following benefit for devfreq implementation: The search fails when an unregistered device pointer is provided. This is a trigger to change the search direction and search for a better fit, however, if we cannot differentiate between a valid search range failure Vs an unregistered device, second search goes through the same fail return condition. This can be avoided by appropriate handling of error return code. With this change, we also fix devfreq for the improved search strategy with updated error code. Signed-off-by: Nishanth Menon Reviewed-by: Kevin Hilman Acked-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 27 +++++++++++++++++++-------- drivers/devfreq/devfreq.c | 4 ++-- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 66888861f9e..c8a908b099c 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -235,7 +235,10 @@ EXPORT_SYMBOL(opp_get_opp_count); * * Searches for exact match in the opp list and returns pointer to the matching * opp if found, else returns ERR_PTR in case of error and should be handled - * using IS_ERR. + * using IS_ERR. Error return values can be: + * EINVAL: for bad pointer + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * * Note: available is a modifier for the search. if available=true, then the * match is for exact matching frequency and is available in the stored OPP @@ -254,7 +257,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, bool available) { struct device_opp *dev_opp; - struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct opp *temp_opp, *opp = ERR_PTR(-ERANGE); dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { @@ -284,7 +287,11 @@ EXPORT_SYMBOL(opp_find_freq_exact); * for a device. * * Returns matching *opp and refreshes *freq accordingly, else returns - * ERR_PTR in case of error and should be handled using IS_ERR. + * ERR_PTR in case of error and should be handled using IS_ERR. Error return + * values can be: + * EINVAL: for bad pointer + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * * Locking: This function must be called under rcu_read_lock(). opp is a rcu * protected pointer. The reason for the same is that the opp pointer which is @@ -295,7 +302,7 @@ EXPORT_SYMBOL(opp_find_freq_exact); struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) { struct device_opp *dev_opp; - struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct opp *temp_opp, *opp = ERR_PTR(-ERANGE); if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); @@ -304,7 +311,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) - return opp; + return ERR_CAST(dev_opp); list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { if (temp_opp->available && temp_opp->rate >= *freq) { @@ -327,7 +334,11 @@ EXPORT_SYMBOL(opp_find_freq_ceil); * for a device. * * Returns matching *opp and refreshes *freq accordingly, else returns - * ERR_PTR in case of error and should be handled using IS_ERR. + * ERR_PTR in case of error and should be handled using IS_ERR. Error return + * values can be: + * EINVAL: for bad pointer + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * * Locking: This function must be called under rcu_read_lock(). opp is a rcu * protected pointer. The reason for the same is that the opp pointer which is @@ -338,7 +349,7 @@ EXPORT_SYMBOL(opp_find_freq_ceil); struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) { struct device_opp *dev_opp; - struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct opp *temp_opp, *opp = ERR_PTR(-ERANGE); if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); @@ -347,7 +358,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) - return opp; + return ERR_CAST(dev_opp); list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { if (temp_opp->available) { diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index b146d76f04c..4fa1a22c55e 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -656,14 +656,14 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, opp = opp_find_freq_floor(dev, freq); /* If not available, use the closest opp */ - if (opp == ERR_PTR(-ENODEV)) + if (opp == ERR_PTR(-ERANGE)) opp = opp_find_freq_ceil(dev, freq); } else { /* The freq is an lower bound. opp should be higher */ opp = opp_find_freq_ceil(dev, freq); /* If not available, use the closest opp */ - if (opp == ERR_PTR(-ENODEV)) + if (opp == ERR_PTR(-ERANGE)) opp = opp_find_freq_floor(dev, freq); } -- cgit v1.2.3 From ea83f81b489be3be268ed7fabfe8dd94bdc45a29 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 31 Oct 2012 01:29:17 +0100 Subject: PM / OPP: using kfree_rcu() to simplify the code The callback function of call_rcu() just calls a kfree(), so we can use kfree_rcu() instead of call_rcu() + callback function. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index c8a908b099c..50b2831e027 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -460,17 +460,6 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) return 0; } -/** - * opp_free_rcu() - helper to clear the struct opp when grace period has - * elapsed without blocking the the caller of opp_set_availability - */ -static void opp_free_rcu(struct rcu_head *head) -{ - struct opp *opp = container_of(head, struct opp, head); - - kfree(opp); -} - /** * opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation @@ -542,7 +531,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, list_replace_rcu(&opp->node, &new_opp->node); mutex_unlock(&dev_opp_list_lock); - call_rcu(&opp->head, opp_free_rcu); + kfree_rcu(opp, head); /* Notify the change of the OPP availability */ if (availability_req) -- cgit v1.2.3 From c122f27e1c1bada4cdf19669afed5a00a69bc5a5 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 23 Oct 2012 01:18:40 +0200 Subject: base: power - use clk_prepare_enable and clk_prepare_disable When PM runtime is enabled in DaVinci and the machine migrates to common clk framework, the clk_enable() gets called without clk_prepare(). This patch is to fix this issue so that PM run time can inter work with common clk framework. Signed-off-by: Murali Karicheri Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index eb78e9640c4..9d8fde70939 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -99,7 +99,7 @@ static void __pm_clk_remove(struct pm_clock_entry *ce) if (ce->status < PCE_STATUS_ERROR) { if (ce->status == PCE_STATUS_ENABLED) - clk_disable(ce->clk); + clk_disable_unprepare(ce->clk); if (ce->status >= PCE_STATUS_ACQUIRED) clk_put(ce->clk); @@ -396,7 +396,7 @@ static void enable_clock(struct device *dev, const char *con_id) clk = clk_get(dev, con_id); if (!IS_ERR(clk)) { - clk_enable(clk); + clk_prepare_enable(clk); clk_put(clk); dev_info(dev, "Runtime PM disabled, clock forced on.\n"); } @@ -413,7 +413,7 @@ static void disable_clock(struct device *dev, const char *con_id) clk = clk_get(dev, con_id); if (!IS_ERR(clk)) { - clk_disable(clk); + clk_disable_unprepare(clk); clk_put(clk); dev_info(dev, "Runtime PM disabled, clock forced off.\n"); } -- cgit v1.2.3 From 883ee4f79d636d13f24c2479c66d42cb652b0239 Mon Sep 17 00:00:00 2001 From: Daniel Walter Date: Tue, 23 Oct 2012 01:20:35 +0200 Subject: PM / sysfs: replace strict_str* with kstrto* Replace strict_strtoul() with kstrtoul() in pm_async_store() and pm_qos_power_write(). [rjw: Modified subject and changelog.] Signed-off-by: Daniel Walter Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- kernel/power/main.c | 2 +- kernel/power/qos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/power/main.c b/kernel/power/main.c index f458238109c..1c16f9167de 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -59,7 +59,7 @@ static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, { unsigned long val; - if (strict_strtoul(buf, 10, &val)) + if (kstrtoul(buf, 10, &val)) return -EINVAL; if (val > 1) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 846bd42c7ed..4da05cee81b 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -500,7 +500,7 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, } else { ascii_value[count] = '\0'; } - ret = strict_strtoul(ascii_value, 16, &ulval); + ret = kstrtoul(ascii_value, 16, &ulval); if (ret) { pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret); return -EINVAL; -- cgit v1.2.3 From 8316bd72c0248adbb9572abf2dd045a95f682bcd Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 23 Oct 2012 01:21:09 +0200 Subject: PM / Hibernate: use rb_entry Since the software suspend extents are organized in an rbtree, use rb_entry instead of container_of, as it is semantically more appropriate in order to get a node as it is iterated. Signed-off-by: Davidlohr Bueso Signed-off-by: Rafael J. Wysocki --- kernel/power/swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 3c9d764eb0d..7c33ed20041 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -126,7 +126,7 @@ static int swsusp_extents_insert(unsigned long swap_offset) /* Figure out where to put the new node */ while (*new) { - ext = container_of(*new, struct swsusp_extent, node); + ext = rb_entry(*new, struct swsusp_extent, node); parent = *new; if (swap_offset < ext->start) { /* Try to merge */ -- cgit v1.2.3 From 4b6d1f12f9c4e0e420d5747d3ae285d8f66d627f Mon Sep 17 00:00:00 2001 From: LongX Zhang Date: Thu, 25 Oct 2012 00:21:28 +0200 Subject: driver core / PM: move the calling to device_pm_remove behind the calling to bus_remove_device We hit an hang issue when removing a mmc device on Medfield Android phone by sysfs interface. device_pm_remove will call pm_runtime_remove which would disable runtime PM of the device. After that pm_runtime_get* or pm_runtime_put* will be ignored. So if we disable the runtime PM before device really be removed, drivers' _remove callback may access HW even pm_runtime_get* fails. That is bad. Consider below call sequence when removing a device: device_del => device_pm_remove => class_intf->remove_dev(dev, class_intf) => pm_runtime_get_sync/put_sync => bus_remove_device => device_release_driver => pm_runtime_get_sync/put_sync remove_dev might call pm_runtime_get_sync/put_sync. Then, generic device_release_driver also calls pm_runtime_get_sync/put_sync. Since device_del => device_pm_remove firstly, later _get_sync wouldn't really wake up the device. I git log -p to find the patch which moves the calling to device_pm_remove ahead. It's below patch: commit 775b64d2b6ca37697de925f70799c710aab5849a Author: Rafael J. Wysocki Date: Sat Jan 12 20:40:46 2008 +0100 PM: Acquire device locks on suspend This patch reorganizes the way suspend and resume notifications are sent to drivers. The major changes are that now the PM core acquires every device semaphore before calling the methods, and calls to device_add() during suspends will fail, while calls to device_del() during suspends will block. It also provides a way to safely remove a suspended device with the help of the PM core, by using the device_pm_schedule_removal() callback introduced specifically for this purpose, and updates two drivers (msr and cpuid) that need to use it. As device_pm_schedule_removal is deleted by another patch, we need also revert other parts of the patch, i.e. move the calling of device_pm_remove after the calling to bus_remove_device. Signed-off-by: LongX Zhang Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index abea76c36a4..150a41580fa 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1180,7 +1180,6 @@ void device_del(struct device *dev) if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); - device_pm_remove(dev); dpm_sysfs_remove(dev); if (parent) klist_del(&dev->p->knode_parent); @@ -1205,6 +1204,7 @@ void device_del(struct device *dev) device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); bus_remove_device(dev); + device_pm_remove(dev); driver_deferred_probe_del(dev); /* Notify the platform of the removal, in case they -- cgit v1.2.3 From 5133375bb46a0d6c3fba07097caed7aa5e629ccd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Nov 2012 13:15:37 +0100 Subject: ACPI / PM: Fix build problem when CONFIG_ACPI or CONFIG_PM is not set Commit e5cc8ef (ACPI / PM: Provide ACPI PM callback routines for subsystems) introduced a build problem occuring if CONFIG_ACPI is unset or CONFIG_PM is unset and errno.h is not included before acpi.h, because in that case ENODEV used in acpi.h is undefined. Fix the issue by making acpi.h include errno.h. Signed-off-by: Rafael J. Wysocki --- include/linux/acpi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 0676b6ac57f..5fdd8727151 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -25,6 +25,7 @@ #ifndef _LINUX_ACPI_H #define _LINUX_ACPI_H +#include #include /* for struct resource */ #ifdef CONFIG_ACPI -- cgit v1.2.3 From 19387b27e42d5e20a8188cfa15dc902114d98c43 Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Thu, 15 Nov 2012 06:59:31 +0000 Subject: ACPI / memory-hotplug: add memory offline code to acpi_memory_device_remove() The memory device can be removed by 2 ways: 1. send eject request by SCI 2. echo 1 >/sys/bus/pci/devices/PNP0C80:XX/eject In the 1st case, acpi_memory_disable_device() will be called. In the 2nd case, acpi_memory_device_remove() will be called. acpi_memory_device_remove() will also be called when we unbind the memory device from the driver acpi_memhotplug or a driver initialization fails. acpi_memory_disable_device() has already implemented a code which offlines memory and releases acpi_memory_info struct. But acpi_memory_device_remove() has not implemented it yet. So the patch move offlining memory and releasing acpi_memory_info struct codes to a new function acpi_memory_remove_memory(). And it is used by both acpi_memory_device_remove() and acpi_memory_disable_device(). Signed-off-by: Yasuaki Ishimatsu Signed-off-by: Wen Congyang Acked-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 1e90e8f0100..736ec047e0f 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -306,25 +306,37 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) return 0; } -static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) +static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) { int result; struct acpi_memory_info *info, *n; - - /* - * Ask the VM to offline this memory range. - * Note: Assume that this function returns zero on success - */ list_for_each_entry_safe(info, n, &mem_device->res_list, list) { if (info->enabled) { result = remove_memory(info->start_addr, info->length); if (result) return result; } + + list_del(&info->list); kfree(info); } + return 0; +} + +static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) +{ + int result; + + /* + * Ask the VM to offline this memory range. + * Note: Assume that this function returns zero on success + */ + result = acpi_memory_remove_memory(mem_device); + if (result) + return result; + /* Power-off and eject the device */ result = acpi_memory_powerdown_device(mem_device); if (result) { @@ -474,12 +486,17 @@ static int acpi_memory_device_add(struct acpi_device *device) static int acpi_memory_device_remove(struct acpi_device *device, int type) { struct acpi_memory_device *mem_device = NULL; - + int result; if (!device || !acpi_driver_data(device)) return -EINVAL; mem_device = acpi_driver_data(device); + + result = acpi_memory_remove_memory(mem_device); + if (result) + return result; + kfree(mem_device); return 0; -- cgit v1.2.3 From 315bbae9c5cb1f54a6d6fd47b9cf325fbedccf05 Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Fri, 16 Nov 2012 02:04:05 +0100 Subject: ACPI / memhotplug: deal with eject request in hotplug queue The memory device can be removed by 2 ways: 1. send eject request by SCI 2. echo 1 >/sys/bus/pci/devices/PNP0C80:XX/eject We handle the 1st case in the module acpi_memhotplug, and handle the 2nd case in ACPI eject notification. This 2 events may happen at the same time, so we may touch acpi_memory_device.res_list at the same time. This patch reimplements memory-hotremove support through an ACPI eject notification. Now the memory device is offlined and hotremoved only in the function acpi_memory_device_remove() which is protected by device_lock(). Signed-off-by: Wen Congyang Reviewed-by: Yasuaki Ishimatsu Reviewed-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 88 +++++------------------------------------- 1 file changed, 9 insertions(+), 79 deletions(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 736ec047e0f..6e12042658b 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -272,40 +272,6 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) return 0; } -static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) -{ - acpi_status status; - struct acpi_object_list arg_list; - union acpi_object arg; - unsigned long long current_status; - - - /* Issue the _EJ0 command */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - status = acpi_evaluate_object(mem_device->device->handle, - "_EJ0", &arg_list, NULL); - /* Return on _EJ0 failure */ - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed")); - return -ENODEV; - } - - /* Evalute _STA to check if the device is disabled */ - status = acpi_evaluate_integer(mem_device->device->handle, "_STA", - NULL, ¤t_status); - if (ACPI_FAILURE(status)) - return -ENODEV; - - /* Check for device status. Device should be disabled */ - if (current_status & ACPI_STA_DEVICE_ENABLED) - return -EINVAL; - - return 0; -} - static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) { int result; @@ -325,34 +291,11 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) return 0; } -static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) -{ - int result; - - /* - * Ask the VM to offline this memory range. - * Note: Assume that this function returns zero on success - */ - result = acpi_memory_remove_memory(mem_device); - if (result) - return result; - - /* Power-off and eject the device */ - result = acpi_memory_powerdown_device(mem_device); - if (result) { - /* Set the status of the device to invalid */ - mem_device->state = MEMORY_INVALID_STATE; - return result; - } - - mem_device->state = MEMORY_POWER_OFF_STATE; - return result; -} - static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) { struct acpi_memory_device *mem_device; struct acpi_device *device; + struct acpi_eject_event *ej_event = NULL; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ switch (event) { @@ -394,32 +337,19 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) break; } - /* - * Currently disabling memory device from kernel mode - * TBD: Can also be disabled from user mode scripts - * TBD: Can also be disabled by Callback registration - * with generic sysfs driver - */ - if (acpi_memory_disable_device(mem_device)) { - printk(KERN_ERR PREFIX "Disable memory device\n"); - /* - * If _EJ0 was called but failed, _OST is not - * necessary. - */ - if (mem_device->state == MEMORY_INVALID_STATE) - return; - + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); + if (!ej_event) { + pr_err(PREFIX "No memory, dropping EJECT\n"); break; } - /* - * Invoke acpi_bus_trim() to remove memory device - */ - acpi_bus_trim(device, 1); + ej_event->handle = handle; + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; + acpi_os_hotplug_execute(acpi_bus_hot_remove_device, + (void *)ej_event); - /* _EJ0 succeeded; _OST is not necessary */ + /* eject is performed asynchronously */ return; - default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); -- cgit v1.2.3 From 386e52b95550db87c93455e3c0efe3cc4543f036 Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Fri, 16 Nov 2012 02:06:06 +0100 Subject: ACPI / memhotplug: fix memory leak when memory device is unbound from acpi_memhotplug We allocate memory to store acpi_memory_info, so we should free it before freeing mem_device. Signed-off-by: Wen Congyang Reviewed-by: Yasuaki Ishimatsu Acked-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 6e12042658b..c5e7b6d08ef 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -125,12 +125,20 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) return AE_OK; } +static void +acpi_memory_free_device_resources(struct acpi_memory_device *mem_device) +{ + struct acpi_memory_info *info, *n; + + list_for_each_entry_safe(info, n, &mem_device->res_list, list) + kfree(info); + INIT_LIST_HEAD(&mem_device->res_list); +} + static int acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) { acpi_status status; - struct acpi_memory_info *info, *n; - if (!list_empty(&mem_device->res_list)) return 0; @@ -138,9 +146,7 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS, acpi_memory_get_resource, mem_device); if (ACPI_FAILURE(status)) { - list_for_each_entry_safe(info, n, &mem_device->res_list, list) - kfree(info); - INIT_LIST_HEAD(&mem_device->res_list); + acpi_memory_free_device_resources(mem_device); return -EINVAL; } @@ -363,6 +369,15 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) return; } +static void acpi_memory_device_free(struct acpi_memory_device *mem_device) +{ + if (!mem_device) + return; + + acpi_memory_free_device_resources(mem_device); + kfree(mem_device); +} + static int acpi_memory_device_add(struct acpi_device *device) { int result; @@ -427,7 +442,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type) if (result) return result; - kfree(mem_device); + acpi_memory_device_free(mem_device); return 0; } -- cgit v1.2.3 From e0b7b24dd9559fcda0f8bfd6acbcad81682c4fdd Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Fri, 16 Nov 2012 02:08:16 +0100 Subject: ACPI / memhotplug: free memory device if acpi_memory_enable_device() failed If acpi_memory_enable_device() fails, acpi_memory_enable_device() will return a non-zero value, which means we fail to bind the memory device to this driver. So we should free memory device before acpi_memory_device_add() returns. Signed-off-by: Wen Congyang Reviewed-by: Yasuaki Ishimatsu Acked-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index c5e7b6d08ef..e52ad5d3792 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -421,9 +421,11 @@ static int acpi_memory_device_add(struct acpi_device *device) if (!acpi_memory_check_device(mem_device)) { /* call add_memory func */ result = acpi_memory_enable_device(mem_device); - if (result) + if (result) { printk(KERN_ERR PREFIX "Error in acpi_memory_enable_device\n"); + acpi_memory_device_free(mem_device); + } } return result; } -- cgit v1.2.3 From 65479472571fbf91502b7854be45ec0026b5229e Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Fri, 16 Nov 2012 02:10:37 +0100 Subject: ACPI / memhotplug: don't allow to eject the memory device if it is being used We eject the memory device even if it is in use. It is very dangerous, and it will cause the kernel to be panicked. Signed-off-by: Wen Congyang Reviewed-by: Yasuaki Ishimatsu Acked-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index e52ad5d3792..f7e30076996 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -78,6 +78,7 @@ struct acpi_memory_info { unsigned short caching; /* memory cache attribute */ unsigned short write_protect; /* memory read/write attribute */ unsigned int enabled:1; + unsigned int failed:1; }; struct acpi_memory_device { @@ -257,9 +258,23 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) node = memory_add_physaddr_to_nid(info->start_addr); result = add_memory(node, info->start_addr, info->length); - if (result) + + /* + * If the memory block has been used by the kernel, add_memory() + * returns -EEXIST. If add_memory() returns the other error, it + * means that this memory block is not used by the kernel. + */ + if (result && result != -EEXIST) { + info->failed = 1; continue; - info->enabled = 1; + } + + if (!result) + info->enabled = 1; + /* + * Add num_enable even if add_memory() returns -EEXIST, so the + * device is bound to this driver. + */ num_enabled++; } if (!num_enabled) { @@ -280,21 +295,30 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) { - int result; + int result = 0; struct acpi_memory_info *info, *n; list_for_each_entry_safe(info, n, &mem_device->res_list, list) { - if (info->enabled) { - result = remove_memory(info->start_addr, info->length); - if (result) - return result; - } + if (info->failed) + /* The kernel does not use this memory block */ + continue; + + if (!info->enabled) + /* + * The kernel uses this memory block, but it may be not + * managed by us. + */ + return -EBUSY; + + result = remove_memory(info->start_addr, info->length); + if (result) + return result; list_del(&info->list); kfree(info); } - return 0; + return result; } static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) -- cgit v1.2.3 From 61d8eff14417fb6d6c5d57e4f0f7925e9e99fce3 Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Fri, 16 Nov 2012 02:12:38 +0100 Subject: ACPI / memhotplug: bind the memory device when the driver is being loaded We had introduced acpi_hotmem_initialized to avoid strange add_memory fail message. But the memory device may not be used by the kernel, and the device should be bound when the driver is being loaded. Remove acpi_hotmem_initialized to allow that the device can be bound when the driver is being loaded. Signed-off-by: Wen Congyang Reviewed-by: Yasuaki Ishimatsu Acked-by: David Rientjes Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index f7e30076996..e0f7425c885 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -87,8 +87,6 @@ struct acpi_memory_device { struct list_head res_list; }; -static int acpi_hotmem_initialized; - static acpi_status acpi_memory_get_resource(struct acpi_resource *resource, void *context) { @@ -433,15 +431,6 @@ static int acpi_memory_device_add(struct acpi_device *device) printk(KERN_DEBUG "%s \n", acpi_device_name(device)); - /* - * Early boot code has recognized memory area by EFI/E820. - * If DSDT shows these memory devices on boot, hotplug is not necessary - * for them. So, it just returns until completion of this driver's - * start up. - */ - if (!acpi_hotmem_initialized) - return 0; - if (!acpi_memory_check_device(mem_device)) { /* call add_memory func */ result = acpi_memory_enable_device(mem_device); @@ -557,7 +546,6 @@ static int __init acpi_memory_device_init(void) return -ENODEV; } - acpi_hotmem_initialized = 1; return 0; } -- cgit v1.2.3 From ddc150f7a33ae0c9cb16eaac3641abc00f56316f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 16 Nov 2012 02:46:28 +0100 Subject: ACPI / PM: Add check preventing transitioning to non-D0 state from D3. No power transitioning from D3 state up to a non-D0 state is allowed so make acpi_device_set_power() fail and complain if such a transition is attempted. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 07a20ee3e69..1f0d457ecbc 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -306,6 +306,12 @@ int acpi_device_set_power(struct acpi_device *device, int state) * a lower-powered state. */ if (state < device->power.state) { + if (device->power.state >= ACPI_STATE_D3_HOT && + state != ACPI_STATE_D0) { + printk(KERN_WARNING PREFIX + "Cannot transition to non-D0 state from D3\n"); + return -ENODEV; + } if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); if (result) -- cgit v1.2.3 From bb74ac23b10820d8722c3e1f4add9ef59e703f63 Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Fri, 16 Nov 2012 02:56:59 +0100 Subject: ACPI: create _SUN sysfs file _SUN method provides the slot unique-ID in the ACPI namespace. And The value is written in Advanced Configuration and Power Interface Specification as follows: "The _SUN value is required to be unique among the slots ofthe same type. It is also recommended that this number match the slot number printed on the physical slot whenever possible." So if we can know the value, we can identify the physical position of the slot in the system. The patch creates "sun" file in sysfs for identifying physical position of the slot. Signed-off-by: Yasuaki Ishimatsu Reviewed-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-devices-sun | 14 ++++++++++++++ drivers/acpi/scan.c | 24 ++++++++++++++++++++++++ include/acpi/acpi_bus.h | 1 + 3 files changed, 39 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-devices-sun diff --git a/Documentation/ABI/testing/sysfs-devices-sun b/Documentation/ABI/testing/sysfs-devices-sun new file mode 100644 index 00000000000..86be9848a77 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-sun @@ -0,0 +1,14 @@ +Whatt: /sys/devices/.../sun +Date: October 2012 +Contact: Yasuaki Ishimatsu +Description: + The file contains a Slot-unique ID which provided by the _SUN + method in the ACPI namespace. The value is written in Advanced + Configuration and Power Interface Specification as follows: + + "The _SUN value is required to be unique among the slots of + the same type. It is also recommended that this number match + the slot number printed on the physical slot whenever possible." + + So reading the sysfs file, we can identify a physical position + of the slot in the system. diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 9d43532d69b..d0b38ab47ab 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -283,11 +283,21 @@ static ssize_t description_show(struct device *dev, } static DEVICE_ATTR(description, 0444, description_show, NULL); +static ssize_t +acpi_device_sun_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%lu\n", acpi_dev->pnp.sun); +} +static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); + static int acpi_device_setup_files(struct acpi_device *dev) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; acpi_handle temp; + unsigned long long sun; int result = 0; /* @@ -329,6 +339,16 @@ static int acpi_device_setup_files(struct acpi_device *dev) if (dev->pnp.unique_id) result = device_create_file(&dev->dev, &dev_attr_uid); + status = acpi_evaluate_integer(dev->handle, "_SUN", NULL, &sun); + if (ACPI_SUCCESS(status)) { + dev->pnp.sun = (unsigned long)sun; + result = device_create_file(&dev->dev, &dev_attr_sun); + if (result) + goto end; + } else { + dev->pnp.sun = (unsigned long)-1; + } + /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. @@ -360,6 +380,10 @@ static void acpi_device_remove_files(struct acpi_device *dev) if (ACPI_SUCCESS(status)) device_remove_file(&dev->dev, &dev_attr_eject); + status = acpi_get_handle(dev->handle, "_SUN", &temp); + if (ACPI_SUCCESS(status)) + device_remove_file(&dev->dev, &dev_attr_sun); + if (dev->pnp.unique_id) device_remove_file(&dev->dev, &dev_attr_uid); if (dev->flags.bus_address) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e8b2877aea3..6f385e5909d 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -179,6 +179,7 @@ struct acpi_device_pnp { acpi_device_name device_name; /* Driver-determined */ acpi_device_class device_class; /* " */ union acpi_object *str_obj; /* unicode string for _STR method */ + unsigned long sun; /* _SUN */ }; #define acpi_device_bid(d) ((d)->pnp.bus_id) -- cgit v1.2.3 From bacaf7cd092a2c42a904bce437e64690e04aaa10 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 16 Nov 2012 11:08:31 +0100 Subject: Revert "ACPI / x86: Add quirk for "CheckPoint P-20-00" to not use bridge _CRS_ info" This reverts commit 0a290ac4252c85205cb924ff7f6da10cfd20fb01 on the basis of the following comment from Bjorn Helgaas: Here's my reasoning: this is a CheckPoint product, and it looks like an appliance, not really a general-purpose machine. The issue has apparently been there from day one, and the kernel shipped on the machine complains noisily about the issue, but apparently nobody bothered to investigate it. This corruption will clearly break other ACPI-related things. We can sort of work around this one (though the workaround does prevent us from doing any PCI resource reassignment), but we have no idea what the other lurking ACPI issues are (and we have no assurance that *only* ACPI things are broken -- maybe the memory corruption affects other unknown things). It may take significant debugging effort to identify the next problem. The only report I've seen (this one) is apparently from a CheckPoint employee, so it's not clear that anybody else is trying to run upstream Linux on it. Being a CheckPoint employee, [...] is probably in a position to get the BIOS fixed. You might still be able to convince me, but it seems like the benefit to a quirk for this platform is small, and it does cost everybody else something in code size and complexity. References: https://bugzilla.kernel.org/show_bug.cgi?id=47981#c36 Signed-off-by: Rafael J. Wysocki --- arch/x86/pci/acpi.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 7010c199b4f..192397c9860 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -98,16 +98,6 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = { DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), }, }, - /* https://bugzilla.kernel.org/show_bug.cgi?id=47981 */ - { - .callback = set_nouse_crs, - .ident = "CheckPoint P-20-00", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "CheckPoint"), - DMI_MATCH(DMI_PRODUCT_NAME, "P-20-00"), - DMI_MATCH(DMI_BOARD_NAME, "Bridgeport"), - }, - }, {} }; -- cgit v1.2.3 From 8a66790b7850a6669129af078768a1d42076a0ef Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 16 Nov 2012 21:55:48 +0100 Subject: ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources walks Currently acpi_dev_process_resource() returns AE_ABORT_METHOD to terminate the acpi_walk_resources() it is called from if the .preproc() routine provided by the caller of acpi_dev_get_resources() initiating the resources walk returns an error code. It is better to use AE_CTRL_TERMINATE for this purpose, however, so do that. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 2bafc25482b..4107c004467 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -446,7 +446,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, ret = c->preproc(ares, c->preproc_data); if (ret < 0) { c->error = ret; - return AE_ABORT_METHOD; + return AE_CTRL_TERMINATE; } else if (ret > 0) { return AE_OK; } -- cgit v1.2.3 From 4000e626156935dfb626321ce09cae2c833eabbb Mon Sep 17 00:00:00 2001 From: Kamil Iskra Date: Fri, 16 Nov 2012 22:28:58 +0100 Subject: ACPI / battery: Correct battery capacity values on Thinkpads Add a quirk to correctly report battery capacity on 2010 and 2011 Lenovo Thinkpad models. The affected models that I tested (x201, t410, t410s, and x220) exhibit a problem where, when battery capacity reporting unit is mAh, the values being reported are wrong. Pre-2010 and 2012 models appear to always report in mWh and are thus unaffected. Also, in mid-2012 Lenovo issued a BIOS update for the 2011 models that fixes the issue (tested on x220 with a post-1.29 BIOS). No such update is available for the 2010 models, so those still need this patch. Problem description: for some reason, the affected Thinkpads switch the reporting unit between mAh and mWh; generally, mAh is used when a laptop is plugged in and mWh when it's unplugged, although a suspend/resume or rmmod/modprobe is needed for the switch to take effect. The values reported in mAh are *always* wrong. This does not appear to be a kernel regression; I believe that the values were never reported correctly. I tested back to kernel 2.6.34, with multiple machines and BIOS versions. Simply plugging a laptop into mains before turning it on is enough to reproduce the problem. Here's a sample /proc/acpi/battery/BAT0/info from Thinkpad x220 (before a BIOS update) with a 4-cell battery: present: yes design capacity: 2886 mAh last full capacity: 2909 mAh battery technology: rechargeable design voltage: 14800 mV design capacity warning: 145 mAh design capacity low: 13 mAh cycle count: 0 capacity granularity 1: 1 mAh capacity granularity 2: 1 mAh model number: 42T4899 serial number: 21064 battery type: LION OEM info: SANYO Once the laptop switches the unit to mWh (unplug from mains, suspend, resume), the output changes to: present: yes design capacity: 28860 mWh last full capacity: 29090 mWh battery technology: rechargeable design voltage: 14800 mV design capacity warning: 1454 mWh design capacity low: 200 mWh cycle count: 0 capacity granularity 1: 1 mWh capacity granularity 2: 1 mWh model number: 42T4899 serial number: 21064 battery type: LION OEM info: SANYO Can you see how the values for "design capacity", etc., differ by a factor of 10 instead of 14.8 (the design voltage of this battery)? On the battery itself it says: 14.8V, 1.95Ah, 29Wh, so clearly the values reported in mWh are correct and the ones in mAh are not. My guess is that this problem has been around ever since those machines were released, but because the most common Thinkpad batteries are rated at 10.8V, the error (8%) is small enough that it simply hasn't been noticed or at least nobody could be bothered to look into it. My patch works around the problem by adjusting the incorrectly reported mAh values by "10000 / design_voltage". The patch also has code to figure out if it should be activated or not. It only activates on Lenovo Thinkpads, only when the unit is mAh, and, as an extra precaution, only when the battery capacity reported through ACPI does not match what is reported through DMI (I've never encountered a machine where the first two conditions would be true but the last would not, but better safe than sorry). I've been using this patch for close to a year on several systems without any problems. References: https://bugzilla.kernel.org/show_bug.cgi?id=41062 Acked-by: Henrique de Moraes Holschuh Cc: Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 45e3e1759fb..7efaeaa53b8 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI_PROCFS_POWER #include @@ -95,6 +96,18 @@ enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, + /* On Lenovo Thinkpad models from 2010 and 2011, the power unit + switches between mWh and mAh depending on whether the system + is running on battery or not. When mAh is the unit, most + reported values are incorrect and need to be adjusted by + 10000/design_voltage. Verified on x201, t410, t410s, and x220. + Pre-2010 and 2012 models appear to always report in mWh and + are thus unaffected (tested with t42, t61, t500, x200, x300, + and x230). Also, in mid-2012 Lenovo issued a BIOS update for + the 2011 models that fixes the issue (tested on x220 with a + post-1.29 BIOS), but as of Nov. 2012, no such update is + available for the 2010 models. */ + ACPI_BATTERY_QUIRK_THINKPAD_MAH, }; struct acpi_battery { @@ -438,6 +451,21 @@ static int acpi_battery_get_info(struct acpi_battery *battery) kfree(buffer.pointer); if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) battery->full_charge_capacity = battery->design_capacity; + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && + battery->power_unit && battery->design_voltage) { + battery->design_capacity = battery->design_capacity * + 10000 / battery->design_voltage; + battery->full_charge_capacity = battery->full_charge_capacity * + 10000 / battery->design_voltage; + battery->design_capacity_warning = + battery->design_capacity_warning * + 10000 / battery->design_voltage; + /* Curiously, design_capacity_low, unlike the rest of them, + is correct. */ + /* capacity_granularity_* equal 1 on the systems tested, so + it's impossible to tell if they would need an adjustment + or not if their values were higher. */ + } return result; } @@ -486,6 +514,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery) && battery->capacity_now >= 0 && battery->capacity_now <= 100) battery->capacity_now = (battery->capacity_now * battery->full_charge_capacity) / 100; + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && + battery->power_unit && battery->design_voltage) { + battery->capacity_now = battery->capacity_now * + 10000 / battery->design_voltage; + } return result; } @@ -595,6 +628,24 @@ static void sysfs_remove_battery(struct acpi_battery *battery) mutex_unlock(&battery->sysfs_lock); } +static void find_battery(const struct dmi_header *dm, void *private) +{ + struct acpi_battery *battery = (struct acpi_battery *)private; + /* Note: the hardcoded offsets below have been extracted from + the source code of dmidecode. */ + if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) { + const u8 *dmi_data = (const u8 *)(dm + 1); + int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6)); + if (dm->length >= 18) + dmi_capacity *= dmi_data[17]; + if (battery->design_capacity * battery->design_voltage / 1000 + != dmi_capacity && + battery->design_capacity * 10 == dmi_capacity) + set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, + &battery->flags); + } +} + /* * According to the ACPI spec, some kinds of primary batteries can * report percentage battery remaining capacity directly to OS. @@ -620,6 +671,32 @@ static void acpi_battery_quirks(struct acpi_battery *battery) battery->capacity_now = (battery->capacity_now * battery->full_charge_capacity) / 100; } + + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags)) + return ; + + if (battery->power_unit && dmi_name_in_vendors("LENOVO")) { + const char *s; + s = dmi_get_system_info(DMI_PRODUCT_VERSION); + if (s && !strnicmp(s, "ThinkPad", 8)) { + dmi_walk(find_battery, battery); + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, + &battery->flags) && + battery->design_voltage) { + battery->design_capacity = + battery->design_capacity * + 10000 / battery->design_voltage; + battery->full_charge_capacity = + battery->full_charge_capacity * + 10000 / battery->design_voltage; + battery->design_capacity_warning = + battery->design_capacity_warning * + 10000 / battery->design_voltage; + battery->capacity_now = battery->capacity_now * + 10000 / battery->design_voltage; + } + } + } } static int acpi_battery_update(struct acpi_battery *battery) -- cgit v1.2.3 From d7895052d97cde63b34e5185da28052384fa8564 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 21 Aug 2012 15:35:32 +0530 Subject: PM / devfreq: Use devm_* functions in exynos4_bus.c devm_* functions are device managed functions and make cleanup code simpler and smaller. devm_kzalloc and devm_regulator_get functions are used. Signed-off-by: Sachin Kamat [renamed the patch title by MyungJoo Ham] Signed-off-by: MyungJoo Ham --- drivers/devfreq/exynos4_bus.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index 88ddc77a9bb..68145316c49 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c @@ -987,7 +987,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int err = 0; - data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL); if (data == NULL) { dev_err(dev, "Cannot allocate memory.\n"); return -ENOMEM; @@ -1012,22 +1012,18 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) err = -EINVAL; } if (err) - goto err_regulator; + return err; - data->vdd_int = regulator_get(dev, "vdd_int"); + data->vdd_int = devm_regulator_get(dev, "vdd_int"); if (IS_ERR(data->vdd_int)) { dev_err(dev, "Cannot get the regulator \"vdd_int\"\n"); - err = PTR_ERR(data->vdd_int); - goto err_regulator; + return PTR_ERR(data->vdd_int); } if (data->type == TYPE_BUSF_EXYNOS4x12) { - data->vdd_mif = regulator_get(dev, "vdd_mif"); + data->vdd_mif = devm_regulator_get(dev, "vdd_mif"); if (IS_ERR(data->vdd_mif)) { dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n"); - err = PTR_ERR(data->vdd_mif); - regulator_put(data->vdd_int); - goto err_regulator; - + return PTR_ERR(data->vdd_mif); } } @@ -1035,8 +1031,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) if (IS_ERR(opp)) { dev_err(dev, "Invalid initial frequency %lu kHz.\n", exynos4_devfreq_profile.initial_freq); - err = PTR_ERR(opp); - goto err_opp_add; + return PTR_ERR(opp); } data->curr_opp = opp; @@ -1046,29 +1041,19 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile, &devfreq_simple_ondemand, NULL); - if (IS_ERR(data->devfreq)) { - err = PTR_ERR(data->devfreq); - goto err_opp_add; - } + if (IS_ERR(data->devfreq)) + return PTR_ERR(data->devfreq); devfreq_register_opp_notifier(dev, data->devfreq); err = register_pm_notifier(&data->pm_notifier); if (err) { dev_err(dev, "Failed to setup pm notifier\n"); - goto err_devfreq_add; + devfreq_remove_device(data->devfreq); + return err; } return 0; -err_devfreq_add: - devfreq_remove_device(data->devfreq); -err_opp_add: - if (data->vdd_mif) - regulator_put(data->vdd_mif); - regulator_put(data->vdd_int); -err_regulator: - kfree(data); - return err; } static __devexit int exynos4_busfreq_remove(struct platform_device *pdev) @@ -1077,10 +1062,6 @@ static __devexit int exynos4_busfreq_remove(struct platform_device *pdev) unregister_pm_notifier(&data->pm_notifier); devfreq_remove_device(data->devfreq); - regulator_put(data->vdd_int); - if (data->vdd_mif) - regulator_put(data->vdd_mif); - kfree(data); return 0; } -- cgit v1.2.3 From e09651fcc295a7dc802f38d9494f5b860dd90bca Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 08:02:23 -0500 Subject: PM / devfreq: documentation cleanups for devfreq header struct parameters need to have ':' in documentation for scripts/kernel-doc to parse appropriately. Fix the errors reported by: ./scripts/kernel-doc include/linux/devfreq.h >/dev/null Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Acked-by: Randy Dunlap Acked-by: MyungJoo Ham Signed-off-by: MyungJoo Ham --- include/linux/devfreq.h | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 7e2e2ea4a70..1461fb2355a 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -25,12 +25,12 @@ struct devfreq; * struct devfreq_dev_status - Data given from devfreq user device to * governors. Represents the performance * statistics. - * @total_time The total time represented by this instance of + * @total_time: The total time represented by this instance of * devfreq_dev_status - * @busy_time The time that the device was working among the + * @busy_time: The time that the device was working among the * total_time. - * @current_frequency The operating frequency. - * @private_data An entry not specified by the devfreq framework. + * @current_frequency: The operating frequency. + * @private_data: An entry not specified by the devfreq framework. * A device and a specific governor may have their * own protocol with private_data. However, because * this is governor-specific, a governor using this @@ -54,21 +54,21 @@ struct devfreq_dev_status { /** * struct devfreq_dev_profile - Devfreq's user device profile - * @initial_freq The operating frequency when devfreq_add_device() is + * @initial_freq: The operating frequency when devfreq_add_device() is * called. - * @polling_ms The polling interval in ms. 0 disables polling. - * @target The device should set its operating frequency at + * @polling_ms: The polling interval in ms. 0 disables polling. + * @target: The device should set its operating frequency at * freq or lowest-upper-than-freq value. If freq is * higher than any operable frequency, set maximum. * Before returning, target function should set * freq at the current frequency. * The "flags" parameter's possible values are * explained above with "DEVFREQ_FLAG_*" macros. - * @get_dev_status The device should provide the current performance + * @get_dev_status: The device should provide the current performance * status to devfreq, which is used by governors. - * @get_cur_freq The device should provide the current frequency + * @get_cur_freq: The device should provide the current frequency * at which it is operating. - * @exit An optional callback that is called when devfreq + * @exit: An optional callback that is called when devfreq * is removing the devfreq object due to error or * from devfreq_remove_device() call. If the user * has registered devfreq->nb at a notifier-head, @@ -87,14 +87,14 @@ struct devfreq_dev_profile { /** * struct devfreq_governor - Devfreq policy governor - * @name Governor's name - * @get_target_freq Returns desired operating frequency for the device. + * @name: Governor's name + * @get_target_freq: Returns desired operating frequency for the device. * Basically, get_target_freq will run * devfreq_dev_profile.get_dev_status() to get the * status of the device (load = busy_time / total_time). * If no_central_polling is set, this callback is called * only with update_devfreq() notified by OPP. - * @event_handler Callback for devfreq core framework to notify events + * @event_handler: Callback for devfreq core framework to notify events * to governors. Events include per device governor * init and exit, opp changes out of devfreq, suspend * and resume of per device devfreq during device idle. @@ -110,23 +110,23 @@ struct devfreq_governor { /** * struct devfreq - Device devfreq structure - * @node list node - contains the devices with devfreq that have been + * @node: list node - contains the devices with devfreq that have been * registered. - * @lock a mutex to protect accessing devfreq. - * @dev device registered by devfreq class. dev.parent is the device + * @lock: a mutex to protect accessing devfreq. + * @dev: device registered by devfreq class. dev.parent is the device * using devfreq. - * @profile device-specific devfreq profile - * @governor method how to choose frequency based on the usage. - * @nb notifier block used to notify devfreq object that it should + * @profile: device-specific devfreq profile + * @governor: method how to choose frequency based on the usage. + * @nb: notifier block used to notify devfreq object that it should * reevaluate operable frequencies. Devfreq users may use * devfreq.nb to the corresponding register notifier call chain. - * @work delayed work for load monitoring. - * @previous_freq previously configured frequency value. - * @data Private data of the governor. The devfreq framework does not + * @work: delayed work for load monitoring. + * @previous_freq: previously configured frequency value. + * @data: Private data of the governor. The devfreq framework does not * touch this. - * @min_freq Limit minimum frequency requested by user (0: none) - * @max_freq Limit maximum frequency requested by user (0: none) - * @stop_polling devfreq polling status of a device. + * @min_freq: Limit minimum frequency requested by user (0: none) + * @max_freq: Limit maximum frequency requested by user (0: none) + * @stop_polling: devfreq polling status of a device. * * This structure stores the devfreq information for a give device. * @@ -186,9 +186,9 @@ extern const struct devfreq_governor devfreq_simple_ondemand; /** * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq * and devfreq_add_device - * @ upthreshold If the load is over this value, the frequency jumps. + * @upthreshold: If the load is over this value, the frequency jumps. * Specify 0 to use the default. Valid value = 0 to 100. - * @ downdifferential If the load is under upthreshold - downdifferential, + * @downdifferential: If the load is under upthreshold - downdifferential, * the governor may consider slowing the frequency down. * Specify 0 to use the default. Valid value = 0 to 100. * downdifferential < upthreshold must hold. -- cgit v1.2.3 From d287de855f97c56ca7146ff627e652bd7cd64f3f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 25 Oct 2012 19:48:59 -0500 Subject: PM / devfreq: Add sysfs node to expose available frequencies devfreq governors such as ondemand are controlled by a min and max frequency, while governors like userspace governor allow us to set a specific frequency. However, for the same specific device, depending on the SoC, the available frequencies can vary. So expose the available frequencies as a snapshot over sysfs to allow informed decisions. This was inspired by cpufreq framework's equivalent for similar usage sysfs node: scaling_available_frequencies. Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Signed-off-by: MyungJoo Ham --- Documentation/ABI/testing/sysfs-class-devfreq | 9 ++++++++ drivers/devfreq/devfreq.c | 32 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index e6cf08e6734..e672ccb02e7 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -51,3 +51,12 @@ Description: The /sys/class/devfreq/.../userspace/set_freq shows and sets the requested frequency for the devfreq object if userspace governor is in effect. + +What: /sys/class/devfreq/.../available_frequencies +Date: October 2012 +Contact: Nishanth Menon +Description: + The /sys/class/devfreq/.../available_frequencies shows + the available frequencies of the corresponding devfreq object. + This is a snapshot of available frequencies and not limited + by the min/max frequency restrictions. diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 789af4ff5c9..c44e562bdfe 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -570,9 +570,41 @@ static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq); } +static ssize_t show_available_freqs(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct devfreq *df = to_devfreq(d); + struct device *dev = df->dev.parent; + struct opp *opp; + ssize_t count = 0; + unsigned long freq = 0; + + rcu_read_lock(); + do { + opp = opp_find_freq_ceil(dev, &freq); + if (IS_ERR(opp)) + break; + + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), + "%lu ", freq); + freq++; + } while (1); + rcu_read_unlock(); + + /* Truncate the trailing space */ + if (count) + count--; + + count += sprintf(&buf[count], "\n"); + + return count; +} + static struct device_attribute devfreq_attrs[] = { __ATTR(governor, S_IRUGO, show_governor, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), + __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL), __ATTR(target_freq, S_IRUGO, show_target_freq, NULL), __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, store_polling_interval), -- cgit v1.2.3 From e552bbaf5b987f57c43e6981a452b8a3c700b1ae Mon Sep 17 00:00:00 2001 From: Jonghwa Lee Date: Thu, 23 Aug 2012 20:00:46 +0900 Subject: PM / devfreq: Add sysfs node for representing frequency transition information. This patch adds sysfs node which can be used to get information of frequency transition. It represents transition table which contains total number of transition of each freqeuncy state and time spent. It is inspired CPUFREQ's status driver. Signed-off-by: Jonghwa Lee [Added Documentation/ABI entry, updated kernel-doc, and resolved merge conflict] Signed-off-by: MyungJoo Ham --- Documentation/ABI/testing/sysfs-class-devfreq | 11 +++ drivers/devfreq/devfreq.c | 101 ++++++++++++++++++++++++++ include/linux/devfreq.h | 15 ++++ 3 files changed, 127 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index e672ccb02e7..40f98a9428d 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -44,6 +44,17 @@ Description: (/sys/class/devfreq/.../central_polling is 0), this value may be useless. +What: /sys/class/devfreq/.../trans_stat +Date: October 2012 +Contact: MyungJoo Ham +Descrtiption: + This ABI shows the statistics of devfreq behavior on a + specific device. It shows the time spent in each state and + the number of transitions between states. + In order to activate this ABI, the devfreq target device + driver should provide the list of available frequencies + with its profile. + What: /sys/class/devfreq/.../userspace/set_freq Date: September 2011 Contact: MyungJoo Ham diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index c44e562bdfe..bf6de38190c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -66,6 +66,51 @@ static struct devfreq *find_device_devfreq(struct device *dev) return ERR_PTR(-ENODEV); } +/** + * devfreq_get_freq_level() - Lookup freq_table for the frequency + * @devfreq: the devfreq instance + * @freq: the target frequency + */ +static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq) +{ + int lev; + + for (lev = 0; lev < devfreq->profile->max_state; lev++) + if (freq == devfreq->profile->freq_table[lev]) + return lev; + + return -EINVAL; +} + +/** + * devfreq_update_status() - Update statistics of devfreq behavior + * @devfreq: the devfreq instance + * @freq: the update target frequency + */ +static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) +{ + int lev, prev_lev; + unsigned long cur_time; + + lev = devfreq_get_freq_level(devfreq, freq); + if (lev < 0) + return lev; + + cur_time = jiffies; + devfreq->time_in_state[lev] += + cur_time - devfreq->last_stat_updated; + if (freq != devfreq->previous_freq) { + prev_lev = devfreq_get_freq_level(devfreq, + devfreq->previous_freq); + devfreq->trans_table[(prev_lev * + devfreq->profile->max_state) + lev]++; + devfreq->total_trans++; + } + devfreq->last_stat_updated = cur_time; + + return 0; +} + /* Load monitoring helper functions for governors use */ /** @@ -112,6 +157,11 @@ int update_devfreq(struct devfreq *devfreq) if (err) return err; + if (devfreq->profile->freq_table) + if (devfreq_update_status(devfreq, freq)) + dev_err(&devfreq->dev, + "Couldn't update frequency transition information.\n"); + devfreq->previous_freq = freq; return err; } @@ -378,6 +428,15 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->data = data; devfreq->nb.notifier_call = devfreq_notifier_call; + devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) * + devfreq->profile->max_state * + devfreq->profile->max_state, + GFP_KERNEL); + devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) * + devfreq->profile->max_state, + GFP_KERNEL); + devfreq->last_stat_updated = jiffies; + dev_set_name(&devfreq->dev, dev_name(dev)); err = device_register(&devfreq->dev); if (err) { @@ -601,6 +660,47 @@ static ssize_t show_available_freqs(struct device *d, return count; } +static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + ssize_t len; + int i, j, err; + unsigned int max_state = devfreq->profile->max_state; + + err = devfreq_update_status(devfreq, devfreq->previous_freq); + if (err) + return 0; + + len = sprintf(buf, " From : To\n"); + len += sprintf(buf + len, " :"); + for (i = 0; i < max_state; i++) + len += sprintf(buf + len, "%8u", + devfreq->profile->freq_table[i]); + + len += sprintf(buf + len, " time(ms)\n"); + + for (i = 0; i < max_state; i++) { + if (devfreq->profile->freq_table[i] + == devfreq->previous_freq) { + len += sprintf(buf + len, "*"); + } else { + len += sprintf(buf + len, " "); + } + len += sprintf(buf + len, "%8u:", + devfreq->profile->freq_table[i]); + for (j = 0; j < max_state; j++) + len += sprintf(buf + len, "%8u", + devfreq->trans_table[(i * max_state) + j]); + len += sprintf(buf + len, "%10u\n", + jiffies_to_msecs(devfreq->time_in_state[i])); + } + + len += sprintf(buf + len, "Total transition : %u\n", + devfreq->total_trans); + return len; +} + static struct device_attribute devfreq_attrs[] = { __ATTR(governor, S_IRUGO, show_governor, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), @@ -610,6 +710,7 @@ static struct device_attribute devfreq_attrs[] = { store_polling_interval), __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq), + __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL), { }, }; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 1461fb2355a..bc35c4aee6a 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -73,6 +73,8 @@ struct devfreq_dev_status { * from devfreq_remove_device() call. If the user * has registered devfreq->nb at a notifier-head, * this is the time to unregister it. + * @freq_table: Optional list of frequencies to support statistics. + * @max_state: The size of freq_table. */ struct devfreq_dev_profile { unsigned long initial_freq; @@ -83,6 +85,9 @@ struct devfreq_dev_profile { struct devfreq_dev_status *stat); int (*get_cur_freq)(struct device *dev, unsigned long *freq); void (*exit)(struct device *dev); + + unsigned int *freq_table; + unsigned int max_state; }; /** @@ -127,6 +132,10 @@ struct devfreq_governor { * @min_freq: Limit minimum frequency requested by user (0: none) * @max_freq: Limit maximum frequency requested by user (0: none) * @stop_polling: devfreq polling status of a device. + * @total_trans: Number of devfreq transitions + * @trans_table: Statistics of devfreq transitions + * @time_in_state: Statistics of devfreq states + * @last_stat_updated: The last time stat updated * * This structure stores the devfreq information for a give device. * @@ -153,6 +162,12 @@ struct devfreq { unsigned long min_freq; unsigned long max_freq; bool stop_polling; + + /* information for device freqeuncy transition */ + unsigned int total_trans; + unsigned int *trans_table; + unsigned long *time_in_state; + unsigned long last_stat_updated; }; #if defined(CONFIG_PM_DEVFREQ) -- cgit v1.2.3 From 2df5021fa9738905e8b1ab92fa0cd685430f54da Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:42 -0500 Subject: PM / devfreq: export update_devfreq Allow update_devfreq to be used by devfreq governor built as modules Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Acked-by: MyungJoo Ham Signed-off-by: MyungJoo Ham --- drivers/devfreq/devfreq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index bf6de38190c..e0002c5cbad 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -165,6 +165,7 @@ int update_devfreq(struct devfreq *devfreq) devfreq->previous_freq = freq; return err; } +EXPORT_SYMBOL(update_devfreq); /** * devfreq_monitor() - Periodically poll devfreq objects. -- cgit v1.2.3 From 3aa173b8db200bb96354481acc0a5b9e123119fe Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:43 -0500 Subject: PM / devfreq: provide hooks for governors to be registered Add devfreq_add_governor and devfreq_remove_governor which can be invoked by governors to register with devfreq. This sets up the stage to dynamically switch governors and allow governors to be dynamically loaded as well. Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Acked-by: MyungJoo Ham --- drivers/devfreq/devfreq.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/devfreq/governor.h | 4 ++ include/linux/devfreq.h | 3 ++ 3 files changed, 98 insertions(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index e0002c5cbad..679ac424472 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -36,6 +36,8 @@ static struct class *devfreq_class; */ static struct workqueue_struct *devfreq_wq; +/* The list of all device-devfreq governors */ +static LIST_HEAD(devfreq_governor_list); /* The list of all device-devfreq */ static LIST_HEAD(devfreq_list); static DEFINE_MUTEX(devfreq_list_lock); @@ -111,6 +113,32 @@ static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) return 0; } +/** + * find_devfreq_governor() - find devfreq governor from name + * @name: name of the governor + * + * Search the list of devfreq governors and return the matched + * governor's pointer. devfreq_list_lock should be held by the caller. + */ +static struct devfreq_governor *find_devfreq_governor(const char *name) +{ + struct devfreq_governor *tmp_governor; + + if (unlikely(IS_ERR_OR_NULL(name))) { + pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); + return ERR_PTR(-EINVAL); + } + WARN(!mutex_is_locked(&devfreq_list_lock), + "devfreq_list_lock must be locked."); + + list_for_each_entry(tmp_governor, &devfreq_governor_list, node) { + if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN)) + return tmp_governor; + } + + return ERR_PTR(-ENODEV); +} + /* Load monitoring helper functions for governors use */ /** @@ -515,6 +543,69 @@ int devfreq_resume_device(struct devfreq *devfreq) } EXPORT_SYMBOL(devfreq_resume_device); +/** + * devfreq_add_governor() - Add devfreq governor + * @governor: the devfreq governor to be added + */ +int devfreq_add_governor(struct devfreq_governor *governor) +{ + struct devfreq_governor *g; + int err = 0; + + if (!governor) { + pr_err("%s: Invalid parameters.\n", __func__); + return -EINVAL; + } + + mutex_lock(&devfreq_list_lock); + g = find_devfreq_governor(governor->name); + if (!IS_ERR(g)) { + pr_err("%s: governor %s already registered\n", __func__, + g->name); + err = -EINVAL; + goto err_out; + } + + list_add(&governor->node, &devfreq_governor_list); + +err_out: + mutex_unlock(&devfreq_list_lock); + + return err; +} +EXPORT_SYMBOL(devfreq_add_governor); + +/** + * devfreq_remove_device() - Remove devfreq feature from a device. + * @governor: the devfreq governor to be removed + */ +int devfreq_remove_governor(struct devfreq_governor *governor) +{ + struct devfreq_governor *g; + int err = 0; + + if (!governor) { + pr_err("%s: Invalid parameters.\n", __func__); + return -EINVAL; + } + + mutex_lock(&devfreq_list_lock); + g = find_devfreq_governor(governor->name); + if (IS_ERR(g)) { + pr_err("%s: governor %s not registered\n", __func__, + g->name); + err = -EINVAL; + goto err_out; + } + + list_del(&governor->node); +err_out: + mutex_unlock(&devfreq_list_lock); + + return err; +} +EXPORT_SYMBOL(devfreq_remove_governor); + static ssize_t show_governor(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index 26432ac0a39..fad7d632197 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -34,4 +34,8 @@ extern void devfreq_monitor_suspend(struct devfreq *devfreq); extern void devfreq_monitor_resume(struct devfreq *devfreq); extern void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay); + +extern int devfreq_add_governor(struct devfreq_governor *governor); +extern int devfreq_remove_governor(struct devfreq_governor *governor); + #endif /* _GOVERNOR_H */ diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index bc35c4aee6a..6484a3f8dda 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -92,6 +92,7 @@ struct devfreq_dev_profile { /** * struct devfreq_governor - Devfreq policy governor + * @node: list node - contains registered devfreq governors * @name: Governor's name * @get_target_freq: Returns desired operating frequency for the device. * Basically, get_target_freq will run @@ -107,6 +108,8 @@ struct devfreq_dev_profile { * Note that the callbacks are called with devfreq->lock locked by devfreq. */ struct devfreq_governor { + struct list_head node; + const char name[DEVFREQ_NAME_LEN]; int (*get_target_freq)(struct devfreq *this, unsigned long *freq); int (*event_handler)(struct devfreq *devfreq, -- cgit v1.2.3 From 83116e66a232184f733ecf09a41817cf893ede98 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:44 -0500 Subject: PM / devfreq: register governors with devfreq framework With the new registration functions, governors can be now registered with devfreq framework. NOTE: generates 'discards qualifiers from pointer target type' build warnings, which the next patche in this series fixes Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Acked-by: MyungJoo Ham Signed-off-by: MyungJoo Ham --- drivers/devfreq/governor_performance.c | 18 ++++++++++++++++++ drivers/devfreq/governor_powersave.c | 18 ++++++++++++++++++ drivers/devfreq/governor_simpleondemand.c | 18 ++++++++++++++++++ drivers/devfreq/governor_userspace.c | 18 ++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index eea3f9bd789..db8ff77dbed 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -45,3 +45,21 @@ const struct devfreq_governor devfreq_performance = { .get_target_freq = devfreq_performance_func, .event_handler = devfreq_performance_handler, }; + +static int __init devfreq_performance_init(void) +{ + return devfreq_add_governor(&devfreq_performance); +} +subsys_initcall(devfreq_performance_init); + +static void __exit devfreq_performance_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_performance); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_performance_exit); diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 2868d98ed3e..30f0fca8d63 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -42,3 +42,21 @@ const struct devfreq_governor devfreq_powersave = { .get_target_freq = devfreq_powersave_func, .event_handler = devfreq_powersave_handler, }; + +static int __init devfreq_powersave_init(void) +{ + return devfreq_add_governor(&devfreq_powersave); +} +subsys_initcall(devfreq_powersave_init); + +static void __exit devfreq_powersave_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_powersave); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_powersave_exit); diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index b5cf0fb24ef..85f9ed531b1 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -125,3 +125,21 @@ const struct devfreq_governor devfreq_simple_ondemand = { .get_target_freq = devfreq_simple_ondemand_func, .event_handler = devfreq_simple_ondemand_handler, }; + +static int __init devfreq_simple_ondemand_init(void) +{ + return devfreq_add_governor(&devfreq_simple_ondemand); +} +subsys_initcall(devfreq_simple_ondemand_init); + +static void __exit devfreq_simple_ondemand_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_simple_ondemand); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_simple_ondemand_exit); diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 7067555bd44..110f178fec0 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -140,3 +140,21 @@ const struct devfreq_governor devfreq_userspace = { .get_target_freq = devfreq_userspace_func, .event_handler = devfreq_userspace_handler, }; + +static int __init devfreq_userspace_init(void) +{ + return devfreq_add_governor(&devfreq_userspace); +} +subsys_initcall(devfreq_userspace_init); + +static void __exit devfreq_userspace_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_userspace); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_userspace_exit); -- cgit v1.2.3 From 1b5c1be2c88e8445a20fa1929e26c37e7ca8c926 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:45 -0500 Subject: PM / devfreq: map devfreq drivers to governor using name Allow devfreq drivers to register a preferred governor name and when the devfreq governor loads itself at a later point required drivers are managed appropriately, at the time of unload of a devfreq governor, stop managing those drivers as well. Since the governor structures do not need to be exposed anymore, remove the definitions and make them static NOTE: devfreq_list_lock is now used to protect governor start and stop - as this allows us to protect governors and devfreq with the proper dependencies as needed. As part of this change, change the registration of exynos bus driver to request for ondemand using the governor name. Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon [Merge conflict resolved by MyungJoo Ham] Signed-off-by: MyungJoo Ham --- drivers/devfreq/devfreq.c | 95 ++++++++++++++++++++++++++++--- drivers/devfreq/exynos4_bus.c | 2 +- drivers/devfreq/governor_performance.c | 2 +- drivers/devfreq/governor_powersave.c | 2 +- drivers/devfreq/governor_simpleondemand.c | 2 +- drivers/devfreq/governor_userspace.c | 2 +- include/linux/devfreq.h | 21 ++----- 7 files changed, 96 insertions(+), 30 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 679ac424472..0d7be03d561 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -159,6 +159,9 @@ int update_devfreq(struct devfreq *devfreq) return -EINVAL; } + if (!devfreq->governor) + return -EINVAL; + /* Reevaluate the proper frequency */ err = devfreq->governor->get_target_freq(devfreq, &freq); if (err) @@ -379,7 +382,9 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip) list_del(&devfreq->node); mutex_unlock(&devfreq_list_lock); - devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL); + if (devfreq->governor) + devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); if (devfreq->profile->exit) devfreq->profile->exit(devfreq->dev.parent); @@ -412,19 +417,20 @@ static void devfreq_dev_release(struct device *dev) * devfreq_add_device() - Add devfreq feature to the device * @dev: the device to add devfreq feature. * @profile: device-specific profile to run devfreq. - * @governor: the policy to choose frequency. + * @governor_name: name of the policy to choose frequency. * @data: private data for the governor. The devfreq framework does not * touch this value. */ struct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, - const struct devfreq_governor *governor, + const char *governor_name, void *data) { struct devfreq *devfreq; + struct devfreq_governor *governor; int err = 0; - if (!dev || !profile || !governor) { + if (!dev || !profile || !governor_name) { dev_err(dev, "%s: Invalid parameters.\n", __func__); return ERR_PTR(-EINVAL); } @@ -452,7 +458,7 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->dev.class = devfreq_class; devfreq->dev.release = devfreq_dev_release; devfreq->profile = profile; - devfreq->governor = governor; + strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN); devfreq->previous_freq = profile->initial_freq; devfreq->data = data; devfreq->nb.notifier_call = devfreq_notifier_call; @@ -478,10 +484,14 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_lock(&devfreq_list_lock); list_add(&devfreq->node, &devfreq_list); - mutex_unlock(&devfreq_list_lock); - err = devfreq->governor->event_handler(devfreq, - DEVFREQ_GOV_START, NULL); + governor = find_devfreq_governor(devfreq->governor_name); + if (!IS_ERR(governor)) + devfreq->governor = governor; + if (devfreq->governor) + err = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_START, NULL); + mutex_unlock(&devfreq_list_lock); if (err) { dev_err(dev, "%s: Unable to start governor for the device\n", __func__); @@ -524,6 +534,9 @@ int devfreq_suspend_device(struct devfreq *devfreq) if (!devfreq) return -EINVAL; + if (!devfreq->governor) + return 0; + return devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_SUSPEND, NULL); } @@ -538,6 +551,9 @@ int devfreq_resume_device(struct devfreq *devfreq) if (!devfreq) return -EINVAL; + if (!devfreq->governor) + return 0; + return devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_RESUME, NULL); } @@ -550,6 +566,7 @@ EXPORT_SYMBOL(devfreq_resume_device); int devfreq_add_governor(struct devfreq_governor *governor) { struct devfreq_governor *g; + struct devfreq *devfreq; int err = 0; if (!governor) { @@ -568,6 +585,38 @@ int devfreq_add_governor(struct devfreq_governor *governor) list_add(&governor->node, &devfreq_governor_list); + list_for_each_entry(devfreq, &devfreq_list, node) { + int ret = 0; + struct device *dev = devfreq->dev.parent; + + if (!strncmp(devfreq->governor_name, governor->name, + DEVFREQ_NAME_LEN)) { + /* The following should never occur */ + if (devfreq->governor) { + dev_warn(dev, + "%s: Governor %s already present\n", + __func__, devfreq->governor->name); + ret = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); + if (ret) { + dev_warn(dev, + "%s: Governor %s stop = %d\n", + __func__, + devfreq->governor->name, ret); + } + /* Fall through */ + } + devfreq->governor = governor; + ret = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_START, NULL); + if (ret) { + dev_warn(dev, "%s: Governor %s start=%d\n", + __func__, devfreq->governor->name, + ret); + } + } + } + err_out: mutex_unlock(&devfreq_list_lock); @@ -582,6 +631,7 @@ EXPORT_SYMBOL(devfreq_add_governor); int devfreq_remove_governor(struct devfreq_governor *governor) { struct devfreq_governor *g; + struct devfreq *devfreq; int err = 0; if (!governor) { @@ -597,6 +647,29 @@ int devfreq_remove_governor(struct devfreq_governor *governor) err = -EINVAL; goto err_out; } + list_for_each_entry(devfreq, &devfreq_list, node) { + int ret; + struct device *dev = devfreq->dev.parent; + + if (!strncmp(devfreq->governor_name, governor->name, + DEVFREQ_NAME_LEN)) { + /* we should have a devfreq governor! */ + if (!devfreq->governor) { + dev_warn(dev, "%s: Governor %s NOT present\n", + __func__, governor->name); + continue; + /* Fall through */ + } + ret = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); + if (ret) { + dev_warn(dev, "%s: Governor %s stop=%d\n", + __func__, devfreq->governor->name, + ret); + } + devfreq->governor = NULL; + } + } list_del(&governor->node); err_out: @@ -609,6 +682,9 @@ EXPORT_SYMBOL(devfreq_remove_governor); static ssize_t show_governor(struct device *dev, struct device_attribute *attr, char *buf) { + if (!to_devfreq(dev)->governor) + return -EINVAL; + return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name); } @@ -645,6 +721,9 @@ static ssize_t store_polling_interval(struct device *dev, unsigned int value; int ret; + if (!df->governor) + return -EINVAL; + ret = sscanf(buf, "%u", &value); if (ret != 1) return -EINVAL; diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index 68145316c49..b8ac28497b3 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c @@ -1040,7 +1040,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) busfreq_mon_reset(data); data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile, - &devfreq_simple_ondemand, NULL); + "simple_ondemand", NULL); if (IS_ERR(data->devfreq)) return PTR_ERR(data->devfreq); diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index db8ff77dbed..865a3695691 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -40,7 +40,7 @@ static int devfreq_performance_handler(struct devfreq *devfreq, return ret; } -const struct devfreq_governor devfreq_performance = { +static struct devfreq_governor devfreq_performance = { .name = "performance", .get_target_freq = devfreq_performance_func, .event_handler = devfreq_performance_handler, diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 30f0fca8d63..8612c0f96b7 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -37,7 +37,7 @@ static int devfreq_powersave_handler(struct devfreq *devfreq, return ret; } -const struct devfreq_governor devfreq_powersave = { +static struct devfreq_governor devfreq_powersave = { .name = "powersave", .get_target_freq = devfreq_powersave_func, .event_handler = devfreq_powersave_handler, diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 85f9ed531b1..a870a24bb56 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -120,7 +120,7 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, return 0; } -const struct devfreq_governor devfreq_simple_ondemand = { +static struct devfreq_governor devfreq_simple_ondemand = { .name = "simple_ondemand", .get_target_freq = devfreq_simple_ondemand_func, .event_handler = devfreq_simple_ondemand_handler, diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 110f178fec0..34fb80f50cf 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -135,7 +135,7 @@ static int devfreq_userspace_handler(struct devfreq *devfreq, return ret; } -const struct devfreq_governor devfreq_userspace = { +static struct devfreq_governor devfreq_userspace = { .name = "userspace", .get_target_freq = devfreq_userspace_func, .event_handler = devfreq_userspace_handler, diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 6484a3f8dda..235248cb2c9 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -125,6 +125,7 @@ struct devfreq_governor { * using devfreq. * @profile: device-specific devfreq profile * @governor: method how to choose frequency based on the usage. + * @governor_name: devfreq governor name for use with this devfreq * @nb: notifier block used to notify devfreq object that it should * reevaluate operable frequencies. Devfreq users may use * devfreq.nb to the corresponding register notifier call chain. @@ -155,6 +156,7 @@ struct devfreq { struct device dev; struct devfreq_dev_profile *profile; const struct devfreq_governor *governor; + char governor_name[DEVFREQ_NAME_LEN]; struct notifier_block nb; struct delayed_work work; @@ -176,7 +178,7 @@ struct devfreq { #if defined(CONFIG_PM_DEVFREQ) extern struct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, - const struct devfreq_governor *governor, + const char *governor_name, void *data); extern int devfreq_remove_device(struct devfreq *devfreq); extern int devfreq_suspend_device(struct devfreq *devfreq); @@ -190,17 +192,7 @@ extern int devfreq_register_opp_notifier(struct device *dev, extern int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq); -#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE -extern const struct devfreq_governor devfreq_powersave; -#endif -#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE -extern const struct devfreq_governor devfreq_performance; -#endif -#ifdef CONFIG_DEVFREQ_GOV_USERSPACE -extern const struct devfreq_governor devfreq_userspace; -#endif #ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND -extern const struct devfreq_governor devfreq_simple_ondemand; /** * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq * and devfreq_add_device @@ -223,7 +215,7 @@ struct devfreq_simple_ondemand_data { #else /* !CONFIG_PM_DEVFREQ */ static struct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, - struct devfreq_governor *governor, + const char *governor_name, void *data) { return NULL; @@ -262,11 +254,6 @@ static int devfreq_unregister_opp_notifier(struct device *dev, return -EINVAL; } -#define devfreq_powersave NULL -#define devfreq_performance NULL -#define devfreq_userspace NULL -#define devfreq_simple_ondemand NULL - #endif /* CONFIG_PM_DEVFREQ */ #endif /* __LINUX_DEVFREQ_H__ */ -- cgit v1.2.3 From eff607fdb1f787da1fedf46ab6e64adc2afd1c5a Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:46 -0500 Subject: PM / devfreq: governors: add GPL module license and allow module build Add GPL module license and remove the static build restrictions for building governors. This allows governors now to be loaded on a need basis and reloaded independently of kernel build Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Acked-by: MyungJoo Ham Signed-off-by: MyungJoo Ham --- drivers/devfreq/Kconfig | 8 ++++---- drivers/devfreq/governor_performance.c | 2 ++ drivers/devfreq/governor_powersave.c | 2 ++ drivers/devfreq/governor_simpleondemand.c | 2 ++ drivers/devfreq/governor_userspace.c | 2 ++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index f6b0a6e2ea5..0f079be1330 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -30,7 +30,7 @@ if PM_DEVFREQ comment "DEVFREQ Governors" config DEVFREQ_GOV_SIMPLE_ONDEMAND - bool "Simple Ondemand" + tristate "Simple Ondemand" help Chooses frequency based on the recent load on the device. Works similar as ONDEMAND governor of CPUFREQ does. A device with @@ -39,7 +39,7 @@ config DEVFREQ_GOV_SIMPLE_ONDEMAND values to the governor with data field at devfreq_add_device(). config DEVFREQ_GOV_PERFORMANCE - bool "Performance" + tristate "Performance" help Sets the frequency at the maximum available frequency. This governor always returns UINT_MAX as frequency so that @@ -47,7 +47,7 @@ config DEVFREQ_GOV_PERFORMANCE at any time. config DEVFREQ_GOV_POWERSAVE - bool "Powersave" + tristate "Powersave" help Sets the frequency at the minimum available frequency. This governor always returns 0 as frequency so that @@ -55,7 +55,7 @@ config DEVFREQ_GOV_POWERSAVE at any time. config DEVFREQ_GOV_USERSPACE - bool "Userspace" + tristate "Userspace" help Sets the frequency at the user specified one. This governor returns the user configured frequency if there diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index 865a3695691..c72f942f30a 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -10,6 +10,7 @@ */ #include +#include #include "governor.h" static int devfreq_performance_func(struct devfreq *df, @@ -63,3 +64,4 @@ static void __exit devfreq_performance_exit(void) return; } module_exit(devfreq_performance_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 8612c0f96b7..0c6bed567e6 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -10,6 +10,7 @@ */ #include +#include #include "governor.h" static int devfreq_powersave_func(struct devfreq *df, @@ -60,3 +61,4 @@ static void __exit devfreq_powersave_exit(void) return; } module_exit(devfreq_powersave_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index a870a24bb56..0720ba84ca9 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include "governor.h" @@ -143,3 +144,4 @@ static void __exit devfreq_simple_ondemand_exit(void) return; } module_exit(devfreq_simple_ondemand_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 34fb80f50cf..35de6e83c1f 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "governor.h" struct userspace_data { @@ -158,3 +159,4 @@ static void __exit devfreq_userspace_exit(void) return; } module_exit(devfreq_userspace_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 0359d1afe4013d1a216908b6be4c6695a1db6fd6 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:47 -0500 Subject: PM / devfreq: allow sysfs governor node to switch governor This allows us to select governor runtime from the default configuration without having to rebuild kernel or the devfreq driver using the sysfs node: /sys/class/devfreq/.../governor cat of the governor will return valid governor and an echo 'governor_name'>governor will switch governor Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Acked-by: MyungJoo Ham Signed-off-by: MyungJoo Ham --- Documentation/ABI/testing/sysfs-class-devfreq | 2 +- drivers/devfreq/devfreq.c | 45 ++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index 40f98a9428d..66876debca1 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -11,7 +11,7 @@ What: /sys/class/devfreq/.../governor Date: September 2011 Contact: MyungJoo Ham Description: - The /sys/class/devfreq/.../governor shows the name of the + The /sys/class/devfreq/.../governor show or set the name of the governor used by the corresponding devfreq object. What: /sys/class/devfreq/.../cur_freq diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 0d7be03d561..ff960f084c1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -688,6 +688,49 @@ static ssize_t show_governor(struct device *dev, return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name); } +static ssize_t store_governor(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct devfreq *df = to_devfreq(dev); + int ret; + char str_governor[DEVFREQ_NAME_LEN + 1]; + struct devfreq_governor *governor; + + ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor); + if (ret != 1) + return -EINVAL; + + mutex_lock(&devfreq_list_lock); + governor = find_devfreq_governor(str_governor); + if (IS_ERR(governor)) { + ret = PTR_ERR(governor); + goto out; + } + if (df->governor == governor) + goto out; + + if (df->governor) { + ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL); + if (ret) { + dev_warn(dev, "%s: Governor %s not stopped(%d)\n", + __func__, df->governor->name, ret); + goto out; + } + } + df->governor = governor; + strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN); + ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL); + if (ret) + dev_warn(dev, "%s: Governor %s not started(%d)\n", + __func__, df->governor->name, ret); +out: + mutex_unlock(&devfreq_list_lock); + + if (!ret) + ret = count; + return ret; +} + static ssize_t show_freq(struct device *dev, struct device_attribute *attr, char *buf) { @@ -873,7 +916,7 @@ static ssize_t show_trans_table(struct device *dev, struct device_attribute *att } static struct device_attribute devfreq_attrs[] = { - __ATTR(governor, S_IRUGO, show_governor, NULL), + __ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL), __ATTR(target_freq, S_IRUGO, show_target_freq, NULL), -- cgit v1.2.3 From 50a5b33e0159f8783ef617cdb9d5fbb6a3955b6f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 29 Oct 2012 15:01:48 -0500 Subject: PM / devfreq: Add sysfs node to expose available governors Now that governor list can be variable, knowing the available governors is useful to be able to select a governor using relevant sysfs node. Cc: Rajagopal Venkat Cc: MyungJoo Ham Cc: Kyungmin Park Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Nishanth Menon Signed-off-by: MyungJoo Ham --- Documentation/ABI/testing/sysfs-class-devfreq | 7 +++++++ drivers/devfreq/devfreq.c | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index 66876debca1..0ba6ea2f89d 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -71,3 +71,10 @@ Description: the available frequencies of the corresponding devfreq object. This is a snapshot of available frequencies and not limited by the min/max frequency restrictions. + +What: /sys/class/devfreq/.../available_governors +Date: October 2012 +Contact: Nishanth Menon +Description: + The /sys/class/devfreq/.../available_governors shows + currently available governors in the system. diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index ff960f084c1..45e053e5b13 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -730,6 +730,27 @@ out: ret = count; return ret; } +static ssize_t show_available_governors(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct devfreq_governor *tmp_governor; + ssize_t count = 0; + + mutex_lock(&devfreq_list_lock); + list_for_each_entry(tmp_governor, &devfreq_governor_list, node) + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), + "%s ", tmp_governor->name); + mutex_unlock(&devfreq_list_lock); + + /* Truncate the trailing space */ + if (count) + count--; + + count += sprintf(&buf[count], "\n"); + + return count; +} static ssize_t show_freq(struct device *dev, struct device_attribute *attr, char *buf) @@ -917,6 +938,7 @@ static ssize_t show_trans_table(struct device *dev, struct device_attribute *att static struct device_attribute devfreq_attrs[] = { __ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor), + __ATTR(available_governors, S_IRUGO, show_available_governors, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL), __ATTR(target_freq, S_IRUGO, show_target_freq, NULL), -- cgit v1.2.3 From dce9dc3a24f03b054dae02ef5cf1df7e97a8f558 Mon Sep 17 00:00:00 2001 From: Sangho Yi Date: Sat, 20 Oct 2012 01:16:34 +0900 Subject: PM / devfreq: exynos4_bus.c: Fixed an alignment of the func call args. I fixed the following check item (via checkpatch.pl --strict option): CHECK: Alignment should match open parenthesis Signed-off-by: Sangho Yi [Merge conflict resolved] Signed-off-by: MyungJoo Ham --- drivers/devfreq/exynos4_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index b8ac28497b3..74183720871 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c @@ -1030,7 +1030,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq); if (IS_ERR(opp)) { dev_err(dev, "Invalid initial frequency %lu kHz.\n", - exynos4_devfreq_profile.initial_freq); + exynos4_devfreq_profile.initial_freq); return PTR_ERR(opp); } data->curr_opp = opp; -- cgit v1.2.3 From f3fd0c8a7fc1e4f3107a09a75e622781d3007b56 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 21 Nov 2012 00:21:39 +0100 Subject: ACPI: Allow ACPI handles of devices to be initialized in advance Currently, the ACPI handles of devices are initialized from within device_add(), by acpi_bind_one() called from acpi_platform_notify() which first uses the .find_device() routine provided by the device's bus type to find the matching device node in the ACPI namespace. This is a source of some computational overhead and, moreover, the correctness of the result depends on the implementation of .find_device() which is known to fail occasionally for some bus types (e.g. PCI). In some cases, however, the corresponding ACPI device node is known already before calling device_add() for the given struct device object and the whole .find_device() dance in acpi_platform_notify() is then simply unnecessary. For this reason, make it possible to initialize the ACPI handles of devices before calling device_add() for them. Modify acpi_platform_notify() to call acpi_bind_one() in advance to check the device's existing ACPI handle and skip the .find_device() search if that is successful. Change acpi_bind_one() accordingly. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/glue.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 2f3849aedc9..3e75d6e5a46 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -130,46 +130,59 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) { struct acpi_device *acpi_dev; acpi_status status; - struct acpi_device_physical_node *physical_node; + struct acpi_device_physical_node *physical_node, *pn; char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2]; int retval = -EINVAL; if (dev->acpi_handle) { - dev_warn(dev, "Drivers changed 'acpi_handle'\n"); - return -EINVAL; + if (handle) { + dev_warn(dev, "ACPI handle is already set\n"); + return -EINVAL; + } else { + handle = dev->acpi_handle; + } } + if (!handle) + return -EINVAL; get_device(dev); status = acpi_bus_get_device(handle, &acpi_dev); if (ACPI_FAILURE(status)) goto err; - physical_node = kzalloc(sizeof(struct acpi_device_physical_node), - GFP_KERNEL); + physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL); if (!physical_node) { retval = -ENOMEM; goto err; } mutex_lock(&acpi_dev->physical_node_lock); + + /* Sanity check. */ + list_for_each_entry(pn, &acpi_dev->physical_node_list, node) + if (pn->dev == dev) { + dev_warn(dev, "Already associated with ACPI node\n"); + goto err_free; + } + /* allocate physical node id according to physical_node_id_bitmap */ physical_node->node_id = find_first_zero_bit(acpi_dev->physical_node_id_bitmap, ACPI_MAX_PHYSICAL_NODE); if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) { retval = -ENOSPC; - mutex_unlock(&acpi_dev->physical_node_lock); - kfree(physical_node); - goto err; + goto err_free; } set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap); physical_node->dev = dev; list_add_tail(&physical_node->node, &acpi_dev->physical_node_list); acpi_dev->physical_node_count++; + mutex_unlock(&acpi_dev->physical_node_lock); - dev->acpi_handle = handle; + if (!dev->acpi_handle) + dev->acpi_handle = handle; if (!physical_node->node_id) strcpy(physical_node_name, PHYSICAL_NODE_STRING); @@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) return 0; err: + dev->acpi_handle = NULL; put_device(dev); return retval; + + err_free: + mutex_unlock(&acpi_dev->physical_node_lock); + kfree(physical_node); + goto err; } static int acpi_unbind_one(struct device *dev) @@ -247,6 +266,10 @@ static int acpi_platform_notify(struct device *dev) acpi_handle handle; int ret = -EINVAL; + ret = acpi_bind_one(dev, NULL); + if (!ret) + goto out; + if (!dev->bus || !dev->parent) { /* bridge devices genernally haven't bus or parent */ ret = acpi_find_bridge_device(dev, &handle); @@ -260,10 +283,11 @@ static int acpi_platform_notify(struct device *dev) } if ((ret = type->find_device(dev, &handle)) != 0) DBG("Can't get handler for %s\n", dev_name(dev)); - end: + end: if (!ret) acpi_bind_one(dev, handle); + out: #if ACPI_GLUE_DEBUG if (!ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -- cgit v1.2.3 From 95f8a082b9b1ead0c2859f2a7b1ac91ff63d8765 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 21 Nov 2012 00:21:50 +0100 Subject: ACPI / driver core: Introduce struct acpi_dev_node and related macros To avoid adding an ACPI handle pointer to struct device on architectures that don't use ACPI, or generally when CONFIG_ACPI is not set, in which cases that pointer is useless, define struct acpi_dev_node that will contain the handle pointer if CONFIG_ACPI is set and will be empty otherwise and use it to represent the ACPI device node field in struct device. In addition to that define macros for reading and setting the ACPI handle of a device that don't generate code when CONFIG_ACPI is unset. Modify the ACPI subsystem to use those macros instead of referring to the given device's ACPI handle directly. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Acked-by: Greg Kroah-Hartman --- drivers/acpi/glue.c | 16 ++++++++-------- drivers/acpi/scan.c | 4 ++-- include/acpi/acpi_bus.h | 2 +- include/linux/device.h | 18 ++++++++++++++++-- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 3e75d6e5a46..01551840d23 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -134,12 +134,12 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2]; int retval = -EINVAL; - if (dev->acpi_handle) { + if (ACPI_HANDLE(dev)) { if (handle) { dev_warn(dev, "ACPI handle is already set\n"); return -EINVAL; } else { - handle = dev->acpi_handle; + handle = ACPI_HANDLE(dev); } } if (!handle) @@ -181,8 +181,8 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) mutex_unlock(&acpi_dev->physical_node_lock); - if (!dev->acpi_handle) - dev->acpi_handle = handle; + if (!ACPI_HANDLE(dev)) + ACPI_HANDLE_SET(dev, acpi_dev->handle); if (!physical_node->node_id) strcpy(physical_node_name, PHYSICAL_NODE_STRING); @@ -200,7 +200,7 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) return 0; err: - dev->acpi_handle = NULL; + ACPI_HANDLE_SET(dev, NULL); put_device(dev); return retval; @@ -217,10 +217,10 @@ static int acpi_unbind_one(struct device *dev) acpi_status status; struct list_head *node, *next; - if (!dev->acpi_handle) + if (!ACPI_HANDLE(dev)) return 0; - status = acpi_bus_get_device(dev->acpi_handle, &acpi_dev); + status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev); if (ACPI_FAILURE(status)) goto err; @@ -246,7 +246,7 @@ static int acpi_unbind_one(struct device *dev) sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name); sysfs_remove_link(&dev->kobj, "firmware_node"); - dev->acpi_handle = NULL; + ACPI_HANDLE_SET(dev, NULL); /* acpi_bind_one increase refcnt by one */ put_device(dev); kfree(entry); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d842569395a..e92ca67d0e4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -386,8 +386,8 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, { struct acpi_device *adev; - if (!ids || !dev->acpi_handle - || ACPI_FAILURE(acpi_bus_get_device(dev->acpi_handle, &adev))) + if (!ids || !ACPI_HANDLE(dev) + || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev))) return NULL; return __acpi_match_device(adev, ids); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index bb1537c5e67..d1659904f2a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -410,7 +410,7 @@ acpi_handle acpi_get_child(acpi_handle, u64); int acpi_is_root_bridge(acpi_handle); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->acpi_handle)) +#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev)) int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); int acpi_disable_wakeup_device_power(struct acpi_device *dev); diff --git a/include/linux/device.h b/include/linux/device.h index cc3aee57a46..05292e48834 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -578,6 +578,12 @@ struct device_dma_parameters { unsigned long segment_boundary_mask; }; +struct acpi_dev_node { +#ifdef CONFIG_ACPI + void *handle; +#endif +}; + /** * struct device - The basic device structure * @parent: The device's "parent" device, the device to which it is attached. @@ -618,7 +624,7 @@ struct device_dma_parameters { * @dma_mem: Internal for coherent mem override. * @archdata: For arch-specific additions. * @of_node: Associated device tree node. - * @acpi_handle: Associated ACPI device node's namespace handle. + * @acpi_node: Associated ACPI device node. * @devt: For creating the sysfs "dev". * @id: device instance * @devres_lock: Spinlock to protect the resource of the device. @@ -683,7 +689,7 @@ struct device { struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ - void *acpi_handle; /* associated ACPI device node */ + struct acpi_dev_node acpi_node; /* associated ACPI device node */ dev_t devt; /* dev_t, creates the sysfs "dev" */ u32 id; /* device instance */ @@ -704,6 +710,14 @@ static inline struct device *kobj_to_dev(struct kobject *kobj) return container_of(kobj, struct device, kobj); } +#ifdef CONFIG_ACPI +#define ACPI_HANDLE(dev) ((dev)->acpi_node.handle) +#define ACPI_HANDLE_SET(dev, _handle_) (dev)->acpi_node.handle = (_handle_) +#else +#define ACPI_HANDLE(dev) (NULL) +#define ACPI_HANDLE_SET(dev, _handle_) do { } while (0) +#endif + /* Get the wakeup routines, which depend on struct device */ #include -- cgit v1.2.3 From 863f9f30e6c1e30cb19a0cd17c5cf8879257dfd7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 21 Nov 2012 00:21:59 +0100 Subject: ACPI / platform: Initialize ACPI handles of platform devices in advance The current platform device creation and registration code in acpi_create_platform_device() is quite convoluted. This function takes an ACPI device node as an argument and eventually calls platform_device_register_resndata() to create and register a platform device object on the basis of the information contained in that code. However, it doesn't associate the new platform device with the ACPI node directly, but instead it relies on acpi_platform_notify(), called from within device_add(), to find that ACPI node again with the help of acpi_platform_find_device() and acpi_platform_match() and then attach the new platform device to it. This causes an additional ACPI namespace walk to happen and is clearly suboptimal. Use the observation that it is now possible to initialize the ACPI handle of a device before calling device_add() for it to make this code more straightforward. Namely, add a new field to struct platform_device_info allowing us to pass the ACPI handle of interest to platform_device_register_full(), which will then use it to initialize the new device's ACPI handle before registering it. This will cause acpi_platform_notify() to use the ACPI handle from the device structure directly instead of using the .find_device() routine provided by the device's bus type. In consequence, acpi_platform_bus, acpi_platform_find_device(), and acpi_platform_match() are not necessary any more, so remove them. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Acked-by: Greg Kroah-Hartman --- drivers/acpi/acpi_platform.c | 76 ++++++----------------------------------- drivers/base/platform.c | 2 ++ include/linux/platform_device.h | 1 + 3 files changed, 13 insertions(+), 66 deletions(-) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 7ac20d8b8f0..b7df9b197bc 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -33,7 +33,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) { struct platform_device *pdev = NULL; struct acpi_device *acpi_parent; - struct device *parent = NULL; + struct platform_device_info pdevinfo; struct resource_list_entry *rentry; struct list_head resource_list; struct resource *resources; @@ -60,11 +60,13 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) acpi_dev_free_resource_list(&resource_list); + memset(&pdevinfo, 0, sizeof(pdevinfo)); /* * If the ACPI node has a parent and that parent has a physical device * attached to it, that physical device should be the parent of the * platform device we are about to create. */ + pdevinfo.parent = NULL; acpi_parent = adev->parent; if (acpi_parent) { struct acpi_device_physical_node *entry; @@ -76,12 +78,16 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) entry = list_first_entry(list, struct acpi_device_physical_node, node); - parent = entry->dev; + pdevinfo.parent = entry->dev; } mutex_unlock(&acpi_parent->physical_node_lock); } - pdev = platform_device_register_resndata(parent, dev_name(&adev->dev), - -1, resources, count, NULL, 0); + pdevinfo.name = dev_name(&adev->dev); + pdevinfo.id = -1; + pdevinfo.res = resources; + pdevinfo.num_res = count; + pdevinfo.acpi_node.handle = adev->handle; + pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { dev_err(&adev->dev, "platform device creation failed: %ld\n", PTR_ERR(pdev)); @@ -94,65 +100,3 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) kfree(resources); return pdev; } - -static acpi_status acpi_platform_match(acpi_handle handle, u32 depth, - void *data, void **return_value) -{ - struct platform_device *pdev = data; - struct acpi_device *adev; - acpi_status status; - - status = acpi_bus_get_device(handle, &adev); - if (ACPI_FAILURE(status)) - return status; - - /* Skip ACPI devices that have physical device attached */ - if (adev->physical_node_count) - return AE_OK; - - if (!strcmp(dev_name(&pdev->dev), dev_name(&adev->dev))) { - *(acpi_handle *)return_value = handle; - return AE_CTRL_TERMINATE; - } - - return AE_OK; -} - -static int acpi_platform_find_device(struct device *dev, acpi_handle *handle) -{ - struct platform_device *pdev = to_platform_device(dev); - char *name, *tmp, *hid; - - /* - * The platform device is named using the ACPI device name - * _HID:INSTANCE so we strip the INSTANCE out in order to find the - * correct device using its _HID. - */ - name = kstrdup(dev_name(dev), GFP_KERNEL); - if (!name) - return -ENOMEM; - - tmp = name; - hid = strsep(&tmp, ":"); - if (!hid) { - kfree(name); - return -ENODEV; - } - - *handle = NULL; - acpi_get_devices(hid, acpi_platform_match, pdev, handle); - - kfree(name); - return *handle ? 0 : -ENODEV; -} - -static struct acpi_bus_type acpi_platform_bus = { - .bus = &platform_bus_type, - .find_device = acpi_platform_find_device, -}; - -static int __init acpi_platform_init(void) -{ - return register_acpi_bus_type(&acpi_platform_bus); -} -arch_initcall(acpi_platform_init); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 7de29ebfce7..49fd96e2346 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -437,6 +437,7 @@ struct platform_device *platform_device_register_full( goto err_alloc; pdev->dev.parent = pdevinfo->parent; + ACPI_HANDLE_SET(&pdev->dev, pdevinfo->acpi_node.handle); if (pdevinfo->dma_mask) { /* @@ -467,6 +468,7 @@ struct platform_device *platform_device_register_full( ret = platform_device_add(pdev); if (ret) { err: + ACPI_HANDLE_SET(&pdev->dev, NULL); kfree(pdev->dev.dma_mask); err_alloc: diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 5711e9525a2..a9ded9a3c17 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -55,6 +55,7 @@ extern int platform_add_devices(struct platform_device **, int); struct platform_device_info { struct device *parent; + struct acpi_dev_node acpi_node; const char *name; int id; -- cgit v1.2.3 From ce2650d40dff23f2c6f9718bb3ec63e12c5c7f27 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Wed, 21 Nov 2012 01:18:30 +0100 Subject: cpufreq: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/longhaul.c | 2 +- drivers/cpufreq/powernow-k8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 53ddbc760af..8d7ebb286e6 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -946,7 +946,7 @@ static struct cpufreq_driver longhaul_driver = { .target = longhaul_target, .get = longhaul_get, .init = longhaul_cpu_init, - .exit = __devexit_p(longhaul_cpu_exit), + .exit = longhaul_cpu_exit, .name = "longhaul", .owner = THIS_MODULE, .attr = longhaul_attr, diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e3ebb4fa2c3..1fd0c8a48ed 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1242,7 +1242,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = { .target = powernowk8_target, .bios_limit = acpi_processor_get_bios_limit, .init = powernowk8_cpu_init, - .exit = __devexit_p(powernowk8_cpu_exit), + .exit = powernowk8_cpu_exit, .get = powernowk8_get, .name = "powernow-k8", .owner = THIS_MODULE, -- cgit v1.2.3 From c5fa4ab5ab417d8d7bd658957ce7b7e6ef0cdaf3 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Wed, 21 Nov 2012 01:18:40 +0100 Subject: cpufreq: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-cpu0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index e9158278c71..52bf36d599f 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -174,7 +174,7 @@ static struct cpufreq_driver cpu0_cpufreq_driver = { .attr = cpu0_cpufreq_attr, }; -static int __devinit cpu0_cpufreq_driver_init(void) +static int cpu0_cpufreq_driver_init(void) { struct device_node *np; int ret; -- cgit v1.2.3 From c0e61cb151f2ff8edd02af23b2bd49f625288124 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Wed, 21 Nov 2012 01:18:49 +0100 Subject: cpufreq: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/longhaul.c | 2 +- drivers/cpufreq/powernow-k8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 8d7ebb286e6..f1fa500ac10 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -930,7 +930,7 @@ static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy) return 0; } -static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) +static int longhaul_cpu_exit(struct cpufreq_policy *policy) { cpufreq_frequency_table_put_attr(policy->cpu); return 0; diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 1fd0c8a48ed..056faf6af1a 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1186,7 +1186,7 @@ err_out: return -ENODEV; } -static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol) +static int powernowk8_cpu_exit(struct cpufreq_policy *pol) { struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); -- cgit v1.2.3 From 876ab79055019e248508cfd0dee7caa3c0c831ed Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 21 Nov 2012 23:12:12 +0100 Subject: ACPI / PM: Add Sony Vaio VPCEB1S1E to nonvs blacklist. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sony Vaio VPCEB1S1E does not resume correctly without acpi_sleep=nonvs, so add it to the ACPI sleep blacklist. References: https://bugzilla.kernel.org/show_bug.cgi?id=48781 Reported-by: Sébastien Wilmet Cc: Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8640782944c..1463c56092c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -534,6 +534,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, { .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1S1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), + }, + }, + { + .callback = init_nvs_nosave, .ident = "Sony Vaio VGN-FW520F", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), -- cgit v1.2.3 From b59bc2fbb4bb67e486c40cdb6a306c06acbaec06 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Wed, 21 Nov 2012 23:13:09 +0100 Subject: ACPI: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/ghes.c | 2 +- drivers/acpi/hed.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 1599566ed1f..da93c003e95 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -994,7 +994,7 @@ err: return rc; } -static int __devexit ghes_remove(struct platform_device *ghes_dev) +static int ghes_remove(struct platform_device *ghes_dev) { struct ghes *ghes; struct acpi_hest_generic *generic; diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 20a0f2c3ca3..b514e81e8cf 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -70,7 +70,7 @@ static int __devinit acpi_hed_add(struct acpi_device *device) return 0; } -static int __devexit acpi_hed_remove(struct acpi_device *device, int type) +static int acpi_hed_remove(struct acpi_device *device, int type) { hed_handle = NULL; return 0; -- cgit v1.2.3 From fbfddae696572e57a441252abbd65f7220e06030 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Wed, 21 Nov 2012 01:36:28 +0000 Subject: ACPI: Add acpi_handle_() interfaces This patch introduces acpi_handle_(), where is a kernel message level such as err/warn/info, to support improved logging messages for ACPI, esp. hot-plug operations. acpi_handle_() appends "ACPI" prefix and ACPI object path to the messages. This improves diagnosis of hotplug operations since an error message in a log file identifies an object that caused an issue. This interface acquires the global namespace mutex to obtain an object path. In interrupt context, it shows the object path as . acpi_handle_() takes acpi_handle as an argument, which is passed to ACPI hotplug notify handlers from the ACPICA. Therefore, it is always available unlike other kernel objects, such as device. For example: acpi_handle_err(handle, "Device don't exist, dropping EJECT\n"); logs an error message like this at KERN_ERR. ACPI: \_SB_.SCK4.CPU4: Device don't exist, dropping EJECT ACPI hot-plug drivers can use acpi_handle_() when they need to identify a target ACPI object path in their messages, such as error cases. The usage model is similar to dev_(). acpi_handle_() can be used when a device is not created or is invalid during hot-plug operations. ACPI object path is also consistent on the platform, unlike device name that gets incremented over hotplug operations. ACPI drivers should use dev_() when a device object is valid. Device name provides more user friendly information, and avoids acquiring the global ACPI namespace mutex. ACPI drivers also continue to use pr_() when they do not need to specify device information, such as boot-up messages. Note: ACPI_[WARNING|INFO|ERROR]() are intended for the ACPICA and are not associated with the kernel message level. Signed-off-by: Toshi Kani Tested-by: Vijay Mohan Pandarathil Signed-off-by: Rafael J. Wysocki --- drivers/acpi/utils.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 462f7e30036..74437130431 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -457,3 +459,39 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, #endif } EXPORT_SYMBOL(acpi_evaluate_hotplug_ost); + +/** + * acpi_handle_printk: Print message with ACPI prefix and object path + * + * This function is called through acpi_handle_ macros and prints + * a message with ACPI prefix and object path. This function acquires + * the global namespace mutex to obtain an object path. In interrupt + * context, it shows the object path as . + */ +void +acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + struct acpi_buffer buffer = { + .length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL + }; + const char *path; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + if (in_interrupt() || + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK) + path = ""; + else + path = buffer.pointer; + + printk("%sACPI: %s: %pV", level, path, &vaf); + + va_end(args); + kfree(buffer.pointer); +} +EXPORT_SYMBOL(acpi_handle_printk); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 87edfcc0ab6..9201ac1f051 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -434,4 +434,47 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, #define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0) #endif +#ifdef CONFIG_ACPI +__printf(3, 4) +void acpi_handle_printk(const char *level, acpi_handle handle, + const char *fmt, ...); +#else /* !CONFIG_ACPI */ +static inline __printf(3, 4) void +acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {} +#endif /* !CONFIG_ACPI */ + +/* + * acpi_handle_: Print message with ACPI prefix and object path + * + * These interfaces acquire the global namespace mutex to obtain an object + * path. In interrupt context, it shows the object path as . + */ +#define acpi_handle_emerg(handle, fmt, ...) \ + acpi_handle_printk(KERN_EMERG, handle, fmt, ##__VA_ARGS__) +#define acpi_handle_alert(handle, fmt, ...) \ + acpi_handle_printk(KERN_ALERT, handle, fmt, ##__VA_ARGS__) +#define acpi_handle_crit(handle, fmt, ...) \ + acpi_handle_printk(KERN_CRIT, handle, fmt, ##__VA_ARGS__) +#define acpi_handle_err(handle, fmt, ...) \ + acpi_handle_printk(KERN_ERR, handle, fmt, ##__VA_ARGS__) +#define acpi_handle_warn(handle, fmt, ...) \ + acpi_handle_printk(KERN_WARNING, handle, fmt, ##__VA_ARGS__) +#define acpi_handle_notice(handle, fmt, ...) \ + acpi_handle_printk(KERN_NOTICE, handle, fmt, ##__VA_ARGS__) +#define acpi_handle_info(handle, fmt, ...) \ + acpi_handle_printk(KERN_INFO, handle, fmt, ##__VA_ARGS__) + +/* REVISIT: Support CONFIG_DYNAMIC_DEBUG when necessary */ +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#define acpi_handle_debug(handle, fmt, ...) \ + acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__) +#else +#define acpi_handle_debug(handle, fmt, ...) \ +({ \ + if (0) \ + acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__); \ + 0; \ +}) +#endif + #endif /*_LINUX_ACPI_H*/ -- cgit v1.2.3 From 47db4547ffe5aa2eb5b053e6c02f0561fbbfa221 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 20 Nov 2012 23:42:27 +0000 Subject: ACPI: Update CPU hotplug error messages Updated CPU hotplug error messages with acpi_handle_(), dev_() and pr_(). Modified some messages for clarity. Added error status / id info to the messages where needed. Signed-off-by: Toshi Kani Tested-by: Vijay Mohan Pandarathil Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 8cc33d0e5d8..e83311bf1eb 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -282,7 +283,9 @@ static int acpi_processor_get_info(struct acpi_device *device) /* Declared with "Processor" statement; match ProcessorID */ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Evaluating processor object\n"); + dev_err(&device->dev, + "Failed to evaluate processor object (0x%x)\n", + status); return -ENODEV; } @@ -301,8 +304,9 @@ static int acpi_processor_get_info(struct acpi_device *device) status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, NULL, &value); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Evaluating processor _UID [%#x]\n", status); + dev_err(&device->dev, + "Failed to evaluate processor _UID (0x%x)\n", + status); return -ENODEV; } device_declaration = 1; @@ -345,7 +349,7 @@ static int acpi_processor_get_info(struct acpi_device *device) if (!object.processor.pblk_address) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); else if (object.processor.pblk_length != 6) - printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n", + dev_err(&device->dev, "Invalid PBLK length [%d]\n", object.processor.pblk_length); else { pr->throttling.address = object.processor.pblk_address; @@ -430,8 +434,8 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, * Initialize missing things */ if (pr->flags.need_hotplug_init) { - printk(KERN_INFO "Will online and init hotplugged " - "CPU: %d\n", pr->id); + pr_info("Will online and init hotplugged CPU: %d\n", + pr->id); WARN(acpi_processor_start(pr), "Failed to start CPU:" " %d\n", pr->id); pr->flags.need_hotplug_init = 0; @@ -492,14 +496,16 @@ static __ref int acpi_processor_start(struct acpi_processor *pr) &pr->cdev->device.kobj, "thermal_cooling"); if (result) { - printk(KERN_ERR PREFIX "Create sysfs link\n"); + dev_err(&device->dev, + "Failed to create sysfs link 'thermal_cooling'\n"); goto err_thermal_unregister; } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); if (result) { - printk(KERN_ERR PREFIX "Create sysfs link\n"); + dev_err(&pr->cdev->device, + "Failed to create sysfs link 'device'\n"); goto err_remove_sysfs_thermal; } @@ -561,8 +567,9 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) */ if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { - printk(KERN_WARNING "BIOS reported wrong ACPI id " - "for the processor\n"); + dev_warn(&device->dev, + "BIOS reported wrong ACPI id %d for the processor\n", + pr->id); result = -ENODEV; goto err_free_cpumask; } @@ -716,7 +723,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, result = acpi_processor_device_add(handle, &device); if (result) { - printk(KERN_ERR PREFIX "Unable to add the device\n"); + acpi_handle_err(handle, "Unable to add the device\n"); break; } @@ -728,17 +735,19 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, "received ACPI_NOTIFY_EJECT_REQUEST\n")); if (acpi_bus_get_device(handle, &device)) { - pr_err(PREFIX "Device don't exist, dropping EJECT\n"); + acpi_handle_err(handle, + "Device don't exist, dropping EJECT\n"); break; } if (!acpi_driver_data(device)) { - pr_err(PREFIX "Driver data is NULL, dropping EJECT\n"); + acpi_handle_err(handle, + "Driver data is NULL, dropping EJECT\n"); break; } ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); if (!ej_event) { - pr_err(PREFIX "No memory, dropping EJECT\n"); + acpi_handle_err(handle, "No memory, dropping EJECT\n"); break; } @@ -848,7 +857,7 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) * and do it when the CPU gets online the first time * TBD: Cleanup above functions and try to do this more elegant. */ - printk(KERN_INFO "CPU %d got hotplugged\n", pr->id); + pr_info("CPU %d got hotplugged\n", pr->id); pr->flags.need_hotplug_init = 1; return AE_OK; -- cgit v1.2.3 From ab6c57099db14d64c383e4d0392eab05d013630f Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 20 Nov 2012 23:42:28 +0000 Subject: ACPI: Update Memory hotplug error messages Updated Memory hotplug error messages with acpi_handle_(), dev_() and pr_(). Added missing "\n". Signed-off-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_memhotplug.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index e0f7425c885..eb30e5ab4ca 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #define ACPI_MEMORY_DEVICE_CLASS "memory" @@ -175,7 +176,7 @@ acpi_memory_get_device(acpi_handle handle, /* Get the parent device */ result = acpi_bus_get_device(phandle, &pdevice); if (result) { - printk(KERN_WARNING PREFIX "Cannot get acpi bus device"); + acpi_handle_warn(phandle, "Cannot get acpi bus device\n"); return -EINVAL; } @@ -185,14 +186,14 @@ acpi_memory_get_device(acpi_handle handle, */ result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE); if (result) { - printk(KERN_WARNING PREFIX "Cannot add acpi bus"); + acpi_handle_warn(handle, "Cannot add acpi bus\n"); return -EINVAL; } end: *mem_device = acpi_driver_data(device); if (!(*mem_device)) { - printk(KERN_ERR "\n driver data not found"); + dev_err(&device->dev, "driver data not found\n"); return -ENODEV; } @@ -229,7 +230,8 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) /* Get the range from the _CRS */ result = acpi_memory_get_device_resources(mem_device); if (result) { - printk(KERN_ERR PREFIX "get_device_resources failed\n"); + dev_err(&mem_device->device->dev, + "get_device_resources failed\n"); mem_device->state = MEMORY_INVALID_STATE; return result; } @@ -276,7 +278,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) num_enabled++; } if (!num_enabled) { - printk(KERN_ERR PREFIX "add_memory failed\n"); + dev_err(&mem_device->device->dev, "add_memory failed\n"); mem_device->state = MEMORY_INVALID_STATE; return -EINVAL; } @@ -336,7 +338,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "\nReceived DEVICE CHECK notification for device\n")); if (acpi_memory_get_device(handle, &mem_device)) { - printk(KERN_ERR PREFIX "Cannot find driver data\n"); + acpi_handle_err(handle, "Cannot find driver data\n"); break; } @@ -344,7 +346,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) break; if (acpi_memory_enable_device(mem_device)) { - printk(KERN_ERR PREFIX "Cannot enable memory device\n"); + acpi_handle_err(handle,"Cannot enable memory device\n"); break; } @@ -356,12 +358,12 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) "\nReceived EJECT REQUEST notification for device\n")); if (acpi_bus_get_device(handle, &device)) { - printk(KERN_ERR PREFIX "Device doesn't exist\n"); + acpi_handle_err(handle, "Device doesn't exist\n"); break; } mem_device = acpi_driver_data(device); if (!mem_device) { - printk(KERN_ERR PREFIX "Driver Data is NULL\n"); + acpi_handle_err(handle, "Driver Data is NULL\n"); break; } @@ -429,13 +431,13 @@ static int acpi_memory_device_add(struct acpi_device *device) /* Set the device state */ mem_device->state = MEMORY_POWER_ON_STATE; - printk(KERN_DEBUG "%s \n", acpi_device_name(device)); + pr_debug("%s\n", acpi_device_name(device)); if (!acpi_memory_check_device(mem_device)) { /* call add_memory func */ result = acpi_memory_enable_device(mem_device); if (result) { - printk(KERN_ERR PREFIX + dev_err(&device->dev, "Error in acpi_memory_enable_device\n"); acpi_memory_device_free(mem_device); } -- cgit v1.2.3 From 3d78bd9ef746d6468b1dbb2518b1287092b997b5 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 20 Nov 2012 23:42:29 +0000 Subject: ACPI: Update Container hotplug error messages Updated Container hotplug error messages with acpi_handle_() and pr_(). Removed an unnecessary check to the device arg in acpi_container_add(). Signed-off-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/container.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 69e2d6be910..811910b50b7 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -110,12 +110,6 @@ static int acpi_container_add(struct acpi_device *device) { struct acpi_container *container; - - if (!device) { - printk(KERN_ERR PREFIX "device is NULL\n"); - return -EINVAL; - } - container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL); if (!container) return -ENOMEM; @@ -177,7 +171,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) case ACPI_NOTIFY_BUS_CHECK: /* Fall through */ case ACPI_NOTIFY_DEVICE_CHECK: - printk(KERN_WARNING "Container driver received %s event\n", + pr_debug("Container driver received %s event\n", (type == ACPI_NOTIFY_BUS_CHECK) ? "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"); @@ -198,7 +192,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) result = container_device_add(&device, handle); if (result) { - printk(KERN_WARNING "Failed to add container\n"); + acpi_handle_warn(handle, "Failed to add container\n"); break; } -- cgit v1.2.3 From cd73018f628e5016792575e54401ad6faab3a901 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 20 Nov 2012 23:42:30 +0000 Subject: ACPI: Update Dock hotplug error messages Updated Dock hotplug error messages with acpi_handle_() and pr_(). Replaced acpi_get_name() & kfree() with apci_handle_(). Added error status to the messages where needed. Signed-off-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index ae4ebf2d4cd..f32bd47b35e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -460,12 +461,8 @@ static void handle_dock(struct dock_station *ds, int dock) struct acpi_object_list arg_list; union acpi_object arg; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); - - printk(KERN_INFO PREFIX "%s - %s\n", - (char *)name_buffer.pointer, dock ? "docking" : "undocking"); + acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking"); /* _DCK method has one argument */ arg_list.count = 1; @@ -474,11 +471,10 @@ static void handle_dock(struct dock_station *ds, int dock) arg.integer.value = dock; status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) - ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute" - " _DCK\n", (char *)name_buffer.pointer)); + acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n", + status); kfree(buffer.pointer); - kfree(name_buffer.pointer); } static inline void dock(struct dock_station *ds) @@ -525,9 +521,11 @@ static void dock_lock(struct dock_station *ds, int lock) status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { if (lock) - printk(KERN_WARNING PREFIX "Locking device failed\n"); + acpi_handle_warn(ds->handle, + "Locking device failed (0x%x)\n", status); else - printk(KERN_WARNING PREFIX "Unlocking device failed\n"); + acpi_handle_warn(ds->handle, + "Unlocking device failed (0x%x)\n", status); } } @@ -667,7 +665,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) dock_lock(ds, 0); eject_dock(ds); if (dock_present(ds)) { - printk(KERN_ERR PREFIX "Unable to undock!\n"); + acpi_handle_err(ds->handle, "Unable to undock!\n"); return -EBUSY; } complete_undock(ds); @@ -715,7 +713,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) begin_dock(ds); dock(ds); if (!dock_present(ds)) { - printk(KERN_ERR PREFIX "Unable to dock!\n"); + acpi_handle_err(handle, "Unable to dock!\n"); complete_dock(ds); break; } @@ -743,7 +741,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) dock_event(ds, event, UNDOCK_EVENT); break; default: - printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); + acpi_handle_err(handle, "Unknown dock event %d\n", event); } } @@ -987,7 +985,7 @@ err_rmgroup: sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); err_unregister: platform_device_unregister(dd); - printk(KERN_ERR "%s encountered error %d\n", __func__, ret); + acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); return ret; } @@ -1043,12 +1041,12 @@ static int __init dock_init(void) ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); if (!dock_station_count) { - printk(KERN_INFO PREFIX "No dock devices found.\n"); + pr_info(PREFIX "No dock devices found.\n"); return 0; } register_acpi_bus_notifier(&dock_acpi_notifier); - printk(KERN_INFO PREFIX "%s: %d docks/bays found\n", + pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); return 0; } -- cgit v1.2.3 From 1399dfcdfe89898ccd791216f9679ba734aea910 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Wed, 21 Nov 2012 23:33:40 +0100 Subject: ACPI / PM: Introduce os_accessible flag for power_state Currently we have valid flag to represent if this ACPI device power state is valid. A device power state is valid does not necessarily mean we, as OSPM, has a mean to put the device into that power state, e.g. D3 cold is always a valid power state for any ACPI device, but if there is no _PS3 or _PRx for this device, we can't really put that device into D3 cold power state. The same is true for D0 power state. So here comes the os_accessible flag, which is only set if the device has provided us the required means to put it into that power state, e.g. if we have _PS3 or _PRx, we can put the device into D3 cold state and thus, D3 cold power state's os_accessible flag will be set in this case. And a new wrapper inline function is added to be used to check if firmware has provided us a way to power off the device during runtime. Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 9 ++++++++- include/acpi/acpi_bus.h | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1fcb8678665..da1416af0c8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -965,8 +965,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) * D3hot is only valid if _PR3 present. */ if (ps->resources.count || - (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) + (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) { ps->flags.valid = 1; + ps->flags.os_accessible = 1; + } ps->power = -1; /* Unknown - driver assigned */ ps->latency = -1; /* Unknown - driver assigned */ @@ -982,6 +984,11 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set) device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1; + /* Presence of _PS3 or _PRx means we can put the device into D3 cold */ + if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set || + device->power.flags.power_resources) + device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; + acpi_bus_init_power(device); return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 80155fda517..c3bc4511e0c 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -201,6 +201,7 @@ struct acpi_device_power_flags { struct acpi_device_power_state { struct { u8 valid:1; + u8 os_accessible:1; u8 explicit_set:1; /* _PSx present? */ u8 reserved:6; } flags; @@ -500,6 +501,11 @@ static inline bool acpi_device_can_wakeup(struct acpi_device *adev) return adev->wakeup.flags.valid; } +static inline bool acpi_device_can_poweroff(struct acpi_device *adev) +{ + return adev->power.states[ACPI_STATE_D3_COLD].flags.os_accessible; +} + #else /* CONFIG_ACPI */ static inline int register_acpi_bus_type(void *bus) { return 0; } -- cgit v1.2.3 From 66fd3835ac9a3740a7bf953b439e54dbc326d272 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 21 Nov 2012 13:46:04 +0000 Subject: ACPI: Fix logging when no pci_irq is allocated Work around a defect in the printk subsystem introduced by a logging change. Signed-off-by: Joe Perches Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_irq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 0eefa12e648..f2c3d74af23 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -459,19 +459,19 @@ int acpi_pci_irq_enable(struct pci_dev *dev) */ if (gsi < 0) { u32 dev_gsi; - dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin)); /* Interrupt Line values above 0xF are forbidden */ if (dev->irq > 0 && (dev->irq <= 0xF) && (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) { - printk(" - using ISA IRQ %d\n", dev->irq); + dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n", + pin_name(pin), dev->irq); acpi_register_gsi(&dev->dev, dev_gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); - return 0; } else { - printk("\n"); - return 0; + dev_warn(&dev->dev, "PCI INT %c: no GSI\n", + pin_name(pin)); } + return 0; } rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); -- cgit v1.2.3 From fd06a20852e145b2b96c7c6b655fcb9f23ac4e00 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 22 Nov 2012 00:09:27 +0100 Subject: cpufreq: exynos: Broadcast frequency change notifications for all cores On Exynos SoCs all cores share the same frequency setting, so changing frequency of one core will affect rest of cores. This patch modifies the exynos-cpufreq driver to inform cpufreq core about this behavior and broadcast frequency change notifications for all cores. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/exynos-cpufreq.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index af2d81e10f7..c0d54a8ba94 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -100,7 +100,8 @@ static int exynos_target(struct cpufreq_policy *policy, } arm_volt = volt_table[index]; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + for_each_cpu(freqs.cpu, policy->cpus) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* When the new frequency is higher than current frequency */ if ((freqs.new > freqs.old) && !safe_arm_volt) { @@ -115,7 +116,8 @@ static int exynos_target(struct cpufreq_policy *policy, if (freqs.new != freqs.old) exynos_info->set_freq(old_index, index); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + for_each_cpu(freqs.cpu, policy->cpus) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); /* When the new frequency is lower than current frequency */ if ((freqs.new < freqs.old) || @@ -235,6 +237,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) cpumask_copy(policy->related_cpus, cpu_possible_mask); cpumask_copy(policy->cpus, cpu_online_mask); } else { + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; cpumask_setall(policy->cpus); } -- cgit v1.2.3 From 5542721a337f3fcfa0585c915827dc391f36fd28 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 22 Nov 2012 00:19:25 +0100 Subject: cpufreq: exynos: Use static for functions used in only this file Fixes following sparse error. drivers/cpufreq/exynos-cpufreq.c:34:5: warning: symbol 'exynos_verify_speed' was not declared. Should it be static? drivers/cpufreq/exynos-cpufreq.c:40:14: warning: symbol 'exynos_getspeed' was not declared. Should it be static? Signed-off-by: Tushar Behera Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/exynos-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index c0d54a8ba94..7012ea8bf1e 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -31,13 +31,13 @@ static unsigned int locking_frequency; static bool frequency_locked; static DEFINE_MUTEX(cpufreq_lock); -int exynos_verify_speed(struct cpufreq_policy *policy) +static int exynos_verify_speed(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, exynos_info->freq_table); } -unsigned int exynos_getspeed(unsigned int cpu) +static unsigned int exynos_getspeed(unsigned int cpu) { return clk_get_rate(exynos_info->cpu_clk) / 1000; } -- cgit v1.2.3 From 05bce79e6d24ee6eb2beddf0f6314358404d472f Mon Sep 17 00:00:00 2001 From: Cyril Roelandt Date: Thu, 22 Nov 2012 23:20:31 +0100 Subject: ACPI: drop unnecessary local variable from acpi_system_write_wakeup_device() The LEN variable is unsigned, therefore checking whether it is less than 0 is useless. Also drop the LEN variable, since the COUNT parameter can be used instead. [rjw: Changed the subject.] Signed-off-by: Cyril Roelandt Signed-off-by: Rafael J. Wysocki --- drivers/acpi/proc.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 27adb090bb3..ef98796b382 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -362,16 +362,13 @@ acpi_system_write_wakeup_device(struct file *file, struct list_head *node, *next; char strbuf[5]; char str[5] = ""; - unsigned int len = count; - if (len > 4) - len = 4; - if (len < 0) - return -EFAULT; + if (count > 4) + count = 4; - if (copy_from_user(strbuf, buffer, len)) + if (copy_from_user(strbuf, buffer, count)) return -EFAULT; - strbuf[len] = '\0'; + strbuf[count] = '\0'; sscanf(strbuf, "%s", str); mutex_lock(&acpi_device_lock); -- cgit v1.2.3 From a093b93ee0e08cd73a07848752bc09ecea68cb13 Mon Sep 17 00:00:00 2001 From: Li Zhong Date: Fri, 23 Nov 2012 00:05:03 +0100 Subject: cpuidle: fix a suspicious RCU usage in menu governor I saw this suspicious RCU usage on the next tree of 11/15 [ 67.123404] =============================== [ 67.123413] [ INFO: suspicious RCU usage. ] [ 67.123423] 3.7.0-rc5-next-20121115-dirty #1 Not tainted [ 67.123434] ------------------------------- [ 67.123444] include/trace/events/timer.h:186 suspicious rcu_dereference_check() usage! [ 67.123458] [ 67.123458] other info that might help us debug this: [ 67.123458] [ 67.123474] [ 67.123474] RCU used illegally from idle CPU! [ 67.123474] rcu_scheduler_active = 1, debug_locks = 0 [ 67.123493] RCU used illegally from extended quiescent state! [ 67.123507] 1 lock held by swapper/1/0: [ 67.123516] #0: (&cpu_base->lock){-.-...}, at: [] .__hrtimer_start_range_ns+0x28c/0x524 [ 67.123555] [ 67.123555] stack backtrace: [ 67.123566] Call Trace: [ 67.123576] [c0000001e2ccb920] [c00000000001275c] .show_stack+0x78/0x184 (unreliable) [ 67.123599] [c0000001e2ccb9d0] [c0000000000c15a0] .lockdep_rcu_suspicious+0x120/0x148 [ 67.123619] [c0000001e2ccba70] [c00000000009601c] .enqueue_hrtimer+0x1c0/0x1c8 [ 67.123639] [c0000001e2ccbb00] [c000000000097aa0] .__hrtimer_start_range_ns+0x37c/0x524 [ 67.123660] [c0000001e2ccbc20] [c0000000005c9698] .menu_select+0x508/0x5bc [ 67.123678] [c0000001e2ccbd20] [c0000000005c740c] .cpuidle_idle_call+0xa8/0x6e4 [ 67.123699] [c0000001e2ccbdd0] [c0000000000459a0] .pSeries_idle+0x10/0x34 [ 67.123717] [c0000001e2ccbe40] [c000000000014dc8] .cpu_idle+0x130/0x280 [ 67.123738] [c0000001e2ccbee0] [c0000000006ffa8c] .start_secondary+0x378/0x384 [ 67.123758] [c0000001e2ccbf90] [c00000000000936c] .start_secondary_prolog+0x10/0x14 hrtimer_start was added in 198fd638 and ae515197. The patch below tries to use RCU_NONIDLE around it to avoid the above report. Signed-off-by: Li Zhong Acked-by: Paul E. McKenney Reviewed-by: Rik van Riel Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 2efee27714a..bd40b943b6d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -407,8 +407,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) perfect_us = perfect_cstate_ms * 1000; if (repeat && (4 * timer_us < data->expected_us)) { - hrtimer_start(hrtmr, ns_to_ktime(1000 * timer_us), - HRTIMER_MODE_REL_PINNED); + RCU_NONIDLE(hrtimer_start(hrtmr, + ns_to_ktime(1000 * timer_us), + HRTIMER_MODE_REL_PINNED)); /* In repeat case, menu hrtimer is started */ per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT; } else if (perfect_us < data->expected_us) { @@ -418,8 +419,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * In that case, it makes sense to re-enter * into a deeper C-state after some time. */ - hrtimer_start(hrtmr, ns_to_ktime(1000 * timer_us), - HRTIMER_MODE_REL_PINNED); + RCU_NONIDLE(hrtimer_start(hrtmr, + ns_to_ktime(1000 * timer_us), + HRTIMER_MODE_REL_PINNED)); /* In general case, menu hrtimer is started */ per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL; } -- cgit v1.2.3 From 907ddf89d0bb7f57e1e21485900e6564a1ab512a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 23 Nov 2012 12:23:40 +0100 Subject: i2c / ACPI: add ACPI enumeration support ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate and configure the I2C slave devices behind the I2C controller. This patch adds helper functions to support I2C slave enumeration. An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices() in order to get its slave devices enumerated, created and bound to the corresponding ACPI handle. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 6 +++ drivers/acpi/Makefile | 1 + drivers/acpi/acpi_i2c.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/i2c/i2c-core.c | 6 +++ include/linux/i2c.h | 9 +++++ 5 files changed, 125 insertions(+) create mode 100644 drivers/acpi/acpi_i2c.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 119d58db834..0300bf61294 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -181,6 +181,12 @@ config ACPI_DOCK This driver supports ACPI-controlled docking stations and removable drive bays such as the IBM Ultrabay and the Dell Module Bay. +config ACPI_I2C + def_tristate I2C + depends on I2C + help + ACPI I2C enumeration support. + config ACPI_PROCESSOR tristate "Processor" select THERMAL diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3223edfb23b..7198b6d6b76 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_ACPI_HED) += hed.o 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_I2C) += acpi_i2c.o # processor has its own "processor." module_param namespace processor-y := processor_driver.o processor_throttling.o diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c new file mode 100644 index 00000000000..82045e3f5ca --- /dev/null +++ b/drivers/acpi/acpi_i2c.c @@ -0,0 +1,103 @@ +/* + * ACPI I2C enumeration support + * + * Copyright (C) 2012, Intel Corporation + * Author: Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +ACPI_MODULE_NAME("i2c"); + +static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) +{ + struct i2c_board_info *info = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_i2c_serialbus *sb; + + sb = &ares->data.i2c_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + info->addr = sb->slave_address; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; + } + } else if (info->irq < 0) { + struct resource r; + + if (acpi_dev_resource_interrupt(ares, 0, &r)) + info->irq = r.start; + } + + /* Tell the ACPI core to skip this resource */ + return 1; +} + +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_adapter *adapter = data; + struct list_head resource_list; + struct i2c_board_info info; + struct acpi_device *adev; + int ret; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + memset(&info, 0, sizeof(info)); + info.acpi_node.handle = handle; + info.irq = -1; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, + acpi_i2c_add_resource, &info); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !info.addr) + return AE_OK; + + strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); + if (!i2c_new_device(adapter, &info)) { + dev_err(&adapter->dev, + "failed to add I2C device %s from ACPI\n", + dev_name(&adev->dev)); + } + + return AE_OK; +} + +/** + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * @adapter: pointer to adapter + * + * Enumerate all I2C slave devices behind this adapter by walking the ACPI + * namespace. When a device is found it will be added to the Linux device + * model and bound to the corresponding ACPI handle. + */ +void acpi_i2c_register_devices(struct i2c_adapter *adapter) +{ + acpi_handle handle; + acpi_status status; + + handle = ACPI_HANDLE(&adapter->dev); + if (!handle) + return; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_i2c_add_device, NULL, + adapter, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&adapter->dev, "failed to enumerate I2C slaves\n"); +} +EXPORT_SYMBOL_GPL(acpi_i2c_register_devices); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a7edf987a33..e388590b44a 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "i2c-core.h" @@ -78,6 +79,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (of_driver_match_device(dev, drv)) return 1; + /* Then ACPI style match */ + if (acpi_driver_match_device(dev, drv)) + return 1; + driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) @@ -539,6 +544,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; + ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle); /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 800de224336..d0c4db7b487 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -259,6 +259,7 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node + * @acpi_node: ACPI device node * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and @@ -279,6 +280,7 @@ struct i2c_board_info { void *platform_data; struct dev_archdata *archdata; struct device_node *of_node; + struct acpi_dev_node acpi_node; int irq; }; @@ -501,4 +503,11 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) i2c_del_driver) #endif /* I2C */ + +#if IS_ENABLED(CONFIG_ACPI_I2C) +extern void acpi_i2c_register_devices(struct i2c_adapter *adap); +#else +static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {} +#endif + #endif /* _LINUX_I2C_H */ -- cgit v1.2.3 From d3c31a773fa33f78a29bb00ed0dcf8fa55dd4b3a Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 23 Nov 2012 20:48:08 +0100 Subject: cpufreq: ondemand: fix wrong delay sampling rate Restore the correct delay value for ondemand's od_dbs_timer, as it was changed erroneously in commit 83f0e55 (cpufreq: governors: remove redundant code). Signed-off-by: Fabio Baltieri Reviewed-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_ondemand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index bdaab920630..cca3e9fee9a 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -234,7 +234,8 @@ static void od_dbs_timer(struct work_struct *work) dbs_info->sample_type = OD_SUB_SAMPLE; delay = dbs_info->freq_hi_jiffies; } else { - delay = delay_for_sampling_rate(dbs_info->rate_mult); + delay = delay_for_sampling_rate(od_tuners.sampling_rate + * dbs_info->rate_mult); } } -- cgit v1.2.3 From 2905875344f977acd188a2b0f1d163491e91459b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 23 Nov 2012 21:07:12 +0100 Subject: ACPI / PNP: skip ACPI device nodes associated with physical nodes already Make pnpacpi_add_device() ignore ACPI device nodes already associated with struct device objects representing physical devices. In particular, this will prevent PNP device objects from being created for ACPI device nodes already associated with platform devices. This change was originally proposed by Mika Westerberg. [rjw: Modified the subject and changelog.] Signed-off-by: Adrian Hunter Signed-off-by: Rafael J. Wysocki --- drivers/pnp/pnpacpi/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 26b5d4b18dd..653d5637a37 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -242,6 +242,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device) char *pnpid; struct acpi_hardware_id *id; + /* Skip devices that are already bound */ + if (device->physical_node_count) + return 0; + /* * If a PnPacpi device is not present , the device * driver should not be loaded. -- cgit v1.2.3 From 142b007b65aa763957627ea5c343a1001d5ed449 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 23 Nov 2012 21:11:47 +0100 Subject: ACPI: add SDHCI to ACPI platform devices Add the generic ACPI SDHCI device ID to acpi_platform_device_ids[] to make the ACPI core create a platform device object for the ACPI device node of that ID. [rjw: Added the changelog.] Signed-off-by: Adrian Hunter Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e92ca67d0e4..671bbe68b96 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -35,6 +35,8 @@ static const char *dummy_hid = "device"; */ static const struct acpi_device_id acpi_platform_device_ids[] = { + { "PNP0D40" }, + { } }; -- cgit v1.2.3 From c4e050376c69bb9d67895842665264df2a2004d9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 23 Nov 2012 21:17:34 +0100 Subject: mmc: sdhci-acpi: add SDHCI ACPI driver Add a driver for SDHCI controllers enumerated via ACPI and identified by the ACPI Compatibility ID PNP0D40 (or other SDHCI-specific ACPI hardware IDs in the future). [rjw: Added the changelog.] Signed-off-by: Adrian Hunter Acked-by: Chris Ball Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/mmc/host/Kconfig | 12 ++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-acpi.c | 304 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 drivers/mmc/host/sdhci-acpi.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9bf10e7bbfa..56eac101c01 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -81,6 +81,18 @@ config MMC_RICOH_MMC If unsure, say Y. +config MMC_SDHCI_ACPI + tristate "SDHCI support for ACPI enumerated SDHCI controllers" + depends on MMC_SDHCI && ACPI + help + This selects support for ACPI enumerated SDHCI controllers, + identified by ACPI Compatibility ID PNP0D40 or specific + ACPI Hardware IDs. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_PLTFM tristate "SDHCI platform and OF driver helper" depends on MMC_SDHCI diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 17ad0a7ba40..0e4960a107d 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o +obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c new file mode 100644 index 00000000000..6ac361744d3 --- /dev/null +++ b/drivers/mmc/host/sdhci-acpi.c @@ -0,0 +1,304 @@ +/* + * Secure Digital Host Controller Interface ACPI driver. + * + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sdhci.h" + +enum { + SDHCI_ACPI_SD_CD = BIT(0), + SDHCI_ACPI_RUNTIME_PM = BIT(1), +}; + +struct sdhci_acpi_chip { + const struct sdhci_ops *ops; + unsigned int quirks; + unsigned int quirks2; + unsigned long caps; + unsigned int caps2; + mmc_pm_flag_t pm_caps; +}; + +struct sdhci_acpi_slot { + const struct sdhci_acpi_chip *chip; + unsigned int quirks; + unsigned int quirks2; + unsigned long caps; + unsigned int caps2; + mmc_pm_flag_t pm_caps; + unsigned int flags; +}; + +struct sdhci_acpi_host { + struct sdhci_host *host; + const struct sdhci_acpi_slot *slot; + struct platform_device *pdev; + bool use_runtime_pm; +}; + +static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) +{ + return c->slot && (c->slot->flags & flag); +} + +static int sdhci_acpi_enable_dma(struct sdhci_host *host) +{ + return 0; +} + +static const struct sdhci_ops sdhci_acpi_ops_dflt = { + .enable_dma = sdhci_acpi_enable_dma, +}; + +static const struct acpi_device_id sdhci_acpi_ids[] = { + { "PNP0D40" }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); + +static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) +{ + const struct acpi_device_id *id; + + for (id = sdhci_acpi_ids; id->id[0]; id++) + if (!strcmp(id->id, hid)) + return (const struct sdhci_acpi_slot *)id->driver_data; + return NULL; +} + +static int __devinit sdhci_acpi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *device; + struct sdhci_acpi_host *c; + struct sdhci_host *host; + struct resource *iomem; + resource_size_t len; + const char *hid; + int err; + + if (acpi_bus_get_device(handle, &device)) + return -ENODEV; + + if (acpi_bus_get_status(device) || !device->status.present) + return -ENODEV; + + hid = acpi_device_hid(device); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) + return -ENOMEM; + + len = resource_size(iomem); + if (len < 0x100) + dev_err(dev, "Invalid iomem size!\n"); + + if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) + return -ENOMEM; + + host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host)); + if (IS_ERR(host)) + return PTR_ERR(host); + + c = sdhci_priv(host); + c->host = host; + c->slot = sdhci_acpi_get_slot(hid); + c->pdev = pdev; + c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); + + platform_set_drvdata(pdev, c); + + host->hw_name = "ACPI"; + host->ops = &sdhci_acpi_ops_dflt; + host->irq = platform_get_irq(pdev, 0); + + host->ioaddr = devm_ioremap_nocache(dev, iomem->start, + resource_size(iomem)); + if (host->ioaddr == NULL) { + err = -ENOMEM; + goto err_free; + } + + if (!dev->dma_mask) { + u64 dma_mask; + + if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) { + /* 64-bit DMA is not supported at present */ + dma_mask = DMA_BIT_MASK(32); + } else { + dma_mask = DMA_BIT_MASK(32); + } + + dev->dma_mask = &dev->coherent_dma_mask; + dev->coherent_dma_mask = dma_mask; + } + + if (c->slot) { + if (c->slot->chip) { + host->ops = c->slot->chip->ops; + host->quirks |= c->slot->chip->quirks; + host->quirks2 |= c->slot->chip->quirks2; + host->mmc->caps |= c->slot->chip->caps; + host->mmc->caps2 |= c->slot->chip->caps2; + host->mmc->pm_caps |= c->slot->chip->pm_caps; + } + host->quirks |= c->slot->quirks; + host->quirks2 |= c->slot->quirks2; + host->mmc->caps |= c->slot->caps; + host->mmc->caps2 |= c->slot->caps2; + host->mmc->pm_caps |= c->slot->pm_caps; + } + + err = sdhci_add_host(host); + if (err) + goto err_free; + + if (c->use_runtime_pm) { + pm_suspend_ignore_children(dev, 1); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + } + + return 0; + +err_free: + platform_set_drvdata(pdev, NULL); + sdhci_free_host(c->host); + return err; +} + +static int __devexit sdhci_acpi_remove(struct platform_device *pdev) +{ + struct sdhci_acpi_host *c = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int dead; + + if (c->use_runtime_pm) { + pm_runtime_get_sync(dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + } + + dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); + sdhci_remove_host(c->host, dead); + platform_set_drvdata(pdev, NULL); + sdhci_free_host(c->host); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int sdhci_acpi_suspend(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_suspend_host(c->host); +} + +static int sdhci_acpi_resume(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_resume_host(c->host); +} + +#else + +#define sdhci_acpi_suspend NULL +#define sdhci_acpi_resume NULL + +#endif + +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_acpi_runtime_suspend(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_runtime_suspend_host(c->host); +} + +static int sdhci_acpi_runtime_resume(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_runtime_resume_host(c->host); +} + +static int sdhci_acpi_runtime_idle(struct device *dev) +{ + return 0; +} + +#else + +#define sdhci_acpi_runtime_suspend NULL +#define sdhci_acpi_runtime_resume NULL +#define sdhci_acpi_runtime_idle NULL + +#endif + +static const struct dev_pm_ops sdhci_acpi_pm_ops = { + .suspend = sdhci_acpi_suspend, + .resume = sdhci_acpi_resume, + .runtime_suspend = sdhci_acpi_runtime_suspend, + .runtime_resume = sdhci_acpi_runtime_resume, + .runtime_idle = sdhci_acpi_runtime_idle, +}; + +static struct platform_driver sdhci_acpi_driver = { + .driver = { + .name = "sdhci-acpi", + .owner = THIS_MODULE, + .acpi_match_table = sdhci_acpi_ids, + .pm = &sdhci_acpi_pm_ops, + }, + .probe = sdhci_acpi_probe, + .remove = __devexit_p(sdhci_acpi_remove), +}; + +module_platform_driver(sdhci_acpi_driver); + +MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From e5f5762177be52fde50ccba88938d66b5103c8e0 Mon Sep 17 00:00:00 2001 From: Li Haifeng Date: Fri, 23 Nov 2012 21:55:19 +0100 Subject: PM / Freezer: Fixup compile error of try_to_freeze_nowarn() If FREEZER is not defined, the error as following will be throw when compiled. arch/arm/kernel/signal.c:645: error: implicit declaration of function 'try_to_freeze_nowarn' Signed-off-by: Haifeng Li Signed-off-by: Rafael J. Wysocki --- include/linux/freezer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/freezer.h b/include/linux/freezer.h index d09af4b67cf..b90091af579 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -177,6 +177,7 @@ static inline int freeze_kernel_threads(void) { return -ENOSYS; } static inline void thaw_processes(void) {} static inline void thaw_kernel_threads(void) {} +static inline bool try_to_freeze_nowarn(void) { return false; } static inline bool try_to_freeze(void) { return false; } static inline void freezer_do_not_count(void) {} -- cgit v1.2.3 From a0e5af3cb89b59aa6c62b1f97c8d553ff3fb51c1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 24 Nov 2012 10:08:47 +0100 Subject: cpufreq: governors: Fix jiffies/cputime mixup (revisited) This change was made by commit 8636fd2 (cpufreq: fix jiffies/cputime mixup in conservative/ondemand governors) before, but then it has been reverted inadvertently by commit 4471a34 (cpufreq: governors: remove redundant code). The changelog of commit 8636fd2's says: The function get_cpu_idle_time_jiffy in both the conservative and ondemand governors use jiffies_to_usecs to convert a cputime value to usecs which gives the wrong value on architectures where cputime and jiffies use different units. Only matters if NO_HZ is disabled, since otherwise get_cpu_idle_time_us should already return a valid value, and get_cpu_idle_time_jiffy isn't actually called. Since now we have only one common get_cpu_idle_time_jiffy() used by both governors in question, modify it along the lines of commit 8636fd2 to restore the correct behavior. Signed-off-by: Rafael J. Wysocki Reviewed-by: Viresh Kumar --- drivers/cpufreq/cpufreq_governor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index be9d255e292..6c5f1d383cd 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -45,9 +45,9 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) idle_time = cur_wall_time - busy_time; if (wall) - *wall = jiffies_to_usecs(cur_wall_time); + *wall = cputime_to_usecs(cur_wall_time); - return jiffies_to_usecs(idle_time); + return cputime_to_usecs(idle_time); } u64 get_cpu_idle_time(unsigned int cpu, u64 *wall) -- cgit v1.2.3 From 35546bd477146b75ae2a9ff2cb9bfcdb0f701015 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 24 Nov 2012 10:10:51 +0100 Subject: PM / QoS: Handle device PM QoS flags while removing constraints PM QoS flags have to be handled by dev_pm_qos_constraints_destroy() in the same way as PM QoS resume latency constraints. That is, if they have been exposed to user space, they have to be hidden from it and the list of flags requests has to be flushed before destroying the device's PM QoS object. Make that happen. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index fdc3894bc33..f03f1ba28c7 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -223,12 +223,14 @@ void dev_pm_qos_constraints_destroy(struct device *dev) struct dev_pm_qos *qos; struct dev_pm_qos_request *req, *tmp; struct pm_qos_constraints *c; + struct pm_qos_flags *f; /* - * If the device's PM QoS resume latency limit has been exposed to user - * space, it has to be hidden at this point. + * If the device's PM QoS resume latency limit or PM QoS flags have been + * exposed to user space, they have to be hidden at this point. */ dev_pm_qos_hide_latency_limit(dev); + dev_pm_qos_hide_flags(dev); mutex_lock(&dev_pm_qos_mtx); @@ -237,8 +239,8 @@ void dev_pm_qos_constraints_destroy(struct device *dev) if (!qos) goto out; + /* Flush the constraints lists for the device. */ c = &qos->latency; - /* Flush the constraints list for the device */ plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { /* * Update constraints list and call the notification @@ -247,6 +249,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev) apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); } + f = &qos->flags; + list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) { + apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); + memset(req, 0, sizeof(*req)); + } spin_lock_irq(&dev->power.lock); dev->power.qos = NULL; -- cgit v1.2.3 From b88ce2a41562d1a9554f209e0f31a32d9f473794 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 26 Nov 2012 10:03:06 +0100 Subject: ACPI / PM: Allow attach/detach routines to change device power states Make it possible to ask the routines used for adding/removing devices to/from the general ACPI PM domain, acpi_dev_pm_attach() and acpi_dev_pm_detach(), respectively, to change the power states of devices so that they are put into the full-power state automatically by acpi_dev_pm_attach() and into the lowest-power state available automatically by acpi_dev_pm_detach(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg --- drivers/acpi/device_pm.c | 28 ++++++++++++++++++++++++---- include/linux/acpi.h | 11 +++++++---- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index a8e059f69d5..f09dc987cf1 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -599,10 +599,12 @@ static struct dev_pm_domain acpi_general_pm_domain = { /** * acpi_dev_pm_attach - Prepare device for ACPI power management. * @dev: Device to prepare. + * @power_on: Whether or not to power on the device. * * If @dev has a valid ACPI handle that has a valid struct acpi_device object * attached to it, install a wakeup notification handler for the device and - * add it to the general ACPI PM domain. + * add it to the general ACPI PM domain. If @power_on is set, the device will + * be put into the ACPI D0 state before the function returns. * * This assumes that the @dev's bus type uses generic power management callbacks * (or doesn't use any power management callbacks at all). @@ -610,7 +612,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { * Callers must ensure proper synchronization of this function with power * management callbacks. */ -int acpi_dev_pm_attach(struct device *dev) +int acpi_dev_pm_attach(struct device *dev, bool power_on) { struct acpi_device *adev = acpi_dev_pm_get_node(dev); @@ -622,6 +624,10 @@ int acpi_dev_pm_attach(struct device *dev) acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); dev->pm_domain = &acpi_general_pm_domain; + if (power_on) { + acpi_dev_pm_full_power(adev); + __acpi_device_run_wake(adev, false); + } return 0; } EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); @@ -629,20 +635,34 @@ EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); /** * acpi_dev_pm_detach - Remove ACPI power management from the device. * @dev: Device to take care of. + * @power_off: Whether or not to try to remove power from the device. * * Remove the device from the general ACPI PM domain and remove its wakeup - * notifier. + * notifier. If @power_off is set, additionally remove power from the device if + * possible. * * Callers must ensure proper synchronization of this function with power * management callbacks. */ -void acpi_dev_pm_detach(struct device *dev) +void acpi_dev_pm_detach(struct device *dev, bool power_off) { struct acpi_device *adev = acpi_dev_pm_get_node(dev); if (adev && dev->pm_domain == &acpi_general_pm_domain) { dev->pm_domain = NULL; acpi_remove_pm_notifier(adev, acpi_wakeup_device); + if (power_off) { + /* + * If the device's PM QoS resume latency limit or flags + * have been exposed to user space, they have to be + * hidden at this point, so that they don't affect the + * choice of the low-power state to put the device into. + */ + dev_pm_qos_hide_latency_limit(dev); + dev_pm_qos_hide_flags(dev); + __acpi_device_run_wake(adev, false); + acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); + } } } EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 5fdd8727151..28ba643c92c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -458,11 +458,14 @@ static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } #endif #if defined(CONFIG_ACPI) && defined(CONFIG_PM) -int acpi_dev_pm_attach(struct device *dev); -int acpi_dev_pm_detach(struct device *dev); +int acpi_dev_pm_attach(struct device *dev, bool power_on); +int acpi_dev_pm_detach(struct device *dev, bool power_off); #else -static inline int acpi_dev_pm_attach(struct device *dev) { return -ENODEV; } -static inline void acpi_dev_pm_detach(struct device *dev) {} +static inline int acpi_dev_pm_attach(struct device *dev, bool power_on) +{ + return -ENODEV; +} +static inline void acpi_dev_pm_detach(struct device *dev, bool power_off) {} #endif #endif /*_LINUX_ACPI_H*/ -- cgit v1.2.3 From 883d588e556347c4b3221ac492a8acd8a75e730a Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Wed, 21 Nov 2012 17:17:11 +0900 Subject: PM / devfreq: remove compiler error when a governor is module With the intruction of patch, eff607fdb1f787da1fedf46ab6e64adc2afd1c5a, it became possible to include a governor as a module. Thus the #ifdef statement for a governor should become #if IS_ENABLED. Signed-off-by: MyungJoo Ham --- include/linux/devfreq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 235248cb2c9..e83ef39b3be 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -192,7 +192,7 @@ extern int devfreq_register_opp_notifier(struct device *dev, extern int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq); -#ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND +#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) /** * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq * and devfreq_add_device -- cgit v1.2.3 From 389baed01edd298c9622c6e28de5e7e250c8767d Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Wed, 21 Nov 2012 19:04:51 +0900 Subject: PM / devfreq: missing rcu_read_lock() added for find_device_opp() opp_get_notifier() uses find_device_opp(), which requires to held rcu_read_lock. In order to keep the notifier-header valid, we have added rcu_read_lock(). Reported-by: Kees Cook Signed-off-by: MyungJoo Ham --- drivers/devfreq/devfreq.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 45e053e5b13..1a78ad9e1bd 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1023,11 +1023,18 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, */ int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { - struct srcu_notifier_head *nh = opp_get_notifier(dev); + struct srcu_notifier_head *nh; + int ret = 0; + rcu_read_lock(); + nh = opp_get_notifier(dev); if (IS_ERR(nh)) - return PTR_ERR(nh); - return srcu_notifier_chain_register(nh, &devfreq->nb); + ret = PTR_ERR(nh); + rcu_read_unlock(); + if (!ret) + ret = srcu_notifier_chain_register(nh, &devfreq->nb); + + return ret; } /** @@ -1042,11 +1049,18 @@ int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) */ int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq) { - struct srcu_notifier_head *nh = opp_get_notifier(dev); + struct srcu_notifier_head *nh; + int ret = 0; + rcu_read_lock(); + nh = opp_get_notifier(dev); if (IS_ERR(nh)) - return PTR_ERR(nh); - return srcu_notifier_chain_unregister(nh, &devfreq->nb); + ret = PTR_ERR(nh); + rcu_read_unlock(); + if (!ret) + ret = srcu_notifier_chain_unregister(nh, &devfreq->nb); + + return ret; } MODULE_AUTHOR("MyungJoo Ham "); -- cgit v1.2.3 From b9e1c8e821e7768d5b8629ad7748456af6feece3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 21 Nov 2012 10:36:13 +0530 Subject: PM / devfreq: Fix incorrect argument in error message 'g' is cast to the error return code. Hence gives the following error which is fixed by this patch. drivers/devfreq/devfreq.c:645 devfreq_remove_governor() error: 'g' dereferencing possible ERR_PTR() Signed-off-by: Sachin Kamat Signed-off-by: MyungJoo Ham --- drivers/devfreq/devfreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 1a78ad9e1bd..ac4334fac2c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -643,7 +643,7 @@ int devfreq_remove_governor(struct devfreq_governor *governor) g = find_devfreq_governor(governor->name); if (IS_ERR(g)) { pr_err("%s: governor %s not registered\n", __func__, - g->name); + governor->name); err = -EINVAL; goto err_out; } -- cgit v1.2.3 From f9c08e2acbbed19ecafc82e4549b7040cc549216 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 21 Nov 2012 10:36:14 +0530 Subject: PM / devfreq: Fix return value in devfreq_remove_governor() Use the value obtained from the function instead of -EINVAL. Signed-off-by: Sachin Kamat Signed-off-by: MyungJoo Ham --- drivers/devfreq/devfreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index ac4334fac2c..34c00c53611 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -644,7 +644,7 @@ int devfreq_remove_governor(struct devfreq_governor *governor) if (IS_ERR(g)) { pr_err("%s: governor %s not registered\n", __func__, governor->name); - err = -EINVAL; + err = PTR_ERR(g); goto err_out; } list_for_each_entry(devfreq, &devfreq_list, node) { -- cgit v1.2.3 From 94d76d5de38d7502c3e78fcd6bf50da95e3e0361 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 26 Nov 2012 10:04:53 +0100 Subject: platform / ACPI: Attach/detach ACPI PM during probe/remove/shutdown Drivers usually expect that the devices they are supposed to handle will be operational when their .probe() routines are called, but that need not be the case on some ACPI-based systems with ACPI-based device enumeration where the BIOSes don't put devices into D0 by default. To work around this problem it is sufficient to change bus type .probe() routines to ensure that devices will be powered on before the drivers' .probe() routines run (and their .remove() and .shutdown() routines accordingly). Modify platform_drv_probe() to run acpi_dev_pm_attach() for devices whose ACPI handles are present, so that ACPI power management is used to change their power states. Analogously, modify platform_drv_remove() and platform_drv_shutdown() to call acpi_dev_pm_detach() for those devices, so that they are not subject to ACPI PM any more. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg --- drivers/base/platform.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 49fd96e2346..b2ee3bcd5a4 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -484,8 +484,16 @@ static int platform_drv_probe(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); + int ret; - return drv->probe(dev); + if (ACPI_HANDLE(_dev)) + acpi_dev_pm_attach(_dev, true); + + ret = drv->probe(dev); + if (ret && ACPI_HANDLE(_dev)) + acpi_dev_pm_detach(_dev, true); + + return ret; } static int platform_drv_probe_fail(struct device *_dev) @@ -497,8 +505,13 @@ static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); + int ret; - return drv->remove(dev); + ret = drv->remove(dev); + if (ACPI_HANDLE(_dev)) + acpi_dev_pm_detach(_dev, true); + + return ret; } static void platform_drv_shutdown(struct device *_dev) @@ -507,6 +520,8 @@ static void platform_drv_shutdown(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); drv->shutdown(dev); + if (ACPI_HANDLE(_dev)) + acpi_dev_pm_detach(_dev, true); } /** -- cgit v1.2.3 From 5923f986ac191a32640429d054b94af185ec73a8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 26 Nov 2012 10:35:07 +0100 Subject: ACPI / platform: include missed header into acpi_platform.c The internal.h declares the acpi_create_platform_device(). Without that include we get a following warning: drivers/acpi/acpi_platform.c:133:24: warning: symbol 'acpi_create_platform_device' was not declared. Should it be static? Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index b7df9b197bc..db129b9f52c 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -17,6 +17,8 @@ #include #include +#include "internal.h" + ACPI_MODULE_NAME("platform"); /** -- cgit v1.2.3 From 752cad760b19e85926341880dc317a99f400eacc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 27 Nov 2012 13:49:36 +0100 Subject: ACPI: remove unnecessary INIT_LIST_HEAD There is no need to initialize the node before appending it to the list. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 4107c004467..a3868f6c222 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -426,7 +426,6 @@ static acpi_status acpi_dev_new_resource_entry(struct resource *r, c->error = -ENOMEM; return AE_NO_MEMORY; } - INIT_LIST_HEAD(&rentry->node); rentry->res = *r; list_add_tail(&rentry->node, c->list); c->count++; -- cgit v1.2.3 From 420993221175a45db5af012c53fd2fef4d9533dc Mon Sep 17 00:00:00 2001 From: Deepak Sikri Date: Tue, 27 Nov 2012 14:05:26 +0100 Subject: cpufreq: SPEAr: Add CPUFreq driver SPEAr is an ARM based family of SoCs. This patch adds in support of cpufreq driver for SPEAr SoCs. It is supported via DT only and so bindings are present in binding document. Signed-off-by: Deepak Sikri Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- .../devicetree/bindings/cpufreq/cpufreq-spear.txt | 42 +++ arch/arm/Kconfig | 1 + drivers/cpufreq/Kconfig.arm | 7 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/spear-cpufreq.c | 291 +++++++++++++++++++++ 5 files changed, 342 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-spear.txt create mode 100644 drivers/cpufreq/spear-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-spear.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-spear.txt new file mode 100644 index 00000000000..f3d44984d91 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-spear.txt @@ -0,0 +1,42 @@ +SPEAr cpufreq driver +------------------- + +SPEAr SoC cpufreq driver for CPU frequency scaling. +It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) systems +which share clock across all CPUs. + +Required properties: +- cpufreq_tbl: Table of frequencies CPU could be transitioned into, in the + increasing order. + +Optional properties: +- clock-latency: Specify the possible maximum transition latency for clock, in + unit of nanoseconds. + +Both required and optional properties listed above must be defined under node +/cpus/cpu@0. + +Examples: +-------- +cpus { + + <...> + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + + <...> + + cpufreq_tbl = < 166000 + 200000 + 250000 + 300000 + 400000 + 500000 + 600000 >; + }; + + <...> + +}; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ade7e924bef..159e99737e3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -904,6 +904,7 @@ config ARCH_NOMADIK config PLAT_SPEAR bool "ST SPEAr" + select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select CLKDEV_LOOKUP diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 5961e6415f0..a0b3661d90b 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -76,3 +76,10 @@ config ARM_EXYNOS5250_CPUFREQ help This adds the CPUFreq driver for Samsung EXYNOS5250 SoC. + +config ARM_SPEAR_CPUFREQ + bool "SPEAr CPUFreq support" + depends on PLAT_SPEAR + default y + help + This adds the CPUFreq driver support for SPEAr SOCs. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 5b1413e4721..1f254ec087c 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o +obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o ################################################################################## # PowerPC platform drivers diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c new file mode 100644 index 00000000000..4575cfe4175 --- /dev/null +++ b/drivers/cpufreq/spear-cpufreq.c @@ -0,0 +1,291 @@ +/* + * drivers/cpufreq/spear-cpufreq.c + * + * CPU Frequency Scaling for SPEAr platform + * + * Copyright (C) 2012 ST Microelectronics + * Deepak Sikri + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +/* SPEAr CPUFreq driver data structure */ +static struct { + struct clk *clk; + unsigned int transition_latency; + struct cpufreq_frequency_table *freq_tbl; + u32 cnt; +} spear_cpufreq; + +int spear_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl); +} + +static unsigned int spear_cpufreq_get(unsigned int cpu) +{ + return clk_get_rate(spear_cpufreq.clk) / 1000; +} + +static struct clk *spear1340_cpu_get_possible_parent(unsigned long newfreq) +{ + struct clk *sys_pclk; + int pclk; + /* + * In SPEAr1340, cpu clk's parent sys clk can take input from + * following sources + */ + const char *sys_clk_src[] = { + "sys_syn_clk", + "pll1_clk", + "pll2_clk", + "pll3_clk", + }; + + /* + * As sys clk can have multiple source with their own range + * limitation so we choose possible sources accordingly + */ + if (newfreq <= 300000000) + pclk = 0; /* src is sys_syn_clk */ + else if (newfreq > 300000000 && newfreq <= 500000000) + pclk = 3; /* src is pll3_clk */ + else if (newfreq == 600000000) + pclk = 1; /* src is pll1_clk */ + else + return ERR_PTR(-EINVAL); + + /* Get parent to sys clock */ + sys_pclk = clk_get(NULL, sys_clk_src[pclk]); + if (IS_ERR(sys_pclk)) + pr_err("Failed to get %s clock\n", sys_clk_src[pclk]); + + return sys_pclk; +} + +/* + * In SPEAr1340, we cannot use newfreq directly because we need to actually + * access a source clock (clk) which might not be ancestor of cpu at present. + * Hence in SPEAr1340 we would operate on source clock directly before switching + * cpu clock to it. + */ +static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq) +{ + struct clk *sys_clk; + int ret = 0; + + sys_clk = clk_get_parent(spear_cpufreq.clk); + if (IS_ERR(sys_clk)) { + pr_err("failed to get cpu's parent (sys) clock\n"); + return PTR_ERR(sys_clk); + } + + /* Set the rate of the source clock before changing the parent */ + ret = clk_set_rate(sys_pclk, newfreq); + if (ret) { + pr_err("Failed to set sys clk rate to %lu\n", newfreq); + return ret; + } + + ret = clk_set_parent(sys_clk, sys_pclk); + if (ret) { + pr_err("Failed to set sys clk parent\n"); + return ret; + } + + return 0; +} + +static int spear_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long newfreq; + struct clk *srcclk; + int index, ret, mult = 1; + + if (cpufreq_frequency_table_target(policy, spear_cpufreq.freq_tbl, + target_freq, relation, &index)) + return -EINVAL; + + freqs.cpu = policy->cpu; + freqs.old = spear_cpufreq_get(0); + + newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; + if (of_machine_is_compatible("st,spear1340")) { + /* + * SPEAr1340 is special in the sense that due to the possibility + * of multiple clock sources for cpu clk's parent we can have + * different clock source for different frequency of cpu clk. + * Hence we need to choose one from amongst these possible clock + * sources. + */ + srcclk = spear1340_cpu_get_possible_parent(newfreq); + if (IS_ERR(srcclk)) { + pr_err("Failed to get src clk\n"); + return PTR_ERR(srcclk); + } + + /* SPEAr1340: src clk is always 2 * intended cpu clk */ + mult = 2; + } else { + /* + * src clock to be altered is ancestor of cpu clock. Hence we + * can directly work on cpu clk + */ + srcclk = spear_cpufreq.clk; + } + + newfreq = clk_round_rate(srcclk, newfreq * mult); + if (newfreq < 0) { + pr_err("clk_round_rate failed for cpu src clock\n"); + return newfreq; + } + + freqs.new = newfreq / 1000; + freqs.new /= mult; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + if (mult == 2) + ret = spear1340_set_cpu_rate(srcclk, newfreq); + else + ret = clk_set_rate(spear_cpufreq.clk, newfreq); + + /* Get current rate after clk_set_rate, in case of failure */ + if (ret) { + pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); + freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return ret; +} + +static int spear_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + + ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl); + if (ret) { + pr_err("cpufreq_frequency_table_cpuinfo() failed"); + return ret; + } + + cpufreq_frequency_table_get_attr(spear_cpufreq.freq_tbl, policy->cpu); + policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency; + policy->cur = spear_cpufreq_get(0); + + cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); + cpumask_copy(policy->related_cpus, policy->cpus); + + return 0; +} + +static int spear_cpufreq_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static struct freq_attr *spear_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver spear_cpufreq_driver = { + .name = "cpufreq-spear", + .flags = CPUFREQ_STICKY, + .verify = spear_cpufreq_verify, + .target = spear_cpufreq_target, + .get = spear_cpufreq_get, + .init = spear_cpufreq_init, + .exit = spear_cpufreq_exit, + .attr = spear_cpufreq_attr, +}; + +static int spear_cpufreq_driver_init(void) +{ + struct device_node *np; + const struct property *prop; + struct cpufreq_frequency_table *freq_tbl; + const __be32 *val; + int cnt, i, ret; + + np = of_find_node_by_path("/cpus/cpu@0"); + if (!np) { + pr_err("No cpu node found"); + return -ENODEV; + } + + if (of_property_read_u32(np, "clock-latency", + &spear_cpufreq.transition_latency)) + spear_cpufreq.transition_latency = CPUFREQ_ETERNAL; + + prop = of_find_property(np, "cpufreq_tbl", NULL); + if (!prop || !prop->value) { + pr_err("Invalid cpufreq_tbl"); + ret = -ENODEV; + goto out_put_node; + } + + cnt = prop->length / sizeof(u32); + val = prop->value; + + freq_tbl = kmalloc(sizeof(*freq_tbl) * (cnt + 1), GFP_KERNEL); + if (!freq_tbl) { + ret = -ENOMEM; + goto out_put_node; + } + + for (i = 0; i < cnt; i++) { + freq_tbl[i].index = i; + freq_tbl[i].frequency = be32_to_cpup(val++); + } + + freq_tbl[i].index = i; + freq_tbl[i].frequency = CPUFREQ_TABLE_END; + + spear_cpufreq.freq_tbl = freq_tbl; + + of_node_put(np); + + spear_cpufreq.clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(spear_cpufreq.clk)) { + pr_err("Unable to get CPU clock\n"); + ret = PTR_ERR(spear_cpufreq.clk); + goto out_put_mem; + } + + ret = cpufreq_register_driver(&spear_cpufreq_driver); + if (!ret) + return 0; + + pr_err("failed register driver: %d\n", ret); + clk_put(spear_cpufreq.clk); + +out_put_mem: + kfree(freq_tbl); + return ret; + +out_put_node: + of_node_put(np); + return ret; +} +late_initcall(spear_cpufreq_driver_init); + +MODULE_AUTHOR("Deepak Sikri "); +MODULE_DESCRIPTION("SPEAr CPUFreq driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3e33ee9e0804748f1b7a01af9ba0e8e1e10f772f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 26 Nov 2012 18:10:12 +0000 Subject: cpufreq: ondemand: update sampling rate only on right CPUs Fix cpufreq_gov_ondemand to skip CPU where another governor is used. The bug present itself as NULL pointer access on the mutex_lock() call, an can be reproduced on an SMP machine by setting the default governor to anything other than ondemand, setting a single CPU's governor to ondemand, then changing the sample rate by writing on: > /sys/devices/system/cpu/cpufreq/ondemand/sampling_rate Backtrace: Nov 26 17:36:54 balto kernel: [ 839.585241] BUG: unable to handle kernel NULL pointer dereference at (null) Nov 26 17:36:54 balto kernel: [ 839.585311] IP: [] __mutex_lock_slowpath+0xb2/0x170 [snip] Nov 26 17:36:54 balto kernel: [ 839.587005] Call Trace: Nov 26 17:36:54 balto kernel: [ 839.587030] [] mutex_lock+0x22/0x40 Nov 26 17:36:54 balto kernel: [ 839.587067] [] store_sampling_rate+0xbf/0x150 Nov 26 17:36:54 balto kernel: [ 839.587110] [] ? __do_page_fault+0x1cc/0x4c0 Nov 26 17:36:54 balto kernel: [ 839.587153] [] kobj_attr_store+0xf/0x20 Nov 26 17:36:54 balto kernel: [ 839.587192] [] sysfs_write_file+0xcd/0x140 Nov 26 17:36:54 balto kernel: [ 839.587234] [] vfs_write+0xac/0x180 Nov 26 17:36:54 balto kernel: [ 839.587271] [] sys_write+0x52/0xa0 Nov 26 17:36:54 balto kernel: [ 839.587306] [] ? do_page_fault+0xe/0x10 Nov 26 17:36:54 balto kernel: [ 839.587345] [] system_call_fastpath+0x16/0x1b Signed-off-by: Fabio Baltieri Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_ondemand.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index cca3e9fee9a..7731f7c7e79 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -40,6 +40,10 @@ static struct dbs_data od_dbs_data; static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info); +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND +static struct cpufreq_governor cpufreq_gov_ondemand; +#endif + static struct od_dbs_tuners od_tuners = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, @@ -279,6 +283,10 @@ static void update_sampling_rate(unsigned int new_rate) policy = cpufreq_cpu_get(cpu); if (!policy) continue; + if (policy->governor != &cpufreq_gov_ondemand) { + cpufreq_cpu_put(policy); + continue; + } dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); cpufreq_cpu_put(policy); -- cgit v1.2.3 From a474a515497ef3566cfc17a2cab3d54d6d50ff1c Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 27 Nov 2012 14:17:58 +0100 Subject: cpuidle: Measure idle state durations with monotonic clock Many cpuidle drivers measure their time spent in an idle state by reading the wallclock time before and after idling and calculating the difference. This leads to erroneous results when the wallclock time gets updated by another processor in the meantime, adding that clock adjustment to the idle state's time counter. If the clock adjustment was negative, the result is even worse due to an erroneous cast from int to unsigned long long of the last_residency variable. The negative 32 bit integer will zero-extend and result in a forward time jump of roughly four billion milliseconds or 1.3 hours on the idle state residency counter. This patch changes all affected cpuidle drivers to either use the monotonic clock for their measurements or make use of the generic time measurement wrapper in cpuidle.c, which was already working correctly. Some superfluous CLIs/STIs in the ACPI code are removed (interrupts should always already be disabled before entering the idle function, and not get reenabled until the generic wrapper has performed its second measurement). It also removes the erroneous cast, making sure that negative residency values are applied correctly even though they should not appear anymore. Signed-off-by: Julius Werner Reviewed-by: Preeti U Murthy Tested-by: Daniel Lezcano Acked-by: Daniel Lezcano Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki --- arch/powerpc/platforms/pseries/processor_idle.c | 4 +- drivers/acpi/processor_idle.c | 57 ++----------------------- drivers/cpuidle/cpuidle.c | 3 +- drivers/idle/intel_idle.c | 14 +----- 4 files changed, 7 insertions(+), 71 deletions(-) diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 45d00e5fe14..4d806b41960 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -36,7 +36,7 @@ static struct cpuidle_state *cpuidle_state_table; static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) { - *kt_before = ktime_get_real(); + *kt_before = ktime_get(); *in_purr = mfspr(SPRN_PURR); /* * Indicate to the HV that we are idle. Now would be @@ -50,7 +50,7 @@ static inline s64 idle_loop_epilog(unsigned long in_purr, ktime_t kt_before) get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr; get_lppaca()->idle = 0; - return ktime_to_us(ktime_sub(ktime_get_real(), kt_before)); + return ktime_to_us(ktime_sub(ktime_get(), kt_before)); } static int snooze_loop(struct cpuidle_device *dev, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index e8086c72530..f1a5da44591 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -735,31 +735,18 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) static int acpi_idle_enter_c1(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - ktime_t kt1, kt2; - s64 idle_time; struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); pr = __this_cpu_read(processors); - dev->last_residency = 0; if (unlikely(!pr)) return -EINVAL; - local_irq_disable(); - - lapic_timer_state_broadcast(pr, cx, 1); - kt1 = ktime_get_real(); acpi_idle_do_entry(cx); - kt2 = ktime_get_real(); - idle_time = ktime_to_us(ktime_sub(kt2, kt1)); - - /* Update device last_residency*/ - dev->last_residency = (int)idle_time; - local_irq_enable(); lapic_timer_state_broadcast(pr, cx, 0); return index; @@ -806,19 +793,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); - ktime_t kt1, kt2; - s64 idle_time_ns; - s64 idle_time; pr = __this_cpu_read(processors); - dev->last_residency = 0; if (unlikely(!pr)) return -EINVAL; - local_irq_disable(); - - if (cx->entry_method != ACPI_CSTATE_FFH) { current_thread_info()->status &= ~TS_POLLING; /* @@ -829,7 +809,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; - local_irq_enable(); return -EINVAL; } } @@ -843,22 +822,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (cx->type == ACPI_STATE_C3) ACPI_FLUSH_CPU_CACHE(); - kt1 = ktime_get_real(); /* Tell the scheduler that we are going deep-idle: */ sched_clock_idle_sleep_event(); acpi_idle_do_entry(cx); - kt2 = ktime_get_real(); - idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1)); - idle_time = idle_time_ns; - do_div(idle_time, NSEC_PER_USEC); - /* Update device last_residency*/ - dev->last_residency = (int)idle_time; + sched_clock_idle_wakeup_event(0); - /* Tell the scheduler how much we idled: */ - sched_clock_idle_wakeup_event(idle_time_ns); - - local_irq_enable(); if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING; @@ -883,13 +852,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); - ktime_t kt1, kt2; - s64 idle_time_ns; - s64 idle_time; - pr = __this_cpu_read(processors); - dev->last_residency = 0; if (unlikely(!pr)) return -EINVAL; @@ -899,16 +863,11 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, return drv->states[drv->safe_state_index].enter(dev, drv, drv->safe_state_index); } else { - local_irq_disable(); acpi_safe_halt(); - local_irq_enable(); return -EBUSY; } } - local_irq_disable(); - - if (cx->entry_method != ACPI_CSTATE_FFH) { current_thread_info()->status &= ~TS_POLLING; /* @@ -919,7 +878,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; - local_irq_enable(); return -EINVAL; } } @@ -934,7 +892,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, */ lapic_timer_state_broadcast(pr, cx, 1); - kt1 = ktime_get_real(); /* * disable bus master * bm_check implies we need ARB_DIS @@ -965,18 +922,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, c3_cpu_count--; raw_spin_unlock(&c3_lock); } - kt2 = ktime_get_real(); - idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1)); - idle_time = idle_time_ns; - do_div(idle_time, NSEC_PER_USEC); - - /* Update device last_residency*/ - dev->last_residency = (int)idle_time; - /* Tell the scheduler how much we idled: */ - sched_clock_idle_wakeup_event(idle_time_ns); + sched_clock_idle_wakeup_event(0); - local_irq_enable(); if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING; @@ -987,6 +935,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, + .en_core_tk_irqen = 1, }; /** diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 711dd83fd3b..8df53dd8dbe 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -109,8 +109,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, /* This can be moved to within driver enter routine * but that results in multiple copies of same code. */ - dev->states_usage[entered_state].time += - (unsigned long long)dev->last_residency; + dev->states_usage[entered_state].time += dev->last_residency; dev->states_usage[entered_state].usage++; } else { dev->last_residency = 0; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index b0f6b4c8ee1..c49c04d9c2b 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -56,7 +56,6 @@ #include #include #include -#include /* ktime_get_real() */ #include #include #include @@ -72,6 +71,7 @@ static struct cpuidle_driver intel_idle_driver = { .name = "intel_idle", .owner = THIS_MODULE, + .en_core_tk_irqen = 1, }; /* intel_idle.max_cstate=0 disables driver */ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1; @@ -281,8 +281,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); unsigned int cstate; - ktime_t kt_before, kt_after; - s64 usec_delta; int cpu = smp_processor_id(); cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; @@ -297,8 +295,6 @@ static int intel_idle(struct cpuidle_device *dev, if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); - kt_before = ktime_get_real(); - stop_critical_timings(); if (!need_resched()) { @@ -310,17 +306,9 @@ static int intel_idle(struct cpuidle_device *dev, start_critical_timings(); - kt_after = ktime_get_real(); - usec_delta = ktime_to_us(ktime_sub(kt_after, kt_before)); - - local_irq_enable(); - if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); - /* Update cpuidle counters */ - dev->last_residency = (int)usec_delta; - return index; } -- cgit v1.2.3 From 261cba2deb7d3bebd180c35d5dbf8961f6e9afc4 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 27 Nov 2012 20:42:11 +0100 Subject: ACPI / thermal: _TMP and _CRT/_HOT/_PSV/_ACx dependency fix On some platforms, _TMP and _CRT/_HOT/_PSV/_ACx have dependency. And there is no way for OS to detect this dependency. commit 9bcb8118965ab4631a65ee0726e6518f75cda6c5 shows us a problem that _TMP must be evaluate after _CRT/_HOT/_PSV/_ACx, or else firmware will shutdown the system. But the machine in https://bugzilla.kernel.org/show_bug.cgi?id=43284 shows us that _PSV would return valid value only if _TMP has been evaluated once. With this patch, all of the control methods will be evaluated once, in the _CRT/_HOT/_PSV/_CRT/_TMP order, before they are actually used. [rjw: Added a local variable for the handle and modified the loop slightly.] Signed-off-by: Zhang Rui Tested-by: katabami Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 804204d4199..6e8cc16b54c 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -984,6 +984,38 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) } } +/* + * On some platforms, the AML code has dependency about + * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx. + * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after + * /_CRT/_HOT/_PSV/_ACx, or else system will be power off. + * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0 + * if _TMP has never been evaluated. + * + * As this dependency is totally transparent to OS, evaluate + * all of them once, in the order of _CRT/_HOT/_PSV/_ACx, + * _TMP, before they are actually used. + */ +static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz) +{ + acpi_handle handle = tz->device->handle; + unsigned long long value; + int i; + + acpi_evaluate_integer(handle, "_CRT", NULL, &value); + acpi_evaluate_integer(handle, "_HOT", NULL, &value); + acpi_evaluate_integer(handle, "_PSV", NULL, &value); + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; + acpi_status status; + + status = acpi_evaluate_integer(handle, name, NULL, &value); + if (status == AE_NOT_FOUND) + break; + } + acpi_evaluate_integer(handle, "_TMP", NULL, &value); +} + static int acpi_thermal_get_info(struct acpi_thermal *tz) { int result = 0; @@ -992,6 +1024,8 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) if (!tz) return -EINVAL; + acpi_thermal_aml_dependency_fix(tz); + /* Get trip points [_CRT, _PSV, etc.] (required) */ result = acpi_thermal_get_trip_points(tz); if (result) -- cgit v1.2.3 From 8c00bdfbc7df40876cfb419580f94e2e0acdef36 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 27 Nov 2012 13:17:42 +0100 Subject: cpupower tools: Remove brace expansion from clean target The clean targets from the cpupower tools' Makefiles use brace expansion to remove some generated files. However, the default shells on many systems do not support this feature resulting in some generated files not being removed by clean. Signed-off-by: Palmer Cox Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/Makefile | 3 ++- tools/power/cpupower/debug/i386/Makefile | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index cf397bd26d0..d875a74a3bd 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -253,7 +253,8 @@ clean: | xargs rm -f -rm -f $(OUTPUT)cpupower -rm -f $(OUTPUT)libcpupower.so* - -rm -rf $(OUTPUT)po/*.{gmo,pot} + -rm -rf $(OUTPUT)po/*.gmo + -rm -rf $(OUTPUT)po/*.pot $(MAKE) -C bench O=$(OUTPUT) clean diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile index 3ba158f0e28..c05cc0ac80c 100644 --- a/tools/power/cpupower/debug/i386/Makefile +++ b/tools/power/cpupower/debug/i386/Makefile @@ -26,7 +26,10 @@ $(OUTPUT)powernow-k8-decode: powernow-k8-decode.c all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode clean: - rm -rf $(OUTPUT){centrino-decode,dump_psb,intel_gsic,powernow-k8-decode} + rm -rf $(OUTPUT)centrino-decode + rm -rf $(OUTPUT)dump_psb + rm -rf $(OUTPUT)intel_gsic + rm -rf $(OUTPUT)powernow-k8-decode install: $(INSTALL) -d $(DESTDIR)${bindir} -- cgit v1.2.3 From 275a4dc441437d0074457591b46a45d7e45a817d Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 27 Nov 2012 13:17:43 +0100 Subject: cpupower tools: Update .gitignore for files created in the debug directories The files generated by the Makefiles in the debug directories aren't listed in the .gitignore file in the root of the cpupower tool which causes these files to show up in the output of 'git status'. Signed-off-by: Palmer Cox Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/.gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore index 8a83dd2ffc1..d42073f1260 100644 --- a/tools/power/cpupower/.gitignore +++ b/tools/power/cpupower/.gitignore @@ -20,3 +20,10 @@ utils/cpufreq-set.o utils/cpufreq-aperf.o cpupower bench/cpufreq-bench +debug/kernel/Module.symvers +debug/i386/centrino-decode +debug/i386/dump_psb +debug/i386/intel_gsic +debug/i386/powernow-k8-decode +debug/x86_64/centrino-decode +debug/x86_64/powernow-k8-decode -- cgit v1.2.3 From fb8eaeb7ab96b09c910e36abf7df7f9ecbb0fb60 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 27 Nov 2012 13:17:44 +0100 Subject: cpupower tools: Fix minor warnings Fix minor warnings reported with GCC 4.6: * The sysfs_write_file function is unused - remove it. * The pr_mon_len in the print_header function is unsed - remove it. Signed-off-by: Palmer Cox Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/helpers/sysfs.c | 19 ------------------- .../cpupower/utils/idle_monitor/cpupower-monitor.c | 3 +-- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 96e28c124b5..38ab9162946 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c @@ -37,25 +37,6 @@ unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) return (unsigned int) numread; } -static unsigned int sysfs_write_file(const char *path, - const char *value, size_t len) -{ - int fd; - ssize_t numwrite; - - fd = open(path, O_WRONLY); - if (fd == -1) - return 0; - - numwrite = write(fd, value, len); - if (numwrite < 1) { - close(fd); - return 0; - } - close(fd); - return (unsigned int) numwrite; -} - /* * Detect whether a CPU is online * diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index 0d6571e418d..7a657f3da23 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -84,7 +84,7 @@ int fill_string_with_spaces(char *s, int n) void print_header(int topology_depth) { int unsigned mon; - int state, need_len, pr_mon_len; + int state, need_len; cstate_t s; char buf[128] = ""; int percent_width = 4; @@ -93,7 +93,6 @@ void print_header(int topology_depth) printf("%s|", buf); for (mon = 0; mon < avail_monitors; mon++) { - pr_mon_len = 0; need_len = monitors[mon]->hw_states_num * (percent_width + 3) - 1; if (mon != 0) { -- cgit v1.2.3 From 53d2000ebe0618219f73ac866701533237180044 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 27 Nov 2012 13:17:45 +0100 Subject: cpupower tools: Fix issues with sysfs_topology_read_file Fix a variety of issues with sysfs_topology_read_file: * The return value of sysfs_topology_read_file function was not properly being checked for failure. * The function was reading int valued sysfs variables and then returning their value. So, even if a function was trying to check the return value of this function, a caller would not be able to tell an failure code apart from reading a negative value. This also conflicted with the comment on the function which said that a return value of 0 indicated success. * The function was parsing int valued sysfs values with strtoul instead of strtol. * The function was non-static even though it was only used in the file it was declared in. Signed-off-by: Palmer Cox Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/helpers/topology.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 4eae2c47ba4..216f3e3466c 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -20,9 +20,8 @@ #include /* returns -1 on failure, 0 on success */ -int sysfs_topology_read_file(unsigned int cpu, const char *fname) +static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) { - unsigned long value; char linebuf[MAX_LINE_LEN]; char *endp; char path[SYSFS_PATH_MAX]; @@ -31,10 +30,10 @@ int sysfs_topology_read_file(unsigned int cpu, const char *fname) cpu, fname); if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) return -1; - value = strtoul(linebuf, &endp, 0); + *result = strtol(linebuf, &endp, 0); if (endp == linebuf || errno == ERANGE) return -1; - return value; + return 0; } struct cpuid_core_info { @@ -82,13 +81,19 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) for (cpu = 0; cpu < cpus; cpu++) { cpu_top->core_info[cpu].cpu = cpu; cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); - cpu_top->core_info[cpu].pkg = - sysfs_topology_read_file(cpu, "physical_package_id"); + if(sysfs_topology_read_file( + cpu, + "physical_package_id", + &(cpu_top->core_info[cpu].pkg)) < 0) + return -1; if ((int)cpu_top->core_info[cpu].pkg != -1 && cpu_top->core_info[cpu].pkg > cpu_top->pkgs) cpu_top->pkgs = cpu_top->core_info[cpu].pkg; - cpu_top->core_info[cpu].core = - sysfs_topology_read_file(cpu, "core_id"); + if(sysfs_topology_read_file( + cpu, + "core_id", + &(cpu_top->core_info[cpu].core)) < 0) + return -1; } cpu_top->pkgs++; -- cgit v1.2.3 From 35a169737cdf9155e890d60eae2b8fffc16d16ba Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 27 Nov 2012 13:17:46 +0100 Subject: cpupower tools: Fix malloc of cpu_info structure The cpu_info member of cpupower_topology was being declared as an unnamed structure. This member was then being malloced using the size of the parent cpupower_topology * the number of cpus. This works because cpu_info is smaller than cpupower_topology. However, there is no guarantee that will always be the case. Making cpu_info its own top level structure (named cpuid_core_info) allows for mallocing the actual size of this structure. This also lets us get rid of a redefinition of the structure in topology.c with slightly different field names. Signed-off-by: Palmer Cox Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/helpers/helpers.h | 17 +++++++++-------- tools/power/cpupower/utils/helpers/topology.c | 14 +++----------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 2eb584cf2f5..f84985f630e 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h @@ -92,6 +92,14 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); extern struct cpupower_cpu_info cpupower_cpu_info; /* cpuid and cpuinfo helpers **************************/ +struct cpuid_core_info { + int pkg; + int core; + int cpu; + + /* flags */ + unsigned int is_online:1; +}; /* CPU topology/hierarchy parsing ******************/ struct cpupower_topology { @@ -101,14 +109,7 @@ struct cpupower_topology { unsigned int threads; /* per core */ /* Array gets mallocated with cores entries, holding per core info */ - struct { - int pkg; - int core; - int cpu; - - /* flags */ - unsigned int is_online:1; - } *core_info; + struct cpuid_core_info *core_info; }; extern int get_cpu_topology(struct cpupower_topology *cpu_top); diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 216f3e3466c..4e2b583ea17 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -36,14 +36,6 @@ static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *re return 0; } -struct cpuid_core_info { - unsigned int pkg; - unsigned int thread; - unsigned int cpu; - /* flags */ - unsigned int is_online:1; -}; - static int __compare(const void *t1, const void *t2) { struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; @@ -52,9 +44,9 @@ static int __compare(const void *t1, const void *t2) return -1; else if (top1->pkg > top2->pkg) return 1; - else if (top1->thread < top2->thread) + else if (top1->core < top2->core) return -1; - else if (top1->thread > top2->thread) + else if (top1->core > top2->core) return 1; else if (top1->cpu < top2->cpu) return -1; @@ -74,7 +66,7 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) { int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF); - cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus); + cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); if (cpu_top->core_info == NULL) return -ENOMEM; cpu_top->pkgs = cpu_top->cores = 0; -- cgit v1.2.3 From ea1021ffa65a81da3d393fcbd7509d6e40d4d325 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 27 Nov 2012 13:17:47 +0100 Subject: cpupower tools: Fix warning and a bug with the cpu package count The pkgs member of cpupower_topology is being used as the number of cpu packages. As the comment in get_cpu_topology notes, the package ids are not guaranteed to be contiguous. So, simply setting pkgs to the value of the highest physical_package_id doesn't actually provide a count of the number of cpu packages. Instead, calculate pkgs by setting it to the number of distinct physical_packge_id values which is pretty easy to do after the core_info structs are sorted. Calculating pkgs this way also has the nice benefit of getting rid of a sign comparison warning that GCC 4.6 was reporting. Signed-off-by: Palmer Cox Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/helpers/topology.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 4e2b583ea17..c13120af519 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -64,7 +64,7 @@ static int __compare(const void *t1, const void *t2) */ int get_cpu_topology(struct cpupower_topology *cpu_top) { - int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF); + int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); if (cpu_top->core_info == NULL) @@ -78,20 +78,28 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) "physical_package_id", &(cpu_top->core_info[cpu].pkg)) < 0) return -1; - if ((int)cpu_top->core_info[cpu].pkg != -1 && - cpu_top->core_info[cpu].pkg > cpu_top->pkgs) - cpu_top->pkgs = cpu_top->core_info[cpu].pkg; if(sysfs_topology_read_file( cpu, "core_id", &(cpu_top->core_info[cpu].core)) < 0) return -1; } - cpu_top->pkgs++; qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), __compare); + /* Count the number of distinct pkgs values. This works + because the primary sort of the core_info struct was just + done by pkg value. */ + last_pkg = cpu_top->core_info[0].pkg; + for(cpu = 1; cpu < cpus; cpu++) { + if(cpu_top->core_info[cpu].pkg != last_pkg) { + last_pkg = cpu_top->core_info[cpu].pkg; + cpu_top->pkgs++; + } + } + cpu_top->pkgs++; + /* Intel's cores count is not consecutively numbered, there may * be a core_id of 3, but none of 2. Assume there always is 0 * Get amount of cores by counting duplicates in a package -- cgit v1.2.3 From c8cfc3c6bf404b0f110631d5bba234982e6ad24f Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 27 Nov 2012 13:17:48 +0100 Subject: cpupower: Provide -c param for cpupower monitor to schedule process on all cores If an MSR based monitor is run in parallel this is not needed. This is the default case on all/most Intel machines. But when only sysfs info is read via cpupower monitor -m Idle_Stats (typically the case for non root users) or when other monitors are PCI based (AMD), Idle_Stats, read from sysfs can be totally bogus: cpupower monitor -m Idle_Stats PKG |CORE|CPU | POLL | C1-N | C3-N | C6-N 0| 0| 0| 0.00| 0.00| 0.24| 99.81 0| 0| 32| 0.00| 0.00| 0.00| 100.7 ... 0| 17| 20| 0.00| 0.00| 0.00| 173.1 0| 17| 52| 0.00| 0.00| 0.07| 173.0 0| 18| 68| 0.00| 0.00| 0.00| 0.00 0| 18| 76| 0.00| 0.00| 0.00| 0.00 ... With the -c option all cores are woken up and the kernel did update cpuidle statistics before reading out sysfs. This causes some overhead. Therefore avoid if possible, use if needed: cpupower monitor -c -m Idle_Stats PKG |CORE|CPU | POLL | C1-N | C3-N | C6-N 0| 0| 0| 0.00| 0.00| 0.00| 100.2 0| 0| 32| 0.00| 0.00| 0.00| 100.2 ... 0| 8| 8| 0.00| 0.00| 0.00| 99.82 0| 8| 40| 0.00| 0.00| 0.00| 99.81 0| 9| 24| 0.00| 0.00| 0.00| 100.3 0| 9| 56| 0.00| 0.00| 0.00| 100.2 0| 16| 4| 0.00| 0.00| 0.00| 99.75 0| 16| 36| 0.00| 0.00| 0.00| 99.38 ... Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/man/cpupower-monitor.1 | 15 +++++++++++++-- tools/power/cpupower/utils/helpers/helpers.h | 1 + .../cpupower/utils/idle_monitor/cpupower-monitor.c | 18 +++++++++++++++++- .../cpupower/utils/idle_monitor/cpupower-monitor.h | 17 +++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1 index 1141c207371..e01c35d13b6 100644 --- a/tools/power/cpupower/man/cpupower-monitor.1 +++ b/tools/power/cpupower/man/cpupower-monitor.1 @@ -7,11 +7,11 @@ cpupower\-monitor \- Report processor frequency and idle statistics .RB "\-l" .B cpupower monitor -.RB [ "\-m ," [ ",..." ] ] +.RB [ -c ] [ "\-m ," [ ",..." ] ] .RB [ "\-i seconds" ] .br .B cpupower monitor -.RB [ "\-m ," [ ",..." ] ] +.RB [ -c ][ "\-m ," [ ",..." ] ] .RB command .br .SH DESCRIPTION @@ -64,6 +64,17 @@ Only display specific monitors. Use the monitor string(s) provided by \-l option Measure intervall. .RE .PP +\-c +.RS 4 +Schedule the process on every core before starting and ending measuring. +This could be needed for the Idle_Stats monitor when no other MSR based +monitor (has to be run on the core that is measured) is run in parallel. +This is to wake up the processors from deeper sleep states and let the +kernel re +-account its cpuidle (C-state) information before reading the +cpuidle timings from sysfs. +.RE +.PP command .RS 4 Measure idle and frequency characteristics of an arbitrary command/workload. diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index f84985f630e..aa9e95486a2 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h @@ -114,6 +114,7 @@ struct cpupower_topology { extern int get_cpu_topology(struct cpupower_topology *cpu_top); extern void cpu_topology_release(struct cpupower_topology cpu_top); + /* CPU topology/hierarchy parsing ******************/ /* X86 ONLY ****************************************/ diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index 7a657f3da23..c4bae9203a6 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -39,6 +39,7 @@ static int mode; static int interval = 1; static char *show_monitors_param; static struct cpupower_topology cpu_top; +static unsigned int wake_cpus; /* ToDo: Document this in the manpage */ static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; @@ -314,16 +315,28 @@ int fork_it(char **argv) int do_interval_measure(int i) { unsigned int num; + int cpu; + + if (wake_cpus) + for (cpu = 0; cpu < cpu_count; cpu++) + bind_cpu(cpu); for (num = 0; num < avail_monitors; num++) { dprint("HW C-state residency monitor: %s - States: %d\n", monitors[num]->name, monitors[num]->hw_states_num); monitors[num]->start(); } + sleep(i); + + if (wake_cpus) + for (cpu = 0; cpu < cpu_count; cpu++) + bind_cpu(cpu); + for (num = 0; num < avail_monitors; num++) monitors[num]->stop(); + return 0; } @@ -332,7 +345,7 @@ static void cmdline(int argc, char *argv[]) int opt; progname = basename(argv[0]); - while ((opt = getopt(argc, argv, "+li:m:")) != -1) { + while ((opt = getopt(argc, argv, "+lci:m:")) != -1) { switch (opt) { case 'l': if (mode) @@ -351,6 +364,9 @@ static void cmdline(int argc, char *argv[]) mode = show; show_monitors_param = optarg; break; + case 'c': + wake_cpus = 1; + break; default: print_wrong_arg_exit(); } diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h index 9312ee1f2db..9e43f3371fb 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h @@ -65,4 +65,21 @@ extern long long timespec_diff_us(struct timespec start, struct timespec end); "could be inaccurate\n"), mes, ov); \ } + +/* Taken over from x86info project sources -> return 0 on success */ +#include +#include +#include +static inline int bind_cpu(int cpu) +{ + cpu_set_t set; + + if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) { + CPU_ZERO(&set); + CPU_SET(cpu, &set); + return sched_setaffinity(getpid(), sizeof(set), &set); + } + return 1; +} + #endif /* __CPUIDLE_INFO_HW__ */ -- cgit v1.2.3 From 8d219e3658c092731cbebe5ab62f15480a815683 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 27 Nov 2012 13:17:49 +0100 Subject: cpupower: IvyBridge (0x3a and 0x3e models) support Signed-off-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/helpers/cpuid.c | 2 ++ tools/power/cpupower/utils/idle_monitor/snb_idle.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c index 906895d21cc..93b0aa74ca0 100644 --- a/tools/power/cpupower/utils/helpers/cpuid.c +++ b/tools/power/cpupower/utils/helpers/cpuid.c @@ -158,6 +158,8 @@ out: cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; case 0x2A: /* SNB */ case 0x2D: /* SNB Xeon */ + case 0x3A: /* IVB */ + case 0x3E: /* IVB Xeon */ cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; cpu_info->caps |= CPUPOWER_CAP_IS_SNB; break; diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c index a1bc07cd53e..a99b43b97d6 100644 --- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c @@ -150,9 +150,15 @@ static struct cpuidle_monitor *snb_register(void) || cpupower_cpu_info.family != 6) return NULL; - if (cpupower_cpu_info.model != 0x2A - && cpupower_cpu_info.model != 0x2D) + switch (cpupower_cpu_info.model) { + case 0x2A: /* SNB */ + case 0x2D: /* SNB Xeon */ + case 0x3A: /* IVB */ + case 0x3E: /* IVB Xeon */ + break; + default: return NULL; + } is_valid = calloc(cpu_count, sizeof(int)); for (num = 0; num < SNB_CSTATE_COUNT; num++) { -- cgit v1.2.3 From 6dcdd8e3cadd8dfcfe63d231631d70e2670970f9 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Wed, 28 Nov 2012 20:29:17 +0100 Subject: PM / devfreq: remove compiler error with module governors (2) Governors compiled as modules may use these functions. Signed-off-by: MyungJoo Ham Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/devfreq.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 34c00c53611..a8f01735054 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -235,6 +235,7 @@ void devfreq_monitor_start(struct devfreq *devfreq) queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms)); } +EXPORT_SYMBOL(devfreq_monitor_start); /** * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance @@ -248,6 +249,7 @@ void devfreq_monitor_stop(struct devfreq *devfreq) { cancel_delayed_work_sync(&devfreq->work); } +EXPORT_SYMBOL(devfreq_monitor_stop); /** * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance @@ -273,6 +275,7 @@ void devfreq_monitor_suspend(struct devfreq *devfreq) mutex_unlock(&devfreq->lock); cancel_delayed_work_sync(&devfreq->work); } +EXPORT_SYMBOL(devfreq_monitor_suspend); /** * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance @@ -297,6 +300,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq) out: mutex_unlock(&devfreq->lock); } +EXPORT_SYMBOL(devfreq_monitor_resume); /** * devfreq_interval_update() - Update device devfreq monitoring interval @@ -343,6 +347,7 @@ void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay) out: mutex_unlock(&devfreq->lock); } +EXPORT_SYMBOL(devfreq_interval_update); /** * devfreq_notifier_call() - Notify that the device frequency requirements -- cgit v1.2.3 From e29482e8487954c87dc7b4fdbc53574bf1d4cce2 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 30 Nov 2012 12:37:36 +0100 Subject: gpio / ACPI: add ACPI support Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins. Needs a gpio controller driver with the acpi handler hook set. Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt resources to Linux GPIO's. Signed-off-by: Mathias Nyman Signed-off-by: Mika Westerberg Acked-by: Grant Likely Signed-off-by: Rafael J. Wysocki --- drivers/gpio/Kconfig | 4 ++++ drivers/gpio/Makefile | 1 + drivers/gpio/gpiolib-acpi.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi_gpio.h | 19 ++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 drivers/gpio/gpiolib-acpi.c create mode 100644 include/linux/acpi_gpio.h diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f11d8e3b404..5c9b384119b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,6 +49,10 @@ config OF_GPIO def_bool y depends on OF +config GPIO_ACPI + def_bool y + depends on ACPI + config DEBUG_GPIO bool "Debug GPIO calls" depends on DEBUG_KERNEL diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed670732..420dbaca05f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c new file mode 100644 index 00000000000..cbad6e908d3 --- /dev/null +++ b/drivers/gpio/gpiolib-acpi.c @@ -0,0 +1,54 @@ +/* + * ACPI helpers for GPIO API + * + * Copyright (C) 2012, Intel Corporation + * Authors: Mathias Nyman + * Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) +{ + if (!gc->dev) + return false; + + return ACPI_HANDLE(gc->dev) == data; +} + +/** + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") + * @pin: ACPI GPIO pin number (0-based, controller-relative) + * + * Returns GPIO number to use with Linux generic GPIO API, or errno error value + */ + +int acpi_get_gpio(char *path, int pin) +{ + struct gpio_chip *chip; + acpi_handle handle; + acpi_status status; + + status = acpi_get_handle(NULL, path, &handle); + if (ACPI_FAILURE(status)) + return -ENODEV; + + chip = gpiochip_find(handle, acpi_gpiochip_find); + if (!chip) + return -ENODEV; + + if (!gpio_is_valid(chip->base + pin)) + return -EINVAL; + + return chip->base + pin; +} +EXPORT_SYMBOL_GPL(acpi_get_gpio); diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h new file mode 100644 index 00000000000..91615a389b6 --- /dev/null +++ b/include/linux/acpi_gpio.h @@ -0,0 +1,19 @@ +#ifndef _LINUX_ACPI_GPIO_H_ +#define _LINUX_ACPI_GPIO_H_ + +#include + +#ifdef CONFIG_GPIO_ACPI + +int acpi_get_gpio(char *path, int pin); + +#else /* CONFIG_GPIO_ACPI */ + +static inline int acpi_get_gpio(char *path, int pin) +{ + return -ENODEV; +} + +#endif /* CONFIG_GPIO_ACPI */ + +#endif /* _LINUX_ACPI_GPIO_H_ */ -- cgit v1.2.3 From 64bee4d28c9e2296f4f12a6c4cc40d085c2c9534 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 30 Nov 2012 12:37:53 +0100 Subject: spi / ACPI: add ACPI enumeration support ACPI 5 introduced SPISerialBus resource that allows us to enumerate and configure the SPI slave devices behind the SPI controller. This patch adds support for this to the SPI core. In addition we bind ACPI nodes to SPI devices. This makes it possible for the slave drivers to get the ACPI handle for further configuration. Signed-off-by: Mika Westerberg Acked-by: Grant Likely Signed-off-by: Rafael J. Wysocki --- drivers/spi/spi.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 84c2861d6f4..1ab05234729 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include static void spidev_release(struct device *dev) { @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) if (of_driver_match_device(dev, drv)) return 1; + /* Then try ACPI */ + if (acpi_driver_match_device(dev, drv)) + return 1; + if (sdrv->id_table) return !!spi_match_id(sdrv->id_table, spi); @@ -888,6 +894,100 @@ static void of_register_spi_devices(struct spi_master *master) static void of_register_spi_devices(struct spi_master *master) { } #endif +#ifdef CONFIG_ACPI +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) +{ + struct spi_device *spi = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_spi_serialbus *sb; + + sb = &ares->data.spi_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + spi->chip_select = sb->device_selection; + spi->max_speed_hz = sb->connection_speed; + + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) + spi->mode |= SPI_CPHA; + if (sb->clock_polarity == ACPI_SPI_START_HIGH) + spi->mode |= SPI_CPOL; + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) + spi->mode |= SPI_CS_HIGH; + } + } else if (spi->irq < 0) { + struct resource r; + + if (acpi_dev_resource_interrupt(ares, 0, &r)) + spi->irq = r.start; + } + + /* Always tell the ACPI core to skip this resource */ + return 1; +} + +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct spi_master *master = data; + struct list_head resource_list; + struct acpi_device *adev; + struct spi_device *spi; + int ret; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "failed to allocate SPI device for %s\n", + dev_name(&adev->dev)); + return AE_NO_MEMORY; + } + + ACPI_HANDLE_SET(&spi->dev, handle); + spi->irq = -1; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, + acpi_spi_add_resource, spi); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !spi->max_speed_hz) { + spi_dev_put(spi); + return AE_OK; + } + + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); + if (spi_add_device(spi)) { + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", + dev_name(&adev->dev)); + spi_dev_put(spi); + } + + return AE_OK; +} + +static void acpi_register_spi_devices(struct spi_master *master) +{ + acpi_status status; + acpi_handle handle; + + handle = ACPI_HANDLE(&master->dev); + if (!handle) + return; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_spi_add_device, NULL, + master, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&master->dev, "failed to enumerate SPI slaves\n"); +} +#else +static inline void acpi_register_spi_devices(struct spi_master *master) {} +#endif /* CONFIG_ACPI */ + static void spi_master_release(struct device *dev) { struct spi_master *master; @@ -1023,8 +1123,9 @@ int spi_register_master(struct spi_master *master) spi_match_master_to_boardinfo(master, &bi->board_info); mutex_unlock(&board_lock); - /* Register devices from the device tree */ + /* Register devices from the device tree and ACPI */ of_register_spi_devices(master); + acpi_register_spi_devices(master); done: return status; } -- cgit v1.2.3 From 0ac1b1d7b7424cd6f129b5454b504b3cae746f0e Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 Nov 2012 12:57:03 +0100 Subject: ACPI: do acpisleep dmi check when CONFIG_ACPI_SLEEP is set The current acpisleep DMI checks only run when CONFIG_SUSPEND is set. And this may break hibernation on some platforms when CONFIG_SUSPEND is cleared. Move acpisleep DMI check into #ifdef CONFIG_ACPI_SLEEP instead. [rjw: Added acpi_sleep_dmi_check() and rebased on top of earlier patches adding entries to acpisleep_dmi_table[].] References: https://bugzilla.kernel.org/show_bug.cgi?id=45921 Signed-off-by: Zhang Rui Cc: Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 348 ++++++++++++++++++++++++++------------------------- 1 file changed, 177 insertions(+), 171 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 1463c56092c..6efef87b405 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -124,6 +124,180 @@ void __init acpi_old_suspend_ordering(void) old_suspend_ordering = true; } +static int __init init_old_suspend_ordering(const struct dmi_system_id *d) +{ + acpi_old_suspend_ordering(); + return 0; +} + +static int __init init_nvs_nosave(const struct dmi_system_id *d) +{ + acpi_nvs_nosave(); + return 0; +} + +static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + { + .callback = init_old_suspend_ordering, + .ident = "Abit KN9 (nForce4 variant)", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), + DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "HP xw4600 Workstation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Panasonic CF51-2L", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Matsushita Electric Industrial Co.,Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW21E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB17FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Everex StepNote Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1Z1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-NW130D", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCCW29FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Averatec AV1020-ED2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI DELUXE", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI Premium", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR26GN_P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1S1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW520F", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54C", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54HR", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), + }, + }, + {}, +}; + +static void acpi_sleep_dmi_check(void) +{ + dmi_check_system(acpisleep_dmi_table); +} + /** * acpi_pm_freeze - Disable the GPEs and suspend EC transactions. */ @@ -239,6 +413,7 @@ static void acpi_pm_end(void) } #else /* !CONFIG_ACPI_SLEEP */ #define acpi_target_sleep_state ACPI_STATE_S0 +static inline void acpi_sleep_dmi_check(void) {} #endif /* CONFIG_ACPI_SLEEP */ #ifdef CONFIG_SUSPEND @@ -397,175 +572,6 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .end = acpi_pm_end, .recover = acpi_pm_finish, }; - -static int __init init_old_suspend_ordering(const struct dmi_system_id *d) -{ - old_suspend_ordering = true; - return 0; -} - -static int __init init_nvs_nosave(const struct dmi_system_id *d) -{ - acpi_nvs_nosave(); - return 0; -} - -static struct dmi_system_id __initdata acpisleep_dmi_table[] = { - { - .callback = init_old_suspend_ordering, - .ident = "Abit KN9 (nForce4 variant)", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), - DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "HP xw4600 Workstation", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Panasonic CF51-2L", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, - "Matsushita Electric Industrial Co.,Ltd."), - DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-FW21E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB17FX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-SR11M", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Everex StepNote Series", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB1Z1E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-NW130D", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCCW29FX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Averatec AV1020-ED2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI DELUXE", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI Premium", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-SR26GN_P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB1S1E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-FW520F", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Asus K54C", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Asus K54HR", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), - }, - }, - {}, -}; #endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATION @@ -896,13 +902,13 @@ int __init acpi_sleep_init(void) u8 type_a, type_b; #ifdef CONFIG_SUSPEND int i = 0; - - dmi_check_system(acpisleep_dmi_table); #endif if (acpi_disabled) return 0; + acpi_sleep_dmi_check(); + sleep_states[ACPI_STATE_S0] = 1; printk(KERN_INFO PREFIX "(supports S0"); -- cgit v1.2.3 From d0c2ce16bec0afa6013b4c5220ca4c9c67210215 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 30 Nov 2012 13:02:50 +0100 Subject: ACPI / video: Add "Asus UL30VT" to ACPI video detect blacklist The ACPI video driver can't control backlight correctly on Asus UL30VT. Vendor driver (asus-laptop) can work. This patch is to add "Asus UL30VT" to ACPI video detect blacklist in order to use asus-laptop for video control on the "Asus UL30VT" rather than ACPI video driver. References: https://bugzilla.kernel.org/show_bug.cgi?id=32592 Reported-by: Alex Williamson Cc: Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video_detect.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index b728880ef10..4ac2593234e 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -156,6 +156,14 @@ static struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "X360"), }, }, + { + .callback = video_detect_force_vendor, + .ident = "Asus UL30VT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), + }, + }, { }, }; -- cgit v1.2.3 From a6b5e88c0e42093b9057856f35770966c8c591e3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 Nov 2012 13:05:05 +0100 Subject: ACPI / PNP: Do not crash due to stale pointer use during system resume During resume from system suspend the 'data' field of struct pnp_dev in pnpacpi_set_resources() may be a stale pointer, due to removal of the associated ACPI device node object in the previous suspend-resume cycle. This happens, for example, if a dockable machine is booted in the docking station and then suspended and resumed and suspended again. If that happens, pnpacpi_build_resource_template() called from pnpacpi_set_resources() attempts to use that pointer and crashes. However, pnpacpi_set_resources() actually checks the device's ACPI handle, attempts to find the ACPI device node object attached to it and returns an error code if that fails, so in fact it knows what the correct value of dev->data should be. Use this observation to update dev->data with the correct value if necessary and dump a call trace if that's the case (once). We still need to fix the root cause of this issue, but preventing systems from crashing because of it is an improvement too. Reported-and-tested-by: Zdenek Kabelac References: https://bugzilla.kernel.org/show_bug.cgi?id=51071 Cc: Signed-off-by: Rafael J. Wysocki --- drivers/pnp/pnpacpi/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 26b5d4b18dd..ec8e914f756 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -95,6 +95,9 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) return -ENODEV; } + if (WARN_ON_ONCE(acpi_dev != dev->data)) + dev->data = acpi_dev; + ret = pnpacpi_build_resource_template(dev, &buffer); if (ret) return ret; -- cgit v1.2.3 From b7e383046c2c7c13ad928cd7407eafff758ddd4b Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 4 Dec 2012 23:23:16 +0100 Subject: ACPI : do not use Lid and Sleep button for S5 wakeup When system enters power off, the _PSW of Lid device is enabled. But this may cause the system to reboot instead of power off. A proper way to fix this is to always disable lid wakeup capability for S5. References: https://bugzilla.kernel.org/show_bug.cgi?id=35262 Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d0b38ab47ab..bd523bfbaad 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -917,8 +917,8 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, static void acpi_bus_set_run_wake_flags(struct acpi_device *device) { struct acpi_device_id button_device_ids[] = { - {"PNP0C0D", 0}, {"PNP0C0C", 0}, + {"PNP0C0D", 0}, {"PNP0C0E", 0}, {"", 0}, }; @@ -930,6 +930,11 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) { device->wakeup.flags.run_wake = 1; + if (!acpi_match_device_ids(device, &button_device_ids[1])) { + /* Do not use Lid/sleep button for S5 wakeup */ + if (device->wakeup.sleep_state == ACPI_STATE_S5) + device->wakeup.sleep_state = ACPI_STATE_S4; + } device_set_wakeup_capable(&device->dev, true); return; } -- cgit v1.2.3 From 129ff8f8d58297b04f47b5d6fad81aa2d08404e1 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 4 Dec 2012 23:30:19 +0100 Subject: ACPI / video: ignore BIOS initial backlight value for HP Folio 13-2000 Or else the laptop will boot with a dimmed screen. References: https://bugzilla.kernel.org/show_bug.cgi?id=51141 Tested-by: Stefan Nagy Signed-off-by: Zhang Rui Cc: Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 0230cb6cbb3..ac9a69cd45f 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -389,6 +389,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d) return 0; } +static int video_ignore_initial_backlight(const struct dmi_system_id *d) +{ + use_bios_initial_backlight = 0; + return 0; +} + static struct dmi_system_id video_dmi_table[] __initdata = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -433,6 +439,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), }, }, + { + .callback = video_ignore_initial_backlight, + .ident = "HP Folio 13-2000", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13 - 2000 Notebook PC"), + }, + }, {} }; -- cgit v1.2.3 From d71f2f88825b31553881944959962b1871099e1f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 5 Dec 2012 11:59:22 +0100 Subject: ACPI / PM: Fix header of acpi_dev_pm_detach() in acpi.h The header of acpi_dev_pm_detach() in include/linux/acpi.h has an incorrect return type, which should be void. Fix that. Signed-off-by: Rafael J. Wysocki --- include/linux/acpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 28ba643c92c..79345cd5ac2 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -459,7 +459,7 @@ static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } #if defined(CONFIG_ACPI) && defined(CONFIG_PM) int acpi_dev_pm_attach(struct device *dev, bool power_on); -int acpi_dev_pm_detach(struct device *dev, bool power_off); +void acpi_dev_pm_detach(struct device *dev, bool power_off); #else static inline int acpi_dev_pm_attach(struct device *dev, bool power_on) { -- cgit v1.2.3 From cdc87c5a30f407ed1ce43d8a22261116873d5ef1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 7 Dec 2012 23:11:14 +0100 Subject: pnpacpi: fix incorrect TEST_ALPHA() test TEST_ALPHA() is broken and always returns 0. [akpm@linux-foundation.org: return false for '@' as well, per Bjorn] Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Cc: Signed-off-by: Rafael J. Wysocki --- drivers/pnp/pnpacpi/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index ec8e914f756..767f526209e 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -58,7 +58,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev) if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \ return 0 #define TEST_ALPHA(c) \ - if (!('@' <= (c) || (c) <= 'Z')) \ + if (!('A' <= (c) && (c) <= 'Z')) \ return 0 static int __init ispnpidacpi(const char *id) { -- cgit v1.2.3 From 59c3987805a92f50f4c37392a36ab951327a6e29 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 7 Dec 2012 23:11:51 +0100 Subject: ACPI: add documentation about ACPI 5 enumeration Add a document that describes how to take advantage of ACPI enumeration for buses like platform, I2C and SPI. In addition to that we document how to translate ACPI GpioIo and GpioInt resources to be useful in Linux device drivers. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/enumeration.txt | 227 +++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 Documentation/acpi/enumeration.txt diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt new file mode 100644 index 00000000000..4f27785ca0c --- /dev/null +++ b/Documentation/acpi/enumeration.txt @@ -0,0 +1,227 @@ +ACPI based device enumeration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ACPI 5 introduced a set of new resources (UartTSerialBus, I2cSerialBus, +SpiSerialBus, GpioIo and GpioInt) which can be used in enumerating slave +devices behind serial bus controllers. + +In addition we are starting to see peripherals integrated in the +SoC/Chipset to appear only in ACPI namespace. These are typically devices +that are accessed through memory-mapped registers. + +In order to support this and re-use the existing drivers as much as +possible we decided to do following: + + o Devices that have no bus connector resource are represented as + platform devices. + + o Devices behind real busses where there is a connector resource + are represented as struct spi_device or struct i2c_device + (standard UARTs are not busses so there is no struct uart_device). + +As both ACPI and Device Tree represent a tree of devices (and their +resources) this implementation follows the Device Tree way as much as +possible. + +The ACPI implementation enumerates devices behind busses (platform, SPI and +I2C), creates the physical devices and binds them to their ACPI handle in +the ACPI namespace. + +This means that when ACPI_HANDLE(dev) returns non-NULL the device was +enumerated from ACPI namespace. This handle can be used to extract other +device-specific configuration. There is an example of this below. + +Platform bus support +~~~~~~~~~~~~~~~~~~~~ +Since we are using platform devices to represent devices that are not +connected to any physical bus we only need to implement a platform driver +for the device and add supported ACPI IDs. If this same IP-block is used on +some other non-ACPI platform, the driver might work out of the box or needs +some minor changes. + +Adding ACPI support for an existing driver should be pretty +straightforward. Here is the simplest example: + + #ifdef CONFIG_ACPI + static struct acpi_device_id mydrv_acpi_match[] = { + /* ACPI IDs here */ + { } + }; + MODULE_DEVICE_TABLE(acpi, mydrv_acpi_match); + #endif + + static struct platform_driver my_driver = { + ... + .driver = { + .acpi_match_table = ACPI_PTR(mydrv_acpi_match), + }, + }; + +If the driver needs to perform more complex initialization like getting and +configuring GPIOs it can get its ACPI handle and extract this information +from ACPI tables. + +Currently the kernel is not able to automatically determine from which ACPI +device it should make the corresponding platform device so we need to add +the ACPI device explicitly to acpi_platform_device_ids list defined in +drivers/acpi/scan.c. This limitation is only for the platform devices, SPI +and I2C devices are created automatically as described below. + +SPI serial bus support +~~~~~~~~~~~~~~~~~~~~~~ +Slave devices behind SPI bus have SpiSerialBus resource attached to them. +This is extracted automatically by the SPI core and the slave devices are +enumerated once spi_register_master() is called by the bus driver. + +Here is what the ACPI namespace for a SPI slave might look like: + + Device (EEP0) + { + Name (_ADR, 1) + Name (_CID, Package() { + "ATML0025", + "AT25", + }) + ... + Method (_CRS, 0, NotSerialized) + { + SPISerialBus(1, PolarityLow, FourWireMode, 8, + ControllerInitiated, 1000000, ClockPolarityLow, + ClockPhaseFirst, "\\_SB.PCI0.SPI1",) + } + ... + +The SPI device drivers only need to add ACPI IDs in a similar way than with +the platform device drivers. Below is an example where we add ACPI support +to at25 SPI eeprom driver (this is meant for the above ACPI snippet): + + #ifdef CONFIG_ACPI + static struct acpi_device_id at25_acpi_match[] = { + { "AT25", 0 }, + { }, + }; + MODULE_DEVICE_TABLE(acpi, at25_acpi_match); + #endif + + static struct spi_driver at25_driver = { + .driver = { + ... + .acpi_match_table = ACPI_PTR(at25_acpi_match), + }, + }; + +Note that this driver actually needs more information like page size of the +eeprom etc. but at the time writing this there is no standard way of +passing those. One idea is to return this in _DSM method like: + + Device (EEP0) + { + ... + Method (_DSM, 4, NotSerialized) + { + Store (Package (6) + { + "byte-len", 1024, + "addr-mode", 2, + "page-size, 32 + }, Local0) + + // Check UUIDs etc. + + Return (Local0) + } + +Then the at25 SPI driver can get this configation by calling _DSM on its +ACPI handle like: + + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; + acpi_status status; + + /* Fill in the input buffer */ + + status = acpi_evaluate_object(ACPI_HANDLE(&spi->dev), "_DSM", + &input, &output); + if (ACPI_FAILURE(status)) + /* Handle the error */ + + /* Extract the data here */ + + kfree(output.pointer); + +I2C serial bus support +~~~~~~~~~~~~~~~~~~~~~~ +The slaves behind I2C bus controller only need to add the ACPI IDs like +with the platform and SPI drivers. However the I2C bus controller driver +needs to call acpi_i2c_register_devices() after it has added the adapter. + +An I2C bus (controller) driver does: + + ... + ret = i2c_add_numbered_adapter(adapter); + if (ret) + /* handle error */ + + of_i2c_register_devices(adapter); + /* Enumerate the slave devices behind this bus via ACPI */ + acpi_i2c_register_devices(adapter); + +Below is an example of how to add ACPI support to the existing mpu3050 +input driver: + + #ifdef CONFIG_ACPI + static struct acpi_device_id mpu3050_acpi_match[] = { + { "MPU3050", 0 }, + { }, + }; + MODULE_DEVICE_TABLE(acpi, mpu3050_acpi_match); + #endif + + static struct i2c_driver mpu3050_i2c_driver = { + .driver = { + .name = "mpu3050", + .owner = THIS_MODULE, + .pm = &mpu3050_pm, + .of_match_table = mpu3050_of_match, + .acpi_match_table ACPI_PTR(mpu3050_acpi_match), + }, + .probe = mpu3050_probe, + .remove = __devexit_p(mpu3050_remove), + .id_table = mpu3050_ids, + }; + +GPIO support +~~~~~~~~~~~~ +ACPI 5 introduced two new resources to describe GPIO connections: GpioIo +and GpioInt. These resources are used be used to pass GPIO numbers used by +the device to the driver. For example: + + Method (_CRS, 0, NotSerialized) + { + Name (SBUF, ResourceTemplate() + { + GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, + IoRestrictionOutputOnly, "\\_SB.PCI0.GPI0", + 0x00, ResourceConsumer,,) + { + // Pin List + 0x0055 + } + ... + + Return (SBUF) + } + } + +These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" +specifies the path to the controller. In order to use these GPIOs in Linux +we need to translate them to the Linux GPIO numbers. + +The driver can do this by including and then calling +acpi_get_gpio(path, gpio). This will return the Linux GPIO number or +negative errno if there was no translation found. + +Other GpioIo parameters must be converted first by the driver to be +suitable to the gpiolib before passing them. + +In case of GpioInt resource an additional call to gpio_to_irq() must be +done before calling request_irq(). -- cgit v1.2.3 From 5e7779f0395833d80d8fa15933737c8dc48759ec Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 7 Dec 2012 23:12:01 +0100 Subject: ACPI: add Haswell LPSS devices to acpi_platform_device_ids list All devices behind Haswell LPSS (Low Power Subsystem) should be represented as platform devices so add them to the acpi_platform_device_ids list. Signed-off-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d59a60736e1..3db115acea5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -37,6 +37,16 @@ static const struct acpi_device_id acpi_platform_device_ids[] = { { "PNP0D40" }, + /* Haswell LPSS devices */ + { "INT33C0", 0 }, + { "INT33C1", 0 }, + { "INT33C2", 0 }, + { "INT33C3", 0 }, + { "INT33C4", 0 }, + { "INT33C5", 0 }, + { "INT33C6", 0 }, + { "INT33C7", 0 }, + { } }; -- cgit v1.2.3 From e5571397175be315bc6177ba39945dab538793b1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 10 Dec 2012 21:18:48 +0100 Subject: mmc: sdhci-acpi: enable runtime-pm for device HID INT33C6 sdhci-acpi supports ACPI devices which have compatibility ID PNP0D40, however it is not possible to know if those devices will all work correctly with runtime-pm, so that must be configured per hardware ID. For INT33C6, several related quirks, capabilities and flags are set: MMC_CAP_NONREMOVABLE The SDIO card will never be removable SDHCI_ACPI_RUNTIME_PM Enable runtime-pm of the host controller MMC_CAP_POWER_OFF_CARD Enable runtime-pm of the SDIO card MMC_PM_KEEP_POWER SDIO card has the capability to remain powered up during system suspend SDHCI_QUIRK2_HOST_OFF_CARD_ON Always do a full reset during system resume because the card may be already initialized having not been powered off. Wake-ups from the INT33C6 host controller are not supported, so the following capability must *not* be set: MMC_PM_WAKE_SDIO_IRQ Enable wake on card interrupt Signed-off-by: Adrian Hunter Acked-by: Chris Ball Signed-off-by: Rafael J. Wysocki --- drivers/mmc/host/sdhci-acpi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 6ac361744d3..12b0a78497f 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -87,7 +87,15 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { .enable_dma = sdhci_acpi_enable_dma, }; +static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, + .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, + .flags = SDHCI_ACPI_RUNTIME_PM, + .pm_caps = MMC_PM_KEEP_POWER, +}; + static const struct acpi_device_id sdhci_acpi_ids[] = { + { "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, { "PNP0D40" }, { }, }; -- cgit v1.2.3