1. Linux hrtimer的實現方案
Linux hrtimer的實現是依賴硬件(通過可編程定時器來實現)的支持的,而且此定時器有自己的專用寄存器, 硬中斷和頻率。比如我的板子上的對應參數如下:
Timer at Vir:0xE0100200 = Phy:0xE0100200, using Irq:27, at Freq:250000000,由此可見,其頻率為250MHz,所以其精度為:1/250000000=4ns,比系統時鐘jiffy(HZ=100,精度為10ms)的精度高得太多了。可是支持此高精度timer是需要付出硬件成本的。即它是一個硬件時鐘。這裡所說的硬件時鐘特指的是硬件計時器時鐘。
2. 硬件時鐘 數據結構
和硬件計時器(本文又稱作硬件時鐘,區別於軟件時鐘)相關的數據結構主要有兩個:
struct clocksource :對硬件設備的抽象,描述時鐘源信息
- struct clocksource {
- /*
- * First part of structure is read mostly
- */
- char *name;
- struct list_head list;
- int rating;
- cycle_t (*read)(struct clocksource *cs);
- int (*enable)(struct clocksource *cs);
- void (*disable)(struct clocksource *cs);
- cycle_t mask;
- u32 mult;
- u32 shift;
- u64 max_idle_ns;
- unsigned long flags;
- cycle_t (*vread)(void);
- void (*suspend)(struct clocksource *cs);
- void (*resume)(struct clocksource *cs);
- #ifdef CONFIG_IA64
- void *fsys_mmio; /* used by fsyscall asm code */
- #define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr))
- #else
- #define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0)
- #endif
-
- /*
- * Second part is written at each timer interrupt
- * Keep it in a different cache line to dirty no
- * more than one cache line.
- */
- cycle_t cycle_last ____cacheline_aligned_in_smp;
-
- #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
- /* Watchdog related data, used by the framework */
- struct list_head wd_list;
- cycle_t wd_last;
- #endif
- };
struct clock_event_device :時鐘的事件信息,包括當硬件時鐘中斷發生時要執行那些操作(實際上保存了相應函數的指針)。本文將該結構稱作為“時鐘事件設備”。
- /**
- * struct clock_event_device - clock event device descriptor
- * @name: ptr to clock event name
- * @features: features
- * @max_delta_ns: maximum delta value in ns
- * @min_delta_ns: minimum delta value in ns
- * @mult: nanosecond to cycles multiplier
- * @shift: nanoseconds to cycles divisor (power of two)
- * @rating: variable to rate clock event devices
- * @irq: IRQ number (only for non CPU local devices)
- * @cpumask: cpumask to indicate for which CPUs this device works
- * @set_next_event: set next event function
- * @set_mode: set mode function
- * @event_handler: Assigned by the framework to be called by the low
- * level handler of the event source
- * @broadcast: function to broadcast events
- * @list: list head for the management code
- * @mode: operating mode assigned by the management code
- * @next_event: local storage for the next event in oneshot mode
- * @retries: number of forced programming retries
- */
- struct clock_event_device {
- const char *name;
- unsigned int features;
- u64 max_delta_ns;
- u64 min_delta_ns;
- u32 mult;
- u32 shift;
- int rating;
- int irq;
- const struct cpumask *cpumask;
- int (*set_next_event)(unsigned long evt,
- struct clock_event_device *);
- void (*set_mode)(enum clock_event_mode mode,
- struct clock_event_device *);
- void (*event_handler)(struct clock_event_device *);
- void (*broadcast)(const struct cpumask *mask);
- struct list_head list;
- enum clock_event_mode mode;
- ktime_t next_event;
- unsigned long retries;
- };
-
上述兩個結構內核源代碼中有較詳細的注解,分別位於文件 clocksource.h 和 clockchips.h 中。需要特別注意的是結構 clock_event_device 的成員 event_handler ,它指定了當硬件時鐘中斷發生時,內核應該執行那些操作,也就是真正的時鐘中斷處理函數。
Linux 內核維護了兩個鏈表,分別存儲了系統中所有時鐘源的信息和時鐘事件設備的信息。這兩個鏈表的表頭在內核中分別是 clocksource_list 和 clockevent_devices 。