Linux-2.6.21 S3c6400中断剖析<一>(原创)-上海嵌入式索漫科技培训教材

xiajiashan   2012-10-10 13:36 楼主
作者:下家山(请尊重原创,转载请注明)  http://www.xiajiashan.com 

一:为什么写这篇文章

        这是我曾经做产品开发时的一个案例!我做研发有个特点就是每做完一个项目习惯写些总结,这是90%搞技术的不能做到的,也许是我记性太差,怕自己忘了曾经解决问题的思路,所以要把她记录下来吧!可以我这一习惯为我研发工作积累了非常宝贵的经验,也为我日后教学准备了非常宝贵的案例教学!

        如果你深入的去想想Linux kernel  中断问题,你会有一系列的疑问。按照常人,或者说自然规律的思考方式(不同的人有不同的头脑,就有不同的思维方式,也就有不同的解决问题的方法,这其中的效率完全不一样。虽然大部分人是常规思维方式,但是千万不要认为你的朋友,对手,同事的思维方式与你一样。),你会有下列疑问:

1.1:中断注册到什么地方去了?

1.2:CPU发生了中断后,kernel是怎么知道的?也就是kernel 是怎么响应到cpu的中断的?

1.3:kernel 响应CPU中断后又怎么回调到当初注册的中断里面去的?

       我们通常在驱动里面要注册中断,都是调用reguest_irq。因为,觉得Linux已经很成熟了,而且各大CPU的BSP也支持得很好。况且我们调试的驱动都是基于当今热门的sumsang ARM MCU。所以,更本就没有去怀疑其BSP。

可是,“最终出问题的地方往往是最先否定的地方”。

我们客户提供的kernel及sumsang 提供的bsp竟然有问题。

二:Linux中断机制流程

言归正传,我带着疑问顺滕摸瓜,揭开Linux-2.6.21-s3c6400中断机制。

2.1 调用的第一个函数request_irq()

我们在写驱动时往往要调用request_irq()函数。那么,我们从这里出发。Reguest_irq的函数原形为

/**见kernel/irq/manage.c

 *    request_irq - allocate an interrupt line

 *    @irq: Interrupt line to allocate

 *    @handler: Function to be called when the IRQ occurs

 *    @irqflags: Interrupt type flags

 *    @devname: An ascii name for the claiming device

 *    @dev_id: A cookie passed back to the handler function

 *

 *    This call allocates interrupt resources and enables the

 *    interrupt line and IRQ handling. From the point this

 *    call is made your handler function may be invoked. Since

 *    your handler function must clear any interrupt the board

 *    raises, you must take care both to initialise your hardware

 *    and to set up the interrupt handler in the right order.

 *

 *    Dev_id must be globally unique. Normally the address of the

 *    device data structure is used as the cookie. Since the handler

 *    receives this value it makes sense to use it.

 *

 *    If your interrupt is shared you must pass a non NULL dev_id

 *    as this is required when freeing the interrupt.

 *

 *    Flags:

 *

 *    IRQF_SHARED           Interrupt is shared

 *    IRQF_DISABLED Disable local interrupts while processing

 *    IRQF_SAMPLE_RANDOM  The interrupt can be used for entropy

 *

 */

int request_irq(unsigned int irq, irq_handler_t handler,

              unsigned long irqflags, const char *devname, void *dev_id)

{

       struct irqaction *action;

       int retval;

#ifdef CONFIG_LOCKDEP

       /*

        * Lockdep wants atomic interrupt handlers:

        */

       irqflags |= IRQF_DISABLED;

#endif

       /*

        * Sanity-check: shared interrupts must pass in a real dev-ID,

        * otherwise we'll have trouble later trying to figure out

        * which interrupt is which (messes up the interrupt freeing

        * logic etc).

        */

       if ((irqflags & IRQF_SHARED) && !dev_id)

              return -EINVAL;

       if (irq >= NR_IRQS)

              return -EINVAL;

       if (irq_desc[irq].status & IRQ_NOREQUEST)

              return -EINVAL;

       if (!handler)

              return -EINVAL;

       action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

       if (!action)

              return -ENOMEM;

       action->handler = handler;/*这一句要注意,我们注册的中断函数句柄就放在这里,当中断发生后,kernel就会调用到这里来,kernel怎么找到这里我后面会讲到*/

       action->flags = irqflags;

       cpus_clear(action->mask);

       action->name = devname;

       action->next = NULL;

       action->dev_id = dev_id;

       select_smp_affinity(irq);

#ifdef CONFIG_DEBUG_SHIRQ

       if (irqflags & IRQF_SHARED) {

              /*

               * It's a shared IRQ -- the driver ought to be prepared for it

               * to happen immediately, so let's make sure....

               * We do this before actually registering it, to make sure that

               * a 'real' IRQ doesn't run in parallel with our fake

               */

              if (irqflags & IRQF_DISABLED) {

                     unsigned long flags;

                     local_irq_save(flags);

                     handler(irq, dev_id);

                     local_irq_restore(flags);

              } else

                     handler(irq, dev_id);

       }

#endif

       retval = setup_irq(irq, action);

       if (retval)

              kfree(action);

       return retval;

}

这个函数其实只做两件事情:

填充(增加)一个活动irq结构体(irqaction)

调用setup_irq函数

2009-2-13   下家山     写于上海.漕河泾

                                   有什么问题可以给我邮件ximenpiaoxue4016@sina.com或加我群198204885

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复