ARM Linux对中断的处理.doc_第1页
ARM Linux对中断的处理.doc_第2页
ARM Linux对中断的处理.doc_第3页
ARM Linux对中断的处理.doc_第4页
ARM Linux对中断的处理.doc_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

ARM Linux对中断的处理-中断管理系统的初始化8ARM Linux对中断的处理-中断注册方法18ARM Linux对中断的处理-中断处理21ARM Linux对中断的处理-内核模式下的中断处理23ARM Linux对中断的处理-用户模式下的中断处理40ARM Linux对中断的处理-相关数据结构中断处理依赖于中断的类型:I/O中断、时钟中断和处理器间中断。不管引起中断的电路的种类如何,所有I/O中断处理程序都执行四个相同的基本操作:在内核态堆栈中保存IRQ的值和寄存器的内容。为正在给IRQ线服务的PIC发送一个应答,这将允许PIC进一步发出中断。执行共享这个IRQ的所有设备的中断服务例程。与中断处理相关的数据结构Linux系统里每个中断通过一个称为中断描述符的结构irq_desc来管理,各中断的信息都在这个结构中得以体现。irq_desc结构体在include/irq.h文件中定义:struct irq_desc unsigned int irq; struct timer_rand_state *timer_rand_state; unsigned int *kstat_irqs;#ifdef CONFIG_INTR_REMAP struct irq_2_iommu *irq_2_iommu;#endif irq_flow_handler_t handle_irq; struct irq_chip *chip; struct msi_desc *msi_desc; void *handler_data; void *chip_data; struct irqaction *action; /* IRQ action list */ unsigned int status; /* IRQ status */ unsigned int depth; /* nested irq disables */ unsigned int wake_depth; /* nested wake enables */ unsigned int irq_count; /* For detecting broken IRQs */ unsigned long last_unhandled; /* Aging timer for unhandled count */ unsigned int irqs_unhandled; spinlock_t lock;#ifdef CONFIG_SMP cpumask_var_t affinity; unsigned int node;#ifdef CONFIG_GENERIC_PENDING_IRQ cpumask_var_t pending_mask;#endif#endif atomic_t threads_active; wait_queue_head_t wait_for_threads;#ifdef CONFIG_PROC_FS struct proc_dir_entry *dir;#endif const char *name; _cacheline_internodealigned_in_smp;irq_desc结构体(中断描述符)中各个字段说明:irq: 中断描述符的中断号timer_rand_state: pointer to timer rand state structkstat_irqs: irq stats per cpuirq_2_iommu: iommu with this irqhandle_irq: 高层的irq时间处理程序(如果为NULL,则默认调用_do_IRQ())chip: 底层的中断硬件访问,指向PIC对象(irq_chip结构),它服务于IRQ线,Linux中断管理系统使用该成员来进行中断控制器的访问。msi_desc: MSI descriptorhandler_data: irq_chip 方法使用的per-IRQ数据chip_data: chip 方法使用的特定平台的per-chip 私有数据,以允许共享chip的实现action: 标识当出现IRQ时要调用的中断服务例程。该字段指向IRQ的irqaction链表的第一个元素。我们用request_irq()注册的中断处理方法,会被用来创建相关的irqaction结构体,对于同一个中断号注册的各个中断方法会被链接在该中断号的中断描述符的该字段上。status: 描述IRQ线状态的一组标志depth: disable-depth用于嵌套的irq_disable()调用,如果IRQ线被激活,则显示0,如果IRQ线被禁止了不止一次,则显示一个正数。wake_depth: enable depth, for multiple set_irq_wake() callersirq_count: 中断计数器,统计IRQ线上发生的中断的次数(仅在诊断时使用)last_unhandled: aging timer for unhandled countirqs_unhandled: 对在IRQ线上发生的无法处理的中断进行计数lock: locking for SMP。用于串行访问IRQ描述符和PIC的自旋锁。affinity: IRQ affinity on SMPnode: node index useful for balancingpending_mask: pending rebalanced interruptsthreads_active: number of irqaction threads currently runningwait_for_threads: wait queue for sync_irq to wait for threaded handlersdir: /proc/irq/ procfs入口name: flow handler name for /proc/interrupts output在具体的ARM SoC芯片中会有很多的中断线,每一个中断线都会用一个irq_desc结构体来描述。如果一个中断内核没有处理,那么这个中断就是意外中断,也就是说,与某个IRQ线相关的中断处理例程(ISR)不存在,或者与某个中断线相关的所有例程都识别不出是否是自己的硬件设备发出的中断。通常,内核检查从IRQ线接收的意外中断的数量,当这条IRQ线的有故障设备没完没了的发中断时,就禁用这条IRQ线,内核不会在每监测到一个意外中断时就立刻禁用IRQ线。由于几个设备可能共享IRQ线,更合适的办法是:内核把中断和意外中断的总次数分别放在irq_desc描述符的irq_count和irqs_unhandled字段中,当第100000次中断产生时,如果意外中断的次数超过99900次内核才禁用这条IRQ线。描述IRQ线状态的标志:IRQ_INPROGRESS /* IRQ handler active - do not enter! */IRQ_DISABLED /* IRQ disabled - do not enter! */IRQ_PENDING /* IRQ pending - replay on enable */IRQ_REPLAY /* IRQ has been replayed but not acked yet */IRQ_AUTODETECT /* IRQ is being autodetected */IRQ_WAITING /* IRQ not yet seen - for autodetection */IRQ_LEVEL /* IRQ level triggered */IRQ_MASKED /* IRQ masked - shouldnt be seen again */IRQ_PER_CPU /* IRQ is per CPU */IRQ_NOPROBE /* IRQ is not valid for probing */IRQ_NOREQUEST /* IRQ cannot be requested */IRQ_NOAUTOEN /* IRQ will not be enabled on request irq */IRQ_WAKEUP /* IRQ triggers system wakeup */IRQ_MOVE_PENDING /* need to re-target IRQ destination */IRQ_NO_BALANCING /* IRQ is excluded from balancing */IRQ_SPURIOUS_DISABLED /* IRQ was disabled by the spurious trap */IRQ_MOVE_PCNTXT /* IRQ migration from process context */IRQ_AFFINITY_SET /* IRQ affinity was set from userspace*/IRQ_SUSPENDED /* IRQ has gone through suspend sequence */IRQ_ONESHOT /* IRQ is not unmasked after hardirq */IRQ_NESTED_THREAD /* IRQ is nested into another, no own handler thread */irq_desc描述符的depth字段和IRQ_DISABLED标志表示IRQ线是否被禁用。每次调用disable_irq()和disable_irq_nosync()函数,depth字段的值增加,如果depth等于0,函数禁用IRQ线并设置它的IRQ_DISABLED标志。相反,每当调用enable_irq()函数,depth字段的值减少,如果depth变为0,函数激活IRQ线并清除IRQ_DISABLED标志。Linux支持许多种类的PIC电路,如PC机的8259A、APIC等。为了以统一的方法处理所有这样的设备,Linux用了一个“PIC对象”,由PIC名字和17个标准方法组成。这种面向对象的方法的优点是,驱动程序不必关注安装在系统中的PIC种类。每个驱动程序可见的中断源透明地连接到适当的控制器。定义PIC对象的数据结构叫irq_chip。内核使用irq_chip结构的成员来完成实际的对于PIC控制器的操作,禁用中断,启用中断等。struct irq_chip const char *name; unsigned int (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*enable)(unsigned int irq); void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*mask)(unsigned int irq); void (*mask_ack)(unsigned int irq); void (*unmask)(unsigned int irq); void (*eoi)(unsigned int irq); void (*end)(unsigned int irq); int (*set_affinity)(unsigned int irq, const struct cpumask *dest); int (*retrigger)(unsigned int irq); int (*set_type)(unsigned int irq, unsigned int flow_type); int (*set_wake)(unsigned int irq, unsigned int on); void (*bus_lock)(unsigned int irq); void (*bus_sync_unlock)(unsigned int irq); /* Currently used only by UML, might disappear one day.*/#ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id);#endif /* * For compatibility, -typename is copied into -name. * Will disappear. */ const char *typename;irq_chip结构体(硬件中断芯片描述符)各个字段说明:name: name for /proc/interruptsstartup: 启动中断(如果为NULL,则默认情况下其与-enable 相同)shutdown: 关闭中断(如果为NULL,则默认情况下其与-disable相同)enable: 使能中断(如果为NULL,则默认情况下其与chip-unmask相同)disable: 禁用中断 (如果为NULL,则默认情况下其与chip-mask相同)ack: 开始一个新的中断,即给予中断控制器以确认,以允许中断的发生mask: 屏蔽一个中断源mask_ack: 确认并屏蔽一个中断源unmask: 取消屏蔽一个中断源eoi: end of interrupt - chip levelend: end of interrupt - flow levelset_affinity: set the CPU affinity on SMP machinesretrigger: 重新发送一个IRQ给CPUset_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQset_wake: enable/disable power-management wake-on of an IRQbus_lock: function to lock access to slow bus (i2c) chipsbus_sync_unlock: function to sync and unlock slow bus (i2c) chipsrelease: release function solely used by UMLtypename: obsoleted by name, kept as migration helper多个设备能共享一个单独的IRQ。因此,内核要维护多个irqaction描述符,其中的每个描述符涉及一个特定的硬件设备和一个特定的中断。这个结构在文件include/interrupt.h中定义:struct irqaction irq_handler_t handler; unsigned long flags; const char *name; void *dev_id; struct irqaction *next; int irq; struct proc_dir_entry *dir; irq_handler_t thread_fn; struct task_struct *thread; unsigned long thread_flags;struct irqaction(中断行为描述符)各字段说明:handler: 中断处理函数,指向一个I/O设备的中断服务例程。这是允许多个设备共享同一个IRQ的关键字段。flags: 标志(参考下面的IRQF_*),描述IRQ与I/O设备之间的关系。name: I/O设备名(通过读/proc/interrupts文件,在列出所服务的IRQ时也显示设备名)。dev_id: I/O设备的私有数据字段。典型情况下,它标识I/O设备本身(例如,它可能等于其主设备号和此设备号),或者它指向设备驱动程序的数据next: 共享中断情况下,指向irqaction链表的下一个元素。链表中的元素指向共享同一个IRQ的硬件设备irq: 中断号dir: 指向proc/irq/NN/name 入口的指针,指向proc文件系统中IRQn相关的目录项。thread_fn: 用于线程化中断的中断处理函数thread: 用于线程化中断的线程指针thread_flags: 与thread 有关的标志irqaction描述符的标志,只是被作为irq处理例程的一部分来使用的,各个标志的说明如下:IRQF_DISABLED 当调用action handler时保持irqs禁用IRQF_SAMPLE_RANDOM 设备可以被看作是事件随机的发生源,一次,内核可以用它做随机数产生器IRQF_SHARED 允许在多个设备间共享中断IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occurIRQF_TIMER 标记该中断为时钟中断的标志IRQF_PERCPU - Interrupt is per cpuIRQF_NOBALANCING - Flag to exclude this interrupt from irq balancingIRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is registered first in an shared interrupt is considered forperformance reasons)IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.Used by threaded interrupts which need to keep theirq line disabled until the threaded handler has been run.最后,irq_stat数组包含NR_CPUS个元素,系统中的每个CPU对应一个元素(kernel/softirq.c文件中):#ifndef _ARCH_IRQ_STATirq_cpustat_t irq_statNR_CPUS _cacheline_aligned;EXPORT_SYMBOL(irq_stat);#endif每个元素的类型为irq_cpustat_t,该类型包含几个计数器和内核记录CPU正在做什么的标志,该结构体的定义因体系结构而已,对于我们的ARM平台,这个结构在arch/arm/include/asm/hardirq.h文件中定义:typedef struct unsigned int _softirq_pending; unsigned int local_timer_irqs; _cacheline_aligned irq_cpustat_t;irq_cpustat_t结构的字段_softirq_pending:表示挂起的软中断local_timer_irqs:本地时钟中断发生的次数在kernel/irq/handle.c中还有定义了一个全局irq_desc结构体数组,用来表示系统中的所有中断:struct irq_desc irq_descNR_IRQS _cacheline_aligned_in_smp = 0 . NR_IRQS-1 = .status = IRQ_DISABLED, .chip = &no_irq_chip, .handle_irq = handle_bad_irq, .depth = 1, .lock = _SPIN_LOCK_UNLOCKED(irq_desc-lock), ;上面的_cacheline_aligned_in_smp在include/linux/cache.h中定义,它是一个宏,在非SMP系统中是空的:#ifdef CONFIG_SMP#define _cacheline_aligned_in_smp _cacheline_aligned#else#define _cacheline_aligned_in_smp#endif /* CONFIG_SMP */用于描述结构体的属性,cache行对齐。内核用结构数组irq_descNR_IRQS来管理中断处理,每一个成员对应于一个中断线。NR_IRQS是一个因平台而异的宏,对于我们的mini2440来说,该宏在arch/arm/mach-s3c2440/include/mach/irqs.h中定义:#ifdef CONFIG_CPU_S3C2443#define NR_IRQS (IRQ_S3C2443_AC97+1)#else#define NR_IRQS (IRQ_S3C2440_AC97+1)#endif这个宏代表平台上最大的中断号。ARM Linux对中断的处理-中断管理系统的初始化中断管理系统的初始化中断管理系统的初始化我们先来看一下Linux系统中,中断管理系统的初始化。中断系统的初始化主要由几个函数来完成。在系统初始化的start_kernel()函数 (在文件init/main.c中定义)中可以看到:asmlinkage void _init start_kernel(void) trap_init(); early_irq_init(); init_IRQ();start_kernel()函数调用trap_init()、early_irq_init()和init_IRQ()三个函数来初始化中断管理系统。对于我们的ARM平台来说trap_init()在arch/arm/kernel/traps.c中定义,为一个空函数。early_irq_init()函数在start_kernel()函数中调用了early_irq_init()函数,这个函数在kernel/handle.c文件中定义。kernel/handle.c文件中,根据内核配置时是否选择了CONFIG_SPARSE_IRQ,而可以选择两个不同版本的该函数early_irq_init()中的一个进行编译。CONFIG_SPARSE_IRQ配置项,用于支持稀疏irq号,对于发行版的内核很有用,它允许定义一个高CONFIG_NR_CPUS值,但仍然不希望消耗太多内存的情况。对于我们的开发板来说,自然不需要打开这个配置项。early_irq_init()函数定义如下: int _init early_irq_init(void) struct irq_desc *desc; int count; int i; init_irq_default_affinity(); printk(KERN_INFO NR_IRQS:%dn, NR_IRQS); desc = irq_desc; count = ARRAY_SIZE(irq_desc); for (i = 0; i count; i+) desci.irq = i; alloc_desc_masks(&desci, 0, true); init_desc_masks(&desci); desci.kstat_irqs = kstat_irqs_alli; return arch_early_irq_init();主要工作即为初始化用于管理中断的irq_descNR_IRQS数组的每个元素,它主要设置数组中每一个成员的中断号,使得数组中每一个元素的kstat_irqs字段(irq stats per cpu),指向定义的二维数组中的对应的行。alloc_desc_masks(&desci, 0, true)和init_desc_masks(&desci)函数在非SMP平台上为空函数。arch_early_irq_init()在主要用于x86平台和PPC平台,其他平台上为空函数。init_IRQ()函数init_IRQ(void)函数是一个特定于体系结构的函数,对于ARM体系结构来说该函数定义如下:-arch/arm/kernel/irq.c 152 void _init init_IRQ(void)153 154 int irq;155 156 for (irq = 0; irq NR_IRQS; irq+)157 irq_descirq.status |= IRQ_NOREQUEST | IRQ_NOPROBE;158 159 init_arch_irq();160 -我们看到这个函数将irq_descNR_IRQS结构数组各个元素的状态字段设置为IRQ_NOREQUEST | IRQ_NOPROBE,也就是未请求和未探测状态。然后调用特定机器平台的中断初始化init_arch_irq()函数。而init_arch_irq()实际上是一个函数指针,其定义如下:-arch/arm/kernel/irq.c50 void (*init_arch_irq)(void) _initdata = NULL;-在前面的博文ARM linux的启动部分源代码简略分析中我们已经说明了setup_arch()函数是如何获取machine_desc,而又如何初始化init_arch_irq函数指针变量的。我们知道,对于我们的mini2440开发板,这个函数指针指向的函数为s3c24xx_init_irq()函数,该函数定义如下在arch/arm/plat-s3c24xx/irq.c中定义:-arch/arm/plat-s3c24xx/irq.c 535 void _init s3c24xx_init_irq(void)536 537 unsigned long pend;538 unsigned long last;539 int irqno;540 int i;541 542 #ifdef CONFIG_FIQ543 init_FIQ();544 #endif545 546 irqdbf(s3c2410_init_irq: clearing interrupt status flagsn);547 548 /* first, clear all interrupts pending. */549 550 last = 0;551 for (i = 0; i 4; i+) 552 pend = _raw_readl(S3C24XX_EINTPEND);553 554 if (pend = 0 | pend = last)555 break;556 557 _raw_writel(pend, S3C24XX_EINTPEND);558 printk(irq: clearing pending ext status %08xn, (int)pend);559 last = pend;560 561 562 last = 0;563 for (i = 0; i 4; i+) 564 pend = _raw_readl(S3C2410_INTPND);565 566 if (pend = 0 | pend = last)567 break;568 569 _raw_writel(pend, S3C2410_SRCPND);570 _raw_writel(pend, S3C2410_INTPND);571 printk(irq: clearing pending status %08xn, (int)pend);572 last = pend;573 574 575 last = 0;576 for (i = 0; i 4; i+) 577 pend = _raw_readl(S3C2410_SUBSRCPND);578 579 if (pend = 0 | pend = last)580 break;581 582 printk(irq: clearing subpending status %08xn, (int)pend);583 _raw_writel(pend, S3C2410_SUBSRCPND);584 last = pend;585 586 587 /* register the main interrupts */588 589 irqdbf(s3c2410_init_irq: registering s3c2410 interrupt handlersn);590 591 for (irqno = IRQ_EINT4t7; irqno = IRQ_ADCPARENT; irqno+) 592 /* set all the s3c2410 internal irqs */593 594 switch (irqno) 595 /* deal with the special IRQs (cascaded) */596 597 case IRQ_EINT4t7:598 case IRQ_EINT8t23:599 case IRQ_UART0:600 case IRQ_UART1:601 case IRQ_UART2:602 case IRQ_ADCPARENT:603 set_irq_chip(irqno, &s3c_irq_level_chip);604 set_irq_handler(irqno, handle_level_irq);605 break;606 607 case IRQ_RESERVED6:608 case IRQ_RESERVED24:609 /* no IRQ here */610 break;611 612 default:613 /irqdbf(registering irq %d (s3c irq)n, irqno);614 set_irq_chip(irqno, &s3c_irq_chip);615 set_irq_handler(irqno, handle_edge_irq);616 set_irq_flags(irqno, IRQF_VALID);617 618 619 620 /* setup the cascade irq handlers */621 622 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);623 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);624 625 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);626 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);627 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);628 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);629 630 /* external interrupts */631 632 for (irqno = IRQ_EINT0; irqno = IRQ_EINT3; irqno+) 633 irqdbf(registering irq %d (ext int)n, irqno);634 set_irq_chip(irqno, &s3c_irq_eint0t4);635 set_irq_handler(irqno, handle_edge_irq);636 set_irq_flags(irqno, IRQF_VALID);637 638 639 for (irqno = IRQ_EINT4; irqno = IRQ_EINT23; irqno+) 640 irqdbf(registering irq %d (extended s3c irq)n, irqno);641 set_irq_chip(irqno, &s3c_irqext_chip);642 set_irq_handler(irqno, handle_edge_irq);643 set_irq_flags(irqno, IRQF_VALID);644 645 646 /* register the uart interrupts */647 648 irqdbf(s3c2410: registering external interruptsn);649 650 for (irqno = IRQ_S3CUART_RX0; irqno = IRQ_S3CUART_ERR0; irqno+) 651 irqdbf(registering irq %d (s3c uart0 irq)n, irqno);652 set_irq_chip(irqno, &s3c_irq_uart0);653 set_irq_handle

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论