现在的位置: 首页 > 综合 > 正文

uclinux-2008r1-rc8(bf561)的中断处理(9):irq_chip

2013年09月22日 ⁄ 综合 ⁄ 共 3099字 ⁄ 字号 评论关闭
 

  
内核使用一个称为irq_chip的结构体来描述中断控制器,对中断的操作(启用/禁用某个中断源)将通过irq_chip的回调函数进行,此结构体的定义位于include/linux/irq.h:
/**
 * struct irq_chip - hardware interrupt chip descriptor
 *
 * @name:     name for /proc/interrupts
 * @startup:       start up the interrupt (defaults to ->enable if NULL)
 * @shutdown:      shut down the interrupt (defaults to ->disable if NULL)
 * @enable:        enable the interrupt (defaults to chip->unmask if NULL)
 * @disable:       disable the interrupt (defaults to chip->mask if NULL)
 * @ack:      start of a new interrupt
 * @mask:     mask an interrupt source
 * @mask_ack:      ack and mask an interrupt source
 * @unmask:        unmask an interrupt source
 * @eoi:      end of interrupt - chip level
 * @end:      end of interrupt - flow level
 * @set_affinity: set the CPU affinity on SMP machines
 * @retrigger:         resend an IRQ to the CPU
 * @set_type:      set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
 * @set_wake:      enable/disable power-management wake-on of an IRQ
 *
 * @release:       release function solely used by UML
 * @typename:      obsoleted by name, kept as migration helper
 */
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);
     void     (*set_affinity)(unsigned int irq, cpumask_t 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);
 
     /* 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进行操作(irq_desc->chip)。
uclinux将bf561的中断分为3类,使用了3个不同的irq_chip来对它们进行控制。
第一类是内部中断,即中断0到中断6,内核使用下述结构体进行控制:
static struct irq_chip bfin_core_irqchip = {
     .ack = ack_noop,
     .mask = bfin_core_mask_irq,
     .unmask = bfin_core_unmask_irq,
};
对于这类中断,对它进行mask和unmask操作时必须直接操作IMASK。
第二类中断是没有共用的外部中断,内核使用下述结构体进行控制:
static struct irq_chip bfin_internal_irqchip = {
     .ack = ack_noop,
     .mask = bfin_internal_mask_irq,
     .unmask = bfin_internal_unmask_irq,
     .mask_ack = bfin_internal_mask_irq,
     .disable = bfin_internal_mask_irq,
     .enable = bfin_internal_unmask_irq,
#ifdef CONFIG_PM
     .set_wake = bfin_internal_set_wake,
#endif
};
对于这类中断,直接操作SIC_IMASK。
第三类中断是共用的外部中断,如PF0-PF7就共用一个中断源,此时内核使用下述结构体进行控制:
static struct irq_chip bfin_gpio_irqchip = {
     .ack = bfin_gpio_ack_irq,
     .mask = bfin_gpio_mask_irq,
     .mask_ack = bfin_gpio_mask_ack_irq,
     .unmask = bfin_gpio_unmask_irq,
     .set_type = bfin_gpio_irq_type,
     .startup = bfin_gpio_irq_startup,
     .shutdown = bfin_gpio_irq_shutdown,
#ifdef CONFIG_PM
     .set_wake = bfin_gpio_set_wake,
#endif
};
对这类中断,需要进行特殊处理,在后面再进行分析。
对于不同中断源的默认处理函数(irq_chip结构体中的handle),内核同样分成了3类。对于PF0-PF47的中断,将调用handle_level_irq进行处理;对于IRQ_PROG0_INTA、IRQ_PROG1_INTA、IRQ_PROG2_INTA这三个由PF口共享的中断则使用bfin_demux_gpio_irq进行处理;对于其它的中断源则使用handle_simple_irq进行处理。

抱歉!评论已关闭.