From: Dmitry Osipenko <digetx@gmail.com>
To: "Thierry Reding" <thierry.reding@gmail.com>,
"MyungJoo Ham" <myungjoo.ham@samsung.com>,
"Kyungmin Park" <kyungmin.park@samsung.com>,
"Chanwoo Choi" <cw00.choi@samsung.com>,
"Jonathan Hunter" <jonathanh@nvidia.com>,
"Tomeu Vizoso" <tomeu.vizoso@collabora.com>,
"Peter Geis" <pgwipeout@gmail.com>,
"Michał Mirosław" <mirq-linux@rere.qmqm.pl>
Cc: linux-pm@vger.kernel.org, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v8 16/18] PM / devfreq: tegra30: Support variable polling interval
Date: Sun, 3 Nov 2019 23:41:28 +0300 [thread overview]
Message-ID: <20191103204130.2172-17-digetx@gmail.com> (raw)
In-Reply-To: <20191103204130.2172-1-digetx@gmail.com>
The ACTMON governor is interrupt-driven and currently hardware's polling
interval is fixed to 16ms in the driver. Devfreq supports variable polling
interval by the generic governors, let's re-use the generic interface for
changing of the polling interval. Now the polling interval can be changed
dynamically via /sys/class/devfreq/devfreq0/polling_interval.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
drivers/devfreq/tegra30-devfreq.c | 83 +++++++++++++++++++++++--------
1 file changed, 61 insertions(+), 22 deletions(-)
diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c
index 852bde6249c7..9c645e83ef8b 100644
--- a/drivers/devfreq/tegra30-devfreq.c
+++ b/drivers/devfreq/tegra30-devfreq.c
@@ -96,9 +96,10 @@ struct tegra_devfreq_device_config {
unsigned int boost_down_threshold;
/*
- * Threshold of activity (cycles) below which the CPU frequency isn't
- * to be taken into account. This is to avoid increasing the EMC
- * frequency when the CPU is very busy but not accessing the bus often.
+ * Threshold of activity (cycles translated to kHz) below which the
+ * CPU frequency isn't to be taken into account. This is to avoid
+ * increasing the EMC frequency when the CPU is very busy but not
+ * accessing the bus often.
*/
u32 avg_dependency_threshold;
};
@@ -126,7 +127,7 @@ static const struct tegra_devfreq_device_config actmon_device_configs[] = {
.boost_down_coeff = 90,
.boost_up_threshold = 27,
.boost_down_threshold = 10,
- .avg_dependency_threshold = 50000,
+ .avg_dependency_threshold = 5 * KHZ,
},
};
@@ -208,9 +209,16 @@ static void device_writel(struct tegra_devfreq_device *dev, u32 val,
writel_relaxed(val, dev->regs + offset);
}
-static unsigned long do_percent(unsigned long val, unsigned int pct)
+static unsigned long do_percent(unsigned long long val, unsigned int pct)
{
- return val * pct / 100;
+ val = val * pct;
+ do_div(val, 100);
+
+ /*
+ * High freq + high boosting percent + large polling interval are
+ * resulting in integer overflow when watermarks are calculated.
+ */
+ return min_t(u64, val, U32_MAX);
}
static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra,
@@ -218,8 +226,9 @@ static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra,
{
u32 avg = dev->avg_count;
u32 avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ;
- u32 band = avg_band_freq * ACTMON_SAMPLING_PERIOD;
+ u32 band = avg_band_freq * tegra->devfreq->profile->polling_ms;
+ avg = min(dev->avg_count, U32_MAX - band);
device_writel(dev, avg + band, ACTMON_DEV_AVG_UPPER_WMARK);
avg = max(dev->avg_count, band);
@@ -229,7 +238,7 @@ static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra,
static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra,
struct tegra_devfreq_device *dev)
{
- u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
+ u32 val = tegra->cur_freq * tegra->devfreq->profile->polling_ms;
device_writel(dev, do_percent(val, dev->config->boost_up_threshold),
ACTMON_DEV_UPPER_WMARK);
@@ -308,10 +317,9 @@ static unsigned long actmon_device_target_freq(struct tegra_devfreq *tegra,
unsigned int avg_sustain_coef;
unsigned long target_freq;
- target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD;
+ target_freq = dev->avg_count / tegra->devfreq->profile->polling_ms;
avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold;
target_freq = do_percent(target_freq, avg_sustain_coef);
- target_freq += dev->boost_freq;
return target_freq;
}
@@ -322,15 +330,18 @@ static void actmon_update_target(struct tegra_devfreq *tegra,
unsigned long cpu_freq = 0;
unsigned long static_cpu_emc_freq = 0;
- if (dev->config->avg_dependency_threshold) {
+ dev->target_freq = actmon_device_target_freq(tegra, dev);
+
+ if (dev->config->avg_dependency_threshold &&
+ dev->config->avg_dependency_threshold <= dev->target_freq) {
cpu_freq = cpufreq_quick_get(0);
static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq);
- }
- dev->target_freq = actmon_device_target_freq(tegra, dev);
-
- if (dev->avg_count >= dev->config->avg_dependency_threshold)
+ dev->target_freq += dev->boost_freq;
dev->target_freq = max(dev->target_freq, static_cpu_emc_freq);
+ } else {
+ dev->target_freq += dev->boost_freq;
+ }
}
static irqreturn_t actmon_thread_isr(int irq, void *data)
@@ -396,15 +407,16 @@ static unsigned long
tegra_actmon_cpufreq_contribution(struct tegra_devfreq *tegra,
unsigned int cpu_freq)
{
+ struct tegra_devfreq_device *dev = &tegra->devices[MCCPU];
unsigned long static_cpu_emc_freq, dev_freq;
+ dev_freq = actmon_device_target_freq(tegra, dev);
+
/* check whether CPU's freq is taken into account at all */
- if (tegra->devices[MCCPU].avg_count <
- tegra->devices[MCCPU].config->avg_dependency_threshold)
+ if (dev_freq < dev->config->avg_dependency_threshold)
return 0;
static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq);
- dev_freq = actmon_device_target_freq(tegra, &tegra->devices[MCCPU]);
if (dev_freq >= static_cpu_emc_freq)
return 0;
@@ -465,7 +477,7 @@ static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
dev->target_freq = tegra->cur_freq;
- dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
+ dev->avg_count = tegra->cur_freq * tegra->devfreq->profile->polling_ms;
device_writel(dev, dev->avg_count, ACTMON_DEV_INIT_AVG);
tegra_devfreq_update_avg_wmark(tegra, dev);
@@ -506,7 +518,10 @@ static int tegra_actmon_start(struct tegra_devfreq *tegra)
unsigned int i;
int err;
- actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1,
+ if (!tegra->devfreq->profile->polling_ms || tegra->cur_freq)
+ return 0;
+
+ actmon_writel(tegra, tegra->devfreq->profile->polling_ms - 1,
ACTMON_GLB_PERIOD_CTRL);
/*
@@ -551,11 +566,16 @@ static int tegra_actmon_start(struct tegra_devfreq *tegra)
clk_notifier_unregister(tegra->emc_clock, &tegra->clk_rate_change_nb);
+ tegra->cur_freq = 0;
+
return err;
}
static void tegra_actmon_stop(struct tegra_devfreq *tegra)
{
+ if (!tegra->devfreq->profile->polling_ms || !tegra->cur_freq)
+ return;
+
disable_irq(tegra->irq);
cpufreq_unregister_notifier(&tegra->cpu_rate_change_nb,
@@ -566,6 +586,8 @@ static void tegra_actmon_stop(struct tegra_devfreq *tegra)
tegra_actmon_stop_devices(tegra);
clk_notifier_unregister(tegra->emc_clock, &tegra->clk_rate_change_nb);
+
+ tegra->cur_freq = 0;
}
static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
@@ -625,7 +647,7 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
stat->busy_time *= 100 / BUS_SATURATION_RATIO;
/* Number of cycles in a sampling period */
- stat->total_time = ACTMON_SAMPLING_PERIOD * cur_freq;
+ stat->total_time = tegra->devfreq->profile->polling_ms * cur_freq;
stat->busy_time = min(stat->busy_time, stat->total_time);
@@ -633,7 +655,7 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
}
static struct devfreq_dev_profile tegra_devfreq_profile = {
- .polling_ms = 0,
+ .polling_ms = ACTMON_SAMPLING_PERIOD,
.target = tegra_devfreq_target,
.get_dev_status = tegra_devfreq_get_dev_status,
};
@@ -673,6 +695,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
unsigned int event, void *data)
{
struct tegra_devfreq *tegra = dev_get_drvdata(devfreq->dev.parent);
+ unsigned int *new_delay = data;
int ret = 0;
/*
@@ -692,6 +715,21 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
devfreq_monitor_stop(devfreq);
break;
+ case DEVFREQ_GOV_INTERVAL:
+ /*
+ * ACTMON hardware supports up to 256 milliseconds for the
+ * sampling period.
+ */
+ if (*new_delay > 256) {
+ ret = -EINVAL;
+ break;
+ }
+
+ tegra_actmon_stop(tegra);
+ devfreq_interval_update(devfreq, new_delay);
+ ret = tegra_actmon_start(tegra);
+ break;
+
case DEVFREQ_GOV_SUSPEND:
tegra_actmon_stop(tegra);
devfreq_monitor_suspend(devfreq);
@@ -711,6 +749,7 @@ static struct devfreq_governor tegra_devfreq_governor = {
.get_target_freq = tegra_governor_get_target,
.event_handler = tegra_governor_event_handler,
.immutable = true,
+ .interrupt_driven = true,
};
static int tegra_devfreq_probe(struct platform_device *pdev)
--
2.23.0
next prev parent reply other threads:[~2019-11-03 20:42 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-03 20:41 [PATCH v8 00/18] More improvements for Tegra30 devfreq driver Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 01/18] PM / devfreq: tegra30: Change irq type to unsigned int Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 02/18] PM / devfreq: tegra30: Keep interrupt disabled while governor is stopped Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 03/18] PM / devfreq: tegra30: Handle possible round-rate error Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 04/18] PM / devfreq: tegra30: Drop write-barrier Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 05/18] PM / devfreq: tegra30: Fix integer overflow on CPU's freq max out Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 06/18] PM / devfreq: tegra30: Use kHz units uniformly in the code Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 07/18] PM / devfreq: tegra30: Use CPUFreq notifier Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 08/18] PM / devfreq: tegra30: Move clk-notifier's registration to governor's start Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 09/18] PM / devfreq: tegra30: Reset boosting on startup Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 10/18] PM / devfreq: tegra30: Don't enable consecutive-down interrupt " Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 11/18] PM / devfreq: tegra30: Constify structs Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 12/18] PM / devfreq: tegra30: Include appropriate header Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 13/18] PM / devfreq: tegra30: Don't enable already enabled consecutive interrupts Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 14/18] PM / devfreq: tegra30: Disable consecutive interrupts when appropriate Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 15/18] PM / devfreq: Add new interrupt_driven flag for governors Dmitry Osipenko
2019-11-04 2:48 ` Chanwoo Choi
2019-11-04 14:15 ` Dmitry Osipenko
2019-11-03 20:41 ` Dmitry Osipenko [this message]
2019-11-04 2:53 ` [PATCH v8 16/18] PM / devfreq: tegra30: Support variable polling interval Chanwoo Choi
2019-11-04 14:36 ` Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 17/18] PM / devfreq: tegra30: Tune up MCCPU boost-down coefficient Dmitry Osipenko
2019-11-03 20:41 ` [PATCH v8 18/18] PM / devfreq: tegra20/30: Add Dmitry as a maintainer Dmitry Osipenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191103204130.2172-17-digetx@gmail.com \
--to=digetx@gmail.com \
--cc=cw00.choi@samsung.com \
--cc=jonathanh@nvidia.com \
--cc=kyungmin.park@samsung.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=mirq-linux@rere.qmqm.pl \
--cc=myungjoo.ham@samsung.com \
--cc=pgwipeout@gmail.com \
--cc=thierry.reding@gmail.com \
--cc=tomeu.vizoso@collabora.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).