/* * ACTMON_AVERAGE_WINDOW_LOG2: default value for @DEV_CTRL_K_VAL, which * translates to 2 ^ (K_VAL + 1). ex: 2 ^ (6 + 1) = 128
*/ #define ACTMON_AVERAGE_WINDOW_LOG2 6 #define ACTMON_SAMPLING_PERIOD 12 /* ms */ #define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */
#define KHZ 1000
#define KHZ_MAX (ULONG_MAX / KHZ)
/* Assume that the bus is saturated if the utilization is 25% */ #define BUS_SATURATION_RATIO 25
/** * struct tegra_devfreq_device_config - configuration specific to an ACTMON * device * * Coefficients and thresholds are percentages unless otherwise noted
*/ struct tegra_devfreq_device_config {
u32 offset;
u32 irq_mask;
/* Factors applied to boost_freq every consecutive watermark breach */ unsignedint boost_up_coeff; unsignedint boost_down_coeff;
/* Define the watermark bounds when applied to the current avg */ unsignedint boost_up_threshold; unsignedint boost_down_threshold;
/* * 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;
};
/** * struct tegra_devfreq_device - state specific to an ACTMON device * * Frequencies are in kHz.
*/ struct tegra_devfreq_device { conststruct tegra_devfreq_device_config *config; void __iomem *regs;
/* Average event count sampled in the last interrupt */
u32 avg_count;
/* * Extra frequency to increase the target by due to consecutive * watermark breaches.
*/ unsignedlong boost_freq;
/* Optimal frequency calculated from the stats for this device */ unsignedlong target_freq;
};
struct tegra_devfreq_soc_data { conststruct tegra_devfreq_device_config *configs; /* Weight value for count measurements */ unsignedint count_weight;
};
staticunsignedlong do_percent(unsignedlonglong val, unsignedint pct)
{
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);
}
/* * Quickly check whether CPU frequency should be taken into account * at all, without blocking CPUFreq's core.
*/ if (mutex_trylock(&tegra->devfreq->lock)) {
old = tegra_actmon_cpufreq_contribution(tegra, freqs->old); new = tegra_actmon_cpufreq_contribution(tegra, freqs->new);
mutex_unlock(&tegra->devfreq->lock);
/* * If CPU's frequency shouldn't be taken into account at * the moment, then there is no need to update the devfreq's * state because ISR will re-check CPU's frequency on the * next interrupt.
*/ if (old == new) return NOTIFY_OK;
}
/* * CPUFreq driver should support CPUFREQ_ASYNC_NOTIFICATION in order * to allow asynchronous notifications. This means we can't block * here for too long, otherwise CPUFreq's core will complain with a * warning splat.
*/
delay = msecs_to_jiffies(ACTMON_SAMPLING_PERIOD);
schedule_delayed_work(&tegra->cpufreq_update_work, delay);
val |= ACTMON_DEV_CTRL_ENB_PERIODIC;
val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1)
<< ACTMON_DEV_CTRL_K_VAL_SHIFT;
val |= (ACTMON_BELOW_WMARK_WINDOW - 1)
<< ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT;
val |= (ACTMON_ABOVE_WMARK_WINDOW - 1)
<< ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT;
val |= ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN;
val |= ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN;
val |= ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
val |= ACTMON_DEV_CTRL_ENB;
/* * CLK notifications are needed in order to reconfigure the upper * consecutive watermark in accordance to the actual clock rate * to avoid unnecessary upper interrupts.
*/
err = clk_notifier_register(tegra->emc_clock,
&tegra->clk_rate_change_nb); if (err) {
dev_err(tegra->devfreq->dev.parent, "Failed to register rate change notifier\n"); return err;
}
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++)
tegra_actmon_configure_device(tegra, &tegra->devices[i]);
/* * We are estimating CPU's memory bandwidth requirement based on * amount of memory accesses and system's load, judging by CPU's * frequency. We also don't want to receive events about CPU's * frequency transaction when governor is stopped, hence notifier * is registered dynamically.
*/
err = cpufreq_register_notifier(&tegra->cpu_rate_change_nb,
CPUFREQ_TRANSITION_NOTIFIER); if (err) {
dev_err(tegra->devfreq->dev.parent, "Failed to register rate change notifier: %d\n", err); goto err_stop;
}
/* * tegra-devfreq driver operates with KHz units, while OPP table * entries use Hz units. Hence we need to convert the units for the * devfreq core.
*/
*freq = target_freq * KHZ;
/* * Couple devfreq-device with the governor early because it is * needed at the moment of governor's start (used by ISR).
*/
tegra->devfreq = devfreq;
switch (event) { case DEVFREQ_GOV_START:
devfreq_monitor_start(devfreq);
ret = tegra_actmon_start(tegra); break;
case DEVFREQ_GOV_STOP:
tegra_actmon_stop(tegra);
devfreq_monitor_stop(devfreq); break;
case DEVFREQ_GOV_UPDATE_INTERVAL: /* * ACTMON hardware supports up to 256 milliseconds for the * sampling period.
*/ if (*new_delay > 256) {
ret = -EINVAL; break;
}
tegra_actmon_pause(tegra);
devfreq_update_interval(devfreq, new_delay);
ret = tegra_actmon_resume(tegra); break;
case DEVFREQ_GOV_SUSPEND:
tegra_actmon_stop(tegra);
devfreq_monitor_suspend(devfreq); break;
case DEVFREQ_GOV_RESUME:
devfreq_monitor_resume(devfreq);
ret = tegra_actmon_start(tegra); break;
}
tegra->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(tegra->regs)) return PTR_ERR(tegra->regs);
tegra->reset = devm_reset_control_get(&pdev->dev, "actmon"); if (IS_ERR(tegra->reset)) {
dev_err(&pdev->dev, "Failed to get reset\n"); return PTR_ERR(tegra->reset);
}
tegra->clock = devm_clk_get(&pdev->dev, "actmon"); if (IS_ERR(tegra->clock)) {
dev_err(&pdev->dev, "Failed to get actmon clock\n"); return PTR_ERR(tegra->clock);
}
tegra->emc_clock = devm_clk_get(&pdev->dev, "emc"); if (IS_ERR(tegra->emc_clock)) return dev_err_probe(&pdev->dev, PTR_ERR(tegra->emc_clock), "Failed to get emc clock\n");
err = platform_get_irq(pdev, 0); if (err < 0) return err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.