/* * local_timer_ack: checks for a local timer interrupt. * * If a local timer interrupt has occurred, acknowledge and return 1. * Otherwise, return 0.
*/ staticint twd_timer_ack(void)
{ if (readl_relaxed(twd_base + TWD_TIMER_INTSTAT)) {
writel_relaxed(1, twd_base + TWD_TIMER_INTSTAT); return 1;
}
/* * Updates clockevent frequency when the cpu frequency changes. * Called on the cpu that is changing frequency with interrupts disabled.
*/ staticvoid twd_update_frequency(void *new_rate)
{
twd_timer_rate = *((unsignedlong *) new_rate);
/* * The twd clock events must be reprogrammed to account for the new * frequency. The timer is local to a cpu, so cross-call to the * changing cpu.
*/ if (flags == POST_RATE_CHANGE)
on_each_cpu(twd_update_frequency,
(void *)&cnd->new_rate, 1);
/* * If this is the first time round, we need to work out how fast * the timer ticks
*/ if (twd_timer_rate == 0) {
pr_info("Calibrating local timer... ");
/* Wait for a tick to start */
waitjiffies = get_jiffies_64() + 1;
while (get_jiffies_64() < waitjiffies)
udelay(10);
/* OK, now the tick has started, let's get the timer going */
waitjiffies += 5;
/* enable, no interrupt or reload */
writel_relaxed(0x1, twd_base + TWD_TIMER_CONTROL);
/* maximum value */
writel_relaxed(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
while (get_jiffies_64() < waitjiffies)
udelay(10);
if (IS_ERR(twd_clk)) {
pr_err("smp_twd: clock not found %d\n", (int) PTR_ERR(twd_clk)); return;
}
err = clk_prepare_enable(twd_clk); if (err) {
pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
clk_put(twd_clk); return;
}
twd_timer_rate = clk_get_rate(twd_clk);
}
/* * Setup the local clock events for a CPU.
*/ staticvoid twd_timer_setup(void)
{ struct clock_event_device *clk = raw_cpu_ptr(twd_evt); int cpu = smp_processor_id();
/* * If the basic setup for this CPU has been done before don't * bother with the below.
*/ if (per_cpu(percpu_setup_called, cpu)) {
writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);
clockevents_register_device(clk);
enable_percpu_irq(clk->irq, 0); return;
}
per_cpu(percpu_setup_called, cpu) = true;
twd_calibrate_rate();
/* * The following is done once per CPU the first time .setup() is * called.
*/
writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);
twd_get_clock(np); if (!of_property_read_bool(np, "always-on"))
twd_features |= CLOCK_EVT_FEAT_C3STOP;
/* * Immediately configure the timer on the boot CPU, unless we need * jiffies to be incrementing to calibrate the rate in which case * setup the timer in late_time_init.
*/ if (twd_timer_rate)
twd_timer_setup(); else
late_time_init = twd_timer_setup;
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.