175struct irq_desc { 176 unsigned int irq; 177 struct timer_rand_state *timer_rand_state; 178 unsigned int *kstat_irqs; 179#ifdef CONFIG_INTR_REMAP 180 struct irq_2_iommu *irq_2_iommu; 181#endif 182 irq_flow_handler_t handle_irq; 183 struct irq_chip *chip; 184 struct msi_desc *msi_desc; 185 void *handler_data; 186 void *chip_data; 187 struct irqaction *action; /* IRQ action list */ 188 unsigned int status; /* IRQ status */ 189 190 unsigned int depth; /* nested irq disables */ 191 unsigned int wake_depth; /* nested wake enables */ 192 unsigned int irq_count; /* For detecting broken IRQs */ 193 unsigned long last_unhandled; /* Aging timer for unhandled count */ 194 unsigned int irqs_unhandled; 195 raw_spinlock_t lock; 196#ifdef CONFIG_SMP 197 cpumask_var_t affinity; 198 const struct cpumask *affinity_hint; 199 unsigned int node; 200#ifdef CONFIG_GENERIC_PENDING_IRQ 201 cpumask_var_t pending_mask; 202#endif 203#endif 204 atomic_t threads_active; 205 wait_queue_head_t wait_for_threads; 206#ifdef CONFIG_PROC_FS 207 struct proc_dir_entry *dir; 208#endif 209 const char *name; 210} ____cacheline_internodealigned_in_smp; 211 212extern void arch_init_copy_chip_data(struct irq_desc *old_desc, 213 struct irq_desc *desc, int node); 214extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc); 215 216#ifndef CONFIG_SPARSE_IRQ 217extern struct irq_desc irq_desc[NR_IRQS]; 175struct irq_desc { 176 unsigned int irq; 177 struct timer_rand_state *timer_rand_state; 178 unsigned int *kstat_irqs; 179#ifdef CONFIG_INTR_REMAP 180 struct irq_2_iommu *irq_2_iommu; 181#endif 182 irq_flow_handler_t handle_irq; 183 struct irq_chip *chip; 184 struct msi_desc *msi_desc; 185 void *handler_data; 186 void *chip_data; 187 struct irqaction *action; /* IRQ action list */ 188 unsigned int status; /* IRQ status */ 189 190 unsigned int depth; /* nested irq disables */ 191 unsigned int wake_depth; /* nested wake enables */ 192 unsigned int irq_count; /* For detecting broken IRQs */ 193 unsigned long last_unhandled; /* Aging timer for unhandled count */ 194 unsigned int irqs_unhandled; 195 raw_spinlock_t lock; 196#ifdef CONFIG_SMP 197 cpumask_var_t affinity; 198 const struct cpumask *affinity_hint; 199 unsigned int node; 200#ifdef CONFIG_GENERIC_PENDING_IRQ 201 cpumask_var_t pending_mask; 202#endif 203#endif 204 atomic_t threads_active; 205 wait_queue_head_t wait_for_threads; 206#ifdef CONFIG_PROC_FS 207 struct proc_dir_entry *dir; 208#endif 209 const char *name; 210} ____cacheline_internodealigned_in_smp; 211 212extern void arch_init_copy_chip_data(struct irq_desc *old_desc, 213 struct irq_desc *desc, int node); 214extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc); 215 216#ifndef CONFIG_SPARSE_IRQ 217extern struct irq_desc irq_desc[NR_IRQS]; 1>irq:表示这个描述符所对应的中断号。 2>handle_irq:指向该IRQ线的公共服务程序(即该IRQ所对应的中断处理程序。 3>chip:它是一个struct irq_chip类型的指针,是中断控制器的描述符 。在2.6以前的版本中它是hw_irq_controller。 4>handler_data:是handler_irq的参数。 5>chip_data:是指向irq_chip的指针。 6>atcion:一个struct irqaction类型的指针,它指向一个单链表。该链表是由该中断线上所有中断服务例程链接起来的。 7>status:表示中断线当前的状态。 8>depth:中断线被激活时,值为0;当值为正数时,表示被禁止的次数。 9>irq_count:表示该中断线上发生中断的次数 10>irqs_unhandled:该IRQ线上未处理中断发生的次数 11>name:申请中断设备的名字。 C.struct irq_chip结构体: struct irq_chip是一个中断控制器的描述符。Linux支持N种可编程中断控制器PIC(中断控制器),通常不同的体系结构就有一套自己的中断处理方式。内核为了统一的处理中断,提供了底层的中断处理抽象接口,对于每个平台都需要实现底层的接口函数。这样对于上层的中断通用处理程序就无需任何改动。 struct irq_chip的具体代码如下: 111struct irq_chip { 112 const char *name; 113 unsigned int (*startup)(unsigned int irq); 114 void (*shutdown)(unsigned int irq); 115 void (*enable)(unsigned int irq); 116 void (*disable)(unsigned int irq); 117 118 void (*ack)(unsigned int irq); 119 void (*mask)(unsigned int irq); 120 void (*mask_ack)(unsigned int irq); 121 void (*unmask)(unsigned int irq); 122 void (*eoi)(unsigned int irq); 123 124 void (*end)(unsigned int irq); 125 int (*set_affinity)(unsigned int irq, 126 const struct cpumask *dest); 127 int (*retrigger)(unsigned int irq); 128 int (*set_type)(unsigned int irq, unsigned int flow_type); 129 int (*set_wake)(unsigned int irq, unsigned int on); 130 131 void (*bus_lock)(unsigned int irq); 132 void (*bus_sync_unlock)(unsigned int irq); 133 134 /* Currently used only by UML, might disappear one day.*/ 135#ifdef CONFIG_IRQ_RELEASE_METHOD 136 void (*release)(unsigned int irq, void *dev_id); 137#endif 138 /* 139 * For compatibility, ->typename is copied into ->name. 140 * Will disappear. 141 */ 142 const char *typename; 143}; 144 111struct irq_chip { 112 const char *name; 113 unsigned int (*startup)(unsigned int irq); 114 void (*shutdown)(unsigned int irq); 115 void (*enable)(unsigned int irq); 116 void (*disable)(unsigned int irq); 117 118 void (*ack)(unsigned int irq); 119 void (*mask)(unsigned int irq); 120 void (*mask_ack)(unsigned int irq); 121 void (*unmask)(unsigned int irq); 122 void (*eoi)(unsigned int irq); 123 124 void (*end)(unsigned int irq); 125 int (*set_affinity)(unsigned int irq, 126 const struct cpumask *dest); 127 int (*retrigger)(unsigned int irq); 128 int (*set_type)(unsigned int irq, unsigned int flow_type); 129 int (*set_wake)(unsigned int irq, unsigned int on); 130 131 void (*bus_lock)(unsigned int irq); 132 void (*bus_sync_unlock)(unsigned int irq); 133 134 /* Currently used only by UML, might disappear one day.*/ 135#ifdef CONFIG_IRQ_RELEASE_METHOD 136 void (*release)(unsigned int irq, void *dev_id); 137#endif 138 /* 139 * For compatibility, ->typename is copied into ->name. 140 * Will disappear. 141 */ 142 const char *typename; 143}; 144
name:中断控制器的名字; Startup:启动中断线; Shutdown:关闭中断线; Enable:允许中断; Disable:禁止中断; 分析了struct irq_desc,struct irq_chip和irqaction的数据结构之后我们来看看他们之间的关系 。 现在深入分析request_irq()内部是如何实现的。 135request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 136 const char *name, void *dev) 137{ 138 return request_threaded_irq(irq, handler, NULL, flags, name, dev); 139} 140 135request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 136 const char *name, void *dev) 137{ 138 return request_threaded_irq(irq, handler, NULL, flags, name, dev); 139} 140 可以看到request_irq()函数里面有封装了request_threaded_irq(irq, handler, NULL, flags, name, dev)函数。 先看一下官方的解释 1006/** 1007 * request_threaded_irq - allocate an interrupt line 1008 * @irq: Interrupt line to allocate 1009 * @handler: Function to be called when the IRQ occurs. 1010 * Primary handler for threaded interrupts 1011 * If NULL and thread_fn != NULL the default 1012 * primary handler is installed 1013 * @thread_fn: Function called from the irq handler thread 1014 * If NULL, no irq thread is created 1015 * @irqflags: Interrupt type flags 1016 * @devname: An ascii name for the claiming device 1017 * @dev_id: A cookie passed back to the handler function 1018 * 1019 * This call allocates interrupt resources and enables the 1020 * interrupt line and IRQ handling. From the point this 1021 * call is made your handler function may be invoked. Since 1022 * your handler function must clear any interrupt the board 1023 * raises, you must take care both to initialise your hardware 1024 * and to set up the interrupt handler in the right order. 1025 * 1026 * If you want to set up a threaded irq handler for your device 1027 * then you need to supply @handler and @thread_fn. @handler ist 1028 * still called in hard interrupt context and has to check 1029 * whether the interrupt originates from the device. If yes it 1030 * needs to disable the interrupt on the device and return 1031 * IRQ_WAKE_THREAD which will wake up the handler thread and run 1032 * @thread_fn. This split handler design is necessary to support 1033 * shared interrupts. 1034 * 1035 * Dev_id must be globally unique. Normally the address of the 1036 * device data structure is used as the cookie. Since the handler 1037 * receives this value it makes sense to use it. 1038 * 1039 * If your interrupt is shared you must pass a non NULL dev_id 1040 * as this is required when freeing the interrupt. 1041 * 1042 * Flags: 1043 * 1044 * IRQF_SHARED Interrupt is shared 1045 * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy 1046 * IRQF_TRIGGER_* Specify active edge(s) or level 1047 * 1048 */ 1006/** 1007 * request_threaded_irq - allocate an interrupt line 1008 * @irq: Interrupt line to allocate 1009 * @handler: Function to be called when the IRQ occurs. 1010 * Primary handler for threaded interrupts 1011 * If NULL and thread_fn != NULL the default 1012 * primary handler is installed 1013 * @thread_fn: Function called from the irq handler thread 1014 * If NULL, no irq thread is created 1015 * @irqflags: Interrupt type flags 1016 * @devname: An ascii name for the claiming device 1017 * @dev_id: A cookie passed back to the handler function 1018 * 1019 * This call allocates interrupt resources and enables the 1020 * interrupt line and IRQ handling. From the point this 1021 * call is made your handler function may be invoked. Since 1022 * your handler function must clear any interrupt the board 1023 * raises, you must take care both to initialise your hardware 1024 * and to set up the interrupt handler in the right order. 1025 * 1026 * If you want to set up a threaded irq handler for your device 1027 * then you need to supply @handler and @thread_fn. @handler ist 1028 * still called in hard interrupt context and has to check 1029 * whether the interrupt originates from the device. If yes it 1030 * needs to disable the interrupt on the device and return 1031 * IRQ_WAKE_THREAD which will wake up the handler thread and run 1032 * @thread_fn. This split handler design is necessary to support 1033 * shared interrupts. 1034 * 1035 * Dev_id must be globally unique. Normally the address of the 1036 * device data structure is used as the cookie. Since the handler 1037 * receives this value it makes sense to use it. 1038 * 1039 * If your interrupt is shared you must pass a non NULL dev_id 1040 * as this is required when freeing the interrupt. 1041 * 1042 * Flags: 1043 * 1044 * IRQF_SHARED Interrupt is shared 1045 * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy 1046 * IRQF_TRIGGER_* Specify active edge(s) or level 1047 * 1048 */ 5.首先分析request_threaded_irq()函数中的各个形参 1>:irq:表示申请的中断号。 2>:handler:表示中断服务例程 3.> thread_fn:中断线程化,此处传递的是NULL。NULL表示没有中断线程化。 此参数是最新版本中才出现的。为什么要提出中断线程化? 在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断 处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不 到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以 有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍 有实时性保证。but,并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器 等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当 被线程化。 4>.irqflags:表示中断标志位。 5>.devname:表示请求中断的设备的名称。 6>.dev_id: 对应于request_irq()函数中所传递的第五个参数,可取任意值,但必须唯一能够代表发出中断请求的设备,通常取描述该设备的结构体。 共享中断时所用。 现在继续迭代深入 request_threaded_irq()内部是如何实现的。 1049int request_threaded_irq(unsigned int irq, irq_handler_t handler, 1050 irq_handler_t thread_fn, unsigned long irqflags, 1051 const char *devname, void *dev_id) 1052{ 1053 struct irqaction *action; 1054 struct irq_desc *desc; 1055 int retval; 1056 1057 /* 1058 * Sanity-check: shared interrupts must pass in a real dev-ID, 1059 * otherwise we"ll have trouble later trying to figure out 1060 * which interrupt is which (messes up the interrupt freeing 1061 * logic etc). 1062 */ 1063 if ((irqflags & IRQF_SHARED) && !dev_id) 1064 return -EINVAL; 1065 1066 desc = irq_to_desc(irq); 1067 if (!desc) 1068 return -EINVAL; 1069 1070 if (desc->status & IRQ_NOREQUEST) 1071 return -EINVAL; 1072 1073 if (!handler) { 1074 if (!thread_fn) 1075 return -EINVAL; 1076 handler = irq_default_primary_handler; 1077 } 1078 1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); 1080 if (!action) 1081 return -ENOMEM; 1082 1083 action->handler = handler; 1084 action->thread_fn = thread_fn; 1085 action->flags = irqflags; 1086 action->name = devname; 1087 action->dev_id = dev_id; 1088 1089 chip_bus_lock(irq, desc); 1090 retval = __setup_irq(irq, desc, action); 1091 chip_bus_sync_unlock(irq, desc); 1092 1093 if (retval) 1094 kfree(action); 1095 1096#ifdef CONFIG_DEBUG_SHIRQ 1097 if (!retval && (irqflags & IRQF_SHARED)) { 1098 /* 1099 * It"s a shared IRQ -- the driver ought to be prepared for it 1100 * to happen immediately, so let"s make sure.... 1101 * We disable the irq to make sure that a "real" IRQ doesn"t 1102 * run in parallel with our fake. 1103 */ 1104 unsigned long flags; 1105 1106 disable_irq(irq); 1107 local_irq_save(flags); 1108 1109 handler(irq, dev_id); 1110 1111 local_irq_restore(flags); 1112 enable_irq(irq); 1113 } 1114#endif 1115 return retval; 1116} 1049int request_threaded_irq(unsigned int irq, irq_handler_t handler, 1050 irq_handler_t thread_fn, unsigned long irqflags, 1051 const char *devname, void *dev_id) 1052{ 1053 struct irqaction *action; 1054 struct irq_desc *desc; 1055 int retval; 1056 1057 /* 1058 * Sanity-check: shared interrupts must pass in a real dev-ID, 1059 * otherwise we"ll have trouble later trying to figure out 1060 * which interrupt is which (messes up the interrupt freeing 1061 * logic etc). 1062 */ 1063 if ((irqflags & IRQF_SHARED) && !dev_id) 1064 return -EINVAL; 1065 1066 desc = irq_to_desc(irq); 1067 if (!desc) 1068 return -EINVAL; 1069 1070 if (desc->status & IRQ_NOREQUEST) 1071 return -EINVAL; 1072 1073 if (!handler) { 1074 if (!thread_fn) 1075 return -EINVAL; 1076 handler = irq_default_primary_handler; 1077 } 1078 1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); 1080 if (!action) 1081 return -ENOMEM; 1082 1083 action->handler = handler; 1084 action->thread_fn = thread_fn; 1085 action->flags = irqflags; 1086 action->name = devname; 1087 action->dev_id = dev_id; 1088 1089 chip_bus_lock(irq, desc); 1090 retval = __setup_irq(irq, desc, action); 1091 chip_bus_sync_unlock(irq, desc); 1092 1093 if (retval) 1094 kfree(action); 1095 1096#ifdef CONFIG_DEBUG_SHIRQ 1097 if (!retval && (irqflags & IRQF_SHARED)) { 1098 /* 1099 * It"s a shared IRQ -- the driver ought to be prepared for it 1100 * to happen immediately, so let"s make sure.... 1101 * We disable the irq to make sure that a "real" IRQ doesn"t 1102 * run in parallel with our fake. 1103 */ 1104 unsigned long flags; 1105 1106 disable_irq(irq); 1107 local_irq_save(flags); 1108 1109 handler(irq, dev_id); 1110 1111 local_irq_restore(flags); 1112 enable_irq(irq); 1113 } 1114#endif 1115 return retval; 1116} 程序的第一行和第二行分别定义了: (1) struct irqaction *action; (2)2struct irq_desc *desc; 两个指针action和desc,它们分别指向了结构体irqaction和 irq_desc。 (3) if ((irqflags & IRQF_SHARED) && !dev_id) return -EINVAL; 作用是:判断中断标志位,如果是共享中断的话就必须要有一个唯一的dev_id,否则返回一个错误。 (4) desc = irq_to_desc(irq); irq_to_desc(irq):根据中断号irq在 irq_desc[NR_IRQS]数组中 返回一个具体的irq_desc。即根据irq找到它的中断处理程序。 (5) if (!desc) return -EINVAL; 当返回一个空值时返回一个错误。说明申请中断号失败。 (6)if (desc->status & IRQ_NOREQUEST) return -EINVAL; 判断中断线的状态,若为IRQ_NOREQUEST时( IRQ_NOREQUEST表示 IRQ 不能被申请) (7) if (!handler) { if (!thread_fn) return -EINVAL; handler = irq_default_primary_handler; } 判断中断服务例程是否为空,如果handler为空,则判断线程中断服务例程,若线程中断服务例程也为空,则返回一个错误值。否则中断服务例程指向: rq_default_primary_handler。 (8) 1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); 1080 if (!action) 1081 return -ENOMEM; 1082 1083 action->handler = handler; 1084 action->thread_fn = thread_fn; 1085 action->flags = irqflags; 1086 action->name = devname; 1087 action->dev_id = dev_id; 从1079~1087:根据requst_irq()函数中传递的参数生成一个irqaction. 1097 if (!retval && (irqflags & IRQF_SHARED)) { 1098 /* 1099 * It"s a shared IRQ -- the driver ought to be prepared for it 1100 * to happen immediately, so let"s make sure.... 1101 * We disable the irq to make sure that a "real" IRQ doesn"t 1102 * run in parallel with our fake. 1103 */ 1104 unsigned long flags; 1105 1106 disable_irq(irq); 1107 local_irq_save(flags); 1108 1109 handler(irq, dev_id); 1110 1111 local_irq_restore(flags); 1112 enable_irq(irq); 1113 } 1097~1113:如果为共享中断的话,在执行中断服务例程之前,要先把这条中断线上的中断屏蔽,让后在执行,执行完之