Commit 9c8cc4d7 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-devfreq'

* pm-devfreq:
  PM / devfreq: Fix the wrong end with semicolon
  PM / devfreq: Fix indentaion of devfreq_summary debugfs node
  PM / devfreq: Clean up the devfreq instance name in sysfs attr
  memory: samsung: exynos5422-dmc: Add module param to control IRQ mode
  memory: samsung: exynos5422-dmc: Adjust polling interval and uptreshold
  memory: samsung: exynos5422-dmc: Use delayed timer as default
  PM / devfreq: Add support delayed timer for polling mode
  dt-bindings: devfreq: rk3399_dmc: Add rockchip,pmu phandle
  PM / devfreq: tegra: Add Dmitry as a maintainer
  PM / devfreq: event: Fix trivial spelling
  PM / devfreq: rk3399_dmc: Fix kernel oops when rockchip,pmu is absent
parents f46cf335 a7ee88c3
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -108,3 +108,15 @@ Description:
		frequency requested by governors and min_freq.
		The max_freq overrides min_freq because max_freq may be
		used to throttle devices to avoid overheating.

What:		/sys/class/devfreq/.../timer
Date:		July 2020
Contact:	Chanwoo Choi <cw00.choi@samsung.com>
Description:
		This ABI shows and stores the kind of work timer by users.
		This work timer is used by devfreq workqueue in order to
		monitor the device status such as utilization. The user
		can change the work timer on runtime according to their demand
		as following:
			echo deferrable > /sys/class/devfreq/.../timer
			echo delayed > /sys/class/devfreq/.../timer
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ Optional properties:
			 format depends on the interrupt controller.
			 It should be a DCF interrupt. When DDR DVFS finishes
			 a DCF interrupt is triggered.
- rockchip,pmu:		 Phandle to the syscon managing the "PMU general register
			 files".

Following properties relate to DDR timing:

