Atheros AR9344中断处理流程

    xiaoxiao2021-12-13  19

    事由: 当我写irq chip的驱动的时候,我发现irq alloc descs这个函数可以不用,我就很奇怪,如果不分配空间创建irqdesc,哪接下来的irq set chip 以及irq set chip data等函数向哪里填充数据。 我继续查看irq set chip等函数,kernel/kernel/irq struct irq_desc *desc=irq_get_desc_lock(irq,&flags)//通过irq来查找desc desc->irq_Data.chip=chip; 那么这个desc肯定是有什么地方创建了 initIRQ->machine_descinit_irq->rkxx_init_irq->gic_init->gic_dist_init-> early_irq_init-> early_irq_init通过arch_probe_nr_irqs获得NR_IRQS,然后分配irq descs

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

    /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

    第一列显示的是中断号,

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

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

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

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

    struct irq_chip {

          const char   *name;

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

     

          

    #ifdefCONFIG_IRQ_RELEASE_METHOD

          void             (*release)(unsigned int irq, void *dev_id);

    #endif

          

          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 __initstart_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 intkstat_irqs_all[NR_IRQS][NR_CPUS];

    int __initearly_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 __initinit_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平台的中断进行初始化。

    {

          

          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

          

          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(unsignedint irq, struct irq_chip *chip,

                         irq_flow_handler_t handle)

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

          set_irq_chip(irq, chip);

          __set_irq_handler(irq, handle, 0, NULL);

    }

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

    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;

    }

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

          

          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;

    }

    #defineATH_CPU_IRQ_BASE        0x00

    #defineATH_MISC_IRQ_BASE             0x10

    #defineATH_GPIO_IRQ_BASE             0x20

    #defineATH_MISC_IRQ_COUNT          14

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

    static void ath_misc_irq_init(intirq_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);

          }

    }

    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(unsignedint irq, irq_handler_t handler,

                         irq_handler_t thread_fn, unsigned longirqflags,

                         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(structirqaction), 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);

    }

    原文:http://blog.csdn.net/suiyuan19840208/article/details/7654265
    转载请注明原文地址: https://ju.6miu.com/read-950092.html

    最新回复(0)