前言
在kernel 中断分析之四——中断申请 [上]中,request_irq、request_threaded_irq、setup_irq、setup_percpu_irq、request_percpu_irq最终都调用了__setup_irq,本篇对该API进行分析,由于代码比较长,分段分析。
请注意,在分析过程中,遇到一些拿捏不定的地方,以用粗体表示,如果有理解错误,欢迎指正。
__setup_irq——线程化处理
895 /*
896 * Internal function to register an irqaction - typically used to
897 * allocate special interrupts that are part of the architecture.
898 */
899 static int
900 __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
901 {
902 struct irqaction *old, **old_ptr;
903 unsigned long flags, thread_mask = 0;
904 int ret, nested, shared = 0;
905 cpumask_var_t mask;
906
907 if (!desc)
908 return -EINVAL;
909
910 if (desc->irq_data.chip == &no_irq_chip)
911 return -ENOSYS;
912 if (!try_module_get(desc->owner))
913 return -ENODEV;
914
915 /*
916 * Check whether the interrupt nests into another interrupt
917 * thread.
918 */
919 nested = irq_settings_is_nested_thread(desc); //判断是否是嵌套中断线程,关于中断嵌套的处理,在后续有分析
920 if (nested) {
921 if (!new->thread_fn) { //嵌套中断不需要有handler,但是thread_fn要有的
922 ret = -EINVAL;
923 goto out_mput;
924 }
925 /*
926 * Replace the primary handler which was provided from
927 * the driver for non nested interrupt handling by the
928 * dummy function which warns when called.
929 */
930 new->handler = irq_nested_primary_handler; //抛出一个警告,nested irq的调用时父中断的handler中处理的,而不是在这里
931 } else {
932 if (irq_settings_can_thread(desc)) //有的中断不允许线程化,设置了IRQ_NOTHREAD标志
933 irq_setup_forced_threading(new); //强制线程化
934 }
irq_setup_forced_threading
879 static void irq_setup_forced_threading(struct irqaction *new)
880 {
881 if (!force_irqthreads) //该全局变量用于表示系统是否允许中断线程化
882 return;
883 if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)) //IRQF_NO_THREAD 或者percpu中断或者已经线程化的中断,直接返回
884 return;
885
886 new->flags |= IRQF_ONESHOT; //线程化中断需要设置IRQF_ONESHOT标志
887//如果thread为NULL(那么handler必不为NULL),此时为了线程化,强制将handler赋给thread_fn,handler设置为irq_default_primary_handler
888 if (!new->thread_fn) {
889 set_bit(IRQTF_FORCED_THREAD, &new->thread_flags); //thread_flags设置IRQTF_FORCED_THREAD,表示经过强制线程化
890 new->thread_fn = new->handler;
891 new->handler = irq_default_primary_handler;
892 }
893 }
我对上述代码的理解,不一定正确:目前的内核实现机制,非nested irq,且非IRQ_NOTHREAD,内核都会将其强制线程化。
以下是IRQF_ONESHOT 的注释:
52 * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
53 * Used by threaded interrupts which need to keep the
54 * irq line disabled until the threaded handler has been run.
另外摘录upstream上IRQF_ONESHOT的commit message如下:
For threaded interrupt handlers we expect the hard interrupt handler
part to mask the interrupt on the originating device. The interrupt
line itself is reenabled after the hard interrupt handler has
executed.
This requires access to