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

Commit c33d4e8d authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "devfreq: memlat: Add suspend/resume for mem_latency"

parents 6b62baa3 cca4b8e8
Loading
Loading
Loading
Loading
+33 −14
Original line number Diff line number Diff line
@@ -9,11 +9,11 @@ Required properties:
- compatible:		Must be "qcom,devbw"
- qcom,src-dst-ports:	A list of tuples where each tuple consists of a bus
			master port number and a bus slave port number.
- qcom,bw-tbl:		A list of meaningful instantaneous bandwidth values
			(in MB/s) that can be requested from the device
			master port to the slave port. The list of values
			depend on the supported bus/slave frequencies and the
			bus width.
- operating-points-v2:	A phandle to the OPP v2 table that holds meaningful
			instantaneous bandwidth values (in MB/s) that can be
			requested from the device master port to the slave port.
			The list of values depend on the supported bus/slave
			frequencies and the bus width.

Optional properties:
- qcom,active-only:	Indicates that the bandwidth votes need to be
@@ -23,17 +23,36 @@ Optional properties:

Example:

	bw_opp_table: bw-opp-table {
		compatible = "operating-points-v2";
		opp-75  {
			opp-hz = /bits/ 64 <  572 >; /*  75 MHz */
		};
		opp-150 {
			opp-hz = /bits/ 64 < 1144 >; /* 150 MHz */
		};
		opp-200 {
			opp-hz = /bits/ 64 < 1525 >; /* 200 MHz */
		};
		opp-307 {
			opp-hz = /bits/ 64 < 2342 >; /* 307 MHz */
		};
		opp-460 {
			opp-hz = /bits/ 64 < 3509 >; /* 460 MHz */
		};
		opp-614 {
			opp-hz = /bits/ 64 < 4684 >; /* 614 MHz */
		};
		opp-800 {
			opp-hz = /bits/ 64 < 6103 >; /* 800 MHz */
		};
		opp-931 {
			opp-hz = /bits/ 64 < 7102 >; /* 931 MHz */
		};
	};
	qcom,cpubw {
		compatible = "qcom,devbw";
		qcom,src-dst-ports = <1 512>, <2 512>;
		qcom,active-only;
		qcom,bw-tbl =
			<  572 /*  75 MHz */ >,
			< 1144 /* 150 MHz */ >,
			< 1525 /* 200 MHz */ >,
			< 2342 /* 307 MHz */ >,
			< 3509 /* 460 MHz */ >,
			< 4684 /* 614 MHz */ >,
			< 6103 /* 800 MHz */ >,
			< 7102 /* 931 MHz */ >;
		operating-points-v2 = <&bw_opp_table>;
	};
+13 −1
Original line number Diff line number Diff line
@@ -542,6 +542,7 @@ static void devfreq_dev_release(struct device *dev)
		devfreq->profile->exit(devfreq->dev.parent);

	mutex_destroy(&devfreq->lock);
	mutex_destroy(&devfreq->sysfs_lock);
	kfree(devfreq);
}

@@ -584,6 +585,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
	}

	mutex_init(&devfreq->lock);
	mutex_init(&devfreq->sysfs_lock);
	mutex_lock(&devfreq->lock);
	devfreq->dev.parent = dev;
	devfreq->dev.class = devfreq_class;
@@ -1003,12 +1005,13 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
		goto out;
	}

	mutex_lock(&df->sysfs_lock);
	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;
			goto gov_stop_out;
		}
	}
	prev_gov = df->governor;
@@ -1026,6 +1029,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
						    NULL);
		}
	}

gov_stop_out:
	mutex_unlock(&df->sysfs_lock);
out:
	mutex_unlock(&devfreq_list_lock);

@@ -1120,8 +1126,10 @@ static ssize_t polling_interval_store(struct device *dev,
	if (ret != 1)
		return -EINVAL;

	mutex_lock(&df->sysfs_lock);
	df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value);
	ret = count;
	mutex_unlock(&df->sysfs_lock);

	return ret;
}
@@ -1139,6 +1147,7 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
	if (ret != 1)
		return -EINVAL;

	mutex_lock(&df->sysfs_lock);
	mutex_lock(&df->lock);
	max = df->max_freq;
	if (value && max && value > max) {
@@ -1151,6 +1160,7 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
	ret = count;
unlock:
	mutex_unlock(&df->lock);
	mutex_unlock(&df->sysfs_lock);
	return ret;
}

@@ -1174,6 +1184,7 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
	if (ret != 1)
		return -EINVAL;

	mutex_lock(&df->sysfs_lock);
	mutex_lock(&df->lock);
	min = df->min_freq;
	if (value && min && value < min) {
@@ -1186,6 +1197,7 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
	ret = count;
unlock:
	mutex_unlock(&df->lock);
	mutex_unlock(&df->sysfs_lock);
	return ret;
}
static DEVICE_ATTR_RW(min_freq);
+10 −47
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2013-2014, 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2014, 2018, 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) "devbw: " fmt
@@ -70,33 +70,15 @@ static int set_bw(struct device *dev, int new_ib, int new_ab)
	return ret;
}

