从下到上分析中断处理

原创文章,转载请注明出处.转载自: Li Haifeng's Blog
本文链接地址: 从下到上分析中断处理

S3C2410中断的定义的中断向量是从16~47.然后外部中断从48~69.70~80.一共有66(80-16)个中断其中70~78 UART是用来与PC进行通信的。


25 #define S3C2410_CPUIRQ_OFFSET (16)
26
27 #define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)
28
29 /* main cpu interrupts */
30 #define IRQ_EINT0 S3C2410_IRQ(0) /* 16 */
31 #define IRQ_EINT1 S3C2410_IRQ(1)
32 #define IRQ_EINT2 S3C2410_IRQ(2)
33 #define IRQ_EINT3 S3C2410_IRQ(3)
34 #define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */
35 #define IRQ_EINT8t23 S3C2410_IRQ(5)
36 #define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */
37 #define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440,s3c2443 */
38 #define IRQ_BATT_FLT S3C2410_IRQ(7)
39 #define IRQ_TICK S3C2410_IRQ(8) /* 24 */
40 #define IRQ_WDT S3C2410_IRQ(9) /* WDT/AC97 for s3c2443 */
41 #define IRQ_TIMER0 S3C2410_IRQ(10)
42 #define IRQ_TIMER1 S3C2410_IRQ(11)
43 #define IRQ_TIMER2 S3C2410_IRQ(12)
44 #define IRQ_TIMER3 S3C2410_IRQ(13)
45 #define IRQ_TIMER4 S3C2410_IRQ(14)
46 #define IRQ_UART2 S3C2410_IRQ(15)
47 #define IRQ_LCD S3C2410_IRQ(16) /* 32 */
48 #define IRQ_DMA0 S3C2410_IRQ(17) /* IRQ_DMA for s3c2443 */
49 #define IRQ_DMA1 S3C2410_IRQ(18)
50 #define IRQ_DMA2 S3C2410_IRQ(19)
51 #define IRQ_DMA3 S3C2410_IRQ(20)
52 #define IRQ_SDI S3C2410_IRQ(21)
53 #define IRQ_SPI0 S3C2410_IRQ(22)
54 #define IRQ_UART1 S3C2410_IRQ(23)
55 #define IRQ_RESERVED24 S3C2410_IRQ(24) /* 40 */
56 #define IRQ_NFCON S3C2410_IRQ(24) /* for s3c2440 */
57 #define IRQ_USBD S3C2410_IRQ(25)
58 #define IRQ_USBH S3C2410_IRQ(26)
59 #define IRQ_IIC S3C2410_IRQ(27)
60 #define IRQ_UART0 S3C2410_IRQ(28) /* 44 */
61 #define IRQ_SPI1 S3C2410_IRQ(29)
62 #define IRQ_RTC S3C2410_IRQ(30)
63 #define IRQ_ADCPARENT S3C2410_IRQ(31)




