Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <rajagopal.venkat@linaro.org>
Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Kevin Hilman <khilman@ti.com>
Cc: linux-pm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Signed-off-by: Nishanth Menon <nm@ti.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>

authored by

Nishanth Menon and committed by
MyungJoo Ham
3aa173b8 2df5021f

+98
+91
drivers/devfreq/devfreq.c
··· 36 36 */ 37 37 static struct workqueue_struct *devfreq_wq; 38 38 39 + /* The list of all device-devfreq governors */ 40 + static LIST_HEAD(devfreq_governor_list); 39 41 /* The list of all device-devfreq */ 40 42 static LIST_HEAD(devfreq_list); 41 43 static DEFINE_MUTEX(devfreq_list_lock); ··· 111 109 devfreq->last_stat_updated = cur_time; 112 110 113 111 return 0; 112 + } 113 + 114 + /** 115 + * find_devfreq_governor() - find devfreq governor from name 116 + * @name: name of the governor 117 + * 118 + * Search the list of devfreq governors and return the matched 119 + * governor's pointer. devfreq_list_lock should be held by the caller. 120 + */ 121 + static struct devfreq_governor *find_devfreq_governor(const char *name) 122 + { 123 + struct devfreq_governor *tmp_governor; 124 + 125 + if (unlikely(IS_ERR_OR_NULL(name))) { 126 + pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); 127 + return ERR_PTR(-EINVAL); 128 + } 129 + WARN(!mutex_is_locked(&devfreq_list_lock), 130 + "devfreq_list_lock must be locked."); 131 + 132 + list_for_each_entry(tmp_governor, &devfreq_governor_list, node) { 133 + if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN)) 134 + return tmp_governor; 135 + } 136 + 137 + return ERR_PTR(-ENODEV); 114 138 } 115 139 116 140 /* Load monitoring helper functions for governors use */ ··· 542 514 DEVFREQ_GOV_RESUME, NULL); 543 515 } 544 516 EXPORT_SYMBOL(devfreq_resume_device); 517 + 518 + /** 519 + * devfreq_add_governor() - Add devfreq governor 520 + * @governor: the devfreq governor to be added 521 + */ 522 + int devfreq_add_governor(struct devfreq_governor *governor) 523 + { 524 + struct devfreq_governor *g; 525 + int err = 0; 526 + 527 + if (!governor) { 528 + pr_err("%s: Invalid parameters.\n", __func__); 529 + return -EINVAL; 530 + } 531 + 532 + mutex_lock(&devfreq_list_lock); 533 + g = find_devfreq_governor(governor->name); 534 + if (!IS_ERR(g)) { 535 + pr_err("%s: governor %s already registered\n", __func__, 536 + g->name); 537 + err = -EINVAL; 538 + goto err_out; 539 + } 540 + 541 + list_add(&governor->node, &devfreq_governor_list); 542 + 543 + err_out: 544 + mutex_unlock(&devfreq_list_lock); 545 + 546 + return err; 547 + } 548 + EXPORT_SYMBOL(devfreq_add_governor); 549 + 550 + /** 551 + * devfreq_remove_device() - Remove devfreq feature from a device. 552 + * @governor: the devfreq governor to be removed 553 + */ 554 + int devfreq_remove_governor(struct devfreq_governor *governor) 555 + { 556 + struct devfreq_governor *g; 557 + int err = 0; 558 + 559 + if (!governor) { 560 + pr_err("%s: Invalid parameters.\n", __func__); 561 + return -EINVAL; 562 + } 563 + 564 + mutex_lock(&devfreq_list_lock); 565 + g = find_devfreq_governor(governor->name); 566 + if (IS_ERR(g)) { 567 + pr_err("%s: governor %s not registered\n", __func__, 568 + g->name); 569 + err = -EINVAL; 570 + goto err_out; 571 + } 572 + 573 + list_del(&governor->node); 574 + err_out: 575 + mutex_unlock(&devfreq_list_lock); 576 + 577 + return err; 578 + } 579 + EXPORT_SYMBOL(devfreq_remove_governor); 545 580 546 581 static ssize_t show_governor(struct device *dev, 547 582 struct device_attribute *attr, char *buf)
+4
drivers/devfreq/governor.h
··· 34 34 extern void devfreq_monitor_resume(struct devfreq *devfreq); 35 35 extern void devfreq_interval_update(struct devfreq *devfreq, 36 36 unsigned int *delay); 37 + 38 + extern int devfreq_add_governor(struct devfreq_governor *governor); 39 + extern int devfreq_remove_governor(struct devfreq_governor *governor); 40 + 37 41 #endif /* _GOVERNOR_H */
+3
include/linux/devfreq.h
··· 92 92 93 93 /** 94 94 * struct devfreq_governor - Devfreq policy governor 95 + * @node: list node - contains registered devfreq governors 95 96 * @name: Governor's name 96 97 * @get_target_freq: Returns desired operating frequency for the device. 97 98 * Basically, get_target_freq will run ··· 108 107 * Note that the callbacks are called with devfreq->lock locked by devfreq. 109 108 */ 110 109 struct devfreq_governor { 110 + struct list_head node; 111 + 111 112 const char name[DEVFREQ_NAME_LEN]; 112 113 int (*get_target_freq)(struct devfreq *this, unsigned long *freq); 113 114 int (*event_handler)(struct devfreq *devfreq,