博文

目前显示的是标签为“irq”的博文

品味内核中断上下半部

在《初尝内核中断》里我们了解了Linux内核中断模块的实现,也体验了一番共享中断的魅力,但上面这样的中断程序把任务都交到了服务子程序里去处理,这在单片机等性能要求不高的嵌入式系统里还好,但在我们的Linux等多任务嵌入式系统里,那这可是大大的浪费效率的做法,故而在Linux的内核中断里有上下半部的处理模式,将响应中断后最紧要的内容处理完后,就把不慌不忙的内容交到下半部去处理,即上半部处理最急需处理的内容,这样不需要非得该中断处理完再去响应同一中断线上的另一个中断请求了,效率也提上来了。 总的来说,上半部(top half)主要是处理与硬件交互等急切的事件,然后就把交互来的数据或请求等需求处理交到下半部(bottom half)去处理,下半部就处理这些比较费时的内容,并且还有可能被打断,下半部的执行由Linux Kernel去安排其时机。 Linux下半部机制由softirq、tasklet和工作队列等来实现,由于softirq与tasklet很相似,在中断里也较少使用,我们这里就学习下tasklet和工作队列(workqueue,在嵌入式Linux较常使用)机制。 1.tasklet机制 tasklet(小任务)也是在软中断(softirq,不是软件中断)的基础上实现的,但两个相同的tasklet是不会同时执行的,就算在不同的处理器上也不行。多次被调试时,tasklet也只运行一次。 在Linux Kernel源码的include/linux/interrupt.h文件里,关于tasklet有如下的结构体: struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; }; 其中,next指向下一个tasklet,state表示当前tasklet的状态,有同一文件里有如下枚举: enum { TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */ TASKLET_S...

初尝内核中断

每台计算机都连接有很多外设,那操作系统对这些外设进行管理时要如何通信呢?一般有轮询(Polling)和中断(Interrupt)两种,第一种是操作系统定时主动去查询这些外设,看有没有设备需要进行处理,而第二种则是外设需要处理时主动向操作系统发送请求信号,然后操作系统再做相应的处理。这第二种不需要定时去查询,只有在设备需要时才进行处理,节省了CPU的消耗,提高了效率。故而我们先尝试下如何去使用Linux内核的中断处理机制,本次采用共享中断的机制来学习我们的中断程序。  一般来说,一个中断有这样的操作步骤: 1.注册中断及服务子程序; 2.使能中断; 3.中断到来时调用服务子程序进行处理,处理完成后退出继续等待下一个中断的到来。  而在Linux内核源码include/linux/interrupt.h里有注册中断需要用到的如下函数: static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) ; 接下来说说这5个参数吧: 1.irq:中断号/中断向量,在嵌入式里经常会用gpio来作为外部中断请求线,经常会用到gpio_to_irq函数来作转换; 2.handler:服务子程序/中断处理程序,指向一个处理本中断的回调函数,其函数原型如下: typedef irqreturn_t (*irq_handler_t)(int, void *); 其两参数分别对应irq和dev; 3.flags:作为gpio请求中断时,该标志可设置触发方式:高电平、低电平、上升延、下降延,还可以设置该中断的处理模式是:屏蔽、共享等,具体可查阅interrupt.h文件里以IRQF_开头的宏; 4.name:中断请求的设备名称,在/proc/interrupts里可查看到中断号、中断次数、中断设备名称; 5.dev:传递给中断处理程序的参数,void*类型表示可以传递任意类型的数据,一般传递设备结构体指针。该参数在设置为共享模式(IRQF_SHARED)时用于标志共享中断的唯一性。 上面说到了中断注册函数,释放时对应的函数为: extern voi...