Loading drivers/devfreq/governor_cpufreq.c +102 −14 Original line number Diff line number Diff line Loading @@ -46,23 +46,96 @@ struct devfreq_node { struct list_head list; struct freq_map **map; struct freq_map *common_map; unsigned int timeout; struct delayed_work dwork; bool drop; unsigned long prev_tgt; }; static LIST_HEAD(devfreq_list); static DEFINE_MUTEX(state_lock); #define show_attr(name) \ static ssize_t show_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct devfreq *df = to_devfreq(dev); \ struct devfreq_node *n = df->data; \ return snprintf(buf, PAGE_SIZE, "%u\n", n->name); \ } #define store_attr(name, _min, _max) \ static ssize_t store_##name(struct device *dev, \ struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct devfreq *df = to_devfreq(dev); \ struct devfreq_node *n = df->data; \ int ret; \ unsigned int val; \ ret = kstrtoint(buf, 10, &val); \ if (ret) \ return ret; \ val = max(val, _min); \ val = min(val, _max); \ n->name = val; \ return count; \ } #define gov_attr(__attr, min, max) \ show_attr(__attr) \ store_attr(__attr, (min), (max)) \ static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr) static int update_node(struct devfreq_node *node) { int ret; struct devfreq *df = node->df; if (!df) return 0; cancel_delayed_work_sync(&node->dwork); mutex_lock(&df->lock); node->drop = false; ret = update_devfreq(df); if (ret) { dev_err(df->dev.parent, "Unable to update frequency\n"); goto out; } if (!node->timeout) goto out; if (df->previous_freq <= df->min_freq) goto out; schedule_delayed_work(&node->dwork, msecs_to_jiffies(node->timeout)); out: mutex_unlock(&df->lock); return ret; } static void update_all_devfreqs(void) { struct devfreq_node *node; list_for_each_entry(node, &devfreq_list, list) { update_node(node); } } static void do_timeout(struct work_struct *work) { struct devfreq_node *node = container_of(to_delayed_work(work), struct devfreq_node, dwork); struct devfreq *df = node->df; if (!node->df) continue; mutex_lock(&df->lock); node->drop = true; update_devfreq(df); mutex_unlock(&df->lock); } } static struct devfreq_node *find_devfreq_node(struct device *dev) Loading Loading @@ -299,10 +372,21 @@ static int devfreq_cpufreq_get_freq(struct devfreq *df, return -ENODEV; } if (node->drop) { *freq = 0; return 0; } for_each_possible_cpu(cpu) tgt_freq = max(tgt_freq, cpu_to_dev_freq(df, cpu)); if (node->timeout && tgt_freq < node->prev_tgt) *freq = 0; else *freq = tgt_freq; node->prev_tgt = tgt_freq; return 0; } Loading Loading @@ -361,8 +445,11 @@ static ssize_t show_map(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(freq_map, 0444, show_map, NULL); gov_attr(timeout, 0U, 100U); static struct attribute *dev_attr[] = { &dev_attr_freq_map.attr, &dev_attr_timeout.attr, NULL, }; Loading Loading @@ -401,17 +488,16 @@ static int devfreq_cpufreq_gov_start(struct devfreq *devfreq) node->dev = devfreq->dev.parent; list_add_tail(&node->list, &devfreq_list); } INIT_DELAYED_WORK(&node->dwork, do_timeout); node->df = devfreq; node->orig_data = devfreq->data; devfreq->data = node; mutex_lock(&devfreq->lock); ret = update_devfreq(devfreq); mutex_unlock(&devfreq->lock); if (ret) { pr_err("Freq update failed!\n"); ret = update_node(node); if (ret) goto update_fail; } mutex_unlock(&state_lock); return 0; Loading @@ -433,6 +519,8 @@ static void devfreq_cpufreq_gov_stop(struct devfreq *devfreq) { struct devfreq_node *node = devfreq->data; cancel_delayed_work_sync(&node->dwork); mutex_lock(&state_lock); devfreq->data = node->orig_data; if (node->map || node->common_map) { Loading Loading
drivers/devfreq/governor_cpufreq.c +102 −14 Original line number Diff line number Diff line Loading @@ -46,23 +46,96 @@ struct devfreq_node { struct list_head list; struct freq_map **map; struct freq_map *common_map; unsigned int timeout; struct delayed_work dwork; bool drop; unsigned long prev_tgt; }; static LIST_HEAD(devfreq_list); static DEFINE_MUTEX(state_lock); #define show_attr(name) \ static ssize_t show_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct devfreq *df = to_devfreq(dev); \ struct devfreq_node *n = df->data; \ return snprintf(buf, PAGE_SIZE, "%u\n", n->name); \ } #define store_attr(name, _min, _max) \ static ssize_t store_##name(struct device *dev, \ struct device_attribute *attr, const char *buf, \ size_t count) \ { \ struct devfreq *df = to_devfreq(dev); \ struct devfreq_node *n = df->data; \ int ret; \ unsigned int val; \ ret = kstrtoint(buf, 10, &val); \ if (ret) \ return ret; \ val = max(val, _min); \ val = min(val, _max); \ n->name = val; \ return count; \ } #define gov_attr(__attr, min, max) \ show_attr(__attr) \ store_attr(__attr, (min), (max)) \ static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr) static int update_node(struct devfreq_node *node) { int ret; struct devfreq *df = node->df; if (!df) return 0; cancel_delayed_work_sync(&node->dwork); mutex_lock(&df->lock); node->drop = false; ret = update_devfreq(df); if (ret) { dev_err(df->dev.parent, "Unable to update frequency\n"); goto out; } if (!node->timeout) goto out; if (df->previous_freq <= df->min_freq) goto out; schedule_delayed_work(&node->dwork, msecs_to_jiffies(node->timeout)); out: mutex_unlock(&df->lock); return ret; } static void update_all_devfreqs(void) { struct devfreq_node *node; list_for_each_entry(node, &devfreq_list, list) { update_node(node); } } static void do_timeout(struct work_struct *work) { struct devfreq_node *node = container_of(to_delayed_work(work), struct devfreq_node, dwork); struct devfreq *df = node->df; if (!node->df) continue; mutex_lock(&df->lock); node->drop = true; update_devfreq(df); mutex_unlock(&df->lock); } } static struct devfreq_node *find_devfreq_node(struct device *dev) Loading Loading @@ -299,10 +372,21 @@ static int devfreq_cpufreq_get_freq(struct devfreq *df, return -ENODEV; } if (node->drop) { *freq = 0; return 0; } for_each_possible_cpu(cpu) tgt_freq = max(tgt_freq, cpu_to_dev_freq(df, cpu)); if (node->timeout && tgt_freq < node->prev_tgt) *freq = 0; else *freq = tgt_freq; node->prev_tgt = tgt_freq; return 0; } Loading Loading @@ -361,8 +445,11 @@ static ssize_t show_map(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(freq_map, 0444, show_map, NULL); gov_attr(timeout, 0U, 100U); static struct attribute *dev_attr[] = { &dev_attr_freq_map.attr, &dev_attr_timeout.attr, NULL, }; Loading Loading @@ -401,17 +488,16 @@ static int devfreq_cpufreq_gov_start(struct devfreq *devfreq) node->dev = devfreq->dev.parent; list_add_tail(&node->list, &devfreq_list); } INIT_DELAYED_WORK(&node->dwork, do_timeout); node->df = devfreq; node->orig_data = devfreq->data; devfreq->data = node; mutex_lock(&devfreq->lock); ret = update_devfreq(devfreq); mutex_unlock(&devfreq->lock); if (ret) { pr_err("Freq update failed!\n"); ret = update_node(node); if (ret) goto update_fail; } mutex_unlock(&state_lock); return 0; Loading @@ -433,6 +519,8 @@ static void devfreq_cpufreq_gov_stop(struct devfreq *devfreq) { struct devfreq_node *node = devfreq->data; cancel_delayed_work_sync(&node->dwork); mutex_lock(&state_lock); devfreq->data = node->orig_data; if (node->map || node->common_map) { Loading