PIT


PIT全称Programmable Interval Timer,是出现比较早的,比较菜的硬件。这种设备有8253/8254,对底层感兴趣的可以读drivers/clocksource/i8253.c,这种硬件的频率是1MHZ左右:

  1. #define PIT_TICK_RATE 1193182ul 

PIT为啥没有落在available_clocksource中呢,因为后起之秀HPET的存在。Kernel中发现可以使用HPET,就不会用PIT作为始终源了。后面我们会分析到。

HPET


PIT 的精度较低,HPET 被设计来替代 PIT 提供高精度时钟中断至少 10MHz)。它是由微软和 Intel 联合开发的。一个 HPET 包括了一个固定频率的数值增加的计数器以及 3 到 32 个独立的计时器,这每一个计时器有包涵了一个比较器和一个寄存器保存一个数值,表示触发中断的时机)。每一个比较器都比较计数器中的数值和寄存器的数值,相等就会产生中断。

HPET这个时钟源的检测和注册是在前文提到的四大初始化中的最后一个:time_init   

 time_init

|________________x86_late_time_init

               |_________x86_init.timers.timer_init (arch/x86/kernel/x86_init.c)

                         |________hpet_time_init

                                  |_____hpet_enable

                                        |____hpet_clocksource_register

                                  |_____set_default_time_irq 

|________________tsc_init

               |________x86_platform.calibrate_tsc (x86_init.c)

                      |______native_calibrate_tsc

                             |___quit_pit_calibrate

在这个时候我们看到,time_init主要是两个部分,TSC是一个,HPETPIT)是一个。

  1. static struct irqaction irq0 = { 
  2.     .handler = timer_interrupt
  3.     .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER, 
  4.     .name = "timer" 
  5. }; 
  6.   
  7. void __init setup_default_timer_irq(void) 
  8.     setup_irq(0, &irq0); 
  9.   
  10. /* Default timer init function */ 
  11. void __init hpet_time_init(void) 
  12.     if (!hpet_enable()
  13.         setup_pit_timer()
  14.     setup_default_timer_irq(); 
  15.   
  16. static __init void x86_late_time_init(void) 
  17.     x86_init.timers.timer_init();  
  18.     tsc_init(); //TSC part 
  19.   
  20. /* 
  21.  * Initialize TSC and delay the periodic timer init to 
  22.  * late x86_late_time_init() so ioremap works. 
  23.  */ 
  24. void __init time_init(void) 
  25.     late_time_init = x86_late_time_init

从上面加粗的部分可以看到,当HPET可以enable的时候,我们就不用PIT作为时钟源了,原因是HPET频率高,精度高。

从我的笔记本Linux的dmesg可看到:

 [ 0.664201] hpet0: 8 comparators, 64-bit 14.318180 MHz counter

我的笔记本的HPET,频率是14.318180MHz。

讲到这里,就不得不讲clocksource。Linux将真实的时钟做了抽象,用数据结构clocksource来管理这些硬件时钟源。

  1. /** 
  2.  * struct clocksource - hardware abstraction for a free running counter 
  3.  *    Provides mostly state-free accessors to the underlying hardware. 
  4.  *    This is the structure used for system time. 
  5.  * 
  6.  * @name:        ptr to clocksource name 
  7.  * @list:        list head for registration 
  8.  * @rating:        rating value for selection (higher is better) 
  9.  *            To avoid rating inflation the following 
  10.  *            list should give you a guide as to how 
  11.  *            to assign your clocksource a rating 
  12.  *            1-99: Unfit for real use 
  13.  *                Only available for bootup and testing purposes. 
  14.  *            100-199: Base level usability. 
  15.  *                Functional for real use, but not desired. 
  16.  *            200-299: Good. 
  17.  *                A correct and usable clocksource. 
  18.  *            300-399: Desired. 
  19.  *                A reasonably fast and accurate clocksource. 
  20.  *            400-499: Perfect 
  21.  *                The ideal clocksource. A must-use where 
  22.  *                available. 
  23.  * @read:        returns a cycle value, passes clocksource as argument 
  24.  * @enable:        optional function to enable the clocksource 
  25.  * @disable:        optional function to disable the clocksource 
  26.  * @mask:        bitmask for two's complement 
  27.  *            subtraction of non 64 bit counters 
  28.  * @mult:        cycle to nanosecond multiplier 
  29.  * @shift:        cycle to nanosecond pisor (power of two) 
  30.  * @max_idle_ns:    max idle time permitted by the clocksource (nsecs) 
  31.  * @maxadj:        maximum adjustment value to mult (~11%) 
  32.  * @flags:        flags describing special properties 
  33.  * @archdata:        arch-specific data 
  34.  * @suspend:        suspend function for the clocksource, if necessary 
  35.  * @resume:        resume function for the clocksource, if necessary 
  36.  * @cycle_last:        most recent cycle counter value seen by ::read() 
  37.  */ 
  38. struct clocksource { 
  39.     /* 
  40.      * Hotpath data, fits in a single cache line when the 
  41.      * clocksource itself is cacheline aligned. 
  42.      */ 
  43.     cycle_t (*read)(struct clocksource *cs); 
  44.     cycle_t cycle_last; 
  45.     cycle_t mask; 
  46.     u32 mult; 
  47.     u32 shift; 
  48.     u64 max_idle_ns; 
  49.     u32 maxadj; 
  50. #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA 
  51.     struct arch_clocksource_data archdata; 
  52. #endif 
  53.   
  54.     const char *name; 
  55.     struct list_head list; 
  56.     int rating; 
  57.     int (*enable)(struct clocksource *cs); 
  58.     void (*disable)(struct clocksource *cs); 
  59.     unsigned long flags; 
  60.     void (*suspend)(struct clocksource *cs); 
  61.     void (*resume)(struct clocksource *cs); 
  62.   
  63.     /* private: */ 
  64. #ifdef CONFIG_CLOCKSOURCE_WATCHDOG 
  65.     /* Watchdog related data, used by the framework */ 
  66.     struct list_head wd_list; 
  67.     cycle_t cs_last; 
  68.     cycle_t wd_last; 
  69. #endif 
  70. } ____cacheline_aligned;     

很重要的一个参数是rating时钟源分优劣,精度越高的时钟源的,rating值越大。从注释中我们可以看到:

  • 1--99: 不适合于用作实际的时钟源,只用于启动过程或用于测试;
  • 100--199:基本可用,可用作真实的时钟源,但不推荐;
  • 200--299:精度较好,可用作真实的时钟源;
  • 300--399:很好,精确的时钟源;
  • 400--499:理想的时钟源,如有可能就必须选择它作为时钟源;
  1. static struct clocksource clocksource_hpet = { 
  2.     .name = "hpet"
  3.     .rating = 250
  4.     .read = read_hpet
  5.     .mask = HPET_MASK
  6.     .flags = CLOCK_SOURCE_IS_CONTINUOUS
  7.     .resume = hpet_resume_counter
  8. #ifdef CONFIG_X86_64 
  9.     .archdata = { .vclock_mode = VCLOCK_HPET }, 
  10. #endif 
  11. }; 

从rating上HPET的rating是250,已经很不错了,为什么最终选择了TSC,available_clocksource中的acpi_pm又是什么?    


相关内容