首先非常感谢陈莉君老师的指点,题目名字也是陈老师起的,也很荣幸此文章能在蜗窝上发表一次,感谢郭大侠给的机会

如下为本人原创,在解决问题的过程中的一点心得,如果有描述不准确的地方还请各位指出,非常感谢

Linux内核版本:linux-4.9.18

曾有一次调试触摸屏的时候遇到如下的问题

/startup/modules #
[ 233.370296] irq : nobody cared (try booting with the "irqpoll" option)
[ 233.376983] CPU: PID: Comm: swapper Tainted: G O 4.9. #
[ 233.383912] Hardware name: Broadcom Cygnus SoC
[ 233.388378] [<c010cbfc>] (unwind_backtrace) from [<c010a5fc>] (show_stack+0x10/0x14)
[ 233.396103] [<c010a5fc>] (show_stack) from [<c0145d38>] (__report_bad_irq+0x24/0xa4)
[ 233.403821]
[<c0145d38>] (__report_bad_irq) from [<c0145fdc>] (note_interrupt+0x1c8/0x274)
[ 233.412052]
[<c0145fdc>] (note_interrupt) from [<c014400c>] (handle_irq_event_percpu+0x44/0x50)
[ 233.420715]
[<c014400c>] (handle_irq_event_percpu) from [<c0144040>] (handle_irq_event+0x28/0x3c)
[ 233.429550]
[<c0144040>] (handle_irq_event) from [<c0146574>] (handle_simple_irq+0x70/0x78)
[ 233.437868]
[<c0146574>] (handle_simple_irq) from [<c01438d8>] (generic_handle_irq+0x18/0x28)
[ 233.446366]
[<c01438d8>] (generic_handle_irq) from [<c02adb3c>] (iproc_gpio_irq_handler+0xd0/0x11c)
[ 233.455376]
[<c02adb3c>] (iproc_gpio_irq_handler) from [<c01438d8>] (generic_handle_irq+0x18/0x28)
[ 233.464297]
[<c01438d8>] (generic_handle_irq) from [<c0143980>] (__handle_domain_irq+0x80/0xa4)
[ 233.472959]
[<c0143980>] (__handle_domain_irq) from [<c01013d0>] (gic_handle_irq+0x50/0x84)
[ 233.481275] [<c01013d0>] (gic_handle_irq) from [<c010b02c>] (__irq_svc+0x6c/0x90)
[ 233.488723] Exception stack(0xc0901f60 to 0xc0901fa8)
[ 233.493754] 1f60: c0112900 c0717028 c0901fb8 c093af4c c0826220
[ 233.501896] 1f80: 414fc091 df9eab80 c0900038 c0901fb0 c010843c c0108440
[ 233.510034] 1fa0: ffffffff
[ 233.513514] [<c010b02c>] (__irq_svc) from [<c0108440>] (arch_cpu_idle+0x2c/0x38)
[ 233.520887] [<c0108440>] (arch_cpu_idle) from [<c013a6ec>] (cpu_startup_entry+0x50/0xc0)
[ 233.528956] [<c013a6ec>] (cpu_startup_entry) from [<c0800d70>] (start_kernel+0x414/0x4b0)
[ 233.537097] handlers:
[ 233.539363]
[<c014408c>] irq_default_primary_handler threaded [<bf03ff68>] synaptics_rmi4_irq [synaptics_dsx]
[ 233.549300] Disabling IRQ #

首先我们顺着错误跟踪linux内核来看下

kernel/irq/spurious.c

因此有提示的log信息可以看出,是走的else的分支,bad_action_ret(action_ret)返回为0

通过此函数的dump_stack的信息,可以追溯到调用者

drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

kernel/irq/chip.c

handle_level_irq

===> handle_irq_event  (kernel/irq/handle.c)

===> handle_irq_event_percpu   (kernel/irq/handle.c)

===>__handle_irq_event_percpu  (kernel/irq/handle.c)

根据log,我们可以在下图看到note_interrupt,即说明noirqdebug=0

Kernel/irq/handle.c

因为上面我们已经分析过bad_action_ret(action_ret)返回为0

