在gic_of_init的时候会调用 set_handle_irq(gic_handle_irq);来设置中断的回调函数
45 void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
46 {
47 if (handle_arch_irq)
48 return;
49
50 handle_arch_irq = handle_irq;
51 }
code很简单就是把gic_handle_irq 赋给handle_arch_irq 。这样当中断发生是就会调用handle_arch_irq ,如下code所示.
arch/arm/kernel/entry-armv.S
41 .macro irq_handler
42 #ifdef CONFIG_MULTI_IRQ_HANDLER
43 ldr r1, =handle_arch_irq
44 mov r0, sp
45 badr lr, 9997f
46 ldr pc, [r1]
47 #else
48 arch_irq_handler_default
49 #endif
我们看看gic_handle_irq 具体做了什么。
asmlinkage 表示用堆栈来传递参数而不是用寄存器.
267 static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
268 {
269 u64 irqnr;
270
271 do {
272 irqnr = gic_read_iar();
273
274 if (likely(irqnr > 15 && irqnr < 1020)) {
275 int err;
276 err = handle_domain_irq(gic_data.domain, irqnr, regs);
277 if (err) {
278 WARN_ONCE(true, "Unexpected SPI received!\n");
279 gic_write_eoir(irqnr);
280 }
281 continue;
282 }
283 if (irqnr < 16) {
284 gic_write_eoir(irqnr);
285 #ifdef CONFIG_SMP
286 handle_IPI(irqnr, regs);
287 #else
288 WARN_ONCE(true, "Unexpected SGI received!\n");
289 #endif
290 continue;
291 }
292 } while (irqnr != ICC_IAR1_EL1_SPURIOUS);
293 }
这个函数做了两件事
272行读取发生中断的irq number.
如果irq number在15 到 1020之间,则调用handle_domain_irq 处理
irq number 如果小于15的话,则属于cpu之间的中断,而不是hw发送过来的中断,调用handle_ipi处理.
handle_domain_irq ->__handle_domain_irq ->generic_handle_irq->generic_handle_irq_desc
145 static inline void generic_handle_irq_desc(struct irq_desc *desc)
146 {
147 desc->handle_irq(desc);
148 }
但这个handle_irq 具体在哪里赋值的呢?
在初始的时候会调用gic_irq_domain_map
588 static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
589 irq_hw_number_t hw)
590 {
591 /* SGIs are private to the core kernel */
592 if (hw < 16)
593 return -EPERM;
594 /* PPIs */
595 if (hw < 32) {
596 irq_set_percpu_devid(irq);
597 irq_set_chip_and_handler(irq, &gic_chip,
598 handle_percpu_devid_irq);
599 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
600 }
601 /* SPIs */
602 if (hw >= 32 && hw < gic_data.irq_nr) {
603 irq_set_chip_and_handler(irq, &gic_chip,
604 handle_fasteoi_irq);
605 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
606 }
607 irq_set_chip_data(irq, d->host_data);
608 return 0;
609 }
我们看irq_set_chip_and_handler实现
526 static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip,
527 irq_flow_handler_t handle)
528 {
529 irq_set_chip_and_handler_name(irq, chip, handle, NULL);
530 }
继续往下
821 irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
822 irq_flow_handler_t handle, const char *name)
823 {
824 irq_set_chip(irq, chip);
825 __irq_set_handler(irq, handle, 0, name);
826 }
继续往下
789 __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
790 const char *name)
791 {
792 unsigned long flags;
793 struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
794
795 if (!desc)
796 return;
797
798 __irq_do_set_handler(desc, handle, is_chained, name);
799 irq_put_desc_busunlock(desc, flags);
800 }
继续往下,看到__irq_do_set_handler的776 行注册handle_irq,而此时的handle是在gic_irq_domain_map 中赋值的,如果irq number <32 ,则handle=handle_percpu_devid_irq,否则handle=handle_fasteoi_irq
733 void
734 __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
735 int is_chained, const char *name)
736 {
776 desc->handle_irq = handle;
777 desc->name = name;
我们继续看看handle_fasteoi_irq的实现
handle_fasteoi_irq-> handle_irq_event->handle_irq_event_percpu
handle_irq_event_percpu 的实现如下,145行看到调用handler了吧,
135 irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
136 {
137 irqreturn_t retval = IRQ_NONE;
138 unsigned int flags = 0, irq = desc->irq_data.irq;
139 struct irqaction *action;
140
141 for_each_action_of_desc(desc, action) {
142 irqreturn_t res;
143
144 trace_irq_handler_entry(irq, action);
145 res = action->handler(irq, action->dev_id);
146 trace_irq_handler_exit(irq, action, res);
147
182 }
这个handler就是就用request_irq时候的第二个参数。
144 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
145 const char *name, void *dev)
146 {
147 return request_threaded_irq(irq, handler, NULL, flags, name, dev);
148 }
哈哈终于调到自己注册的函数了
相关文章
- 性能分析之排队论简述三
- Apache Spark源码走读之3 -- Task运行期之函数调用关系分析
- Android源码面试宝典之JobScheduler从使用到原理分析(一)【JobScheduler的使用】
- Android源码分析之SharedPreferences
- 前端性能精进之优化方法论(二)——分析
- Java源码分析之String
- 必应词典手机版(IOS版)与有道词典(IOS版)之问卷分析
- 公主连结衣之咲璃乃值不值得培养 衣之咲璃乃强度分析
- RESTful源码笔记之RESTful Framework的APIview, Viewset总结分析
- Appium Android Bootstrap源码分析之启动运行