Commit 589cb2c0 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'devfreq-fixes-for-5.19-rc5' of...

Merge tag 'devfreq-fixes-for-5.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux

Pull devfreq fixes for 5.19-rc5 from Chanwoo Choi:

"1. Fix devfreq passive governor issue when cpufreq policies are not
    ready during kernel boot because some CPUs turn on after kernel
    booting or others.

    - Re-initialize the vairables of struct devfreq_passive_data when
      PROBE_DEFER happens when cpufreq_get() returns NULL.

    - Use dev_err_probe to mute warning when PROBE_DEFER.

    - Fix cpufreq passive unregister erroring on PROBE_DEFER
      by using the allocated parent_cpu_data list to free resouce
      instead of for_each_possible_cpu().

    - Remove duplicate cpufreq passive unregister and warning when
      PROBE_DEFER.

    - Use HZ_PER_KZH macro in units.h.

    - Fix wrong indentation in SPDX-License line.

 2. Fix reference count leak in exynos-ppmu.c by using of_node_put().

 3. Rework freq_table to be local to devfreq struct

    - struct devfreq_dev_profile includes freq_table array to store
      the supported frequencies. If devfreq driver doesn't initialize
      the freq_table, devfreq core allocates the memory and initializes
      the freq_table.

      On a devfreq PROBE_DEFER, the freq_table in the driver profile
      struct is never reset and may be left in an undefined state. To fix
      this and correctly handle PROBE_DEFER, use a local freq_table and
      max_state in the devfreq struct."

* tag 'devfreq-fixes-for-5.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux:
  PM / devfreq: passive: revert an editing accident in SPDX-License line
  PM / devfreq: Fix kernel warning with cpufreq passive register fail
  PM / devfreq: Rework freq_table to be local to devfreq struct
  PM / devfreq: exynos-ppmu: Fix refcount leak in of_get_devfreq_events
  PM / devfreq: passive: Use HZ_PER_KHZ macro in units.h
  PM / devfreq: Fix cpufreq passive unregister erroring on PROBE_DEFER
  PM / devfreq: Mute warning on governor PROBE_DEFER
  PM / devfreq: Fix kernel panic with cpu based scaling to passive gov
parents 03c765b0 f08fe6fc
Loading
Loading
Loading
Loading
+37 −39
Original line number Original line Diff line number Diff line
@@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
			    unsigned long *min_freq,
			    unsigned long *min_freq,
			    unsigned long *max_freq)
			    unsigned long *max_freq)
{
{
	unsigned long *freq_table = devfreq->profile->freq_table;
	unsigned long *freq_table = devfreq->freq_table;
	s32 qos_min_freq, qos_max_freq;
	s32 qos_min_freq, qos_max_freq;


	lockdep_assert_held(&devfreq->lock);
	lockdep_assert_held(&devfreq->lock);
@@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
	 * The devfreq drivers can initialize this in either ascending or
	 * The devfreq drivers can initialize this in either ascending or
	 * descending order and devfreq core supports both.
	 * descending order and devfreq core supports both.
	 */
	 */
	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
	if (freq_table[0] < freq_table[devfreq->max_state - 1]) {
		*min_freq = freq_table[0];
		*min_freq = freq_table[0];
		*max_freq = freq_table[devfreq->profile->max_state - 1];
		*max_freq = freq_table[devfreq->max_state - 1];
	} else {
	} else {
		*min_freq = freq_table[devfreq->profile->max_state - 1];
		*min_freq = freq_table[devfreq->max_state - 1];
		*max_freq = freq_table[0];
		*max_freq = freq_table[0];
	}
	}


@@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
{
{
	int lev;
	int lev;


	for (lev = 0; lev < devfreq->profile->max_state; lev++)
	for (lev = 0; lev < devfreq->max_state; lev++)
		if (freq == devfreq->profile->freq_table[lev])
		if (freq == devfreq->freq_table[lev])
			return lev;
			return lev;


	return -EINVAL;
	return -EINVAL;
@@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)


static int set_freq_table(struct devfreq *devfreq)
static int set_freq_table(struct devfreq *devfreq)
{
{
	struct devfreq_dev_profile *profile = devfreq->profile;
	struct dev_pm_opp *opp;
	struct dev_pm_opp *opp;
	unsigned long freq;
	unsigned long freq;
	int i, count;
	int i, count;
@@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq *devfreq)
	if (count <= 0)
	if (count <= 0)
		return -EINVAL;
		return -EINVAL;


	profile->max_state = count;
	devfreq->max_state = count;
	profile->freq_table = devm_kcalloc(devfreq->dev.parent,
	devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
					profile->max_state,
					   devfreq->max_state,
					sizeof(*profile->freq_table),
					   sizeof(*devfreq->freq_table),
					   GFP_KERNEL);
					   GFP_KERNEL);
	if (!profile->freq_table) {
	if (!devfreq->freq_table)
		profile->max_state = 0;
		return -ENOMEM;
		return -ENOMEM;
	}


	for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
	for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
		opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
		opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
		if (IS_ERR(opp)) {
		if (IS_ERR(opp)) {
			devm_kfree(devfreq->dev.parent, profile->freq_table);
			devm_kfree(devfreq->dev.parent, devfreq->freq_table);
			profile->max_state = 0;
			return PTR_ERR(opp);
			return PTR_ERR(opp);
		}
		}
		dev_pm_opp_put(opp);
		dev_pm_opp_put(opp);
		profile->freq_table[i] = freq;
		devfreq->freq_table[i] = freq;
	}
	}


	return 0;
	return 0;
