linux 中断处理(基于linux-3.7.2 arm linux)

所有中断入口都是由异常向量,再到中断向量的
汇编到C的中断入口asm_do_IRQ

arch/arm/kernel/irq.c
 86 /*
 87  * asm_do_IRQ is the interface to be used from assembly code.
 88  */
 89 asmlinkage void __exception_irq_entry
 90 asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
 91 {
 92         handle_IRQ(irq, regs);
 93 }
 在同一文件中
 58 /*
 59  * handle_IRQ handles all hardware IRQ's.  Decoded IRQs should
 60  * not come via this function.  Instead, they should provide their
 61  * own 'handler'.  Used by platform code implementing C-based 1st
 62  * level decoding.
 63  */
 64 void handle_IRQ(unsigned int irq, struct pt_regs *regs)
 65 {
 66         struct pt_regs *old_regs = set_irq_regs(regs);
 67
 68         irq_enter();
 69
 70         /*
 71          * Some hardware gives randomly wrong interrupts.  Rather
 72          * than crashing, do something sensible.
 73          */
 74         if (unlikely(irq >= nr_irqs)) {
 75                 if (printk_ratelimit())
 76                         printk(KERN_WARNING "Bad IRQ%u\n", irq);
 77                 ack_bad_irq(irq);
 78         } else {
 79                 generic_handle_irq(irq);
 80         }
 81
 82         irq_exit();
 83         set_irq_regs(old_regs);
 84 }
可以看到调用了handle_IRQ后又调用了generic_handle_irq(irq);
kernel/irq/irqdesc.c
303 /**
304  * generic_handle_irq - Invoke the handler for a particular irq
305  * @irq:        The irq number to handle
306  *
307  */
308 int generic_handle_irq(unsigned int irq)
309 {
310         struct irq_desc *desc = irq_to_desc(irq);
311
312         if (!desc)
313                 return -EINVAL;
314         generic_handle_irq_desc(irq, desc);
315         return 0;
316 }
317 EXPORT_SYMBOL_GPL(generic_handle_irq);

include/linux/irqdesc.h
/*
 * Architectures call this to let the generic IRQ layer
 * handle an interrupt. If the descriptor is attached to an
 * irqchip-style controller then we call the ->handle_irq() handler,
 * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
 */
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
        desc->handle_irq(irq, desc);
}
是通过irq_desc 结构体的handle_irq函数调用的,这个函数应该在哪里注册才对

中断初始化
115 void __init init_IRQ(void)
116 {
117         machine_desc->init_irq();
118 }

异常向量表
arch/arm/kernel/entry-armv.S
1163         .globl  __vectors_start
1164 __vectors_start:
1165  ARM(   swi     SYS_ERROR0      )
1166  THUMB( svc     #0              )
1167  THUMB( nop                     )
1168         W(b)    vector_und + stubs_offset
1169         W(ldr)  pc, .LCvswi + stubs_offset
1170         W(b)    vector_pabt + stubs_offset
1171         W(b)    vector_dabt + stubs_offset
1172         W(b)    vector_addrexcptn + stubs_offset
1173         W(b)    vector_irq + stubs_offset
1174         W(b)    vector_fiq + stubs_offset
中断向量的拷贝
arch/arm/kernel/traps.c
820 void __init early_trap_init(void *vectors_base)
821 {
822         unsigned long vectors = (unsigned long)vectors_base;
823         extern char __stubs_start[], __stubs_end[];
824         extern char __vectors_start[], __vectors_end[];
825         extern char __kuser_helper_start[], __kuser_helper_end[];
826         int kuser_sz = __kuser_helper_end - __kuser_helper_start;
827
828         vectors_page = vectors_base;
829
830         /*
831          * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
832          * into the vector page, mapped at 0xffff0000, and ensure these
833          * are visible to the instruction stream.
834          */
835         memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
836         memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
837         memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
838
839         /*
840          * Do processor specific fixups for the kuser helpers
841          */
842         kuser_get_tls_init(vectors);
843
844         /*
845          * Copy signal return handlers into the vector page, and
846          * set sigreturn to be a pointer to these.
847          */
848         memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
849                sigreturn_codes, sizeof(sigreturn_codes));
850
851         flush_icache_range(vectors, vectors + PAGE_SIZE);
852         modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
853 }


