中断
分类
向量中断:由硬件提供中断服务程序的入口地址。
非向量中断:由软件提供中断服务程序的入口地址。
顶半部(top half)/底半部(bottom half)
top half: 读取中断状态、清除中断标志后作“登记中断”的工作;—便于服务更多的中断
bottom half:完成中断处理的大部分工作;一般比较耗时。
Note:一个中断处理不一定都要分为两部分。如果top half本身能够完成整个中断处理,那bottom half也就不需要了。
Linux中断编程
申请/释放中断:request_irq/free_irq
屏蔽/使能中断:
屏蔽/使能某中断源
disable_irq/disable_irq_nosync;
enable_irq
屏蔽/恢复本cpu内所有中断
local_irq_save/local_irq_disable;
local_irq_restore/local_irq_enable
底半部机制
- tasklet
- 定义底半部处理函数my_tasklet_func(),并利用DECLARE_TASKLET将my_tasklet_func()与my_tasklet_func()绑定起来: DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);
- 在驱动加载函数中申请中断(request_irq),该函数调用中断顶半部处理函数xxx_interrupt;
- 在顶半部处理函数中,调用tasklet_schedule(&my_task),则会调用底半部处理函数my_tasklet_func();
- 在驱动卸载函数中释放中断(free_irq)
- 工作队列
- 定义一个工作队列和底半部处理函数;
struct work_struct my_wq;
void my_wq_func(unsigned long); - 在驱动加载函数中申请中断并初始化工作队列;
request_irq; / * 调用中断顶半部处理函数xxx_interrupt * /
INIT_WORK(&my_wq, (void (*)(void *)) my_wq_func, NULL); - 在顶半部处理函数中,调用schedule_work(&my_wq),最终调用底半部处理函数my_wq_func;
- 在驱动卸载函数中释放中断(free_irq)
- 软中断
- local_bh_enable()/local_bh_disable(); 使能/禁止软中断
- 软中断/tasklet运行于中断上下文,不能睡眠;工作队列运行于进程上下文,则允许睡眠。
中断共享
- 多个设备共享一条硬件中断线,如PCI设备
- 申请中断request_irq时均使用SA_SHIRQ 标志,且有最后一个参数dev_id。
- 在中断到来后,在top half中应尽快根据dev_id判断是否是该设备的中断,若不是应迅速返回(return IRQ_NONE;)
内核定时器编程
利用timer_list结构体和一组函数实现。
struct timer_list {
struct list_head entry; //定时器列表
unsigned long expires; //定时器到期时间
void (*function)(unsigned long); //定时器处理函数
unsigned long data; //作为参数被传入定时器处理函数
struct timer_base_s *base;
};
- 定义一个定时器:
struct time_list my_timer;
- 初始化定时器
2.1Init_timer(&my_timer);
//初始化timer_list中的entry的next为NULL,并给base赋值。
TIMER_INITIALIZER(_function, _expires, _data);
//初始化timer_list中的function、expires、data 和base成员。
2.2 另外,也可调用setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data)
//初始化定时器并赋值其成员。 - 注册内核定时器:
add_timer(&my_timer);
- 删除定时器:
del_timer(&my_timer);
- 修改定时器:
mod_timer(struct timer_list *timer, unsigned long expires);
内核延迟
忙等待
-
短延迟
1.1ndelay(); //纳秒延迟
1.2udelay(); //微秒延迟
1.3mdelay(); //毫秒延迟,最好不要直接使用(会无谓的耗费CPU资源
1.4毫秒及以上的延迟:推荐用睡眠延迟
-
长延迟:
time_before(jiffies, delay);
睡眠等待
- msleep();
- msleep_interruptible();
- ssleep();
**NOTE:**为了充分利用CPU资源,使系统有更好的吞吐性能,在对延迟时间的要求并不是很精确的情况下,睡眠等待通常是值得推荐的。