Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32029895 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "PM / devfreq: Add timeout feature for cpufreq governor" into msm-4.9

parents 8054aded f6acbff6
Loading
Loading
Loading
Loading
+102 −14
Original line number Diff line number Diff line
@@ -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)
@@ -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;
}

@@ -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,
};

@@ -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;
@@ -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) {