Skip to content

Commit 11eb6ec

Browse files
digetxchanwoochoi
authored andcommitted
PM / devfreq: tegra30: Use CPUFreq notifier
The CPU's client need to take into account that CPUFreq may change while memory activity not, staying high. Thus an appropriate frequency notifier should be used in addition to the clk-notifier. Reviewed-by: Chanwoo Choi <[email protected]> Tested-by: Peter Geis <[email protected]> Signed-off-by: Dmitry Osipenko <[email protected]> Signed-off-by: Chanwoo Choi <[email protected]>
1 parent 0ce3884 commit 11eb6ec

File tree

1 file changed

+155
-25
lines changed

1 file changed

+155
-25
lines changed

drivers/devfreq/tegra30-devfreq.c

Lines changed: 155 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/platform_device.h>
1818
#include <linux/pm_opp.h>
1919
#include <linux/reset.h>
20+
#include <linux/workqueue.h>
2021

2122
#include "governor.h"
2223

@@ -34,6 +35,8 @@
3435
#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN BIT(30)
3536
#define ACTMON_DEV_CTRL_ENB BIT(31)
3637

38+
#define ACTMON_DEV_CTRL_STOP 0x00000000
39+
3740
#define ACTMON_DEV_UPPER_WMARK 0x4
3841
#define ACTMON_DEV_LOWER_WMARK 0x8
3942
#define ACTMON_DEV_INIT_AVG 0xc
@@ -159,7 +162,10 @@ struct tegra_devfreq {
159162
struct clk *emc_clock;
160163
unsigned long max_freq;
161164
unsigned long cur_freq;
162-
struct notifier_block rate_change_nb;
165+
struct notifier_block clk_rate_change_nb;
166+
167+
struct delayed_work cpufreq_update_work;
168+
struct notifier_block cpu_rate_change_nb;
163169

164170
struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)];
165171

@@ -303,22 +309,32 @@ static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra,
303309
return 0;
304310
}
305311

312+
static unsigned long actmon_device_target_freq(struct tegra_devfreq *tegra,
313+
struct tegra_devfreq_device *dev)
314+
{
315+
unsigned int avg_sustain_coef;
316+
unsigned long target_freq;
317+
318+
target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD;
319+
avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold;
320+
target_freq = do_percent(target_freq, avg_sustain_coef);
321+
target_freq += dev->boost_freq;
322+
323+
return target_freq;
324+
}
325+
306326
static void actmon_update_target(struct tegra_devfreq *tegra,
307327
struct tegra_devfreq_device *dev)
308328
{
309329
unsigned long cpu_freq = 0;
310330
unsigned long static_cpu_emc_freq = 0;
311-
unsigned int avg_sustain_coef;
312331

313332
if (dev->config->avg_dependency_threshold) {
314-
cpu_freq = cpufreq_get(0);
333+
cpu_freq = cpufreq_quick_get(0);
315334
static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq);
316335
}
317336

318-
dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD;
319-
avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold;
320-
dev->target_freq = do_percent(dev->target_freq, avg_sustain_coef);
321-
dev->target_freq += dev->boost_freq;
337+
dev->target_freq = actmon_device_target_freq(tegra, dev);
322338

323339
if (dev->avg_count >= dev->config->avg_dependency_threshold)
324340
dev->target_freq = max(dev->target_freq, static_cpu_emc_freq);
@@ -349,8 +365,8 @@ static irqreturn_t actmon_thread_isr(int irq, void *data)
349365
return handled ? IRQ_HANDLED : IRQ_NONE;
350366
}
351367

