arm_arch_timer代码阅读

2 篇文章 0 订阅

arm_arch_timer代码阅读


画个图镇楼,凭空想象凭空捏造,有错请指出,我肯定会改。

在这里插入图片描述

硬件中断以及设备树配置

设备树配置:

arm-timer {
    compatible = "arm,armv8-timer";
    interrupts = 	<1 13 0xf04>,
    				<1 14 0xf04>;
    clock-frequency = <50000000>;
};

硬件定时器中断号:

硬件中断号中断描述
29Secure physical Timer
30Non-secure physical Timer

根据drivers/irqchip/irq-gic-v3.c里面的代码来看,这两个定时器的中断是属于PPI中断,从设备树映射时,会将中断号+16处理,即<1 13 0xf04>里面的13+16才是真实的硬件中断号29

在这里插入图片描述

从设备的/proc/interrupt中获取中断号:(第二个中断arch_timer-no名称被我修改了)

# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
  1:          0          0          0          0     GIC-0  29 Level     arch_timer
  2:       1881       1858       1782       1876     GIC-0  30 Level     arch_timer-no

定时器初始化的简要过程

arch_timer_of_init()892行出对设备树里面的中断号进行了解析,也就是第一章节里面的硬件中断号配置,然后存放到arch_timer_ppi`数组里面。

在这里插入图片描述

获取时钟频率

中断映射的过程就先不看了,看一下时钟频率的读取。一开始先从设备树解析时钟频率,这里因为设备树有配置,所以读出来了50MHz的频率;如果设备树解析不到,那么根据第一个参数输入的情况,选择走if还是else分支,这里参数是NULL,走的是else分支。

在这里插入图片描述

看一下读芯片频率的代码:

在这里插入图片描述

查看arm-v8a手册,可以看到是ARM自带的一个寄存器:通过mrs指令读取。

在这里插入图片描述

申请中断

接下来看arch_timer_init()函数。一开始如果是 HYP 模式或者虚拟的计时器没有中断,那么走入这个判断分支。当前配置是没有 HYP 模式, 也没有虚拟中断号。所以此分支会执行到。

在这里插入图片描述

接下来是为定时器申请中断:当前注册两个,PHYS_SECURE_PPIPHYS_NONSECURE_PPI,和第一节的内容是对应的。

在这里插入图片描述

在这里插入图片描述

中断处理函数

这里先看一下中断处理函数:arch_timer_handler_phys(),调用timer_handler()函数,并将访问类型设置为ARCH_TIMER_PHYS_ACCESS

在这里插入图片描述

在这里插入图片描述

timer_handler()函数先读定时器的访问控制寄存器,有中断来时清中断,并调用注册的时钟事件设备的回调函数,这个注册的函数回头再看,这里往下看一下读寄存器的过程。

在这里插入图片描述

时钟事件设备的处理函数目前来看应该是tick_handle_periodic(),在周期性时钟事件注册的部分有描述到。

访问定时器的控制寄存器

arch_timer_reg_read()函数根据访问类型选择不同分支,这里走arch_timer_reg_read_cp15()

在这里插入图片描述

arch_timer_reg_read_cp15()函数根据访问类型和寄存器类型,当前读取cntp_ctl_el0寄存器。

在这里插入图片描述

在手册中瞄一眼这个寄存器:

在这里插入图片描述

定时器的一些通用初始化

在这里插入图片描述

打印时钟相关信息的如下:

在这里插入图片描述

当前设备上的打印如下:

arm_arch_timer: Architected cp15 timer(s) running at 50.00MHz (phys).

在这里插入图片描述

读定时器计数值

arch_timer_read_counter函数指针被赋值为arch_counter_get_cntvct(),读定时器的虚拟计数定时器,里面的数值和物理计数定时器的计数值一致。

在这里插入图片描述

arch_timer_reg_read_stable()如下:

在这里插入图片描述

read_sysreg()则是汇编指令的宏:

在这里插入图片描述

关于后续的clocksourceclockcountertimercountersched clock这些内容,预计还是很大的代码量,暂时先略过,后续有机会补充。

周期性时钟事件的注册

注册周期性的设备里面走的路子比较远,这里就简单看一下过程好了:

CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);arch_timer_of_init()irq_of_parse_and_map()arch_timer_detect_rate()arch_timer_init()arch_timer_register()request_percpu_irq()
                →  PHYS_SECURE_PPI      → arch_timer_handler_phys()
                →  PHYS_NONSECURE_PPI   → arch_timer_handler_phys()arch_timer_cpu_pm_init()cpu_pm_register_notifier()cpuhp_setup_state()arch_timer_starting_cpu()arch_timer_dying_cpu()__cpuhp_setup_state()cpuhp_issue_call()cpuhp_invoke_callback()arch_timer_starting_cpu()__arch_timer_setup()clockevents_config_and_register()clockevents_register_device()tick_check_new_device()tick_setup_device()tick_setup_periodic()tick_handle_periodic()

获取每CPU变量arch_timer_evt的当前CPU变量,交个__arch_timer_setup()作为入参。

在这里插入图片描述

调用clockevents_config_and_register()注册和配置时钟事件设备:

在这里插入图片描述

clockevents_config_and_register()配置完后,调用clockevents_register_device()注册时钟事件设备。

在这里插入图片描述

clockevents_register_device()调用tick_check_new_device()注册tick设备。

在这里插入图片描述

tick_check_new_device()调用tick_setup_device()建立新的tick设备。

在这里插入图片描述

tick_setup_device()调用tick_setup_periodic()建立周期性的tick事件。

在这里插入图片描述

在这里插入图片描述

tick_setup_periodic()调用tick_set_periodic_handler()设置时钟事件设备的回调。

在这里插入图片描述

当前来看应该是设置的tick_handle_periodic()回调。

在这里插入图片描述

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值