Android 工程之enable_irq_wake問題

/*****************************************************************************
 * Author : Elvins Fu    [email protected]
 *
 * Info : xxx Inc,(C) 2018-01-11, All rights revseved.
 *
 * Description : This document is summed up by the author for that the company of xxxs  
 * R&D debug interrupt on the android platform driver。
 *
 * This context describes that sd card problem and methods to analysis.
****************************************************************************/

1.先補充點理論知識enable_irq & enable_irq_wake

一、Unbalanced enable for IRQ XX
使能中斷不平衡,主要原因是在申請中斷時已經調用了一次enable_irq()。所以在申請中斷成功後,使用enable_irq()之前需要先調用一次disable_irq()。
如果產生不平衡,則會報出dump_stack(),如上的Unbalanced enable for IRQ XX。
同樣的,如果連續調用同一個中斷的enable_irq()或者disable_irq(),也會產生dump_stack(),不能連續使能,這個就靠代碼邏輯了。

二、enable_irq & enable_irq_wake
enable_irq():用於使能中斷,只在系統正常運行狀態下產生的IRQ會上報。
enable_irq_wake():用於使能中斷,不僅在系統正常運行狀態下產生的IRQ會上報,同時在系統休眠的情況下產生的IRQ會上報。

2.irq導致的unbalance實例分析和修改

1)串口信息

[   51.932842] ------------[ cut here ]------------
[   51.936438] WARNING: CPU: 0 PID: 3039 at /home/fujw/fujw/Android8.0/QT4004/LINUX/android/kernel/msm-3.18/kernel/irq/manage.c:543 irq_set_irq_wake+0x88/0xec()
[   51.950494] Unbalanced IRQ 119 wake disable
[   51.954654] Modules linked in:
[   51.957696] CPU: 0 PID: 3039 Comm: NonUiTaskBuilde Not tainted 3.18.71-svn2976 #5
[   51.965172] [<c010e384>] (unwind_backtrace) from [<c010b3f8>] (show_stack+0x10/0x14)
[   51.972901] [<c010b3f8>] (show_stack) from [<c0c6eadc>] (dump_stack+0x78/0x98)
[   51.980109] [<c0c6eadc>] (dump_stack) from [<c011d3ec>] (warn_slowpath_common+0x64/0x88)
[   51.988182] [<c011d3ec>] (warn_slowpath_common) from [<c011d43c>] (warn_slowpath_fmt+0x2c/0x3c)
[   51.996863] [<c011d43c>] (warn_slowpath_fmt) from [<c016dc30>] (irq_set_irq_wake+0x88/0xec)
[   52.005198] [<c016dc30>] (irq_set_irq_wake) from [<c0604e30>] (pn544_disable_irq+0x40/0x58)
[   52.013525] [<c0604e30>] (pn544_disable_irq) from [<c0605338>] (pn544_dev_irq_handler+0x14/0x80)
[   52.022284] [<c0605338>] (pn544_dev_irq_handler) from [<c016d630>] (handle_irq_event_percpu+0xa4/0x294)
[   52.031655] [<c016d630>] (handle_irq_event_percpu) from [<c016d85c>] (handle_irq_event+0x3c/0x5c)
[   52.040511] [<c016d85c>] (handle_irq_event) from [<c0170580>] (handle_level_irq+0xdc/0x120)
[   52.048844] [<c0170580>] (handle_level_irq) from [<c016cd68>] (generic_handle_irq+0x20/0x2c)
[   52.057265] [<c016cd68>] (generic_handle_irq) from [<c040a5ec>] (msm_gpio_irq_handler+0x100/0x158)
[   52.066205] [<c040a5ec>] (msm_gpio_irq_handler) from [<c016cd68>] (generic_handle_irq+0x20/0x2c)
[   52.074972] [<c016cd68>] (generic_handle_irq) from [<c016d040>] (__handle_domain_irq+0x94/0xd0)
[   52.083652] [<c016d040>] (__handle_domain_irq) from [<c010071c>] (gic_handle_irq+0x48/0x7c)
[   52.091986] [<c010071c>] (gic_handle_irq) from [<c0c7ad50>] (__irq_usr+0x50/0x80)
[   52.099445] Exception stack(0xdcd89fb0 to 0xdcd89ff8)
[   52.104484] 9fa0:                                     a7cb2c30 000003b8 00000001 00000180
[   52.112645] 9fc0: b09808c0 a6a7a408 a7ca5e60 a7c80000 b0980040 a6a7a408 12c12128 13ac0160
[   52.120803] 9fe0: b369162c 988fc708 b365d517 b365d536 20070030 ffffffff
[   52.127397] ---[ end trace e7065b488e5a0a12 ]---
[   52.134735] CPU2: shutdown