65 /* interrupts generated from the external interrupts sources */
66 #define IRQ_EINT4 S3C2410_IRQ(32) /* 48 */
67 #define IRQ_EINT5 S3C2410_IRQ(33)
68 #define IRQ_EINT6 S3C2410_IRQ(34)
69 #define IRQ_EINT7 S3C2410_IRQ(35)
70 #define IRQ_EINT8 S3C2410_IRQ(36)
71 #define IRQ_EINT9 S3C2410_IRQ(37)
72 #define IRQ_EINT10 S3C2410_IRQ(38)
73 #define IRQ_EINT11 S3C2410_IRQ(39)
74 #define IRQ_EINT12 S3C2410_IRQ(40)
75 #define IRQ_EINT13 S3C2410_IRQ(41)
76 #define IRQ_EINT14 S3C2410_IRQ(42)
77 #define IRQ_EINT15 S3C2410_IRQ(43)
78 #define IRQ_EINT16 S3C2410_IRQ(44)
79 #define IRQ_EINT17 S3C2410_IRQ(45)
80 #define IRQ_EINT18 S3C2410_IRQ(46)
81 #define IRQ_EINT19 S3C2410_IRQ(47)
82 #define IRQ_EINT20 S3C2410_IRQ(48) /* 64 */
83 #define IRQ_EINT21 S3C2410_IRQ(49)
84 #define IRQ_EINT22 S3C2410_IRQ(50)
85 #define IRQ_EINT23 S3C2410_IRQ(51)
86
87
88 #define IRQ_EINT(x) S3C2410_IRQ((x >= 4) ? (IRQ_EINT4 + (x) - 4) : (S3C2410_IRQ(0) + (x)))
89
90 #define IRQ_LCD_FIFO S3C2410_IRQ(52)
91 #define IRQ_LCD_FRAME S3C2410_IRQ(53)
98 #define S3C2410_IRQSUB(x) S3C2410_IRQ((x)+54)
99
100 #define IRQ_S3CUART_RX0 S3C2410_IRQSUB(0) /* 70 */
101 #define IRQ_S3CUART_TX0 S3C2410_IRQSUB(1)
102 #define IRQ_S3CUART_ERR0 S3C2410_IRQSUB(2)
103
104 #define IRQ_S3CUART_RX1 S3C2410_IRQSUB(3) /* 73 */
105 #define IRQ_S3CUART_TX1 S3C2410_IRQSUB(4)
106 #define IRQ_S3CUART_ERR1 S3C2410_IRQSUB(5)
107
108 #define IRQ_S3CUART_RX2 S3C2410_IRQSUB(6) /* 76 */
109 #define IRQ_S3CUART_TX2 S3C2410_IRQSUB(7)
110 #define IRQ_S3CUART_ERR2 S3C2410_IRQSUB(8)
111
112 #define IRQ_TC S3C2410_IRQSUB(9)
113 #define IRQ_ADC S3C2410_IRQSUB(10)
114
115 /* extra irqs for s3c2440 */
...


那么前16就是trap了。
这些中断向量的初始化是由