352-
static int tegra_actmon_rate_notify_cb(struct notifier_block *nb,
353-
unsigned long action, void *ptr)
368+
static int tegra_actmon_clk_notify_cb(struct notifier_block *nb,
369+
unsigned long action, void *ptr)
354370
{
355371
struct clk_notifier_data *data = ptr;
356372
struct tegra_devfreq *tegra;
@@ -360,7 +376,7 @@ static int tegra_actmon_rate_notify_cb(struct notifier_block *nb,
360376
if (action != POST_RATE_CHANGE)
361377
return NOTIFY_OK;
362378

363-
tegra = container_of(nb, struct tegra_devfreq, rate_change_nb);
379+
tegra = container_of(nb, struct tegra_devfreq, clk_rate_change_nb);
364380

365381
tegra->cur_freq = data->new_rate / KHZ;
366382

@@ -373,6 +389,79 @@ static int tegra_actmon_rate_notify_cb(struct notifier_block *nb,
373389
return NOTIFY_OK;
374390
}
375391

392+
static void tegra_actmon_delayed_update(struct work_struct *work)
393+
{
394+
struct tegra_devfreq *tegra = container_of(work, struct tegra_devfreq,
395+
cpufreq_update_work.work);
396+
397+
mutex_lock(&tegra->devfreq->lock);
398+
update_devfreq(tegra->devfreq);
399+
mutex_unlock(&tegra->devfreq->lock);
400+
}
401+
402+
static unsigned long
403+
tegra_actmon_cpufreq_contribution(struct tegra_devfreq *tegra,
404+
unsigned int cpu_freq)
405+
{
406+
unsigned long static_cpu_emc_freq, dev_freq;
407+
408+
/* check whether CPU's freq is taken into account at all */
409+
if (tegra->devices[MCCPU].avg_count <
410+
tegra->devices[MCCPU].config->avg_dependency_threshold)
411+
return 0;
412+
413+
static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq);
414+
dev_freq = actmon_device_target_freq(tegra, &tegra->devices[MCCPU]);
415+
416+
if (dev_freq >= static_cpu_emc_freq)
417+
return 0;
418+
419+
return static_cpu_emc_freq;
420+
}
421+
422+
static int tegra_actmon_cpu_notify_cb(struct notifier_block *nb,
423+
unsigned long action, void *ptr)
424+
{
425+
struct cpufreq_freqs *freqs = ptr;
426+
struct tegra_devfreq *tegra;
427+
unsigned long old, new, delay;
428+
429+
if (action != CPUFREQ_POSTCHANGE)
430+
return NOTIFY_OK;
431+
432+
tegra = container_of(nb, struct tegra_devfreq, cpu_rate_change_nb);
433+
434+
/*
435+
* Quickly check whether CPU frequency should be taken into account
436+
* at all, without blocking CPUFreq's core.
437+
*/
438+
if (mutex_trylock(&tegra->devfreq->lock)) {
439+
old = tegra_actmon_cpufreq_contribution(tegra, freqs->old);
440+
new = tegra_actmon_cpufreq_contribution(tegra, freqs->new);
441+
mutex_unlock(&tegra->devfreq->lock);
442+
443+
/*
444+
* If CPU's frequency shouldn't be taken into account at
445+
* the moment, then there is no need to update the devfreq's
446+
* state because ISR will re-check CPU's frequency on the
447+
* next interrupt.
448+
*/
449+
if (old == new)
450+
return NOTIFY_OK;
451+
}
452+
453+
/*
454+
* CPUFreq driver should support CPUFREQ_ASYNC_NOTIFICATION in order
455+
* to allow asynchronous notifications. This means we can't block
456+
* here for too long, otherwise CPUFreq's core will complain with a
457+
* warning splat.
458+
*/
459+
delay = msecs_to_jiffies(ACTMON_SAMPLING_PERIOD);
460+
schedule_delayed_work(&tegra->cpufreq_update_work, delay);
461+
462+
return NOTIFY_OK;
463+
}
464+
376465
static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
377466
struct tegra_devfreq_device *dev)
378467
{
@@ -405,30 +494,64 @@ static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
405494
device_writel(dev, val, ACTMON_DEV_CTRL);
406495
}
407496

408-
static void tegra_actmon_start(struct tegra_devfreq *tegra)
497+
static void tegra_actmon_stop_devices(struct tegra_devfreq *tegra)
498+
{
499+
struct tegra_devfreq_device *dev = tegra->devices;
500+
unsigned int i;
501+
502+
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++, dev++) {
503+
device_writel(dev, ACTMON_DEV_CTRL_STOP, ACTMON_DEV_CTRL);
504+
device_writel(dev, ACTMON_INTR_STATUS_CLEAR,
505+
ACTMON_DEV_INTR_STATUS);
506+
}
507+
}
508+
509+
static int tegra_actmon_start(struct tegra_devfreq *tegra)
409510
{
410511
unsigned int i;
512+
int err;
411513

412514
actmon_writel(tegra, ACTMON_SAMPLING_PERIOD - 1,
413515
ACTMON_GLB_PERIOD_CTRL);
414516

415517
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++)
416518
tegra_actmon_configure_device(tegra, &tegra->devices[i]);
417519

