From f140232c39456dcc1246cee56141f718a7d4a028 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Fri, 11 Aug 2023 19:25:27 +0530 Subject: [PATCH] cnss2: Fix DEV SOL interrupt issue Fix misfiring of DEV SOL interrupt during enable_irq(). Ignore DEV SOL interrupt in case of device power off as it is expected as part of off sequence. In case of HOST triggered recovery, CNSS driver tries to put device to RDDM first using MHI_SYS_ERR and HOST_RESET_REQUEST if MHI_SYS_ERR fails. With SOL enable, replace HOST_RESET_REQUEST with HOST_SOL. Change-Id: I90c1a2dbd68c4c9c2e56d87dd1304a6ab0db53eb CRs-Fixed: 3590408 --- cnss2/bus.c | 17 +++++++++++++++- cnss2/bus.h | 3 ++- cnss2/debug.c | 7 ++++++- cnss2/main.c | 14 ++++++++----- cnss2/main.h | 3 ++- cnss2/pci.c | 56 ++++++++++++++++++++++++++++++++++++++++++--------- cnss2/pci.h | 3 ++- cnss2/power.c | 5 ++++- 8 files changed, 88 insertions(+), 20 deletions(-) diff --git a/cnss2/bus.c b/cnss2/bus.c index e6472cfeca..b263bedbe2 100644 --- a/cnss2/bus.c +++ b/cnss2/bus.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "bus.h" @@ -586,6 +586,21 @@ int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv) } } +int cnss_bus_shutdown_cleanup(struct cnss_plat_data *plat_priv) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_shutdown_cleanup(plat_priv->bus_priv); + default: + cnss_pr_dbg("Unsupported bus type: %d\n", + plat_priv->bus_type); + return 0; + } +} + int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv) { if (!plat_priv) diff --git a/cnss2/bus.h b/cnss2/bus.h index eadea243d3..7834e79760 100644 --- a/cnss2/bus.h +++ b/cnss2/bus.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CNSS_BUS_H @@ -55,6 +55,7 @@ int cnss_bus_update_status(struct cnss_plat_data *plat_priv, int cnss_bus_update_uevent(struct cnss_plat_data *plat_priv, enum cnss_driver_status status, void *data); int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv); +int cnss_bus_shutdown_cleanup(struct cnss_plat_data *plat_priv); int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv); int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv); int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset, diff --git a/cnss2/debug.c b/cnss2/debug.c index 7d3fd8db9c..469aab4d1d 100644 --- a/cnss2/debug.c +++ b/cnss2/debug.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ -/* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -174,6 +174,9 @@ static int cnss_stats_show_state(struct seq_file *s, case CNSS_DRIVER_REGISTERED: seq_puts(s, "DRIVER REGISTERED"); continue; + case CNSS_POWER_OFF: + seq_puts(s, "POWER OFF"); + continue; } seq_printf(s, "UNKNOWN-%d", i); @@ -262,6 +265,8 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp, 0, NULL); clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state); } else if (sysfs_streq(cmd, "assert_host_sol")) { + pci_priv = plat_priv->bus_priv; + cnss_auto_resume(&pci_priv->pci_dev->dev); ret = cnss_set_host_sol_value(plat_priv, 1); } else if (sysfs_streq(cmd, "deassert_host_sol")) { ret = cnss_set_host_sol_value(plat_priv, 0); diff --git a/cnss2/main.c b/cnss2/main.c index e7525ae97e..9aa4e390b9 100644 --- a/cnss2/main.c +++ b/cnss2/main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1694,7 +1694,6 @@ int cnss_enable_dev_sol_irq(struct cnss_plat_data *plat_priv) if (sol_gpio->dev_sol_gpio < 0 || sol_gpio->dev_sol_irq <= 0) return 0; - enable_irq(sol_gpio->dev_sol_irq); ret = enable_irq_wake(sol_gpio->dev_sol_irq); if (ret) cnss_pr_err("Failed to enable device SOL as wake IRQ, err = %d\n", @@ -1715,7 +1714,6 @@ int cnss_disable_dev_sol_irq(struct cnss_plat_data *plat_priv) if (ret) cnss_pr_err("Failed to disable device SOL as wake IRQ, err = %d\n", ret); - disable_irq(sol_gpio->dev_sol_irq); return ret; } @@ -1735,9 +1733,15 @@ static irqreturn_t cnss_dev_sol_handler(int irq, void *data) struct cnss_plat_data *plat_priv = data; struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio; + if (test_bit(CNSS_POWER_OFF, &plat_priv->driver_state)) { + cnss_pr_dbg("Ignore Dev SOL during device power off"); + return IRQ_HANDLED; + } + sol_gpio->dev_sol_counter++; - cnss_pr_dbg("WLAN device SOL IRQ (%u) is asserted #%u\n", - irq, sol_gpio->dev_sol_counter); + cnss_pr_dbg("WLAN device SOL IRQ (%u) is asserted #%u, dev_sol_val: %d\n", + irq, sol_gpio->dev_sol_counter, + cnss_get_dev_sol_value(plat_priv)); /* Make sure abort current suspend */ cnss_pm_stay_awake(plat_priv); diff --git a/cnss2/main.h b/cnss2/main.h index a610e5c16c..645b88c7d6 100644 --- a/cnss2/main.h +++ b/cnss2/main.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CNSS_MAIN_H @@ -362,6 +362,7 @@ enum cnss_driver_state { CNSS_FS_READY = 25, CNSS_DRIVER_REGISTERED, CNSS_DMS_DEL_SERVER, + CNSS_POWER_OFF, }; struct cnss_recovery_data { diff --git a/cnss2/pci.c b/cnss2/pci.c index 1edd7052a6..e500240e76 100644 --- a/cnss2/pci.c +++ b/cnss2/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1838,6 +1838,20 @@ int cnss_pci_is_device_down(struct device *dev) } EXPORT_SYMBOL(cnss_pci_is_device_down); +int cnss_pci_shutdown_cleanup(struct cnss_pci_data *pci_priv) +{ + int ret; + + if (!pci_priv) { + cnss_pr_err("pci_priv is NULL\n"); + return -ENODEV; + } + + ret = del_timer(&pci_priv->dev_rddm_timer); + cnss_pr_dbg("%s RDDM timer deleted", ret ? "Active" : "Inactive"); + return ret; +} + void cnss_pci_lock_reg_window(struct device *dev, unsigned long *flags) { spin_lock_bh(&pci_reg_window_lock); @@ -2310,9 +2324,6 @@ retry_mhi_suspend: ret = mhi_force_rddm_mode(pci_priv->mhi_ctrl); if (ret) { cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret); - - cnss_pr_dbg("Sending host reset req\n"); - ret = cnss_mhi_force_reset(pci_priv); cnss_rddm_trigger_check(pci_priv); } break; @@ -5975,8 +5986,24 @@ static void cnss_pci_dump_debug_reg(struct cnss_pci_data *pci_priv) static int cnss_pci_assert_host_sol(struct cnss_pci_data *pci_priv) { - if (cnss_get_host_sol_value(pci_priv->plat_priv)) - return -EINVAL; + int ret; + + ret = cnss_get_host_sol_value(pci_priv->plat_priv); + if (ret) { + if (ret < 0) { + cnss_pr_dbg("Host SOL functionality is not enabled\n"); + return ret; + } else { + cnss_pr_dbg("Host SOL is already high\n"); + /* + * Return success if HOST SOL is already high. + * This will indicate caller that a HOST SOL is + * already asserted from some other thread and + * no further action required from the caller. + */ + return 0; + } + } cnss_pr_dbg("Assert host SOL GPIO to retry RDDM, expecting link down\n"); cnss_set_host_sol_value(pci_priv->plat_priv, 1); @@ -6100,6 +6127,11 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv) return 0; } + /* + * Fist try MHI SYS_ERR, if fails try HOST SOL and return. + * If SOL is not enabled try HOST Reset Rquest after MHI + * SYS_ERRR fails. + */ ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_TRIGGER_RDDM); if (ret) { if (pci_priv->is_smmu_fault) { @@ -6119,6 +6151,13 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv) cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS); return 0; } + + cnss_pr_dbg("Sending Host Reset Req\n"); + if (!cnss_mhi_force_reset(pci_priv)) { + ret = 0; + goto runtime_pm_put; + } + cnss_pci_dump_debug_reg(pci_priv); cnss_schedule_recovery(&pci_priv->pci_dev->dev, CNSS_REASON_DEFAULT); @@ -6734,9 +6773,6 @@ static void cnss_dev_rddm_timeout_hdlr(struct timer_list *t) cnss_fatal_err("Timeout waiting for RDDM notification\n"); - if (!cnss_pci_assert_host_sol(pci_priv)) - return; - mhi_ee = mhi_get_exec_env(pci_priv->mhi_ctrl); if (mhi_ee == MHI_EE_PBL) cnss_pr_err("Device MHI EE is PBL, unable to collect dump\n"); @@ -6746,6 +6782,8 @@ static void cnss_dev_rddm_timeout_hdlr(struct timer_list *t) cnss_schedule_recovery(&pci_priv->pci_dev->dev, CNSS_REASON_RDDM); } else { + if (!cnss_pci_assert_host_sol(pci_priv)) + return; cnss_mhi_debug_reg_dump(pci_priv); cnss_pci_bhi_debug_reg_dump(pci_priv); cnss_pci_soc_scratch_reg_dump(pci_priv); diff --git a/cnss2/pci.h b/cnss2/pci.h index 6dcfd3e07d..833d16cc8f 100644 --- a/cnss2/pci.h +++ b/cnss2/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CNSS_PCI_H @@ -312,6 +312,7 @@ int cnss_pci_update_status(struct cnss_pci_data *pci_priv, int cnss_pci_call_driver_uevent(struct cnss_pci_data *pci_priv, enum cnss_driver_status status, void *data); int cnss_pcie_is_device_down(struct cnss_pci_data *pci_priv); +int cnss_pci_shutdown_cleanup(struct cnss_pci_data *pci_priv); int cnss_pci_suspend_bus(struct cnss_pci_data *pci_priv); int cnss_pci_resume_bus(struct cnss_pci_data *pci_priv); int cnss_pci_debug_reg_read(struct cnss_pci_data *pci_priv, u32 offset, diff --git a/cnss2/power.c b/cnss2/power.c index e92b8d8af7..f87fd40417 100644 --- a/cnss2/power.c +++ b/cnss2/power.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1209,6 +1209,7 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset) } plat_priv->powered_on = true; + clear_bit(CNSS_POWER_OFF, &plat_priv->driver_state); cnss_enable_dev_sol_irq(plat_priv); cnss_set_host_sol_value(plat_priv, 0); @@ -1229,6 +1230,8 @@ void cnss_power_off_device(struct cnss_plat_data *plat_priv) return; } + set_bit(CNSS_POWER_OFF, &plat_priv->driver_state); + cnss_bus_shutdown_cleanup(plat_priv); cnss_disable_dev_sol_irq(plat_priv); cnss_select_pinctrl_state(plat_priv, false); cnss_clk_off(plat_priv, &plat_priv->clk_list);