@@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)


	if (lev != prev_lev) {
	if (lev != prev_lev) {
		devfreq->stats.trans_table[
		devfreq->stats.trans_table[
			(prev_lev * devfreq->profile->max_state) + lev]++;
			(prev_lev * devfreq->max_state) + lev]++;
		devfreq->stats.total_trans++;
		devfreq->stats.total_trans++;
	}
	}


@@ -835,6 +831,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
		if (err < 0)
		if (err < 0)
			goto err_dev;
			goto err_dev;
		mutex_lock(&devfreq->lock);
		mutex_lock(&devfreq->lock);
	} else {
		devfreq->freq_table = devfreq->profile->freq_table;
		devfreq->max_state = devfreq->profile->max_state;
	}
	}


	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
@@ -870,8 +869,8 @@ struct devfreq *devfreq_add_device(struct device *dev,


	devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
	devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
			array3_size(sizeof(unsigned int),
			array3_size(sizeof(unsigned int),
				    devfreq->profile->max_state,
				    devfreq->max_state,
				    devfreq->profile->max_state),
				    devfreq->max_state),
			GFP_KERNEL);
			GFP_KERNEL);
	if (!devfreq->stats.trans_table) {
	if (!devfreq->stats.trans_table) {
		mutex_unlock(&devfreq->lock);
		mutex_unlock(&devfreq->lock);
@@ -880,7 +879,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
	}
	}


	devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
	devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
			devfreq->profile->max_state,
			devfreq->max_state,
			sizeof(*devfreq->stats.time_in_state),
			sizeof(*devfreq->stats.time_in_state),
			GFP_KERNEL);
			GFP_KERNEL);
	if (!devfreq->stats.time_in_state) {
	if (!devfreq->stats.time_in_state) {
@@ -932,7 +931,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
	err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
	err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
						NULL);
						NULL);
	if (err) {
	if (err) {
		dev_err(dev, "%s: Unable to start governor for the device\n",
		dev_err_probe(dev, err,
			"%s: Unable to start governor for the device\n",
			 __func__);
			 __func__);
		goto err_init;
		goto err_init;
	}
	}
@@ -1665,9 +1665,9 @@ static ssize_t available_frequencies_show(struct device *d,


	mutex_lock(&df->lock);
	mutex_lock(&df->lock);


	for (i = 0; i < df->profile->max_state; i++)
	for (i = 0; i < df->max_state; i++)
		count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
		count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
				"%lu ", df->profile->freq_table[i]);
				"%lu ", df->freq_table[i]);


	mutex_unlock(&df->lock);
	mutex_unlock(&df->lock);
	/* Truncate the trailing space */
	/* Truncate the trailing space */