520+
/*
521+
* We are estimating CPU's memory bandwidth requirement based on
522+
* amount of memory accesses and system's load, judging by CPU's
523+
* frequency. We also don't want to receive events about CPU's
524+
* frequency transaction when governor is stopped, hence notifier
525+
* is registered dynamically.
526+
*/
527+
err = cpufreq_register_notifier(&tegra->cpu_rate_change_nb,
528+
CPUFREQ_TRANSITION_NOTIFIER);
529+
if (err) {
530+
dev_err(tegra->devfreq->dev.parent,
531+
"Failed to register rate change notifier: %d\n", err);
532+
goto err_stop;
533+
}
534+
418535
enable_irq(tegra->irq);
536+
537+
return 0;
538+
539+
err_stop:
540+
tegra_actmon_stop_devices(tegra);
541+
542+
return err;
419543
}
420544

421545
static void tegra_actmon_stop(struct tegra_devfreq *tegra)
422546
{
423-
unsigned int i;
424-
425547
disable_irq(tegra->irq);
426548

427-
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
428-
device_writel(&tegra->devices[i], 0x00000000, ACTMON_DEV_CTRL);
429-
device_writel(&tegra->devices[i], ACTMON_INTR_STATUS_CLEAR,
430-
ACTMON_DEV_INTR_STATUS);
431-
}
549+
cpufreq_unregister_notifier(&tegra->cpu_rate_change_nb,
550+
CPUFREQ_TRANSITION_NOTIFIER);
551+
552+
cancel_delayed_work_sync(&tegra->cpufreq_update_work);
553+
554+
tegra_actmon_stop_devices(tegra);
432555
}
433556

434557
static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
@@ -536,6 +659,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
536659
unsigned int event, void *data)
537660
{
538661
struct tegra_devfreq *tegra = dev_get_drvdata(devfreq->dev.parent);
662+
int ret = 0;
539663

540664
/*
541665
* Couple devfreq-device with the governor early because it is
@@ -546,7 +670,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
546670
switch (event) {
547671
case DEVFREQ_GOV_START:
548672
devfreq_monitor_start(devfreq);
549-
tegra_actmon_start(tegra);
673+
ret = tegra_actmon_start(tegra);
550674
break;
551675

552676
case DEVFREQ_GOV_STOP:
@@ -561,11 +685,11 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
561685

562686
case DEVFREQ_GOV_RESUME:
563687
devfreq_monitor_resume(devfreq);
564-
tegra_actmon_start(tegra);
688+
ret = tegra_actmon_start(tegra);
565689
break;
566690
}
567691

568-
return 0;
692+
return ret;
569693
}
570694

571695
static struct devfreq_governor tegra_devfreq_governor = {
@@ -672,8 +796,14 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
672796

673797
platform_set_drvdata(pdev, tegra);
674798

675-
tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb;
676-
err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb);
799+
tegra->cpu_rate_change_nb.notifier_call = tegra_actmon_cpu_notify_cb;
800+
801+
INIT_DELAYED_WORK(&tegra->cpufreq_update_work,
802+
tegra_actmon_delayed_update);
803+
804+
tegra->clk_rate_change_nb.notifier_call = tegra_actmon_clk_notify_cb;
805+
err = clk_notifier_register(tegra->emc_clock,
806+
&tegra->clk_rate_change_nb);
677807
if (err) {
678808
dev_err(&pdev->dev,
679809
"Failed to register rate change notifier\n");
@@ -701,7 +831,7 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
701831
devfreq_remove_governor(&tegra_devfreq_governor);
702832

703833
unreg_notifier:
704-
clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb);
834+
clk_notifier_unregister(tegra->emc_clock, &tegra->clk_rate_change_nb);
705835

706836
remove_opps:
707837
dev_pm_opp_remove_all_dynamic(&pdev->dev);
@@ -719,7 +849,7 @@ static int tegra_devfreq_remove(struct platform_device *pdev)
719849
devfreq_remove_device(tegra->devfreq);
720850
devfreq_remove_governor(&tegra_devfreq_governor);
721851

722-
clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb);
852+
clk_notifier_unregister(tegra->emc_clock, &tegra->clk_rate_change_nb);
723853
dev_pm_opp_remove_all_dynamic(&pdev->dev);
724854

725855
reset_control_reset(tegra->reset);

0 commit comments

Comments
 (0)