Atheros AR9344中断处理流程

最近由于工作的原因,开始接触了Atheros AR9344无线通信芯片,对硬件关注的比较少。Atheros AR9344是mips为内核的处理芯片。之前主要关注的是ARM内核,对mips内核的相关知识,还是比较欠缺。今天就看看Atheros AR9344中的中断处理流程。

首先站在系统的最高层来看看,系统中申请了那些中断。

/proc # cat interrupts

           CPU0      

  2:          0      dummy_cctv  wifi0

  3:        537            MIPS  ehci_hcd:usb1

  4:        534            MIPS  eth0

  6:          0            MIPS  cascade_cctv

  7:      27152            MIPS  timer

 18:          0  ath_misc_cctv_suiyuan  cascade_cctv

 19:       1189  ath_misc_cctv_suiyuan  serial

 64:          0    ath_pci_cctv  wifi1

第一列显示的是中断号,

第二列显示的是中断的次数,

第三列为:此中断对应的struct irq_chip结构中的name,因为每一个irq于一个特定的struct irq_chip相联系。

第四列为:申请此中断时的名称。

重要的一个数据结构,硬件中断描述符。

/**

 * 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);

       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);

 

       /* 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;

};

 

Handle.c (z:\wlan\src\linux\kernels\mips-linux-2.6.31\kernel\irq)   

Irq.c (z:\wlan\src\linux\kernels\mips-linux-2.6.31\arch\mips\kernel)     

 

asmlinkage void __init start_kernel(void)

{

early_irq_init();

init_IRQ();//用来初始化中断相关的代码。

}

struct irq_desc irq_desc[NR_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),

       }

};

static unsigned int kstat_irqs_all[NR_IRQS][NR_CPUS];

int __init early_irq_init(void)

{

       struct irq_desc *desc;

       int count;

       int i;

       init_irq_default_affinity();

       printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS); //NR_IRQS:128

       desc = irq_desc;

       count = ARRAY_SIZE(irq_desc);

       for (i = 0; i < count; i++) {

              desc[i].irq = i;

              alloc_desc_masks(&desc[i], 0, true);

              init_desc_masks(&desc[i]);

              desc[i].kstat_irqs = kstat_irqs_all[i];

       }

       return arch_early_irq_init();

}

 

void __init init_IRQ(void)

{

       int i;

#ifdef CONFIG_KGDB

       if (kgdb_early_setup)

              return;

#endif

       for (i = 0; i < NR_IRQS; i++){

              set_irq_noprobe(i);

       }

       printk("cctv: %s: line:%d\n", __FUNCTION__,__LINE__);

       arch_init_irq();

 

#ifdef CONFIG_KGDB

       if (!kgdb_early_setup)

              kgdb_early_setup = 1;

#endif

}

 

Irq.c (z:\wlan\src\linux\kernels\mips-linux-2.6.31\arch\mips\atheros)

void __init arch_init_irq(void) //主要对AR9344平台的中断进行初始化。

{

       /*

        * initialize our interrupt controllers

        */

       printk("cctv: %s: line:%d\n", __FUNCTION__,__LINE__);

       mips_cpu_irq_init();

       ath_misc_irq_init(ATH_MISC_IRQ_BASE);

       ath_gpio_irq_init(ATH_GPIO_IRQ_BASE);

#ifdef CONFIG_PCI

       ath_pci_irq_init(ATH_PCI_IRQ_BASE);

#endif

       /*

        * enable cascades

        */

       setup_irq(ATH_CPU_IRQ_MISC, &cascade);

       setup_irq(ATH_MISC_IRQ_GPIO, &cascade);

 

#ifdef CONFIG_PCI

       setup_irq(ATH_CPU_IRQ_PCI, &cascade);

#endif

       ath_arch_init_irq();

       set_c0_status(ST0_IM);

}

//先看看下面这个函数:给特定的中断号建立起一个特定的中断处理函数

Void set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,

                      irq_flow_handler_t handle)

{//下面这俩个函数主要就是对irq对应的struct irq_desc的成员进行赋值。

       set_irq_chip(irq, chip);

       __set_irq_handler(irq, handle, 0, NULL);

}

//下面这个函数是将一个特定的中断号于数据结构struct irq_chip建立其联系,我们可以从函数的俩个参数看出来。

/**

 *    set_irq_chip - set the irq chip for an irq

 *    @irq:     irq number

 *    @chip:   pointer to irq chip description structure

 */