661 void __init s3c24xx_init_irq(void)
662 {
663 unsigned long pend;
664 unsigned long last;
665 int irqno;
666 int i;
667
668 irqdbf("s3c2410_init_irq: clearing interrupt status flagsn");
669
670 /* first, clear all interrupts pending... */
671
672 last = 0;
673 for (i = 0; i < 4; i++) {
674 pend = __raw_readl(S3C24XX_EINTPEND);
675
676 if (pend == 0 || pend == last)
677 break;
678
679 __raw_writel(pend, S3C24XX_EINTPEND);
680 printk("irq: clearing pending ext status %08xn", (int)pend);
681 last = pend;
682 }
683
684 last = 0;
685 for (i = 0; i < 4; i++) {
686 pend = __raw_readl(S3C2410_INTPND);
687
688 if (pend == 0 || pend == last)
689 break;
690
691 __raw_writel(pend, S3C2410_SRCPND);
692 __raw_writel(pend, S3C2410_INTPND);
693 printk("irq: clearing pending status %08xn", (int)pend);
694 last = pend;
695 }
696
697 last = 0;
698 for (i = 0; i < 4; i++) {
699 pend = __raw_readl(S3C2410_SUBSRCPND);
700
701 if (pend == 0 || pend == last)
702 break;
703
704 printk("irq: clearing subpending status %08xn", (int)pend);
705 __raw_writel(pend, S3C2410_SUBSRCPND);
706 last = pend;
707 }
708
709 /* register the main interrupts */
710
711 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlersn");
712
713 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
714 /* set all the s3c2410 internal irqs */
715
716 switch (irqno) {
717 /* deal with the special IRQs (cascaded) */
718
719 case IRQ_EINT4t7:
720 case IRQ_EINT8t23:
721 case IRQ_UART0:
722 case IRQ_UART1:
723 case IRQ_UART2:
724 case IRQ_ADCPARENT:
725 set_irq_chip(irqno, &s3c_irq_level_chip);
726 set_irq_handler(irqno, handle_level_irq);
727 break;
728
729 case IRQ_RESERVED6:
730 case IRQ_RESERVED24:
731 /* no IRQ here */
732 break;
733
734 default:
735 //irqdbf("registering irq %d (s3c irq)n", irqno);
736 set_irq_chip(irqno, &s3c_irq_chip);
737 set_irq_handler(irqno, handle_edge_irq);
738 set_irq_flags(irqno, IRQF_VALID);
739 }
740 }
741
742 /* setup the cascade irq handlers */
743
744 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
745 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
746
747 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
748 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
749 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
750 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
751
752 /* external interrupts */
753
754 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
755 irqdbf("registering irq %d (ext int)n", irqno);
756 set_irq_chip(irqno, &s3c_irq_eint0t4);
757 set_irq_handler(irqno, handle_edge_irq);
758 set_irq_flags(irqno, IRQF_VALID);
759 }
760
761 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
762 irqdbf("registering irq %d (extended s3c irq)n", irqno);
763 set_irq_chip(irqno, &s3c_irqext_chip);
764 set_irq_handler(irqno, handle_edge_irq);
765 set_irq_flags(irqno, IRQF_VALID);
766 }
767
768 /* register the uart interrupts */
769
770 irqdbf("s3c2410: registering external interruptsn");
771
772 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
773 irqdbf("registering irq %d (s3c uart0 irq)n", irqno);
774 set_irq_chip(irqno, &s3c_irq_uart0);
775 set_irq_handler(irqno, handle_level_irq);
776 set_irq_flags(irqno, IRQF_VALID);
777 }
778
779 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
780 irqdbf("registering irq %d (s3c uart1 irq)n", irqno);
781 set_irq_chip(irqno, &s3c_irq_uart1);
782 set_irq_handler(irqno, handle_level_irq);
783 set_irq_flags(irqno, IRQF_VALID);
784 }
785
786 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
787 irqdbf("registering irq %d (s3c uart2 irq)n", irqno);
788 set_irq_chip(irqno, &s3c_irq_uart2);
789 set_irq_handler(irqno, handle_level_irq);
790 set_irq_flags(irqno, IRQF_VALID);
791 }
792
793 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
794 irqdbf("registering irq %d (s3c adc irq)n", irqno);
795 set_irq_chip(irqno, &s3c_irq_adc);
796 set_irq_handler(irqno, handle_edge_irq);
797 set_irq_flags(irqno, IRQF_VALID);
798 }
799
800 irqdbf("s3c2410: registered interrupt handlersn");
801 }


上面便是对中断向量进行赋值了。其中set_irq_chip是设置irq上的中断控制器。set_irq_handle便是设置该中断线上的处理函数了,比如ack mark之类的。set_irq_flags是设置该中断线的标志位,有哪些呢?


49 #define IRQ_INPROGRESS 0x00000100 /* IRQ handler active - do not enter! */
50 #define IRQ_DISABLED 0x00000200 /* IRQ disabled - do not enter! */
51 #define IRQ_PENDING 0x00000400 /* IRQ pending - replay on enable */
52 #define IRQ_REPLAY 0x00000800 /* IRQ has been replayed but not acked yet */
53 #define IRQ_AUTODETECT 0x00001000 /* IRQ is being autodetected */
54 #define IRQ_WAITING 0x00002000 /* IRQ not yet seen - for autodetection */
55 #define IRQ_LEVEL 0x00004000 /* IRQ level triggered */
56 #define IRQ_MASKED 0x00008000 /* IRQ masked - shouldn't be seen again */
57 #define IRQ_PER_CPU 0x00010000 /* IRQ is per CPU */
58 #define IRQ_NOPROBE 0x00020000 /* IRQ is not valid for probing */
59 #define IRQ_NOREQUEST 0x00040000 /* IRQ cannot be requested */
60 #define IRQ_NOAUTOEN 0x00080000 /* IRQ will not be enabled on request irq */
61 #define IRQ_WAKEUP 0x00100000 /* IRQ triggers system wakeup */
62 #define IRQ_MOVE_PENDING 0x00200000 /* need to re-target IRQ destination */
63 #define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */


另外set_irq_handler我们来看一下:


534 void
535 __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
536 const char *name)
537 {
538 struct irq_desc *desc;
539 unsigned long flags;
540
541 if (irq >= NR_IRQS) {
542 printk(KERN_ERR
543 "Trying to install type control for IRQ%dn", irq);
544 return;
545 }
546
547 desc = irq_desc + irq;
548
549 if (!handle) //如果形参handle没有被赋值,那么先将之赋值为handle_bad_irq.在后面567行我们会看到,实际上是会执行卸载操作
550 handle = handle_bad_irq;
551 else if (desc->chip == &no_irq_chip) {
552 printk(KERN_WARNING "Trying to install %sinterrupt handler "
553 "for IRQ%dn", is_chained ? "chained " : "", irq);
554 /*
555 * Some ARM implementations install a handler for really dumb
556 * interrupt hardware without setting an irq_chip. This worked
557 * with the ARM no_irq_chip but the check in setup_irq would
558 * prevent us to setup the interrupt at all. Switch it to
559 * dummy_irq_chip for easy transition.
560 */
561 desc->chip = &dummy_irq_chip;
562 }
563
564 spin_lock_irqsave(&desc->lock, flags);
565
566 /* Uninstall? */
567 if (handle == handle_bad_irq) {
568 if (desc->chip != &no_irq_chip)
569 mask_ack_irq(desc, irq);
570 desc->status |= IRQ_DISABLED;
571 desc->depth = 1;
572 }
573 desc->handle_irq = handle;
574 desc->name = name;


另外,现在已经设置好中断向量了,那么这些中断向量在哪里放着呢?因为如果要响应中断的话,必须找到入口啊。
看一下trap_init函数:


678 void __init trap_init(void)
679 {
680 unsigned long vectors = CONFIG_VECTORS_BASE;
681 extern char __stubs_start[], __stubs_end[];
682 extern char __vectors_start[], __vectors_end[];
683 extern char __kuser_helper_start[], __kuser_helper_end[];
684 int kuser_sz = __kuser_helper_end - __kuser_helper_start;
685
686 /*
687 * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
688 * into the vector page, mapped at 0xffff0000, and ensure these
689 * are visible to the instruction stream.
690 */
691 memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
692 memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
693 memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
694
695 /*
696 * Copy signal return handlers into the vector page, and
697 * set sigreturn to be a pointer to these.
698 */
699 memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
700 sizeof(sigreturn_codes));
701
702 flush_icache_range(vectors, vectors + PAGE_SIZE);
703 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
704 }


看到了吧,将__vectors_start~__vectors_end还有stub都移到了vector的位置,而vector的位置既是 CONFIG_VECTORS_BASE,


147 #define CONFIG_VECTORS_BASE 0xffff0000


那么__vector_start在哪里捏?
~/linux-2.6.21.1/arch/arm/kernel/entry-armv.S


1062 __vectors_start:
1063 swi SYS_ERROR0
1064 b vector_und + stubs_offset
1065 ldr pc, .LCvswi + stubs_offset
1066 b vector_pabt + stubs_offset
1067 b vector_dabt + stubs_offset
1068 b vector_addrexcptn + stubs_offset
1069 b vector_irq + stubs_offset
1070 b vector_fiq + stubs_offset
1071
1072 .globl __vectors_end
1073 __vectors_end:


在该文件,我们也可以找到__stub_start的变量地址。

From Li Haifeng's Blog, post 从下到上分析中断处理

Post Footer automatically generated by wp-posturl plugin for wordpress.

分享到: