From: Chungwoo Park Date: Wed, 23 May 2018 00:46:03 +0000 (+0900) Subject: [COMMON] devfreq: Update to devfreq core code. X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=af32ac20f6cad6d24611ef3d60282a7d86898911;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [COMMON] devfreq: Update to devfreq core code. This patch updated devfreq core related code. Change-Id: I74c069783c8f87779107cddb35b2f984d359627e Signed-off-by: Chungwoo Park --- diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 202476fbbc4c..520d0128695a 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,15 @@ #include #include "governor.h" +#ifdef CONFIG_ARM_EXYNOS_DEVFREQ +#include + +#ifdef CONFIG_EXYNOS_DVFS_MANAGER +#include +#endif + +#endif + static struct class *devfreq_class; /* @@ -130,7 +140,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq) */ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) { - int lev, prev_lev, ret = 0; + int lev, prev_lev = 0, ret = 0; unsigned long cur_time; cur_time = jiffies; @@ -154,7 +164,13 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) goto out; } - if (lev != prev_lev) { + if (freq != devfreq->previous_freq) { + prev_lev = devfreq_get_freq_level(devfreq, + devfreq->previous_freq); + if (prev_lev && prev_lev < 0) { + pr_err("DEVFREQ: invalid index to update status\n"); + return -EINVAL; + } devfreq->trans_table[(prev_lev * devfreq->profile->max_state) + lev]++; devfreq->total_trans++; @@ -192,6 +208,66 @@ static struct devfreq_governor *find_devfreq_governor(const char *name) return ERR_PTR(-ENODEV); } +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) +static int devfreq_frequency_scaler(int dm_type, void *devdata, + u32 target_freq, unsigned int relation) +{ + struct device *dev; + struct devfreq *devfreq; + unsigned long freq = target_freq; + u32 flags = 0; + int err = 0; + + dev = find_exynos_devfreq_device(devdata); + if (IS_ERR(dev)) { + pr_err("%s: No such devfreq device for dm_type(%d)\n", __func__, dm_type); + err = -ENODEV; + 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: No such devfreq for the device\n", __func__); + err = -ENODEV; + goto err_out; + } + + /* + * Adjust the freuqency with user freq and QoS. + * + * List from the highest proiority + * max_freq (probably called by thermal when it's too hot) + * min_freq + */ + + if (devfreq->min_freq && freq < devfreq->min_freq) { + freq = devfreq->min_freq; + flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ + } + if (devfreq->max_freq && freq > devfreq->max_freq) { + freq = devfreq->max_freq; + flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ + } + + err = devfreq->profile->target(devfreq->dev.parent, &freq, flags); + 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; + +err_out: + return err; +} +#endif + +#if !defined(CONFIG_EXYNOS_DVFS_MANAGER) || !defined(CONFIG_ARM_EXYNOS_DEVFREQ) static int devfreq_notify_transition(struct devfreq *devfreq, struct devfreq_freqs *freqs, unsigned int state) { @@ -214,6 +290,7 @@ static int devfreq_notify_transition(struct devfreq *devfreq, return 0; } +#endif /* Load monitoring helper functions for governors use */ @@ -226,10 +303,19 @@ static int devfreq_notify_transition(struct devfreq *devfreq, */ int update_devfreq(struct devfreq *devfreq) { - struct devfreq_freqs freqs; - unsigned long freq, cur_freq; + unsigned long freq; int err = 0; +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + int dm_type; + unsigned long pm_qos_max; +#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_INTERACTIVE) + struct devfreq_simple_interactive_data *gov_data = devfreq->data; +#endif +#else u32 flags = 0; + unsigned long cur_freq; + struct devfreq_freqs freqs; +#endif if (!mutex_is_locked(&devfreq->lock)) { WARN(true, "devfreq->lock must be locked by the caller.\n"); @@ -244,6 +330,24 @@ int update_devfreq(struct devfreq *devfreq) if (err) return err; +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + err = find_exynos_devfreq_dm_type(devfreq->dev.parent, &dm_type); + if (err) + return -EINVAL; + + pm_qos_max = devfreq->max_freq; + +#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_INTERACTIVE) + if (!strcmp(devfreq->governor->name, "interactive") && gov_data->pm_qos_class_max) + pm_qos_max = (unsigned long)pm_qos_request(gov_data->pm_qos_class_max); +#endif + if (devfreq->str_freq) + policy_update_call_to_DM(dm_type, devfreq->str_freq, + devfreq->str_freq); + else + policy_update_call_to_DM(dm_type, freq, pm_qos_max); + DM_CALL(dm_type, &freq); +#else /* * Adjust the frequency with user freq and QoS. * @@ -286,6 +390,7 @@ int update_devfreq(struct devfreq *devfreq) "Couldn't update frequency transition information.\n"); devfreq->previous_freq = freq; +#endif return err; } EXPORT_SYMBOL(update_devfreq); @@ -303,11 +408,15 @@ static void devfreq_monitor(struct work_struct *work) mutex_lock(&devfreq->lock); err = update_devfreq(devfreq); - if (err) + if (err && err != -EAGAIN) dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err); - +#ifdef CONFIG_SCHED_HMP + mod_delayed_work_on(0, devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); +#else queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms)); +#endif mutex_unlock(&devfreq->lock); } @@ -322,7 +431,7 @@ static void devfreq_monitor(struct work_struct *work) */ void devfreq_monitor_start(struct devfreq *devfreq) { - INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor); + INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor); if (devfreq->profile->polling_ms) queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms)); @@ -517,8 +626,10 @@ struct devfreq *devfreq_add_device(struct device *dev, { struct devfreq *devfreq; struct devfreq_governor *governor; - static atomic_t devfreq_no = ATOMIC_INIT(-1); int err = 0; +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + int dm_type; +#endif if (!dev || !profile || !governor_name) { dev_err(dev, "%s: Invalid parameters.\n", __func__); @@ -559,8 +670,7 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_lock(&devfreq->lock); } - dev_set_name(&devfreq->dev, "devfreq%d", - atomic_inc_return(&devfreq_no)); + dev_set_name(&devfreq->dev, "%s", dev_name(dev)); err = device_register(&devfreq->dev); if (err) { mutex_unlock(&devfreq->lock); @@ -582,6 +692,16 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_unlock(&devfreq->lock); +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + err = find_exynos_devfreq_dm_type(dev, &dm_type); + if (err) + goto err_dm_type; + + err = register_exynos_dm_freq_scaler(dm_type, devfreq_frequency_scaler); + if (err) + goto err_dm_scaler; +#endif + mutex_lock(&devfreq_list_lock); list_add(&devfreq->node, &devfreq_list); @@ -604,11 +724,14 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_unlock(&devfreq_list_lock); return devfreq; - err_init: list_del(&devfreq->node); mutex_unlock(&devfreq_list_lock); - +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + unregister_exynos_dm_freq_scaler(dm_type); +err_dm_scaler: +err_dm_type: +#endif device_unregister(&devfreq->dev); err_dev: if (devfreq) @@ -626,9 +749,20 @@ EXPORT_SYMBOL(devfreq_add_device); */ int devfreq_remove_device(struct devfreq *devfreq) { +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + int dm_type; + int err = 0; +#endif if (!devfreq) return -EINVAL; +#if defined(CONFIG_EXYNOS_DVFS_MANAGER) && defined(CONFIG_ARM_EXYNOS_DEVFREQ) + err = find_exynos_devfreq_dm_type(devfreq->dev.parent, &dm_type); + if (err) + return err; + + unregister_exynos_dm_freq_scaler(dm_type); +#endif device_unregister(&devfreq->dev); return 0; @@ -1055,60 +1189,6 @@ static ssize_t polling_interval_store(struct device *dev, } static DEVICE_ATTR_RW(polling_interval); -static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct devfreq *df = to_devfreq(dev); - unsigned long value; - int ret; - unsigned long max; - - ret = sscanf(buf, "%lu", &value); - if (ret != 1) - return -EINVAL; - - mutex_lock(&df->lock); - max = df->max_freq; - if (value && max && value > max) { - ret = -EINVAL; - goto unlock; - } - - df->min_freq = value; - update_devfreq(df); - ret = count; -unlock: - mutex_unlock(&df->lock); - return ret; -} - -static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct devfreq *df = to_devfreq(dev); - unsigned long value; - int ret; - unsigned long min; - - ret = sscanf(buf, "%lu", &value); - if (ret != 1) - return -EINVAL; - - mutex_lock(&df->lock); - min = df->min_freq; - if (value && min && value < min) { - ret = -EINVAL; - goto unlock; - } - - df->max_freq = value; - update_devfreq(df); - ret = count; -unlock: - mutex_unlock(&df->lock); - return ret; -} - #define show_one(name) \ static ssize_t name##_show \ (struct device *dev, struct device_attribute *attr, char *buf) \ @@ -1118,8 +1198,8 @@ static ssize_t name##_show \ show_one(min_freq); show_one(max_freq); -static DEVICE_ATTR_RW(min_freq); -static DEVICE_ATTR_RW(max_freq); +static DEVICE_ATTR_RO(min_freq); +static DEVICE_ATTR_RO(max_freq); static ssize_t available_frequencies_show(struct device *d, struct device_attribute *attr, @@ -1196,6 +1276,28 @@ static ssize_t trans_stat_show(struct device *dev, } static DEVICE_ATTR_RO(trans_stat); +static ssize_t time_in_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + ssize_t len = 0; + int i, err; + unsigned int max_state = devfreq->profile->max_state; + + err = devfreq_update_status(devfreq, devfreq->previous_freq); + if (err) + return 0; + + for (i = 0; i < max_state; i++) { + len += sprintf(buf + len, "%8lu", + devfreq->profile->freq_table[i]); + len += sprintf(buf + len, "%10u\n", + jiffies_to_msecs(devfreq->time_in_state[i])); + } + return len; +} +static DEVICE_ATTR_RO(time_in_state); + static struct attribute *devfreq_attrs[] = { &dev_attr_governor.attr, &dev_attr_available_governors.attr, @@ -1206,6 +1308,7 @@ static struct attribute *devfreq_attrs[] = { &dev_attr_min_freq.attr, &dev_attr_max_freq.attr, &dev_attr_trans_stat.attr, + &dev_attr_time_in_state.attr, NULL, }; ATTRIBUTE_GROUPS(devfreq);