From 5a313f8705efcb1f4bd77bb20ecf49f6be1d2d7c Mon Sep 17 00:00:00 2001 From: xizx Date: Fri, 17 Apr 2020 20:28:56 +0800 Subject: [PATCH] qpnp-power-on-mmi: support hw_warmreset feature When system is freezed or has no response, DFers often reset the phone by long-press power btn. So there is no useful log for developpers and the issue becomes very hard to analysis. This hw_warmreset feature will trigger a warmreset reboot, so that next cycle system can save the lastkmsg and re-trigger a clean hardware cold reboot. Only when the command line is configured with "hw_warmreset_enable=1", the feature will take effect. Change-Id: I9e0abcf3757b69175125bcf14188ad54f78a087d Reviewed-on: https://gerrit.mot.com/1536790 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Zhenxin Xi Submit-Approved: Jira Key --- .../qpnp_power_on_mmi/qpnp-power-on-mmi.c | 98 ++++++++++++++++++- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c b/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c index 4e2b152296b5..07639fd4c070 100644 --- a/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c +++ b/drivers/input/misc/qpnp_power_on_mmi/qpnp-power-on-mmi.c @@ -40,8 +40,28 @@ struct qpnp_pon_mmi { struct platform_device *pdev; struct delayed_work kpd_bark_work; u32 kpd_bark_irq; + u32 kpd_hw_warmreset; }; +static bool is_hw_warmreset_enabled() +{ + struct device_node *np = of_find_node_by_path("/chosen"); + bool value = false; + const char *bootargs = NULL; + + if (!np) + return false; + + if ((!of_property_read_string(np, "bootargs", &bootargs)) + && (strstr(bootargs, "hw_warmreset_enable=1"))) { + value = true; + } + + of_node_put(np); + + return value; +} + static bool mmi_kungpow_check(void) { struct device_node *soc = of_find_node_by_path("/soc"); @@ -58,16 +78,79 @@ static bool mmi_kungpow_check(void) return has_kungpow; } +static unsigned int get_boot_seq(void) +{ + unsigned int boot_seq = 0; + struct device_node *n = of_find_node_by_path("/chosen"); + + if (n == NULL) + return 0; + + of_property_read_u32(n, "mmi,boot_seq", &boot_seq); + of_node_put(n); + + return boot_seq; +} + +static int print_blocked_tasks() +{ + mm_segment_t fs; + char cmd; + size_t written; + loff_t pos = 0; + struct file *filep; + int rc = 0; + + fs = get_fs(); + set_fs(KERNEL_DS); + + filep = filp_open("/proc/sysrq-trigger", O_WRONLY, 0200); + if (IS_ERR_OR_NULL(filep)) { + rc = PTR_ERR(filep); + pr_err("opening sysrq errno=%d\n", rc); + set_fs(fs); + return rc; + } + + pr_info("set default console loglevel\n"); + cmd = '7'; + written = vfs_write(filep, &cmd, 1, &pos); + if (written < 1) { + pr_err("failed to write sysrq\n"); + rc = -EIO; + } + + pr_info("start to print block task\n"); + cmd = 'w'; + written = vfs_write(filep, &cmd, 1, &pos); + if (written < 1) { + pr_err("failed to write sysrq\n"); + rc = -EIO; + } + + set_fs(fs); + filp_close(filep, NULL); + + return rc; +} + static void kpd_bark_work_func(struct work_struct *work) { struct qpnp_pon_mmi *pon = container_of(work, struct qpnp_pon_mmi, kpd_bark_work.work); - dev_err(&pon->pdev->dev, "HW User Reset! 2 sec to Reset!\n"); - qpnp_pon_store_extra_reset_info(RESET_EXTRA_RESET_KUNPOW_REASON, - mmi_kungpow_check() ? 0 : RESET_EXTRA_RESET_KUNPOW_REASON); - qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); - kernel_halt(); + if (pon->kpd_hw_warmreset) { + pr_err("trigger hw_warmreset, BOOT_SEQ=%d\n", get_boot_seq()); + /* print blocked tasks */ + print_blocked_tasks(); + kernel_restart("hw_warmreset"); + } else { + dev_err(&pon->pdev->dev, "HW User Reset! 2 sec to Reset!\n"); + qpnp_pon_store_extra_reset_info(RESET_EXTRA_RESET_KUNPOW_REASON, + mmi_kungpow_check() ? 0 : RESET_EXTRA_RESET_KUNPOW_REASON); + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + kernel_halt(); + } } static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon) @@ -114,6 +197,11 @@ static int qpnp_pon_mmi_probe(struct platform_device *pdev) return rc; } + if (is_hw_warmreset_enabled()) { + pon->kpd_hw_warmreset = 1; + pr_info("hw_warmreset feature is enabled\n"); + } + return 0; }