From d6f1f617d46e5f1a14aa09761ac00376a8dd62f9 Mon Sep 17 00:00:00 2001 From: Prashanth Bhatta Date: Thu, 25 Aug 2016 13:57:25 -0700 Subject: [PATCH 1/4] icnss: Separete IPC logging for register access Hardware register access logs added for reset sequence is way too much log but it is necessary for debugging purpose. So create separate IPC logging buffer for register access and make it as depends on debug feature so that it can be configured out in production. CRs-fixed: 1060274 Change-Id: I690e7af912ce3aee5f0a2817e20f00d6a0ec9608 Signed-off-by: Prashanth Bhatta --- drivers/soc/qcom/Kconfig | 9 +++++ drivers/soc/qcom/icnss.c | 72 ++++++++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 0e74093eeb2b..f884f829b51c 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -417,6 +417,15 @@ config ICNSS control messages to FW over QMI channel. It is also responsible for handling WLAN PD restart notifications. +config ICNSS_DEBUG + bool "ICNSS debug support" + depends on ICNSS + ---help--- + Say 'Y' here to enable ICNSS driver debug support. Debug support + primarily consists of logs consisting of information related to + hardware register access and enabling BUG_ON for certain cases to aid + the debugging. + config MSM_SECURE_BUFFER bool "Helper functions for securing buffers through TZ" help diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 26b1cad9d5aa..40ad9cee7a21 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -44,11 +44,11 @@ #include "wlan_firmware_service_v01.h" -#define ICNSS_PANIC 1 #define WLFW_TIMEOUT_MS 3000 #define WLFW_SERVICE_INS_ID_V01 0 #define MAX_PROP_SIZE 32 -#define NUM_LOG_PAGES 4 +#define NUM_LOG_PAGES 10 +#define NUM_REG_LOG_PAGES 4 /* * Registers: MPM2_PSHOLD @@ -156,6 +156,15 @@ ipc_log_string(icnss_ipc_log_context, _x); \ } while (0) +#ifdef CONFIG_ICNSS_DEBUG +#define icnss_ipc_log_long_string(_x...) do { \ + if (icnss_ipc_log_long_context) \ + ipc_log_string(icnss_ipc_log_long_context, _x); \ + } while (0) +#else +#define icnss_ipc_log_long_string(_x...) +#endif + #define icnss_pr_err(_fmt, ...) do { \ pr_err(_fmt, ##__VA_ARGS__); \ icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \ @@ -180,7 +189,13 @@ ##__VA_ARGS__); \ } while (0) -#ifdef ICNSS_PANIC +#define icnss_reg_dbg(_fmt, ...) do { \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("REG: " pr_fmt(_fmt), \ + ##__VA_ARGS__); \ + } while (0) + +#ifdef CONFIG_ICNSS_DEBUG #define ICNSS_ASSERT(_condition) do { \ if (!(_condition)) { \ icnss_pr_err("ASSERT at line %d\n", \ @@ -215,6 +230,10 @@ module_param(quirks, ulong, 0600); void *icnss_ipc_log_context; +#ifdef CONFIG_ICNSS_DEBUG +void *icnss_ipc_log_long_context; +#endif + #define ICNSS_EVENT_PENDING 2989 enum icnss_driver_event_type { @@ -383,7 +402,7 @@ static u32 icnss_hw_read_reg(void *base, u32 offset) { u32 rdata = readl_relaxed(base + offset); - icnss_pr_dbg(" READ: offset: 0x%06x 0x%08x\n", offset, rdata); + icnss_reg_dbg(" READ: offset: 0x%06x 0x%08x\n", offset, rdata); return rdata; } @@ -395,7 +414,7 @@ static void icnss_hw_write_reg_field(void *base, u32 offset, u32 mask, u32 val) val = (rdata & ~mask) | (val << shift); - icnss_pr_dbg("WRITE: offset: 0x%06x 0x%08x -> 0x%08x\n", + icnss_reg_dbg("WRITE: offset: 0x%06x 0x%08x -> 0x%08x\n", offset, rdata, val); icnss_hw_write_reg(base, offset, val); @@ -414,12 +433,12 @@ static int icnss_hw_poll_reg_field(void *base, u32 offset, u32 mask, u32 val, rdata = readl_relaxed(base + offset); - icnss_pr_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", + icnss_reg_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", offset, val, rdata, mask); while ((rdata & mask) != val) { if (retry != 0 && r >= retry) { - icnss_pr_err(" POLL FAILED: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", + icnss_pr_err("POLL FAILED: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", offset, val, rdata, mask); return -EIO; @@ -430,8 +449,8 @@ static int icnss_hw_poll_reg_field(void *base, u32 offset, u32 mask, u32 val, rdata = readl_relaxed(base + offset); if (retry) - icnss_pr_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", - offset, val, rdata, mask); + icnss_reg_dbg(" POLL: offset: 0x%06x 0x%08x == 0x%08x & 0x%08x\n", + offset, val, rdata, mask); } @@ -1239,7 +1258,7 @@ int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index) index, &addr, size, ret); goto out; } - icnss_pr_dbg("hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", + icnss_pr_dbg("Hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", index, source_vmlist[0], dest_nelems, dest_vmids[0], dest_vmids[1], dest_vmids[2]); out: @@ -3416,6 +3435,8 @@ static int icnss_probe(struct platform_device *pdev) return -EEXIST; } + icnss_pr_dbg("Platform driver probe\n"); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -3515,9 +3536,8 @@ static int icnss_probe(struct platform_device *pdev) } else { priv->smmu_iova_start = res->start; priv->smmu_iova_len = resource_size(res); - icnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: %zu\n", - &priv->smmu_iova_start, - priv->smmu_iova_len); + icnss_pr_dbg("SMMU IOVA start: %pa, len: %zu\n", + &priv->smmu_iova_start, priv->smmu_iova_len); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -3527,7 +3547,7 @@ static int icnss_probe(struct platform_device *pdev) } else { priv->smmu_iova_ipa_start = res->start; priv->smmu_iova_ipa_len = resource_size(res); - icnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n", + icnss_pr_dbg("SMMU IOVA IPA start: %pa, len: %zu\n", &priv->smmu_iova_ipa_start, priv->smmu_iova_ipa_len); } @@ -3688,6 +3708,26 @@ static struct platform_driver icnss_driver = { }, }; +#ifdef CONFIG_ICNSS_DEBUG +static void __init icnss_ipc_log_long_context_init(void) +{ + icnss_ipc_log_long_context = ipc_log_context_create(NUM_REG_LOG_PAGES, + "icnss_long", 0); + if (!icnss_ipc_log_long_context) + icnss_pr_err("Unable to create register log context\n"); +} + +static void __exit icnss_ipc_log_long_context_destroy(void) +{ + ipc_log_context_destroy(icnss_ipc_log_long_context); + icnss_ipc_log_long_context = NULL; +} +#else + +static void __init icnss_ipc_log_long_context_init(void) { } +static void __exit icnss_ipc_log_long_context_destroy(void) { } +#endif + static int __init icnss_initialize(void) { icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES, @@ -3695,6 +3735,8 @@ static int __init icnss_initialize(void) if (!icnss_ipc_log_context) icnss_pr_err("Unable to create log context\n"); + icnss_ipc_log_long_context_init(); + return platform_driver_register(&icnss_driver); } @@ -3703,6 +3745,8 @@ static void __exit icnss_exit(void) platform_driver_unregister(&icnss_driver); ipc_log_context_destroy(icnss_ipc_log_context); icnss_ipc_log_context = NULL; + + icnss_ipc_log_long_context_destroy(); } From 8080b08a6c08cbb8da348454519e9d75bcc76148 Mon Sep 17 00:00:00 2001 From: Prashanth Bhatta Date: Thu, 25 Aug 2016 17:01:24 -0700 Subject: [PATCH 2/4] defconfig: msmcortex: Enable CONFIG_ICNSS_DEBUG Enable CONFIG_ICNSS_DEBUG to enable driver debugging. CRs-fixed: 1060274 Change-Id: I0c594ca4db2a39078a480e45e422c24aa5afba04 Signed-off-by: Prashanth Bhatta --- arch/arm64/configs/msmcortex_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 686e1c22c5ae..6933757a1869 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -523,6 +523,7 @@ CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_IRQ_HELPER=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y CONFIG_MSM_GLADIATOR_ERP_V2=y CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y From b0aac0da3df6bb3fc89ac822f166cf0f0376e0ec Mon Sep 17 00:00:00 2001 From: Prashanth Bhatta Date: Thu, 25 Aug 2016 17:01:43 -0700 Subject: [PATCH 3/4] icnss: Enhance debugging capabilities There are instances of QMI message timeout and because of this stability issues are seen way after the QMI message failure. To aid the debugging, enhance the debug capabilities by adding ASSERT in case of failure. Also update the logs properly to indicate which message really failed. CRs-fixed: 1060274 Change-Id: Ie817970cb10c879d04ffe5e2a853ada8bf8a1f88 Signed-off-by: Prashanth Bhatta --- drivers/soc/qcom/icnss.c | 169 +++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 87 deletions(-) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 40ad9cee7a21..6812aaea37ff 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1254,7 +1254,7 @@ int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index) ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) { - icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", + icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", index, &addr, size, ret); goto out; } @@ -1290,7 +1290,7 @@ int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index) ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) { - icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", + icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", index, &addr, size, ret); goto out; } @@ -1329,16 +1329,14 @@ static void icnss_remove_msa_permissions(struct icnss_priv *priv) static int wlfw_msa_mem_info_send_sync_msg(void) { - int ret = 0; + int ret; int i; struct wlfw_msa_info_req_msg_v01 req; struct wlfw_msa_info_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending MSA mem info, state: 0x%lx\n", penv->state); @@ -1361,15 +1359,14 @@ static int wlfw_msa_mem_info_send_sync_msg(void) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); + icnss_pr_err("Send MSA Mem info req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI MSA Mem info request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.msa_info_err++; goto out; } @@ -1380,7 +1377,6 @@ static int wlfw_msa_mem_info_send_sync_msg(void) icnss_pr_err("Invalid memory region length received: %d\n", resp.mem_region_info_len); ret = -EINVAL; - penv->stats.msa_info_err++; goto out; } @@ -1398,7 +1394,11 @@ static int wlfw_msa_mem_info_send_sync_msg(void) penv->icnss_mem_region[i].secure_flag); } + return 0; + out: + penv->stats.msa_info_err++; + ICNSS_ASSERT(false); return ret; } @@ -1409,10 +1409,8 @@ static int wlfw_msa_ready_send_sync_msg(void) struct wlfw_msa_ready_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending MSA ready request message, state: 0x%lx\n", penv->state); @@ -1432,20 +1430,23 @@ static int wlfw_msa_ready_send_sync_msg(void) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - penv->stats.msa_ready_err++; - icnss_pr_err("Send req failed %d\n", ret); + icnss_pr_err("Send MSA ready req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI MSA ready request failed %d %d\n", resp.resp.result, resp.resp.error); - penv->stats.msa_ready_err++; ret = resp.resp.result; goto out; } penv->stats.msa_ready_resp++; + + return 0; + out: + penv->stats.msa_ready_err++; + ICNSS_ASSERT(false); return ret; } @@ -1456,10 +1457,8 @@ static int wlfw_ind_register_send_sync_msg(void) struct wlfw_ind_register_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending indication register message, state: 0x%lx\n", penv->state); @@ -1487,21 +1486,24 @@ static int wlfw_ind_register_send_sync_msg(void) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); - penv->stats.ind_register_resp++; if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.ind_register_err++; + icnss_pr_err("Send indication register req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI indication register request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.ind_register_err++; goto out; } + penv->stats.ind_register_resp++; + + return 0; + out: + penv->stats.ind_register_err++; + ICNSS_ASSERT(false); return ret; } @@ -1512,10 +1514,8 @@ static int wlfw_cap_send_sync_msg(void) struct wlfw_cap_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending capability message, state: 0x%lx\n", penv->state); @@ -1534,16 +1534,14 @@ static int wlfw_cap_send_sync_msg(void) &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.cap_err++; + icnss_pr_err("Send capability req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI capability request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.cap_err++; goto out; } @@ -1565,7 +1563,12 @@ static int wlfw_cap_send_sync_msg(void) penv->board_info.board_id, penv->soc_info.soc_id, penv->fw_version_info.fw_version, penv->fw_version_info.fw_build_timestamp); + + return 0; + out: + penv->stats.cap_err++; + ICNSS_ASSERT(false); return ret; } @@ -1576,10 +1579,8 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) struct wlfw_wlan_mode_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; /* During recovery do not send mode request for WLAN OFF as * FW not able to process it. @@ -1611,20 +1612,24 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.mode_req_err++; + icnss_pr_err("Send mode req failed, mode: %d ret: %d\n", + mode, ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", - resp.resp.result, resp.resp.error); + icnss_pr_err("QMI mode request failed mode: %d, %d %d\n", + mode, resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.mode_req_err++; goto out; } penv->stats.mode_resp++; + + return 0; + out: + penv->stats.mode_req_err++; + ICNSS_ASSERT(false); return ret; } @@ -1635,10 +1640,8 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) struct wlfw_wlan_cfg_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { + if (!penv || !penv->wlfw_clnt) return -ENODEV; - goto out; - } icnss_pr_dbg("Sending config request, state: 0x%lx\n", penv->state); @@ -1660,20 +1663,23 @@ static int wlfw_wlan_cfg_send_sync_msg(struct wlfw_wlan_cfg_req_msg_v01 *data) &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("Send req failed %d\n", ret); - penv->stats.cfg_req_err++; + icnss_pr_err("Send config req failed %d\n", ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", + icnss_pr_err("QMI config request failed %d %d\n", resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.cfg_req_err++; goto out; } penv->stats.cfg_resp++; + + return 0; + out: + penv->stats.cfg_req_err++; + ICNSS_ASSERT(false); return ret; } @@ -1684,10 +1690,8 @@ static int wlfw_ini_send_sync_msg(bool enable_fw_log) struct wlfw_ini_resp_msg_v01 resp; struct msg_desc req_desc, resp_desc; - if (!penv || !penv->wlfw_clnt) { - ret = -ENODEV; - goto out; - } + if (!penv || !penv->wlfw_clnt) + return -ENODEV; icnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log: %d\n", penv->state, enable_fw_log); @@ -1711,20 +1715,24 @@ static int wlfw_ini_send_sync_msg(bool enable_fw_log) ret = qmi_send_req_wait(penv->wlfw_clnt, &req_desc, &req, sizeof(req), &resp_desc, &resp, sizeof(resp), WLFW_TIMEOUT_MS); if (ret < 0) { - icnss_pr_err("send req failed %d\n", ret); - penv->stats.ini_req_err++; + icnss_pr_err("Send INI req failed fw_log: %d, ret: %d\n", + enable_fw_log, ret); goto out; } if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("QMI request failed %d %d\n", - resp.resp.result, resp.resp.error); + icnss_pr_err("QMI INI request failed fw_log: %d, %d %d\n", + enable_fw_log, resp.resp.result, resp.resp.error); ret = resp.resp.result; - penv->stats.ini_req_err++; goto out; } penv->stats.ini_resp++; + + return 0; + out: + penv->stats.ini_req_err++; + ICNSS_ASSERT(false); return ret; } @@ -1808,12 +1816,11 @@ static int icnss_driver_event_server_arrive(void *data) goto out; } - ret = qmi_connect_to_service(penv->wlfw_clnt, - WLFW_SERVICE_ID_V01, - WLFW_SERVICE_VERS_V01, - WLFW_SERVICE_INS_ID_V01); + ret = qmi_connect_to_service(penv->wlfw_clnt, WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, + WLFW_SERVICE_INS_ID_V01); if (ret < 0) { - icnss_pr_err("Server not found : %d\n", ret); + icnss_pr_err("QMI WLAN Service not found : %d\n", ret); goto fail; } @@ -1834,10 +1841,8 @@ static int icnss_driver_event_server_arrive(void *data) goto fail; ret = wlfw_ind_register_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to send indication message: %d\n", ret); + if (ret < 0) goto err_power_on; - } if (!penv->msa_va) { icnss_pr_err("Invalid MSA address\n"); @@ -1846,27 +1851,21 @@ static int icnss_driver_event_server_arrive(void *data) } ret = wlfw_msa_mem_info_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to send MSA info: %d\n", ret); + if (ret < 0) goto err_power_on; - } + ret = icnss_setup_msa_permissions(penv); - if (ret < 0) { - icnss_pr_err("Failed to setup msa permissions: %d\n", - ret); + if (ret < 0) goto err_power_on; - } + ret = wlfw_msa_ready_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to send MSA ready : %d\n", ret); + if (ret < 0) goto err_setup_msa; - } ret = wlfw_cap_send_sync_msg(); - if (ret < 0) { - icnss_pr_err("Failed to get capability: %d\n", ret); + if (ret < 0) goto err_setup_msa; - } + return ret; err_setup_msa: @@ -2699,14 +2698,10 @@ int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req.shadow_reg_len); ret = wlfw_wlan_cfg_send_sync_msg(&req); - if (ret) { - icnss_pr_err("Failed to send cfg, ret = %d\n", ret); + if (ret) goto out; - } skip: ret = wlfw_wlan_mode_send_sync_msg(mode); - if (ret) - icnss_pr_err("Failed to send mode, ret = %d\n", ret); out: if (test_bit(SKIP_QMI, &quirks)) ret = 0; From 39e464dffcfcfc86050407effa9e1c50cdf47cd2 Mon Sep 17 00:00:00 2001 From: Prashanth Bhatta Date: Thu, 8 Sep 2016 16:21:11 -0700 Subject: [PATCH 4/4] icnss: Add IO reset logic Add IO reset logic without which hardware IO freezes. CRs-fixed: 1062502 Change-Id: I58b05ae64706865a16cc52a1f81e484c396cc6f0 Signed-off-by: Prashanth Bhatta --- drivers/soc/qcom/icnss.c | 45 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 6812aaea37ff..aaca82f87159 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -57,9 +57,12 @@ #define MPM_WCSSAON_CONFIG_OFFSET 0x18 #define MPM_WCSSAON_CONFIG_ARES_N BIT(0) #define MPM_WCSSAON_CONFIG_WLAN_DISABLE BIT(1) +#define MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD BIT(6) +#define MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD_VAL BIT(7) #define MPM_WCSSAON_CONFIG_FORCE_ACTIVE BIT(14) #define MPM_WCSSAON_CONFIG_FORCE_XO_ENABLE BIT(19) #define MPM_WCSSAON_CONFIG_DISCONNECT_CLR BIT(21) +#define MPM_WCSSAON_CONFIG_M2W_CLAMP_EN BIT(22) /* * Registers: WCSS_SR_SHADOW_REGISTERS @@ -148,6 +151,10 @@ #define ICNSS_HW_REG_RETRY 10 +#define WCSS_HM_A_PMM_HW_VERSION_V10 0x40000000 +#define WCSS_HM_A_PMM_HW_VERSION_V20 0x40010000 +#define WCSS_HM_A_PMM_HW_VERSION_Q10 0x40010001 + #define ICNSS_SERVICE_LOCATION_CLIENT_NAME "ICNSS-WLAN" #define ICNSS_WLAN_SERVICE_NAME "wlan/fw" @@ -777,6 +784,32 @@ static void icnss_hw_top_level_reset(struct icnss_priv *priv) ICNSS_HW_REG_RETRY); } +static void icnss_hw_io_reset(struct icnss_priv *priv, bool on) +{ + u32 hw_version = priv->soc_info.soc_id; + + if (on && !test_bit(ICNSS_FW_READY, &priv->state)) + return; + + icnss_pr_dbg("HW io reset: %s, SoC: 0x%x, state: 0x%lx\n", + on ? "ON" : "OFF", priv->soc_info.soc_id, priv->state); + + if (hw_version == WCSS_HM_A_PMM_HW_VERSION_V10 || + hw_version == WCSS_HM_A_PMM_HW_VERSION_V20) { + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD_VAL, 0); + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_MSM_CLAMP_EN_OVRD, on); + } else if (hw_version == WCSS_HM_A_PMM_HW_VERSION_Q10) { + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_M2W_CLAMP_EN, + on); + } +} + int icnss_hw_reset_wlan_ss_power_down(struct icnss_priv *priv) { u32 rdata; @@ -1142,7 +1175,7 @@ static int icnss_hw_power_on(struct icnss_priv *priv) int ret = 0; unsigned long flags; - icnss_pr_dbg("Power on: state: 0x%lx\n", priv->state); + icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state); spin_lock_irqsave(&priv->on_off_lock, flags); if (test_bit(ICNSS_POWER_ON, &priv->state)) { @@ -1162,6 +1195,8 @@ static int icnss_hw_power_on(struct icnss_priv *priv) icnss_hw_top_level_release_reset(priv); + icnss_hw_io_reset(penv, 1); + return ret; out: clear_bit(ICNSS_POWER_ON, &priv->state); @@ -1176,7 +1211,7 @@ static int icnss_hw_power_off(struct icnss_priv *priv) if (test_bit(HW_ALWAYS_ON, &quirks)) return 0; - icnss_pr_dbg("Power off: 0x%lx\n", priv->state); + icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state); spin_lock_irqsave(&priv->on_off_lock, flags); if (!test_bit(ICNSS_POWER_ON, &priv->state)) { @@ -1186,6 +1221,8 @@ static int icnss_hw_power_off(struct icnss_priv *priv) clear_bit(ICNSS_POWER_ON, &priv->state); spin_unlock_irqrestore(&priv->on_off_lock, flags); + icnss_hw_io_reset(penv, 0); + icnss_hw_reset(priv); icnss_clk_deinit(priv); @@ -1210,6 +1247,8 @@ int icnss_power_on(struct device *dev) return -EINVAL; } + icnss_pr_dbg("Power On: 0x%lx\n", priv->state); + return icnss_hw_power_on(priv); } EXPORT_SYMBOL(icnss_power_on); @@ -1224,6 +1263,8 @@ int icnss_power_off(struct device *dev) return -EINVAL; } + icnss_pr_dbg("Power Off: 0x%lx\n", priv->state); + return icnss_hw_power_off(priv); } EXPORT_SYMBOL(icnss_power_off);