因此在note_interrupt函数里面只会从如下分支进去

Kernel/irq/spurious.c

从上图可以看出,如果想出现那样的错误,必须满足条件

desc->irqs_unhandled > 99900 为真

如要要满足如上条件的话,那么只有如下地方会让irqs_unhandled++

Kernel/irq/spurious.c

通过上图,我们可以看到,必须满足条件:

action_ret == IRQ_NONE为真

再继续看回如下图,action_ret就是retval

res即为action_ret

而 action->handler的回调函数是:

request_threaded_irq线程化注册中断的第2个参数

kernel/irq/manage.c

因为handler为NULL,所以handler = irq_default_primary_handler

action_ret = IRQ_WAKE_THREAD

Kernel/irq/spurious.c

经过如上图,我们可以发现action_ret = IRQ_NONE

那么我们接下来看看到底是怎么被调用到这里的,一个中断的产生又是怎样的?

首先handle_level_irq这个函数是在这里注册到kernel中的

drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

static int iproc_gpio_probe(struct platform_device *pdev)

===> gpiochip_irqchip_add

Include/linux/gpio/driver.h

typedef    void (*irq_flow_handler_t)(struct irq_desc *desc);

这里即gpiochip->irq_handler = handle_level_irq

struct irqaction *action

一个中断开始的时候

arch/arm/kernel/entry-armv.S

这里有一个全局的handle_arch_irq

这个全局的handle_arch_irq会在如下地方被赋值

arch/arm/kernel/setup.c

void __init setup_arch(char **cmdline_p)

===> handle_arch_irq被赋值

那么接下来我们就要找到mdesc->handle_irq又是在哪里被赋值了呢?

drivers/irqchip/irq-gic.c

这里有这样的函数set_handle_irq

接下来我们看下这个函数的实现就知道了

arch/arm/kernel/irq.c

那么这个set_handle_irq又是在哪里被调用的呢?

针对内核版本Linux-4.9.18

drivers/irqchip/irq-gic.c

gic_of_init

===>__gic_init_bases

===>set_handle_irq

Include/linux/irqchip.h

Include/linux/of.h

Include/linux/of.h

因此我们得出一个结论:

handle_arch_irq = gic_handle_irq

一个中断开始后,从entry-armv.S中进入

handle_domain_irq

===> __handle_domain_irq

===>generic_handle_irq

===>generic_handle_irq_desc

这里的desc->handle_irq 其实就是handle_level_irq

这里是如何转换过去的呢?

drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

gpiochip_set_chained_irqchip

===> irq_set_chained_handler_and_data

===> __irq_do_set_handler

Kernel/irq/chip.c

回归到最初的问题,之前我们分析出如下的结论:

如果想出现log那样的错误,必须满足条件

desc->irqs_unhandled > 99900 为真

如要要满足如上条件的话,那么只有让irqs_unhandled++

那么满足这个条件就必须action_ret == IRQ_NONE

#define SPURIOUS_DEFERRED        0x80000000

如下图:

也就是必须要满足handled != desc->threads_handled_last 为假

这里handled = threads_handled

而desc->threads_handled_last会在如下位置设置为SPURIOUS_DEFERRED

再看下图

Kernel/irq/manage.c

Irq_thread

这里会一直将threads_handled++ ,这里handled = threads_handled

直到满足handled != desc->threads_handled_last 为假

那么为什么这个threads_handled会一直++呢?

因为这里:

上图是正确的修改,如果gpiochip_irqchip_add的第四个参数是handle_simple_irq的话,

那么就会出现threads_handled会一直++的情况,从而产生本文最开头的错误

[  233.370296] irq 44: nobody cared (try booting with the "irqpoll" option)

[  233.549300] Disabling IRQ #44

这里我们就要对handle_simple_irq 与handle_level_irq做个分析了,具体的分析大家可以网上看蜗窝的资料以及csdn上很多对这块有详细的描述,我这里简单叙述下我个人的理解

首先上代码:

大家可以看出来,handle_simple_irq做的事情很简单,而handle_level_irq却做了这个动作:

mask_ack_irq(desc); 因为是电平中断,如果不做mask中断的动作的话,会因为中断电平一直是有效电平导致中断控制器会源源不断地给cpu发中断

