desc结构
中断描述符irq_desc的定义如下:
46 struct irq_desc {
47 struct irq_common_data irq_common_data;
48 struct irq_data irq_data;
49 unsigned int __percpu *kstat_irqs;
50 irq_flow_handler_t handle_irq;
51 #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
52 irq_preflow_handler_t preflow_handler;
53 #endif
54 struct irqaction *action; /* IRQ action list */
55 unsigned int status_use_accessors;
56 unsigned int core_internal_state__do_not_mess_with_it;
57 unsigned int depth; /* nested irq disables */
58 unsigned int wake_depth; /* nested wake enables */
59 unsigned int irq_count; /* For detecting broken IRQs */
60 unsigned long last_unhandled; /* Aging timer for unhandled count */
61 unsigned int irqs_unhandled;
62 atomic_t threads_handled;
63 int threads_handled_last;
64 raw_spinlock_t lock;
65 struct cpumask *percpu_enabled;
66 #ifdef CONFIG_SMP
67 const struct cpumask *affinity_hint;
68 struct irq_affinity_notify *affinity_notify;
69 #ifdef CONFIG_GENERIC_PENDING_IRQ
70 cpumask_var_t pending_mask;
71 #endif
72 #endif
73 unsigned long threads_oneshot;
74 atomic_t threads_active;
75 wait_queue_head_t wait_for_threads;
76 #ifdef CONFIG_PM_SLEEP
77 unsigned int nr_actions;
78 unsigned int no_suspend_depth;
79 unsigned int cond_suspend_depth;
80 unsigned int force_resume_depth;
81 #endif
82 #ifdef CONFIG_PROC_FS
83 struct proc_dir_entry *dir;
84 #endif
85 int parent_irq;
86 struct module *owner;
87 const char *name;
88 } ____cacheline_internodealigned_in_smp;
结构体中有个成员handle_irq和action。
handle_irq: handle_irq就是highlevel irq-events handler,何谓high level?站在高处自然看不到细节。我认为high level是和specific相对,specific handler处理具体的事务,例如处理一个按键中断、处理一个磁盘中断。而high level则是对处理各种中断交互过程的一个抽象
action: action中的handle进行具体的事务处理。action指向一个struct irqaction的链表。如果一个interrupt request line允许共享,那么该链表中的成员可以是多个,否则,该链表只有一个节点
中断生命周期
vector_irq()->vector_irq()->__irq_svc()
->svc_entry()--------------------------------------------------------------------------保护中断现场
->irq_handler()->gic_handle_irq()------------------------------------------------具体到GIC中断控制器对应的就是gic_handle_irq(),此处从架构相关进入了GIC相关处理。
->GIC_CPU_INTACK--------------------------------------------------------------读取IAR寄存器,响应中断。
->handle_domain_irq()
->irq_enter()------------------------------------------------------------------------进入硬中断上下文
->generic_handle_irq()
->generic_handle_irq_desc()->handle_fasteoi_irq()--------------------根据中断号分辨不同类型的中断,对应不同处理函数,这里中断号取大于等于32。
->handle_irq_event()->handle_irq_event_percpu()
->action->handler()-----------------------------------------------------------对应到特定中断的处理函数,即上半部。
->__irq_wake_thread()-----------------------------------------------------如果中断函数处理返回IRQ_WAKE_THREAD,则唤醒中断线程进行处理,但不是立即执行中断线程。
->irq_exit()---------------------------------------------------------------------------退出硬中断上下文。视情况处理软中断。
->invoke_softirq()-----------------------------------------------------------------处理软中断,超出一定条件任务就会交给软中断线程处理。
->GIC_CPU_EOI--------------------------------------------------------------------写EOI寄存器,表示结束中断。至此GIC才会接收新的硬件中断,此前一直是屏蔽硬件中断的。
->svc_exit-------------------------------------------------------------------------------恢复中断现场
handle_irq和action赋值
handle_irq的赋值
irq_create_fwspec_mapping
----->irq_domain_alloc_irqs
------>__irq_domain_alloc_irqs
------>irq_domain_alloc_irqs_recursive
- irq_domain_alloc_irqs_recursive
主要工作是在1138行调用domain->ops->alloc函数,因为domain是GIC,则调用gic_irq_domain_alloc
1128 static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
1129 unsigned int irq_base,
1130 unsigned int nr_irqs, void *arg)
1131 {
1132 int ret = 0;
1133 struct irq_domain *parent = domain->parent;
1134 bool recursive = irq_domain_is_auto_recursive(domain);
1135
1136 BUG_ON(recursive && !parent);
1137 if (recursive)
1138 ret = irq_domain_alloc_irqs_recursive(parent, irq_base,
1139 nr_irqs, arg);
1140 if (ret >= 0)
1141 ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg);
1142 if (ret < 0 && recursive)
1143 irq_domain_free_irqs_recursive(parent, irq_base, nr_irqs);
1144
1145 return ret;
1146 }
- gic_irq_domain_alloc
1014 static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
1015 unsigned int nr_irqs, void *arg)
1016 {
1017 int i, ret;
1018 irq_hw_number_t hwirq;
1019 unsigned int type = IRQ_TYPE_NONE;
1020 struct irq_fwspec *fwspec = arg;
1021
1022 ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type);
1023 if (ret)
1024 return ret;
1025
1026 for (i = 0; i < nr_irqs; i++)
1027 gic_irq_domain_map(domain, virq + i, hwirq + i);
1028
1029 return 0;
1030 }
在1027行调用gic_irq_domain_map函数。
3. gic_irq_domain_map
933 static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
934 irq_hw_number_t hw)
935 {
936 struct irq_chip *chip = &gic_chip;
937
938 if (static_key_true(&supports_deactivate)) {
939 if (d->host_data == (void *)&gic_data[0])
940 chip = &gic_eoimode1_chip;
941 }
942
943 if (hw < 32) {
944 irq_set_percpu_devid(irq);
945 irq_domain_set_info(d, irq, hw, chip, d->host_data,
946 handle_percpu_devid_irq, NULL, NULL);
947 irq_set_status_flags(irq, IRQ_NOAUTOEN);
948 } else {
949 irq_domain_set_info(d, irq, hw, chip, d->host_data,
950 handle_fasteoi_irq, NULL, NULL);
951 irq_set_probe(irq);
952 }
953 return 0;
954 }
在949行调用irq_domain_set_info函数,把handle_fasteoi_irq赋值给irq对应的desc中的handle_irq。
4. irq_domain_set_info
1052 void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
1053 irq_hw_number_t hwirq, struct irq_chip *chip,
1054 void *chip_data, irq_flow_handler_t handler,
1055 void *handler_data, const char *handler_name)
1056 {
1057 irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
1058 __irq_set_handler(virq, handler, 0, handler_name);
1059 irq_set_handler_data(virq, handler_data);
1060 }
5. __irq_set_handler
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 }
6. __irq_do_set_handler
733 void
734 __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
735 int is_chained, const char *name)
736 {
737 if (!handle) {
738 handle = handle_bad_irq;
739 } else {
740 struct irq_data *irq_data = &desc->irq_data;
741 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
742 /*
743 * With hierarchical domains we might run into a
744 * situation where the outermost chip is not yet set
745 * up, but the inner chips are there. Instead of
746 * bailing we install the handler, but obviously we
747 * cannot enable/startup the interrupt at this point.
748 */
749 while (irq_data) {
750 if (irq_data->chip != &no_irq_chip)
751 break;
752 /*
753 * Bail out if the outer chip is not set up
754 * and the interrrupt supposed to be started
755 * right away.
756 */
757 if (WARN_ON(is_chained))
758 return;
759 /* Try the parent */
760 irq_data = irq_data->parent_data;
761 }
762 #endif
763 if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
764 return;
765 }
766
767 /* Uninstall? */
768 if (handle == handle_bad_irq) {
769 if (desc->irq_data.chip != &no_irq_chip)
770 mask_ack_irq(desc);
771 irq_state_set_disabled(desc);
772 if (is_chained)
773 desc->action = NULL;
774 desc->depth = 1;
775 }
776 desc->handle_irq = handle;
777 desc->name = name;
778
779 if (handle != handle_bad_irq && is_chained) {
780 irq_settings_set_noprobe(desc);
781 irq_settings_set_norequest(desc);
782 irq_settings_set_nothread(desc);
783 desc->action = &chained_action;
784 irq_startup(desc, true);
785 }
786 }
action赋值
以串口节点为例子:
drivers/tty/serial/amba-pl011.c
pl011_startup
------>pl011_allocate_irq
pl011_allocate_irq
1586 static int pl011_allocate_irq(struct uart_amba_port *uap)
1587 {
1588 writew(uap->im, uap->port.membase + UART011_IMSC);
1590
1591 return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
1592 }
request_irq
133 static inline int __must_check
134 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
135 const char *name, void *dev)
136 {
137 return request_threaded_irq(irq, handler, NULL, flags, name, dev);
138 }
request_threaded_irq
1617 int request_threaded_irq(unsigned int irq, irq_handler_t handler,
1618 irq_handler_t thread_fn, unsigned long irqflags,
1619 const char *devname, void *dev_id)
1620 {
1621 struct irqaction *action;
1622 struct irq_desc *desc;
1623 int retval;
1624
1625 /*
1626 * Sanity-check: shared interrupts must pass in a real dev-ID,
1627 * otherwise we'll have trouble later trying to figure out
1628 * which interrupt is which (messes up the interrupt freeing
1629 * logic etc).
1630 *
1631 * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and
1632 * it cannot be set along with IRQF_NO_SUSPEND.
1633 */
1634 if (((irqflags & IRQF_SHARED) && !dev_id) ||
1635 (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||
1636 ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))
1637 return -EINVAL;
1638
1639 desc = irq_to_desc(irq);
1640 if (!desc)
1641 return -EINVAL;
1642
1643 if (!irq_settings_can_request(desc) ||
1644 WARN_ON(irq_settings_is_per_cpu_devid(desc)))
1645 return -EINVAL;
1646
1647 if (!handler) {
1648 if (!thread_fn)
1649 return -EINVAL;
1650 handler = irq_default_primary_handler;
1651 }
1652
1653 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
1654 if (!action)
1655 return -ENOMEM;
1656
1657 action->handler = handler;
1658 action->thread_fn = thread_fn;
1659 action->flags = irqflags;
1660 action->name = devname;
1661 action->dev_id = dev_id;
1662
1663 chip_bus_lock(desc);
1664 retval = __setup_irq(irq, desc, action);
1665 chip_bus_sync_unlock(desc);
1666
1667 if (retval) {
1668 kfree(action->secondary);
1669 kfree(action);
1670 }
1671
1672 #ifdef CONFIG_DEBUG_SHIRQ_FIXME
1673 if (!retval && (irqflags & IRQF_SHARED)) {
1674 /*
1675 * It's a shared IRQ -- the driver ought to be prepared for it
1676 * to happen immediately, so let's make sure....
1677 * We disable the irq to make sure that a 'real' IRQ doesn't
1678 * run in parallel with our fake.
1679 */
1680 unsigned long flags;
1681
1682 disable_irq(irq);
1683 local_irq_save(flags);
1684
1685 handler(irq, dev_id);
1686
1687 local_irq_restore(flags);
1688 enable_irq(irq);
1689 }
1690 #endif
1691 return retval;
1692 }
在1664行使用__setup_irq把这个函数存放到irq对应的desc函数的action链表中。