概述
arch_timer的初始化
static void __init arch_timer_common_init(void)
{
arch_timer_banner(arch_timers_present);//打印计时器的信息
arch_counter_register(arch_timers_present);//注册计数器
arch_timer_arch_init();
}
static int __init arch_timer_register(void)
{
arch_timer_evt = alloc_percpu(struct clock_event_device);
ppi = arch_timer_ppi[PHYS_SECURE_PPI];
err = request_percpu_irq(ppi, arch_timer_handler_phys, "arch_timer", arch_timer_evt);
ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
err = request_percpu_irq(ppi, arch_timer_handler_phys, "arch_timer", arch_timer_evt);
}//虽然申请了两个中断,但只看到一个arch_timer发生了中断
static void __init arch_timer_init(void)
{
arch_timer_register();
arch_timer_common_init();
}
static void __init arch_timer_of_init(struct device_node *np)
{
arch_timer_init();
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
static struct clocksource clocksource_counter = {
.name = "arch_sys_counter",
.rating = 400,
.read = arch_counter_read,
.mask = CLOCKSOURCE_MASK(56),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static struct cyclecounter cyclecounter = {
.read = arch_counter_read_cc,
.mask = CLOCKSOURCE_MASK(56),
};
static void __init arch_counter_register(unsigned type)
{
u64 start_count;
/* Register the CP15 based counter if we have one */
if (type & ARCH_CP15_TIMER) {
if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual)
arch_timer_read_counter = arch_counter_get_cntvct;
else
arch_timer_read_counter = arch_counter_get_cntpct;
}
start_count = arch_timer_read_counter();
clocksource_register_hz(&clocksource_counter, arch_timer_rate);
cyclecounter.mult = clocksource_counter.mult;
cyclecounter.shift = clocksource_counter.shift;
timecounter_init(&timecounter, &cyclecounter, start_count);
/* 56 bits minimum, so we assume worst case rollover */
sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
}
看下中断处理函数
static __always_inline irqreturn_t timer_handler(const int access,
struct clock_event_device *evt)
{
evt->event_handler(evt);
}
static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
}
event_handler可以通过cat /proc/timer_list查看,如
Tick Device: mode: 1
Per CPU device: 7
Clock Event Device: arch_sys_timer
max_delta_ns: 82595524660
min_delta_ns: 1000
mult: 111669150
shift: 32
mode: 1
next_event: 6436132000000 nsecs
set_next_event: arch_timer_set_next_event_phys
shutdown: arch_timer_shutdown_phys
event_handler: hrtimer_interrupt
retries: 1
然后可以通过在hrtimer_interrupt函数中加入WARN(1, "xxxxxx.n");打印相应的调用关系。
重点关注下hrtimer_interrupt函数
void hrtimer_interrupt(struct clock_event_device *dev)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
entry_time = now = hrtimer_update_base(cpu_base);
__hrtimer_run_queues(cpu_base, now);//找出到期的定时器执行其功能
expires_next = __hrtimer_get_next_event(cpu_base);//找出下次的超时时间
tick_program_event(expires_next, 0);//将定时时间设置到机器的计数模块
}
static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now)
{
struct hrtimer_clock_base *base = cpu_base->clock_base;
unsigned int active = cpu_base->active_bases;
for (; active; base++, active >>= 1) {
struct timerqueue_node *node;
ktime_t basenow;
if (!(active & 0x01))
continue;
basenow = ktime_add(now, base->offset);
while ((node = timerqueue_getnext(&base->active))) {
struct hrtimer *timer;
timer = container_of(node, struct hrtimer, node);
if (basenow.tv64 < hrtimer_get_softexpires_tv64(timer))
break;
__run_hrtimer(cpu_base, base, timer, &basenow);
}
}
}
static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
struct hrtimer_clock_base *base,
struct hrtimer *timer, ktime_t *now)
{
enum hrtimer_restart (*fn)(struct hrtimer *);
fn = timer->function;
restart = fn(timer);
}
同样,查看/proc/timer_list可以查看在运行的每个cpu上不同类型的高精度定时器,如
/*
* The timer bases:
*
* There are more clockids than hrtimer bases. Thus, we index
* into the timer bases by the hrtimer_base_type enum. When trying
* to reach a base using a clockid, hrtimer_clockid_to_base()
* is used to convert from clockid to the proper hrtimer_base_type.
*/
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
.lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
.seq = SEQCNT_ZERO(hrtimer_bases.seq),
.clock_base =
{
{
.index = HRTIMER_BASE_MONOTONIC,
.clockid = CLOCK_MONOTONIC,
.get_time = &ktime_get,
},
{
.index = HRTIMER_BASE_REALTIME,
.clockid = CLOCK_REALTIME,
.get_time = &ktime_get_real,
},
{
.index = HRTIMER_BASE_BOOTTIME,
.clockid = CLOCK_BOOTTIME,
.get_time = &ktime_get_boottime,
},
{
.index = HRTIMER_BASE_TAI,
.clockid = CLOCK_TAI,
.get_time = &ktime_get_clocktai,
},
}
};
高精度的类型
enum hrtimer_base_type {
HRTIMER_BASE_MONOTONIC,
HRTIMER_BASE_REALTIME,
HRTIMER_BASE_BOOTTIME,
HRTIMER_BASE_TAI,
HRTIMER_MAX_CLOCK_BASES,
};
clock 0指HRTIMER_BASE_MONOTONIC
cpu 3指cpu3上的
//重点关注调度定时器
调度的周期 tick_period
union ktime {
s64 tv64;
};
typedef union ktime ktime_t; /* Kill this */
#define NSEC_PER_SEC 1000000000L
CONFIG_HZ=100
tick_period = ktime_set(0, NSEC_PER_SEC / HZ); 10ms
static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs)
{
if (unlikely(secs >= KTIME_SEC_MAX))
return (ktime_t){ .tv64 = KTIME_MAX };
return (ktime_t) { .tv64 = secs * NSEC_PER_SEC + (s64)nsecs };
}
void tick_setup_sched_timer(void)
{
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
ktime_t now = ktime_get();
hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
ts->sched_timer.function = tick_sched_timer;
hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
hrtimer_forward(&ts->sched_timer, now, tick_period);
hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED);
tick_nohz_activate(ts, NOHZ_MODE_HIGHRES);
}
static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
{
struct tick_sched *ts =
container_of(timer, struct tick_sched, sched_timer);
struct pt_regs *regs = get_irq_regs();
ktime_t now = ktime_get();
tick_sched_do_timer(now); //更新jiffies变量和墙上时间
/*
* Do not call, when we are not in irq context and have
* no valid regs pointer
*/
if (regs)
tick_sched_handle(ts, regs);//周期性调度进程
/* No need to reprogram if we are in idle or full dynticks mode */
if (unlikely(ts->tick_stopped))
return HRTIMER_NORESTART;
hrtimer_forward(timer, now, tick_period);
return HRTIMER_RESTART;
}
static void tick_sched_do_timer(ktime_t now)
{
tick_do_update_jiffies64(now);
}
static void tick_do_update_jiffies64(ktime_t now)
{
do_timer(++ticks);
update_wall_time();
}
void do_timer(unsigned long ticks)
{
jiffies_64 += ticks;
}
static inline u64 tk_clock_read(struct tk_read_base *tkr)
{
struct clocksource *clock = READ_ONCE(tkr->clock);
return clock->read(clock);
}
void update_wall_time(void)
{
offset = clocksource_delta(tk_clock_read(&tk->tkr_mono),tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
}
static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
{
update_process_times(user_mode(regs));
}
void update_process_times(int user_tick)
{
run_local_timers();//找出超时的定时器运行
scheduler_tick();
}
void run_local_timers(void)
{
hrtimer_run_queues();//高精度定时器
raise_softirq(TIMER_SOFTIRQ);//低精度定时器
}
void scheduler_tick(void)
{
int cpu = smp_processor_id();
curr->sched_class->task_tick(rq, curr, 0);//调度
calc_global_load_tick(rq);
#ifdef CONFIG_SMP
rq->idle_balance = idle_cpu(cpu);
trigger_load_balance(rq);//触发负载平衡
#endif
}
最后
以上就是奋斗季节为你收集整理的arch_timer驱动分析的全部内容,希望文章能够帮你解决arch_timer驱动分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复