int set_irq_chip(unsigned int irq, struct irq_chip *chip)

{

       struct irq_desc *desc = irq_to_desc(irq);//根据irq号,取出irq_desc

       unsigned long flags;

       if (!desc) {

              WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);

              return -EINVAL;

       }

       if (!chip)

              chip = &no_irq_chip;

       spin_lock_irqsave(&desc->lock, flags);

       irq_chip_set_defaults(chip);

       desc->chip = chip; //将参数赋值给特定中断对应的chip。

       spin_unlock_irqrestore(&desc->lock, flags);

       return 0;

}

/*

 * Fixup enable/disable function pointers

 */

void irq_chip_set_defaults(struct irq_chip *chip)

{//给struct irq_chip结构成员赋初始值。

       if (!chip->enable)

              chip->enable = default_enable;

       if (!chip->disable)

              chip->disable = default_disable;

       if (!chip->startup)

              chip->startup = default_startup;

       /*

        * We use chip->disable, when the user provided its own. When

        * we have default_disable set for chip->disable, then we need

        * to use default_shutdown, otherwise the irq line is not

        * disabled on free_irq():

        */

       if (!chip->shutdown)

              chip->shutdown = chip->disable != default_disable ?

                     chip->disable : default_shutdown;

       if (!chip->name)

              chip->name = chip->typename;

       if (!chip->end)

              chip->end = dummy_irq_chip.end;

}

/*

 * Determine interrupt source among interrupts that use IP6

       ath_misc_irq_init(ATH_MISC_IRQ_BASE);

 */

/*

 * IRQ Map.

 * There are 4 conceptual ICs in the system. We generally give a block of 16

 * irqs to each IC.

 *    CPU :    0 - 0xf

 *    MISC: 0x10 - 0x1f

 *    GPIO: 0x20 - 0x3f

 *    PCI : 0x40 - 0x4f

 *

 */

#define ATH_CPU_IRQ_BASE        0x00

#define ATH_MISC_IRQ_BASE             0x10

#define ATH_GPIO_IRQ_BASE             0x20

#define ATH_MISC_IRQ_COUNT          14

下面的函数主要也就是对特定的中断号关联特定的handler。

static void ath_misc_irq_init(int irq_base)

{

       int i;

       for (i = irq_base; i < irq_base + ATH_MISC_IRQ_COUNT; i++) {

              irq_desc[i].status = IRQ_DISABLED;

              irq_desc[i].action = NULL;

              irq_desc[i].depth = 1;

              set_irq_chip_and_handler(i, &ath_misc_irq_controller,

                                    handle_percpu_irq);

       }

}

/**

 *    setup_irq - setup an interrupt

 *    @irq: Interrupt line to setup

 *    @act: irqaction for the interrupt

 *

 * Used to statically setup interrupts in the early boot process.

 */

int setup_irq(unsigned int irq, struct irqaction *act)

{

       struct irq_desc *desc = irq_to_desc(irq);

       return __setup_irq(irq, desc, act);

}

///////////////////////////////////////////////////////////////////////////////////////

下面来看看驱动中对注册到系统的中断是如何申请和处理的。

static inline int __must_check

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,

           const char *name, void *dev)

{//中断申请函数。

       return request_threaded_irq(irq, handler, NULL, flags, name, dev);

}

ret = request_irq(ATH_GPIO_IRQn(BUTTON_GPIO), ar9344buttons_interrupt, 0,"ar9344 button", NULL);

 

 

函数中的主要完成的事情为:   

desc = irq_to_desc(irq);和retval = __setup_irq(irq, desc, action);

int request_threaded_irq(unsigned int irq, irq_handler_t handler,

                      irq_handler_t thread_fn, unsigned long irqflags,

                      const char *devname, void *dev_id){

       struct irqaction *action;

       struct irq_desc *desc;

       int retval;

       desc = irq_to_desc(irq);

       if (!desc)

              return -EINVAL;

       if (desc->status & IRQ_NOREQUEST)

              return -EINVAL;

       if (!handler)

              return -EINVAL;

       action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);

       if (!action)

              return -ENOMEM;

       action->handler = handler;

       action->thread_fn = thread_fn;

       action->flags = irqflags;

       action->name = devname;

       action->dev_id = dev_id;

       retval = __setup_irq(irq, desc, action);

}

 


你可能感兴趣的:(数据结构,function,struct,null,action,Descriptor)