+9 −0
Original line number Diff line number Diff line
@@ -11097,6 +11097,15 @@ F: Documentation/core-api/boot-time-mm.rst
F:	include/linux/memblock.h
F:	mm/memblock.c
MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA
M:	Dmitry Osipenko <digetx@gmail.com>
L:	linux-pm@vger.kernel.org
L:	linux-tegra@vger.kernel.org
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
S:	Maintained
F:	drivers/devfreq/tegra20-devfreq.c
F:	drivers/devfreq/tegra30-devfreq.c
MEMORY MANAGEMENT
M:	Andrew Morton <akpm@linux-foundation.org>
L:	linux-mm@kvack.org
+2 −2
Original line number Diff line number Diff line
@@ -293,7 +293,7 @@ static void devfreq_event_release_edev(struct device *dev)
/**
 * devfreq_event_add_edev() - Add new devfreq-event device.
 * @dev		: the device owning the devfreq-event device being created
 * @desc	: the devfreq-event device's decriptor which include essential
 * @desc	: the devfreq-event device's descriptor which include essential
 *		  data for devfreq-event device.
 *
 * Note that this function add new devfreq-event device to devfreq-event class
@@ -385,7 +385,7 @@ static void devm_devfreq_event_release(struct device *dev, void *res)
/**
 * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev()
 * @dev		: the device owning the devfreq-event device being created
 * @desc	: the devfreq-event device's decriptor which include essential
 * @desc	: the devfreq-event device's descriptor which include essential
 *		  data for devfreq-event device.
 *
 * Note that this function manages automatically the memory of devfreq-event
+151 −44
Original line number Diff line number Diff line
@@ -49,6 +49,11 @@ static LIST_HEAD(devfreq_governor_list);
static LIST_HEAD(devfreq_list);
static DEFINE_MUTEX(devfreq_list_lock);

static const char timer_name[][DEVFREQ_NAME_LEN] = {
	[DEVFREQ_TIMER_DEFERRABLE] = { "deferrable" },
	[DEVFREQ_TIMER_DELAYED] = { "delayed" },
};

/**
 * find_device_devfreq() - find devfreq struct using device pointer
 * @dev:	device pointer used to lookup device devfreq.
@@ -454,7 +459,17 @@ void devfreq_monitor_start(struct devfreq *devfreq)
	if (devfreq->governor->interrupt_driven)
		return;

	switch (devfreq->profile->timer) {
	case DEVFREQ_TIMER_DEFERRABLE:
		INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
		break;
	case DEVFREQ_TIMER_DELAYED:
		INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor);
		break;
	default:
		return;
	}

	if (devfreq->profile->polling_ms)
		queue_delayed_work(devfreq_wq, &devfreq->work,
			msecs_to_jiffies(devfreq->profile->polling_ms));
@@ -771,6 +786,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
	devfreq->data = data;
	devfreq->nb.notifier_call = devfreq_notifier_call;

	if (devfreq->profile->timer < 0
		|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
		goto err_out;
	}

	if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
		mutex_unlock(&devfreq->lock);
		err = set_freq_table(devfreq);
@@ -1260,18 +1280,20 @@ EXPORT_SYMBOL(devfreq_remove_governor);
static ssize_t name_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	struct devfreq *devfreq = to_devfreq(dev);
	return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent));
	struct devfreq *df = to_devfreq(dev);
	return sprintf(buf, "%s\n", dev_name(df->dev.parent));
}
static DEVICE_ATTR_RO(name);

static ssize_t governor_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{
	if (!to_devfreq(dev)->governor)
	struct devfreq *df = to_devfreq(dev);

	if (!df->governor)
		return -EINVAL;

	return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
	return sprintf(buf, "%s\n", df->governor->name);
}

static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
@@ -1282,6 +1304,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
	char str_governor[DEVFREQ_NAME_LEN + 1];
	const struct devfreq_governor *governor, *prev_governor;

	if (!df->governor)
		return -EINVAL;

	ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
	if (ret != 1)
		return -EINVAL;
@@ -1295,20 +1320,18 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
	if (df->governor == governor) {
		ret = 0;
		goto out;
	} else if ((df->governor && df->governor->immutable) ||
					governor->immutable) {
	} else if (df->governor->immutable || governor->immutable) {
		ret = -EINVAL;
		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;
	}
	}

	prev_governor = df->governor;
	df->governor = governor;
	strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN);
@@ -1343,13 +1366,16 @@ static ssize_t available_governors_show(struct device *d,
	struct devfreq *df = to_devfreq(d);
	ssize_t count = 0;

	if (!df->governor)
		return -EINVAL;

	mutex_lock(&devfreq_list_lock);

	/*
	 * The devfreq with immutable governor (e.g., passive) shows
	 * only own governor.
	 */
	if (df->governor && df->governor->immutable) {
	if (df->governor->immutable) {
		count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
				  "%s ", df->governor_name);
	/*
@@ -1383,27 +1409,37 @@ static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
			     char *buf)
{
	unsigned long freq;
	struct devfreq *devfreq = to_devfreq(dev);
	struct devfreq *df = to_devfreq(dev);

	if (devfreq->profile->get_cur_freq &&
		!devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
	if (!df->profile)
		return -EINVAL;

	if (df->profile->get_cur_freq &&
		!df->profile->get_cur_freq(df->dev.parent, &freq))
		return sprintf(buf, "%lu\n", freq);

	return sprintf(buf, "%lu\n", devfreq->previous_freq);
	return sprintf(buf, "%lu\n", df->previous_freq);
}
static DEVICE_ATTR_RO(cur_freq);

static ssize_t target_freq_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
	struct devfreq *df = to_devfreq(dev);

	return sprintf(buf, "%lu\n", df->previous_freq);
}
static DEVICE_ATTR_RO(target_freq);

static ssize_t polling_interval_show(struct device *dev,
				     struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
	struct devfreq *df = to_devfreq(dev);

	if (!df->profile)
		return -EINVAL;

	return sprintf(buf, "%d\n", df->profile->polling_ms);
}

static ssize_t polling_interval_store(struct device *dev,
@@ -1531,6 +1567,9 @@ static ssize_t available_frequencies_show(struct device *d,
	ssize_t count = 0;
	int i;

	if (!df->profile)
		return -EINVAL;

	mutex_lock(&df->lock);

	for (i = 0; i < df->profile->max_state; i++)
@@ -1551,49 +1590,53 @@ static DEVICE_ATTR_RO(available_frequencies);
static ssize_t trans_stat_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	struct devfreq *devfreq = to_devfreq(dev);
	struct devfreq *df = to_devfreq(dev);
	ssize_t len;
	int i, j;
	unsigned int max_state = devfreq->profile->max_state;
	unsigned int max_state;

	if (!df->profile)
		return -EINVAL;
	max_state = df->profile->max_state;

	if (max_state == 0)
		return sprintf(buf, "Not Supported.\n");

	mutex_lock(&devfreq->lock);
	if (!devfreq->stop_polling &&
			devfreq_update_status(devfreq, devfreq->previous_freq)) {
		mutex_unlock(&devfreq->lock);
	mutex_lock(&df->lock);
	if (!df->stop_polling &&
			devfreq_update_status(df, df->previous_freq)) {
		mutex_unlock(&df->lock);
		return 0;
	}
	mutex_unlock(&devfreq->lock);
	mutex_unlock(&df->lock);

	len = sprintf(buf, "     From  :   To\n");
	len += sprintf(buf + len, "           :");
	for (i = 0; i < max_state; i++)
		len += sprintf(buf + len, "%10lu",
				devfreq->profile->freq_table[i]);
				df->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) {
		if (df->profile->freq_table[i]
					== df->previous_freq) {
			len += sprintf(buf + len, "*");
		} else {
			len += sprintf(buf + len, " ");
		}
		len += sprintf(buf + len, "%10lu:",
				devfreq->profile->freq_table[i]);
				df->profile->freq_table[i]);
		for (j = 0; j < max_state; j++)
			len += sprintf(buf + len, "%10u",
				devfreq->stats.trans_table[(i * max_state) + j]);
				df->stats.trans_table[(i * max_state) + j]);

		len += sprintf(buf + len, "%10llu\n", (u64)
			jiffies64_to_msecs(devfreq->stats.time_in_state[i]));
			jiffies64_to_msecs(df->stats.time_in_state[i]));
	}

	len += sprintf(buf + len, "Total transition : %u\n",
					devfreq->stats.total_trans);
					df->stats.total_trans);
	return len;
}

@@ -1604,6 +1647,9 @@ static ssize_t trans_stat_store(struct device *dev,
	struct devfreq *df = to_devfreq(dev);
	int err, value;

	if (!df->profile)
		return -EINVAL;

	if (df->profile->max_state == 0)
		return count;

@@ -1625,6 +1671,69 @@ static ssize_t trans_stat_store(struct device *dev,
}
static DEVICE_ATTR_RW(trans_stat);

static ssize_t timer_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{
	struct devfreq *df = to_devfreq(dev);

	if (!df->profile)
		return -EINVAL;

	return sprintf(buf, "%s\n", timer_name[df->profile->timer]);
}

static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
			      const char *buf, size_t count)
{
	struct devfreq *df = to_devfreq(dev);
	char str_timer[DEVFREQ_NAME_LEN + 1];
	int timer = -1;
	int ret = 0, i;

	if (!df->governor || !df->profile)
		return -EINVAL;

	ret = sscanf(buf, "%16s", str_timer);
	if (ret != 1)
		return -EINVAL;

	for (i = 0; i < DEVFREQ_TIMER_NUM; i++) {
		if (!strncmp(timer_name[i], str_timer, DEVFREQ_NAME_LEN)) {
			timer = i;
			break;
		}
	}

	if (timer < 0) {
		ret = -EINVAL;
		goto out;
	}

	if (df->profile->timer == timer) {
		ret = 0;
		goto out;
	}

	mutex_lock(&df->lock);
	df->profile->timer = timer;
	mutex_unlock(&df->lock);

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

	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:
	return ret ? ret : count;
}
static DEVICE_ATTR_RW(timer);

static struct attribute *devfreq_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_governor.attr,
@@ -1636,6 +1745,7 @@ static struct attribute *devfreq_attrs[] = {
	&dev_attr_min_freq.attr,
	&dev_attr_max_freq.attr,
	&dev_attr_trans_stat.attr,
	&dev_attr_timer.attr,
	NULL,
};
ATTRIBUTE_GROUPS(devfreq);
@@ -1657,8 +1767,7 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
	unsigned long cur_freq, min_freq, max_freq;
	unsigned int polling_ms;

	seq_printf(s, "%-30s %-10s %-10s %-15s %10s %12s %12s %12s\n",
			"dev_name",
	seq_printf(s, "%-30s %-30s %-15s %10s %12s %12s %12s\n",
			"dev",
			"parent_dev",
			"governor",
@@ -1666,10 +1775,9 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
			"cur_freq_Hz",
			"min_freq_Hz",
			"max_freq_Hz");
	seq_printf(s, "%30s %10s %10s %15s %10s %12s %12s %12s\n",
	seq_printf(s, "%30s %30s %15s %10s %12s %12s %12s\n",
			"------------------------------",
			"------------------------------",
			"----------",
			"----------",
			"---------------",
			"----------",
			"------------",
@@ -1692,14 +1800,13 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
#endif

		mutex_lock(&devfreq->lock);
		cur_freq = devfreq->previous_freq,
		cur_freq = devfreq->previous_freq;
		get_freq_range(devfreq, &min_freq, &max_freq);
		polling_ms = devfreq->profile->polling_ms,
		polling_ms = devfreq->profile->polling_ms;
		mutex_unlock(&devfreq->lock);

		seq_printf(s,
			"%-30s %-10s %-10s %-15s %10d %12ld %12ld %12ld\n",
			dev_name(devfreq->dev.parent),
			"%-30s %-30s %-15s %10d %12ld %12ld %12ld\n",
			dev_name(&devfreq->dev),
			p_devfreq ? dev_name(&p_devfreq->dev) : "null",
			devfreq->governor_name,
Loading