arch/arm/mm/mmu.c
1085 /*
1086  * Set up the device mappings.  Since we clear out the page tables for all
1087  * mappings above VMALLOC_START, we will remove any debug device mappings.
1088  * This means you have to be careful how you debug this function, or any
1089  * called function.  This means you can't use any function or debugging
1090  * method which may touch any device, otherwise the kernel _will_ crash.
1091  */
1092 static void __init devicemaps_init(struct machine_desc *mdesc)
1093 {
1094         struct map_desc map;
1095         unsigned long addr;
1096         void *vectors;
1097
1098         /*
1099          * Allocate the vector page early.
1100          */
1101         vectors = early_alloc(PAGE_SIZE);
1102
1103         early_trap_init(vectors);
…………
由这里调用early_trap_init
在同一文件中paging_init调用 devicemaps_init
1207 /*
1208  * paging_init() sets up the page tables, initialises the zone memory
1209  * maps, and sets up the zero page, bad page and bad page tables.
1210  */
1211 void __init paging_init(struct machine_desc *mdesc)
1212 {
1213         void *zero_page;
1214
1215         memblock_set_current_limit(arm_lowmem_limit);
1216
1217         build_mem_type_table();
1218         prepare_page_table();
1219         map_lowmem();
1220         dma_contiguous_remap();
1221         devicemaps_init(mdesc);
1222         kmap_init();
1223
1224         top_pmd = pmd_off_k(0xffff0000);
1225
1226         /* allocate the zero page. */
1227         zero_page = early_alloc(PAGE_SIZE);
1228
1229         bootmem_init();
1230
1231         empty_zero_page = virt_to_page(zero_page);
1232         __flush_dcache_page(NULL, empty_zero_page);
1233 }

arch/arm/kernel/setup.c
722 void __init setup_arch(char **cmdline_p)
723 {
724         struct machine_desc *mdesc;
725
726         setup_processor();
727         mdesc = setup_machine_fdt(__atags_pointer);
728         if (!mdesc)
729                 mdesc = setup_machine_tags(__atags_pointer, machine_arch_type);
730         machine_desc = mdesc;
731         machine_name = mdesc->name;
732
733         setup_dma_zone(mdesc);
734
735         if (mdesc->restart_mode)
736                 reboot_setup(&mdesc->restart_mode);
737
738         init_mm.start_code = (unsigned long) _text;
739         init_mm.end_code   = (unsigned long) _etext;
740         init_mm.end_data   = (unsigned long) _edata;
741         init_mm.brk        = (unsigned long) _end;
742
743         /* populate cmd_line too for later use, preserving boot_command_line */
744         strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
745         *cmdline_p = cmd_line;
746
747         parse_early_param();
748
749         sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
750         sanity_check_meminfo();
751         arm_memblock_init(&meminfo, mdesc);
752
753         paging_init(mdesc);  
在setup_arch调用了 paging_init

setup_arch由start_kernel调用
init/main.c
468 asmlinkage void __init start_kernel(void)
469 {
……
499         setup_arch(&command_line);
…………
}


include/linux/interrupt.h
中断注册函数
129 static inline int __must_check
130 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
131             const char *name, void *dev)
132 {
133         return request_threaded_irq(irq, handler, NULL, flags, name, dev);
134 }
kernel/irq/manage.c
1376 int request_threaded_irq(unsigned int irq, irq_handler_t handler,
1377                          irq_handler_t thread_fn, unsigned long irqflags,
1378                          const char *devname, void *dev_id)
1379 {
1380         struct irqaction *action;
1381         struct irq_desc *desc;
1382         int retval;
1383
1384         /*
1385          * Sanity-check: shared interrupts must pass in a real dev-ID,
1386          * otherwise we'll have trouble later trying to figure out
1387          * which interrupt is which (messes up the interrupt freeing
1388          * logic etc).
1389          */
1390         if ((irqflags & IRQF_SHARED) && !dev_id)
1391                 return -EINVAL;
1392
1393         desc = irq_to_desc(irq);
1394         if (!desc)
1395                 return -EINVAL;
1396
1397         if (!irq_settings_can_request(desc) ||
1398             WARN_ON(irq_settings_is_per_cpu_devid(desc)))
1399                 return -EINVAL;
1400
1401         if (!handler) {
1402                 if (!thread_fn)
1403                         return -EINVAL;
1404                 handler = irq_default_primary_handler;
1405         }
1406
1407         action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
1408         if (!action)
1409                 return -ENOMEM;
1410
1411         action->handler = handler;
1412         action->thread_fn = thread_fn;
1413         action->flags = irqflags;
1414         action->name = devname;
1415         action->dev_id = dev_id;
1416
1417         chip_bus_lock(desc);
1418         retval = __setup_irq(irq, desc, action);
1419         chip_bus_sync_unlock(desc);

在这里,将申请的中断与struct irqaction *action;关联
__setup_irq将action与desc中的irq_handler进行关联
111 struct irq_desc *irq_to_desc(unsigned int irq)
112 {
113         return radix_tree_lookup(&irq_desc_tree, irq);
114 }
115 EXPORT_SYMBOL(irq_to_desc);
include/linux/irqnr.h
 14 #define irq_to_desc(irq)        (&irq_desc[irq])
kernel/irq/irqdesc.c
243 struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
244         [0 ... NR_IRQS-1] = {
245                 .handle_irq     = handle_bad_irq,
246                 .depth          = 1,
247                 .lock           = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
248         }
249 };


include/linux/interrupt.h
106 struct irqaction {
107         irq_handler_t           handler;
108         void                    *dev_id;
109         void __percpu           *percpu_dev_id;
110         struct irqaction        *next;
111         irq_handler_t           thread_fn;
112         struct task_struct      *thread;
113         unsigned int            irq;
114         unsigned int            flags;
115         unsigned long           thread_flags;
116         unsigned long           thread_mask;
117         const char              *name;
118         struct proc_dir_entry   *dir;
119 } ____cacheline_internodealigned_in_smp;
这个结构体就是用户中断处理函数关联入的地方
例子:定时器中就是利用setup_irq(irq_number, &s5p_clock_event_irq);函数将用户中断链入
252 static struct irqaction s5p_clock_event_irq = {
253         .name           = "s5p_time_irq",
254         .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
255         .handler        = s5p_clock_event_isr,
256         .dev_id         = &time_event_device,
257 };

 

kernel/irq/chip.c
462 /**
463  *      handle_edge_irq - edge type IRQ handler
464  *      @irq:   the interrupt number
465  *      @desc:  the interrupt description structure for this irq
466  *
467  *      Interrupt occures on the falling and/or rising edge of a hardware
468  *      signal. The occurrence is latched into the irq controller hardware
469  *      and must be acked in order to be reenabled. After the ack another
470  *      interrupt can happen on the same source even before the first one
471  *      is handled by the associated event handler. If this happens it
472  *      might be necessary to disable (mask) the interrupt depending on the
473  *      controller hardware. This requires to reenable the interrupt inside
474  *      of the loop which handles the interrupts which have arrived while
475  *      the handler was running. If all pending interrupts are handled, the
476  *      loop is left.
477  */
478 void
479 handle_edge_irq(unsigned int irq, struct irq_desc *desc)
480 {
…………
519                 handle_irq_event(desc);
…………
359 /**
360  *      handle_level_irq - Level type irq handler
361  *      @irq:   the interrupt number
362  *      @desc:  the interrupt description structure for this irq
363  *
364  *      Level type interrupts are active as long as the hardware line has
365  *      the active level. This may require to mask the interrupt and unmask
366  *      it after the associated handler has acknowledged the device, so the
367  *      interrupt line is back to inactive.
368  */
369 void
370 handle_level_irq(unsigned int irq, struct irq_desc *desc)
371 {
372         raw_spin_lock(&desc->lock);
373         mask_ack_irq(desc);
374
375         if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
376                 if (!irq_check_poll(desc))
377                         goto out_unlock;
378
379         desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
380         kstat_incr_irqs_this_cpu(irq, desc);
381
382         /*
383          * If its disabled or no action available
384          * keep it masked and get out of here
385          */
386         if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
387                 desc->istate |= IRQS_PENDING;
388                 goto out_unlock;
389         }
390
391         handle_irq_event(desc);
392
393         cond_unmask_irq(desc);
394
395 out_unlock:
396         raw_spin_unlock(&desc->lock);
397 }
398 EXPORT_SYMBOL_GPL(handle_level_irq);

kernel/irq/handle.c
182 irqreturn_t handle_irq_event(struct irq_desc *desc)
183 {
184         struct irqaction *action = desc->action;
185         irqreturn_t ret;
186
187         desc->istate &= ~IRQS_PENDING;
188         irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
189         raw_spin_unlock(&desc->lock);
190
191         ret = handle_irq_event_percpu(desc, action);
192
193         raw_spin_lock(&desc->lock);
194         irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
195         return ret;
196 }

kernel/irq/handle.c
132 irqreturn_t
133 handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
134 {
135         irqreturn_t retval = IRQ_NONE;
136         unsigned int flags = 0, irq = desc->irq_data.irq;
137
138         do {
139                 irqreturn_t res;
140
141                 trace_irq_handler_entry(irq, action);
142                 res = action->handler(irq, action->dev_id);
143                 trace_irq_handler_exit(irq, action, res);
144
145                 if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
146                               irq, action->handler))
147                         local_irq_disable();
148
149                 switch (res) {
150                 case IRQ_WAKE_THREAD:
151                         /*
152                          * Catch drivers which return WAKE_THREAD but
153                          * did not set up a thread function
154                          */
155                         if (unlikely(!action->thread_fn)) {
156                                 warn_no_thread(irq, action);
157                                 break;
158                         }
159
160                         irq_wake_thread(desc, action);
161
162                         /* Fall through to add to randomness */
163                 case IRQ_HANDLED:
164                         flags |= action->flags;
165                         break;
166
167                 default:
168                         break;
169                 }
170
171                 retval |= res;
172                 action = action->next;
173         } while (action);
174
最终会调用到142行的res = action->handler(irq, action->dev_id);