而handle_simple_irq就是非常简单的处理中断,没有mask中断,原本代码是写的handle_simple_irq,而触摸屏的中断是设置为线程化的,并且为电平触发方式,那么如果没有mask该中断,那么当一次线程化中断处理函数还未执行完成的时候,又会有源源不断地中断一直进来,那么就会出现threads_handled会一直++的情况,从而产生本文最开头的错误

到此这个问题就已经分析完了

感谢网友smcdef的建议

我们分析如下

中断控制器怎么判断哪个是哪个handle_level_irq?
中断控制器流程:
gic_handle_irq
    ===>handle_domain_irq
        ===>__handle_domain_irq
            ===>irq_find_mapping 
            ===>generic_handle_irq
 
irq_find_mapping这个函数来找之前irq_create_mapping的irq映射
找到返回中断号后,再去执行handle_level_irq
 

因此不同的驱动在注册的时候可以注册自己所需要的中断控制器驱动方式

request_threaded_irq
    ===>__setup_irq
        ==>__irq_set_trigger
            ===>irq_set_type

所以可以这样改,驱动注册的时候可以通过这个函数来设置自己的中断控制器需要走哪种流控处理

内核也有其他驱动有类似的改法
drivers/gpio/gpio-aspeed.c
static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)
{
u32 type0 = ;
u32 type1 = ;
u32 type2 = ;
u32 bit, reg;
const struct aspeed_gpio_bank *bank;
irq_flow_handler_t handler;
struct aspeed_gpio *gpio;
unsigned long flags;
void __iomem *addr;
int rc; rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit);
if (rc)
return -EINVAL; switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_BOTH:
type2 |= bit;
case IRQ_TYPE_EDGE_RISING:
type0 |= bit;
case IRQ_TYPE_EDGE_FALLING:
handler = handle_edge_irq;
break;
case IRQ_TYPE_LEVEL_HIGH:
type0 |= bit;
case IRQ_TYPE_LEVEL_LOW:
type1 |= bit;
handler = handle_level_irq;
break;
default:
return -EINVAL;
} spin_lock_irqsave(&gpio->lock, flags); addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE0);
reg = ioread32(addr);
reg = (reg & ~bit) | type0;
iowrite32(reg, addr); addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE1);
reg = ioread32(addr);
reg = (reg & ~bit) | type1;
iowrite32(reg, addr); addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE2);
reg = ioread32(addr);
reg = (reg & ~bit) | type2;
iowrite32(reg, addr); spin_unlock_irqrestore(&gpio->lock, flags); irq_set_handler_locked(d, handler); return ;
}

如下只是个小记录:

这个函数的作用是检查是否有中断嵌套

参考:

http://www.wowotech.net/irq_subsystem/request_threaded_irq.html

http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html

https://blog.csdn.net/tiantao2012/article/details/78062621

https://blog.csdn.net/tiantao2012/article/details/78094691

https://blog.csdn.net/zhao2272062978/article/details/70599978

https://blog.csdn.net/droidphone/article/details/7467436

https://blog.csdn.net/droidphone/article/details/7445825

https://blog.csdn.net/droidphone/article/category/1118447

https://blog.csdn.net/phenix_lord/article/details/45116259

https://blog.csdn.net/phenix_lord/article/details/45116595

https://blog.csdn.net/phenix_lord/article/details/45116689

https://blog.csdn.net/DroidPhone/article/details/7489756