@@ -1690,7 +1690,7 @@ static ssize_t trans_stat_show(struct device *dev,


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


	if (max_state == 0)
	if (max_state == 0)
		return sprintf(buf, "Not Supported.\n");
		return sprintf(buf, "Not Supported.\n");
@@ -1707,19 +1707,17 @@ static ssize_t trans_stat_show(struct device *dev,
	len += sprintf(buf + len, "           :");
	len += sprintf(buf + len, "           :");
	for (i = 0; i < max_state; i++)
	for (i = 0; i < max_state; i++)
		len += sprintf(buf + len, "%10lu",
		len += sprintf(buf + len, "%10lu",
				df->profile->freq_table[i]);
				df->freq_table[i]);


	len += sprintf(buf + len, "   time(ms)\n");
	len += sprintf(buf + len, "   time(ms)\n");


	for (i = 0; i < max_state; i++) {
	for (i = 0; i < max_state; i++) {
		if (df->profile->freq_table[i]
		if (df->freq_table[i] == df->previous_freq)
					== df->previous_freq) {
			len += sprintf(buf + len, "*");
			len += sprintf(buf + len, "*");
		} else {
		else
			len += sprintf(buf + len, " ");
			len += sprintf(buf + len, " ");
		}

		len += sprintf(buf + len, "%10lu:",
		len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
				df->profile->freq_table[i]);
		for (j = 0; j < max_state; j++)
		for (j = 0; j < max_state; j++)
			len += sprintf(buf + len, "%10u",
			len += sprintf(buf + len, "%10u",
				df->stats.trans_table[(i * max_state) + j]);
				df->stats.trans_table[(i * max_state) + j]);
@@ -1743,7 +1741,7 @@ static ssize_t trans_stat_store(struct device *dev,
	if (!df->profile)
	if (!df->profile)
		return -EINVAL;
		return -EINVAL;


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


	err = kstrtoint(buf, 10, &value);
	err = kstrtoint(buf, 10, &value);
@@ -1751,11 +1749,11 @@ static ssize_t trans_stat_store(struct device *dev,
		return -EINVAL;
		return -EINVAL;


	mutex_lock(&df->lock);
	mutex_lock(&df->lock);
	memset(df->stats.time_in_state, 0, (df->profile->max_state *
	memset(df->stats.time_in_state, 0, (df->max_state *
					sizeof(*df->stats.time_in_state)));
					sizeof(*df->stats.time_in_state)));
	memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
	memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
					df->profile->max_state,
					df->max_state,
					df->profile->max_state));
					df->max_state));
	df->stats.total_trans = 0;
	df->stats.total_trans = 0;
	df->stats.last_update = get_jiffies_64();
	df->stats.last_update = get_jiffies_64();
	mutex_unlock(&df->lock);
	mutex_unlock(&df->lock);
+6 −2
Original line number Original line Diff line number Diff line
@@ -519,15 +519,19 @@ static int of_get_devfreq_events(struct device_node *np,


	count = of_get_child_count(events_np);
	count = of_get_child_count(events_np);
	desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
	desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
	if (!desc)
	if (!desc) {
		of_node_put(events_np);
		return -ENOMEM;
		return -ENOMEM;
	}
	info->num_events = count;
	info->num_events = count;


	of_id = of_match_device(exynos_ppmu_id_match, dev);
	of_id = of_match_device(exynos_ppmu_id_match, dev);
	if (of_id)
	if (of_id)
		info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
		info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
	else
	else {
		of_node_put(events_np);
		return -EINVAL;
		return -EINVAL;
	}


	j = 0;
	j = 0;
	for_each_child_of_node(events_np, node) {
	for_each_child_of_node(events_np, node) {
+27 −35
Original line number Original line Diff line number Diff line
@@ -14,10 +14,9 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/devfreq.h>
#include <linux/devfreq.h>
#include <linux/units.h>
#include "governor.h"
#include "governor.h"


#define HZ_PER_KHZ	1000

static struct devfreq_cpu_data *
static struct devfreq_cpu_data *
get_parent_cpu_data(struct devfreq_passive_data *p_data,
get_parent_cpu_data(struct devfreq_passive_data *p_data,
		    struct cpufreq_policy *policy)
		    struct cpufreq_policy *policy)
@@ -34,6 +33,20 @@ get_parent_cpu_data(struct devfreq_passive_data *p_data,
	return NULL;
	return NULL;
}
}


static void delete_parent_cpu_data(struct devfreq_passive_data *p_data)
{
	struct devfreq_cpu_data *parent_cpu_data, *tmp;

	list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) {
		list_del(&parent_cpu_data->node);

		if (parent_cpu_data->opp_table)
			dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);

		kfree(parent_cpu_data);
	}
}

static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
						struct opp_table *p_opp_table,
						struct opp_table *p_opp_table,
						struct opp_table *opp_table,
						struct opp_table *opp_table,
@@ -131,18 +144,18 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
		goto out;
		goto out;


	/* Use interpolation if required opps is not available */
	/* Use interpolation if required opps is not available */
	for (i = 0; i < parent_devfreq->profile->max_state; i++)
	for (i = 0; i < parent_devfreq->max_state; i++)
		if (parent_devfreq->profile->freq_table[i] == *freq)
		if (parent_devfreq->freq_table[i] == *freq)
			break;
			break;


	if (i == parent_devfreq->profile->max_state)
	if (i == parent_devfreq->max_state)
		return -EINVAL;
		return -EINVAL;


	if (i < devfreq->profile->max_state) {
	if (i < devfreq->max_state) {
		child_freq = devfreq->profile->freq_table[i];
		child_freq = devfreq->freq_table[i];
	} else {
	} else {
		count = devfreq->profile->max_state;
		count = devfreq->max_state;
		child_freq = devfreq->profile->freq_table[count - 1];
		child_freq = devfreq->freq_table[count - 1];
	}
	}


out:
out:
@@ -222,8 +235,7 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
{
{
	struct devfreq_passive_data *p_data
	struct devfreq_passive_data *p_data
			= (struct devfreq_passive_data *)devfreq->data;
			= (struct devfreq_passive_data *)devfreq->data;
	struct devfreq_cpu_data *parent_cpu_data;
	int ret;
	int cpu, ret = 0;


	if (p_data->nb.notifier_call) {
	if (p_data->nb.notifier_call) {
		ret = cpufreq_unregister_notifier(&p_data->nb,
		ret = cpufreq_unregister_notifier(&p_data->nb,
@@ -232,27 +244,9 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
			return ret;
			return ret;
	}
	}


	for_each_possible_cpu(cpu) {
	delete_parent_cpu_data(p_data);
		struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
		if (!policy) {
			ret = -EINVAL;
			continue;
		}


		parent_cpu_data = get_parent_cpu_data(p_data, policy);
	return 0;
		if (!parent_cpu_data) {
			cpufreq_cpu_put(policy);
			continue;
		}

		list_del(&parent_cpu_data->node);
		if (parent_cpu_data->opp_table)
			dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
		kfree(parent_cpu_data);
		cpufreq_cpu_put(policy);
	}

	return ret;
}
}


static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
@@ -336,7 +330,6 @@ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
err_put_policy:
err_put_policy:
	cpufreq_cpu_put(policy);
	cpufreq_cpu_put(policy);
err:
err:
	WARN_ON(cpufreq_passive_unregister_notifier(devfreq));


	return ret;
	return ret;
}
}
@@ -407,7 +400,6 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
	if (!p_data)
	if (!p_data)
		return -EINVAL;
		return -EINVAL;


	if (!p_data->this)
	p_data->this = devfreq;
	p_data->this = devfreq;


	switch (event) {
	switch (event) {
+5 −0
Original line number Original line Diff line number Diff line
@@ -148,6 +148,8 @@ struct devfreq_stats {
 *		reevaluate operable frequencies. Devfreq users may use
 *		reevaluate operable frequencies. Devfreq users may use
 *		devfreq.nb to the corresponding register notifier call chain.
 *		devfreq.nb to the corresponding register notifier call chain.
 * @work:	delayed work for load monitoring.
 * @work:	delayed work for load monitoring.
 * @freq_table:		current frequency table used by the devfreq driver.
 * @max_state:		count of entry present in the frequency table.
 * @previous_freq:	previously configured frequency value.
 * @previous_freq:	previously configured frequency value.
 * @last_status:	devfreq user device info, performance statistics
 * @last_status:	devfreq user device info, performance statistics
 * @data:	Private data of the governor. The devfreq framework does not
 * @data:	Private data of the governor. The devfreq framework does not
@@ -185,6 +187,9 @@ struct devfreq {
	struct notifier_block nb;
	struct notifier_block nb;
	struct delayed_work work;
	struct delayed_work work;


	unsigned long *freq_table;
	unsigned int max_state;

	unsigned long previous_freq;
	unsigned long previous_freq;
	struct devfreq_dev_status last_status;
	struct devfreq_dev_status last_status;