• riscv_clocksource


    static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs)
    {
            return get_cycles64();
    }

    clocksource

    clocksource 提供了对不同软硬件时钟的抽象。可以理解为时间源,为 kernel 提供当前时间。

    struct clocksource {
        cycle_t (*read)(struct clocksource *cs);            // 指向读取时钟的函数
        cycle_t mask;                                       // 能够表示的 cycle 上限,通常是 32/64 位的全 f,做与操作可以避免对 overflow 进行专门处理
        u32 mult;                                           // 将时间源的计数单位 (cycle_t) 转换为 ns
        u32 shift;                                          // 换算公式为 (cycles * mult) >> shift
        u64 max_idle_ns;                                    // 允许的最大空闲时间,单位 ns。当设置 CONFIG_NO_HZ 时,使用动态 tick,不限制 kernel 的睡眠时间,需要进行限制
        u32 maxadj;                                         // 允许的最大调整值,避免转换时 overflow
    #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
        struct arch_clocksource_data archdata;              // 架构专有(目前只有 x86 和 ia64)。
    #endif
        u64 max_cycles;                                     // 设置了 cycle 上限,避免换算时溢出
        const char *name;                                   // 时间源名称
        struct list_head list;                              // 注册了该时间源?
        int rating;                                         // 优先级
        int (*enable)(struct clocksource *cs);              // 启用时间源函数
        void (*disable)(struct clocksource *cs);            // 停用时间源函数
        unsigned long flags;
        void (*suspend)(struct clocksource *cs);            // 暂停时间源函数
        void (*resume)(struct clocksource *cs);             // 恢复时间源函数
    
        /* private: */
    #ifdef CONFIG_CLOCKSOURCE_WATCHDOG                      // 用于监控时间源,校验时间是否准确
        /* Watchdog related data, used by the framework */
        struct list_head wd_list;
        cycle_t cs_last;
        cycle_t wd_last;
    #endif
        struct module *owner;                               // 指向拥有该时间源的内核模块
    };

    其中 rating 表示了时间源的准确度,它将作为 Linux 选择时钟源时的优先级:

    • 1-99 - Only available for bootup and testing purposes;
    • 100-199 - Functional for real use, but not desired.
    • 200-299 - A correct and usable clocksource.
    • 300-399 - A reasonably fast and accurate clocksource.
    • 400-499 - The ideal clocksource. A must-use where available;

    只有 rating 最高的时间源会被选用

    riscv_clocksource

    static struct clocksource riscv_clocksource = {
            .name           = "riscv_clocksource",
            .rating         = 300,
            .mask           = CLOCKSOURCE_MASK(64),
            .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
            .read           = riscv_clocksource_rdtime,
    };

    riscv_timer_init_dt注册 riscv clocksource

    riscv_timer_init_dt
         clocksource_register_hz(&riscv_clocksource, riscv_timebase);
          sched_clock_register(riscv_sched_clock, 64, riscv_timebase);

    jiffies clocksource

    在 Linux 中作为软件维护的时钟。表示一小段短暂而不确定的时间。

    属于低精度时间源,因为没有 CLOCK_SOURCE_VALID_FOR_HRES 的 flag,所以不会出现在 available_clocksource 中。

      static struct clocksource clocksource_jiffies = {
      .name = "jiffies",
      .rating = 1, /* lowest valid rating*/ // 优先级最低
      .read = jiffies_read, // 读时返回 jiffies
      .mask = CLOCKSOURCE_MASK(32),
      .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
      .shift = JIFFIES_SHIFT, // NSEC_PER_JIFFY 和 JIFFIES_SHIFT 由 CONFIG_HZ 决定
      .max_cycles = 10,
      };

    Linux 用全局变量 jiffies / jiffies_64 来存放系统启动后经过的 jiffy 数目:

      extern u64 __jiffy_data jiffies_64; // x86_64 下使用,非原子,读时需要加锁,如 get_jiffies_64 用了 seqlock
      extern unsigned long volatile __jiffy_data jiffies; // x86_32 下使用

    根据 arch/x86/kernel/vmlinux.lds.S,在 32 位下,jiffies 指向 jiffies_64 的低 32 位。

    每当收到 clock_event_device (后详)发出的中断时,会调用其 handler ,即 tick_handle_periodic ,于是有

    tick_handle_periodic => tick_periodic => do_timer => jiffies_64 += ticks

    由于 do_timer 的参数为 1,因此 jiffies_64 += 1。而根据 tick_setup_device 中 tick_period = ktime_set(0, NSEC_PER_SEC / HZ) ,表示 tick_device 每个 tick 间隔为 1 / HZ 秒。于是每个 jiffies 代表的时间为 1/ HZ 秒,系统启动至今所经过的秒数 = jiffies_64 / HZ。HZ 由 CONFIG_HZ 决定,而 CONFIG_HZ 由 CONFIG_HZ_* 决定,有 100/250/300/1000 可选,一般为 1000。所以每隔 1 毫秒,jiffies "时钟" 就会加一,1 jiffy 等于 1 毫秒。

    从 jiffies 我们可以发现,时钟源的不仅能够通过读取硬件时钟源来实现,还能通过 tick_device,更本质上来说是定时器来实现

    不采用TIMER_OF_DECLARE(riscv_timer, "riscv", riscv_timer_init_dt);

    # cat /sys/bus/clocksource/devices/clocksource0/current_clocksource 
    arm,sp804
    # cat /sys/bus/clocksource/devices/clocksource0/available_clocksource 
    arm,sp804 jiffies 
  • 相关阅读:
    %
    【收藏】Javascript调用后台代码的方法
    C++Builder2010中配置OpenCV2.2
    【收藏】Visual studio 2008 && 2010 快捷键大全
    队列的练习
    哈希表
    poj 3750 链表
    C/C++内存存储 mark在此
    二叉树,深搜,广搜
    链表的练习
  • 原文地址:https://www.cnblogs.com/dream397/p/15724445.html
Copyright © 2020-2023  润新知