Skip to content

Commit f61ee20

Browse files
digetxchanwoochoi
authored andcommitted
PM / devfreq: tegra30: Support variable polling interval
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 <[email protected]> Reviewed-by: Chanwoo Choi <[email protected]> Signed-off-by: Chanwoo Choi <[email protected]>
1 parent 5c0f6c7 commit f61ee20

File tree

1 file changed

+66
-12
lines changed

1 file changed

+66
-12
lines changed

drivers/devfreq/tegra30-devfreq.c

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ struct tegra_devfreq {
171171
struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)];
172172

173173
unsigned int irq;
174+
175+
bool started;
174176
};
175177

176178
struct tegra_actmon_emc_ratio {
@@ -209,18 +211,26 @@ static void device_writel(struct tegra_devfreq_device *dev, u32 val,
209211
writel_relaxed(val, dev->regs + offset);
210212
}
211213

212-
static unsigned long do_percent(unsigned long val, unsigned int pct)
214+
static unsigned long do_percent(unsigned long long val, unsigned int pct)
213215
{
214-
return val * pct / 100;
216+
val = val * pct;
217+
do_div(val, 100);
218+
219+
/*
220+
* High freq + high boosting percent + large polling interval are
221+
* resulting in integer overflow when watermarks are calculated.
222+
*/
223+
return min_t(u64, val, U32_MAX);
215224
}
216225

217226
static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra,
218227
struct tegra_devfreq_device *dev)
219228
{
220-
u32 avg = dev->avg_count;
221229
u32 avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ;
222-
u32 band = avg_band_freq * ACTMON_SAMPLING_PERIOD;
230+
u32 band = avg_band_freq * tegra->devfreq->profile->polling_ms;
231+
u32 avg;
223232

233+
avg = min(dev->avg_count, U32_MAX - band);
224234
device_writel(dev, avg + band, ACTMON_DEV_AVG_UPPER_WMARK);
225235

226236
avg = max(dev->avg_count, band);
@@ -230,7 +240,7 @@ static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq *tegra,
230240
static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra,
231241
struct tegra_devfreq_device *dev)
232242
{
233-
u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
243+
u32 val = tegra->cur_freq * tegra->devfreq->profile->polling_ms;
234244

235245
device_writel(dev, do_percent(val, dev->config->boost_up_threshold),
236246
ACTMON_DEV_UPPER_WMARK);
@@ -309,7 +319,7 @@ static unsigned long actmon_device_target_freq(struct tegra_devfreq *tegra,
309319
unsigned int avg_sustain_coef;
310320
unsigned long target_freq;
311321

312-
target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD;
322+
target_freq = dev->avg_count / tegra->devfreq->profile->polling_ms;
313323
avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold;
314324
target_freq = do_percent(target_freq, avg_sustain_coef);
315325

@@ -469,7 +479,7 @@ static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
469479

470480
dev->target_freq = tegra->cur_freq;
471481

472-
dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
482+
dev->avg_count = tegra->cur_freq * tegra->devfreq->profile->polling_ms;
473483
device_writel(dev, dev->avg_count, ACTMON_DEV_INIT_AVG);
474484

475485
tegra_devfreq_update_avg_wmark(tegra, dev);
@@ -505,12 +515,15 @@ static void tegra_actmon_stop_devices(struct tegra_devfreq *tegra)
505515
}
506516
}
507517

508-
static int tegra_actmon_start(struct tegra_devfreq *tegra)
518+
static int tegra_actmon_resume(struct tegra_devfreq *tegra)
509519
{
510520
unsigned int i;
511521
int err;
512522

513-
actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1,
523+
if (!tegra->devfreq->profile->polling_ms || !tegra->started)
524+
return 0;
525+
526+
actmon_writel(tegra, tegra->devfreq->profile->polling_ms - 1,
514527
ACTMON_GLB_PERIOD_CTRL);
515528

516529
/*
@@ -558,8 +571,26 @@ static int tegra_actmon_start(struct tegra_devfreq *tegra)
558571
return err;
559572
}
560573

561-
static void tegra_actmon_stop(struct tegra_devfreq *tegra)
574+
static int tegra_actmon_start(struct tegra_devfreq *tegra)
562575
{
576+
int ret = 0;
577+
578+
if (!tegra->started) {
579+
tegra->started = true;
580+
581+
ret = tegra_actmon_resume(tegra);
582+
if (ret)
583+
tegra->started = false;
584+
}
585+
586+
return ret;
587+
}
588+
589+
static void tegra_actmon_pause(struct tegra_devfreq *tegra)
590+
{
591+
if (!tegra->devfreq->profile->polling_ms || !tegra->started)
592+
return;
593+
563594
disable_irq(tegra->irq);
564595

565596
cpufreq_unregister_notifier(&tegra->cpu_rate_change_nb,
@@ -572,6 +603,12 @@ static void tegra_actmon_stop(struct tegra_devfreq *tegra)
572603
clk_notifier_unregister(tegra->emc_clock, &tegra->clk_rate_change_nb);
573604
}
574605

606+
static void tegra_actmon_stop(struct tegra_devfreq *tegra)
607+
{
608+
tegra_actmon_pause(tegra);
609+
tegra->started = false;
610+
}
611+
575612
static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
576613
u32 flags)
577614
{
@@ -629,15 +666,15 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
629666
stat->busy_time *= 100 / BUS_SATURATION_RATIO;
630667

631668
/* Number of cycles in a sampling period */
632-
stat->total_time = ACTMON_SAMPLING_PERIOD * cur_freq;
669+
stat->total_time = tegra->devfreq->profile->polling_ms * cur_freq;
633670

634671
stat->busy_time = min(stat->busy_time, stat->total_time);
635672

636673
return 0;
637674
}
638675

639676
static struct devfreq_dev_profile tegra_devfreq_profile = {
640-
.polling_ms = 0,
677+
.polling_ms = ACTMON_SAMPLING_PERIOD,
641678
.target = tegra_devfreq_target,
642679
.get_dev_status = tegra_devfreq_get_dev_status,
643680
};
@@ -677,6 +714,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
677714
unsigned int event, void *data)
678715
{
679716
struct tegra_devfreq *tegra = dev_get_drvdata(devfreq->dev.parent);
717+
unsigned int *new_delay = data;
680718
int ret = 0;
681719

682720
/*
@@ -696,6 +734,21 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
696734
devfreq_monitor_stop(devfreq);
697735
break;
698736

737+
case DEVFREQ_GOV_INTERVAL:
738+
/*
739+
* ACTMON hardware supports up to 256 milliseconds for the
740+
* sampling period.
741+
*/
742+
if (*new_delay > 256) {
743+
ret = -EINVAL;
744+
break;
745+
}
746+
747+
tegra_actmon_pause(tegra);
748+
devfreq_interval_update(devfreq, new_delay);
749+
ret = tegra_actmon_resume(tegra);
750+
break;
751+
699752
case DEVFREQ_GOV_SUSPEND:
700753
tegra_actmon_stop(tegra);
701754
devfreq_monitor_suspend(devfreq);
@@ -715,6 +768,7 @@ static struct devfreq_governor tegra_devfreq_governor = {
715768
.get_target_freq = tegra_governor_get_target,
716769
.event_handler = tegra_governor_event_handler,
717770
.immutable = true,
771+
.interrupt_driven = true,
718772
};
719773

720774
static int tegra_devfreq_probe(struct platform_device *pdev)

0 commit comments

Comments
 (0)