2)中斷代碼出錯分析

int irq_set_irq_wake(unsigned int irq, unsigned int on)
{
        unsigned long flags;
        struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
        int ret = 0;

        if (!desc)
                return -EINVAL;

        /* wakeup-capable irqs can be shared between drivers that
         * don't need to have the same sleep mode behaviors.
         */
        if (on) {
                if (desc->wake_depth++ == 0) {
                        ret = set_irq_wake_real(irq, on);
                        if (ret)
                                desc->wake_depth = 0;
                        else
                                irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
                }
        } else {
                if (desc->wake_depth == 0) {
                        WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
                } else if (--desc->wake_depth == 0) {
                        ret = set_irq_wake_real(irq, on);
                        if (ret)
                                desc->wake_depth = 1;
                        else
                                irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);
                }
        }
        irq_put_desc_busunlock(desc, flags);
        return ret;
}

3)分析原因及其修改

根據一個做++操作,一個做–操作。可以得出disable_irq與enable_irq需要成對的使用。屏蔽掉irq_wake做測試即可。

Index: kernel/msm-3.18/drivers/nfc/pn544/pn54x.c
===================================================================
--- kernel/msm-3.18/drivers/nfc/pn544/pn54x.c (revision 3020)
+++ kernel/msm-3.18/drivers/nfc/pn544/pn54x.c (working copy)
@@ -99,7 +99,7 @@
     spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags);
     if (pn544_dev->irq_enabled) {
         disable_irq_nosync(pn544_dev->client->irq);
-        disable_irq_wake(pn544_dev->client->irq);
+ //       disable_irq_wake(pn544_dev->client->irq);
         pn544_dev->irq_enabled = false;
     }
     spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags);
@@ -146,7 +146,7 @@
         while (1) {
             pn544_dev->irq_enabled = true;
             enable_irq(pn544_dev->client->irq);
-            enable_irq_wake(pn544_dev->client->irq);
+//            enable_irq_wake(pn544_dev->client->irq);
             ret = wait_event_interruptible(
                     pn544_dev->read_wq,
                     !pn544_dev->irq_enabled);
@@ -741,7 +741,7 @@
     unsigned long tempJ = msecs_to_jiffies(timeout);
     if(down_timeout(&ese_access_sema, tempJ) != 0)
     {
-        printk("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state);
+        pr_info("get_ese_lock: timeout p61_current_state = %d\n", p61_current_state);  //printk ----> pr_info
         return -EBUSY;
     }
     return 0;
@@ -930,7 +930,7 @@
         goto err_request_irq_failed;
     }
     pr_info("%s : Enabling IRQ Wake\n", __func__);
-    enable_irq_wake(pn544_dev->client->irq);
+//    enable_irq_wake(pn544_dev->client->irq);
     pn544_disable_irq(pn544_dev);
     i2c_set_clientdata(client, pn544_dev);

 

3.推薦兩篇比較全面和專業的博客

1.irq balance詳解:https://blog.csdn.net/whrszzc/article/details/50533866

2.linux request irq詳解 :https://blog.csdn.net/wealoong/article/details/7566546

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章