对中断的理解handle_level_irq【原创】的更多相关文章

  1. ARM7中断的理解

    谈谈对中断的理解?   中断是计算机中处理异步事件的重要机制      中断触发的方式:       1)中断源级设置          按键:(CPU之外的硬件)               设置中 ...

  2. ARM学习篇 中断定时理解

    1. 中断控制器 a. 中断处理流程 P1--摘自S3C2440A手册 P1简要阐述了S3C2440A内置中断控制器处理中断的流程: ●​若某中断有自中断,则先接收子中断请求,否则,直接接受源中断. ...

  3. STM32外部中断初理解

    PA0,PB0...PG0--->EXTI0 PA1,PB1...PG1--->EXTI1 ....... PA15,PB15...PG15--->EXTI15 以上为GPIO和中断 ...

  4. 理解Linux中断 (1)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/7425685 版权声明:本文为博主原创文章,未经博主允许不得转载. 一直认为,理解中断是理解内核 ...

  5. 对中断interrupt的理解

    一.中断 线程的几种状态:新建.就绪.运行.阻塞.死亡.参考:线程的几种状态转换 线程的可运行状态并不代表线程一定在运行(runnable != running ) . 大家都知道:所有现代桌面和服务 ...

  6. 【原创】Linux中断子系统(三)-softirq和tasklet

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  7. Linux kernel的中断子系统之(三):IRQ number和中断描述符

    返回目录:<ARM-Linux中断系统>. 总结: 二描述了中断处理示意图,以及关中断.开中断,和IRQ number重要概念. 三介绍了三个重要的结构体,irq_desc.irq_dat ...

  8. linux kernel的中断子系统之(三):IRQ number和中断描述符【转】

    转自:http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html 一.前言 本文主要围绕IRQ number和中断描述符(interr ...

  9. Linux系统的中断、系统调用和调度概述【转】

    转自:http://blog.csdn.net/yanlinwang/article/details/8169725 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近学习Linux操作系统, ...

随机推荐

  1. Swift 2.2 的新特性

    导读:本文来自SwiftGG翻译组,作者@walkingway基于苹果Swift官方博客中Ted Kremenek所撰写的"Swift 2.2 Released!"文章进行了关于S ...

  2. var 和 let 的异同?

    相同点 声明后未赋值表现一致 不同点 1.使用未声明的变量表现不同 2.变量作用范围不同 3.var可以声明多次 let只能声明一次 let的好处就是当我们在写代码的时候可以避免在不知道的情况下重复声 ...

  3. python之路--day8---day9--两日内容

    一.不使用函数的问题 1,代码的组织结构不清晰,可读性差 2,遇到重复的功能只能重复编写实现代码,代码冗余 3,功能需要扩展时,需要找出所有实现该功能的地方修改,无法统一管理且维护难度极大 二.函数是 ...

  4. WebDriverException : Missing 'type' parameter

    下载最新的geckodriver即可 v0.17.0 Releases · mozilla/geckodriver · GitHubhttps://github.com/mozilla/geckodr ...

  5. js解决IE8不支持html5,css3的问题(respond.js 的使用注意)

    IE8.0及以下不支持html5,css3的解析.目前为止IE8以下的版本使用率在10%左右,网站还是有必要兼容的. 1,在你的所有css最后判断引入两个js文件. html5.js  是用来让ie8 ...

  6. AngularJS1.X学习笔记12-Ajax

    说到Ajax,你一定是思绪万千,想到XMLHttpRequest,$.ajax(),跨域,异步之类的.本文将探讨一下AngularJS的Ajax. 一.一个简单的例子 <!DOCTYPE htm ...

  7. DSkin 的WebUI开发模式介绍,Html快速开发Winform的UI

    新版WebUI开发模式采用MiniBlink内核,这个内核功能更完善,dll压缩之后才5M,而且提供开发者功能,内核还在更新中,而且是开源项目:https://github.com/weolar/mi ...

  8. 高级OOP特性(6)

    PHP不支持的高级OPP特性 PHP不支持通过函数重载实现多态 PHP不支持多重继承 PHP不支持根据所修改数据类型为操作符赋予新的含义 对象克隆 克隆实例 在对象前面添加clone关键字来克隆对象, ...

  9. final类与final方法

    inal---用于类.方法前. final类---不可被继承. final方法---不可被覆盖. final类不能被继承. 如果我们不希望一个类被继承,我们使用final来修饰这个类.这个类将无法被继 ...

  10. python实现归并排序,归并排序的详细分析。

    学习归并排序的过程是十分痛苦的.它并不常用,看起来时间复杂度好像是几种排序中最低的,比快排的时间复杂度还要低,但是它的执行速度不是最快的.很多朋友不理解时间复杂度低为什么运行速度不一定快,这个不清楚的 ...