Linux hrtimer的实现
Linux hrtimer的实现
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 。
|
评论暂时关闭