include/linux/irqdesc.h
38 struct irq_desc {
 39         struct irq_data         irq_data;
 40         unsigned int __percpu   *kstat_irqs;
 41         irq_flow_handler_t      handle_irq;
 42 #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
 43         irq_preflow_handler_t   preflow_handler;
 44 #endif
 45         struct irqaction        *action;        /* IRQ action list */
 46         unsigned int            status_use_accessors;
 47         unsigned int            core_internal_state__do_not_mess_with_it;
 48         unsigned int            depth;          /* nested irq disables */
 49         unsigned int            wake_depth;     /* nested wake enables */
 50         unsigned int            irq_count;      /* For detecting broken IRQs */
 51         unsigned long           last_unhandled; /* Aging timer for unhandled count */
 52         unsigned int            irqs_unhandled;
 53         raw_spinlock_t          lock;
 54         struct cpumask          *percpu_enabled;
 55 #ifdef CONFIG_SMP
 56         const struct cpumask    *affinity_hint;
 57         struct irq_affinity_notify *affinity_notify;
 58 #ifdef CONFIG_GENERIC_PENDING_IRQ
 59         cpumask_var_t           pending_mask;
 60 #endif
 61 #endif
 62         unsigned long           threads_oneshot;
 63         atomic_t                threads_active;
 64         wait_queue_head_t       wait_for_threads;
 65 #ifdef CONFIG_PROC_FS
 66         struct proc_dir_entry   *dir;
 67 #endif
 68         struct module           *owner;
 69         const char              *name;
 70 } ____cacheline_internodealigned_in_smp;


arch/arm/plat-samsung/s5p-irq-eint.c
202 static int __init s5p_init_irq_eint(void)
203 {
204         int irq;
205
206         for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
207                 irq_set_chip(irq, &s5p_irq_vic_eint);
208
209         for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
210                 irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
211                 set_irq_flags(irq, IRQF_VALID);
212         }
213
214         irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
215         return 0;
216 }
217
218 arch_initcall(s5p_init_irq_eint);

s5pv210通过irq_set_chip_and_handler来设置外部中断为电平触发
irq_set_chained_handler用来设置s5p_irq_demux_eint16_31为中断处理函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值