ACPI_PM


这个是传说中的ACPI Power Management Time,这个其实我也知之不详,对这个感兴趣的可以去找下CU的彭东,这小子写OS,应该会经常和这种硬件纠缠不清。到了硬件驱动层,我水平基本温饱线以下。

  1. #define PMTMR_TICKS_PER_SEC 3579545 
  2.   
  3.  66 static struct clocksource clocksource_acpi_pm = { 
  4.           .name = "acpi_pm"
  5.           .rating = 200
  6.           .read = acpi_pm_read
  7.           .mask = (cycle_t)ACPI_PM_MASK, 
  8.           .mult = 0, /*to be calculated*/ 
  9.           .shift = 22
  10.           .flags = CLOCK_SOURCE_IS_CONTINUOUS
  11.   
  12.  }; 
  13. fs_initcall(init_acpi_pm_clocksource) 

我们看到了频率在3Mhz这个级别,rating是200,低于HPET。至于初始化在fs_initcall这一步做。

TSC


TSC是Time Stamp Counter。CPU 执行指令需要一个外部振荡器产生时钟信号,从 CLK 管脚输入。x86 提供了一个 TSC 寄存器,该寄存器的值在每次收到一个时钟信号时加一。比如 CPU 的主频为 1GHZ,则每一秒时间内,TSC 寄存器的值将增加 1G 次,或者说每一个纳秒加一次。x86 还提供了 rtdsc 指令来读取该值,因此 TSC 也可以作为时钟设备。TSC 提供了比 RTC 更高精度的时间,即纳秒级的时间精度。这个很牛X,看时钟频率是和CPU的频率一个水平线的。远远超过HPET,PIT这些小鱼小虾米。看下我的笔记本的TSC 频率:

  1. manu@manu:~/code/c/classical/linux-3.4.61$ dmesg |grep Detected 
  2. [ 0.004000] Detected 2127.727 MHz processor. 
  3.   
  4. manu@manu:~$ cat /proc/cpuinfo  
  5. processor   : 0 
  6. vendor_id   : GenuineIntel 
  7. cpu family  : 6 
  8. model    : 37 
  9. model name  : Intel(R) Core(TM) i3 CPU       M 330  @ 2.13GHz 
  10.   
  11. 。。。。。 

看这时钟频率,相当的吓人,看下clocksource的rating:

  1. static struct clocksource clocksource_tsc = { 
  2.     .name = "tsc"
  3.     .rating = 300
  4.     .read = read_tsc
  5.     .resume = resume_tsc
  6.     .mask = CLOCKSOURCE_MASK(64), 
  7.     .flags = CLOCK_SOURCE_IS_CONTINUOUS | 
  8.                   CLOCK_SOURCE_MUST_VERIFY, 
  9. #ifdef CONFIG_X86_64 
  10.     .archdata = { .vclock_mode = VCLOCK_TSC }, 
  11. #endif 
  12. }; 

TSC的init和register分别在tsc_init和init_tsc_clocksource中进行

 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

  1. static int __init init_tsc_clocksource(void) 
  2.     if (!cpu_has_tsc || tsc_disabled > 0 || !tsc_khz) 
  3.         return 0; 
  4.  
  5.     if (tsc_clocksource_reliable) 
  6.         clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; 
  7.     /* lower the rating if we already know its unstable: */ 
  8.     if (check_tsc_unstable()) { 
  9.         clocksource_tsc.rating = 0
  10.         clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS; 
  11.     } 
  12.  
  13.     /* 
  14.      * Trust the results of the earlier calibration on systems 
  15.      * exporting a reliable TSC. 
  16.      */ 
  17.     if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { 
  18.         clocksource_register_khz(&clocksource_tsc, tsc_khz); 
  19.         return 0; 
  20.     } 
  21.   
  22.     schedule_delayed_work(&tsc_irqwork, 0); 
  23.     return 0; 
  24. /* 
  25.  * We use device_initcall here, to ensure we run after the hpet 
  26.  * is fully initialized, which may occur at fs_initcall time. 
  27.  */ 
  28. device_initcall(init_tsc_clocksource); 

所以,clocksource 的PK之战中,TSC技压群雄,完爆HPET/PIT/ACPI_PM,成为current_clocksource。clocksource之战如何进行,如何选择当前时钟源,新的时钟源注册会带来什么影响。Linux如何根据时钟源完成计时,这个就在下一篇clocksource中介绍。


相关内容