static void find_freq(struct devfreq_dev_profile *p, unsigned long *freq,
			u32 flags)
{
	int i;
	unsigned long atmost, atleast, f;

	atmost = p->freq_table[0];
	atleast = p->freq_table[p->max_state-1];
	for (i = 0; i < p->max_state; i++) {
		f = p->freq_table[i];
		if (f <= *freq)
			atmost = max(f, atmost);
		if (f >= *freq)
			atleast = min(f, atleast);
	}

	if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND)
		*freq = atmost;
	else
		*freq = atleast;
}

static int devbw_target(struct device *dev, unsigned long *freq, u32 flags)
{
	struct dev_data *d = dev_get_drvdata(dev);
	struct dev_pm_opp *opp;

	opp = devfreq_recommended_opp(dev, freq, flags);
	if (!IS_ERR(opp))
		dev_pm_opp_put(opp);

	find_freq(&d->dp, freq, flags);
	return set_bw(dev, *freq, d->gov_ab);
}

@@ -110,14 +92,13 @@ static int devbw_get_dev_status(struct device *dev,
}

#define PROP_PORTS "qcom,src-dst-ports"
#define PROP_TBL "qcom,bw-tbl"
#define PROP_ACTIVE "qcom,active-only"

int devfreq_add_devbw(struct device *dev)
{
	struct dev_data *d;
	struct devfreq_dev_profile *p;
	u32 *data, ports[MAX_PATHS * 2];
	u32 ports[MAX_PATHS * 2];
	const char *gov_name;
	int ret, len, i, num_paths;

@@ -166,27 +147,9 @@ int devfreq_add_devbw(struct device *dev)
	p->target = devbw_target;
	p->get_dev_status = devbw_get_dev_status;

	if (of_find_property(dev->of_node, PROP_TBL, &len)) {
		len /= sizeof(*data);
		data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
		if (!data)
			return -ENOMEM;

		p->freq_table = devm_kzalloc(dev,
					     len * sizeof(*p->freq_table),
					     GFP_KERNEL);
		if (!p->freq_table)
			return -ENOMEM;

		ret = of_property_read_u32_array(dev->of_node, PROP_TBL,
						 data, len);
	ret = dev_pm_opp_of_add_table(dev);
	if (ret)
			return ret;

		for (i = 0; i < len; i++)
			p->freq_table[i] = data[i];
		p->max_state = len;
	}
		dev_err(dev, "Couldn't parse OPP table:%d\n", ret);

	d->bus_client = msm_bus_scale_register_client(&d->bw_data);
	if (!d->bus_client) {
+71 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2017, 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2018, 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) "mem_lat: " fmt
@@ -35,6 +35,7 @@ struct memlat_node {
	struct memlat_hwmon *hw;
	struct devfreq_governor *gov;
	struct attribute_group *attr_grp;
	unsigned long resume_freq;
};

static LIST_HEAD(memlat_list);
@@ -204,6 +205,39 @@ static int gov_start(struct devfreq *df)
	return ret;
}

static int gov_suspend(struct devfreq *df)
{
	struct memlat_node *node = df->data;
	unsigned long prev_freq = df->previous_freq;

	node->mon_started = false;
	devfreq_monitor_suspend(df);

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

	node->resume_freq = max(prev_freq, 1UL);

	return 0;
}

static int gov_resume(struct devfreq *df)
{
	struct memlat_node *node = df->data;

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

	node->resume_freq = 0;

	devfreq_monitor_resume(df);
	node->mon_started = true;

	return 0;
}

static void gov_stop(struct devfreq *df)
{
	struct memlat_node *node = df->data;
@@ -225,6 +259,18 @@ static int devfreq_memlat_get_freq(struct devfreq *df,
	unsigned long max_freq = 0;
	unsigned int ratio;

	/*
	 * node->resume_freq is set to 0 at the end of resume (after the update)
	 * and is set to df->prev_freq at the end of suspend (after the update).
	 * This function will be called as part of the update_devfreq call in
	 * both scenarios. As a result, this block will cause a 0 vote during
	 * suspend and a vote for df->prev_freq during resume.
	 */
	if (!node->mon_started) {
		*freq = node->resume_freq;
		return 0;
	}

	hw->get_cnt(hw);

	for (i = 0; i < hw->num_cores; i++) {
@@ -323,6 +369,30 @@ static int devfreq_memlat_ev_handler(struct devfreq *df,
			"Disabled Memory Latency governor\n");
		break;

	case DEVFREQ_GOV_SUSPEND:
		ret = gov_suspend(df);
		if (ret) {
			dev_err(df->dev.parent,
				"Unable to suspend memlat governor (%d)\n",
				ret);
			return ret;
		}

		dev_dbg(df->dev.parent, "Suspended memlat governor\n");
		break;

	case DEVFREQ_GOV_RESUME:
		ret = gov_resume(df);
		if (ret) {
			dev_err(df->dev.parent,
				"Unable to resume memlat governor (%d)\n",
				ret);
			return ret;
		}

		dev_dbg(df->dev.parent, "Resumed memlat governor\n");
		break;

	case DEVFREQ_GOV_INTERVAL:
		sample_ms = *(unsigned int *)data;
		sample_ms = max(MIN_MS, sample_ms);
+1 −0
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ struct devfreq {
	struct list_head node;

	struct mutex lock;
	struct mutex sysfs_lock;
	struct device dev;
	struct devfreq_dev_profile *profile;
	const struct devfreq_governor *governor;