diff options
Diffstat (limited to 'drivers/soc/qcom/icnss.c')
| -rw-r--r-- | drivers/soc/qcom/icnss.c | 206 |
1 files changed, 173 insertions, 33 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 21be894414bc..bf815cb68f90 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -13,6 +13,7 @@ #define pr_fmt(fmt) "icnss: " fmt #include <asm/dma-iommu.h> +#include <linux/of_address.h> #include <linux/clk.h> #include <linux/iommu.h> #include <linux/export.h> @@ -83,34 +84,58 @@ module_param(qmi_timeout, ulong, 0600); } while (0) #define icnss_pr_err(_fmt, ...) do { \ - pr_err(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + printk("%s" pr_fmt(_fmt), KERN_ERR, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_warn(_fmt, ...) do { \ - pr_warn(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("WRN: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + printk("%s" pr_fmt(_fmt), KERN_WARNING, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) #define icnss_pr_info(_fmt, ...) do { \ - pr_info(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("INF: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + printk("%s" pr_fmt(_fmt), KERN_INFO, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ } while (0) +#if defined(CONFIG_DYNAMIC_DEBUG) #define icnss_pr_dbg(_fmt, ...) do { \ - pr_debug(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_string("DBG: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_string(pr_fmt(_fmt), ##__VA_ARGS__); \ } while (0) #define icnss_pr_vdbg(_fmt, ...) do { \ - pr_debug(_fmt, ##__VA_ARGS__); \ - icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \ - ##__VA_ARGS__); \ + pr_debug(_fmt, ##__VA_ARGS__); \ + icnss_ipc_log_long_string(pr_fmt(_fmt), ##__VA_ARGS__); \ } while (0) +#elif defined(DEBUG) +#define icnss_pr_dbg(_fmt, ...) do { \ + printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) + +#define icnss_pr_vdbg(_fmt, ...) do { \ + printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) +#else +#define icnss_pr_dbg(_fmt, ...) do { \ + no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) + +#define icnss_pr_vdbg(_fmt, ...) do { \ + no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__); \ + icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "", \ + ##__VA_ARGS__); \ + } while (0) +#endif #ifdef CONFIG_ICNSS_DEBUG #define ICNSS_ASSERT(_condition) do { \ @@ -365,6 +390,7 @@ struct icnss_stats { uint32_t vbatt_req; uint32_t vbatt_resp; uint32_t vbatt_req_err; + u32 rejuvenate_ind; uint32_t rejuvenate_ack_req; uint32_t rejuvenate_ack_resp; uint32_t rejuvenate_ack_err; @@ -456,6 +482,10 @@ static struct icnss_priv { struct icnss_wlan_mac_addr wlan_mac_addr; bool bypass_s1_smmu; struct mutex dev_lock; + u8 cause_for_rejuvenation; + u8 requesting_sub_system; + u16 line_number; + char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -1691,6 +1721,60 @@ out: return ret; } +static int icnss_decode_rejuvenate_ind(void *msg, unsigned int msg_len) +{ + struct msg_desc ind_desc; + struct wlfw_rejuvenate_ind_msg_v01 ind_msg; + int ret = 0; + + if (!penv || !penv->wlfw_clnt) { + ret = -ENODEV; + goto out; + } + + memset(&ind_msg, 0, sizeof(ind_msg)); + + ind_desc.msg_id = QMI_WLFW_REJUVENATE_IND_V01; + ind_desc.max_msg_len = WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN; + ind_desc.ei_array = wlfw_rejuvenate_ind_msg_v01_ei; + + ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len); + if (ret < 0) { + icnss_pr_err("Failed to decode rejuvenate ind message: ret %d, msg_len %u\n", + ret, msg_len); + goto out; + } + + if (ind_msg.cause_for_rejuvenation_valid) + penv->cause_for_rejuvenation = ind_msg.cause_for_rejuvenation; + else + penv->cause_for_rejuvenation = 0; + if (ind_msg.requesting_sub_system_valid) + penv->requesting_sub_system = ind_msg.requesting_sub_system; + else + penv->requesting_sub_system = 0; + if (ind_msg.line_number_valid) + penv->line_number = ind_msg.line_number; + else + penv->line_number = 0; + if (ind_msg.function_name_valid) + memcpy(penv->function_name, ind_msg.function_name, + QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1); + else + memset(penv->function_name, 0, + QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1); + + icnss_pr_info("Cause for rejuvenation: 0x%x, requesting sub-system: 0x%x, line number: %u, function name: %s\n", + penv->cause_for_rejuvenation, + penv->requesting_sub_system, + penv->line_number, + penv->function_name); + + penv->stats.rejuvenate_ind++; +out: + return ret; +} + static int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv) { int ret; @@ -1884,6 +1968,7 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, msg_id, penv->state); icnss_ignore_qmi_timeout(true); + icnss_decode_rejuvenate_ind(msg, msg_len); event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return; @@ -2518,21 +2603,22 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, if (event_data == NULL) return notifier_from_errno(-ENOMEM); + event_data->crashed = true; + if (state == NULL) { - event_data->crashed = true; priv->stats.recovery.root_pd_crash++; goto event_post; } switch (*state) { case ROOT_PD_WDOG_BITE: - event_data->crashed = true; event_data->wdog_bite = true; priv->stats.recovery.root_pd_crash++; break; case ROOT_PD_SHUTDOWN: cause = ICNSS_ROOT_PD_SHUTDOWN; priv->stats.recovery.root_pd_shutdown++; + event_data->crashed = false; break; case USER_PD_STATE_CHANGE: if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) { @@ -2544,7 +2630,6 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, } break; default: - event_data->crashed = true; priv->stats.recovery.root_pd_crash++; break; } @@ -3786,6 +3871,26 @@ static int icnss_stats_show_capability(struct seq_file *s, return 0; } +static int icnss_stats_show_rejuvenate_info(struct seq_file *s, + struct icnss_priv *priv) +{ + if (priv->stats.rejuvenate_ind) { + seq_puts(s, "\n<---------------- Rejuvenate Info ----------------->\n"); + seq_printf(s, "Number of Rejuvenations: %u\n", + priv->stats.rejuvenate_ind); + seq_printf(s, "Cause for Rejuvenation: 0x%x\n", + priv->cause_for_rejuvenation); + seq_printf(s, "Requesting Sub-System: 0x%x\n", + priv->requesting_sub_system); + seq_printf(s, "Line Number: %u\n", + priv->line_number); + seq_printf(s, "Function Name: %s\n", + priv->function_name); + } + + return 0; +} + static int icnss_stats_show_events(struct seq_file *s, struct icnss_priv *priv) { int i; @@ -3851,6 +3956,7 @@ static int icnss_stats_show(struct seq_file *s, void *data) ICNSS_STATS_DUMP(s, priv, vbatt_req); ICNSS_STATS_DUMP(s, priv, vbatt_resp); ICNSS_STATS_DUMP(s, priv, vbatt_req_err); + ICNSS_STATS_DUMP(s, priv, rejuvenate_ind); ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req); ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp); ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err); @@ -3875,6 +3981,8 @@ static int icnss_stats_show(struct seq_file *s, void *data) icnss_stats_show_capability(s, priv); + icnss_stats_show_rejuvenate_info(s, priv); + icnss_stats_show_events(s, priv); icnss_stats_show_state(s, priv); @@ -4215,6 +4323,9 @@ static int icnss_probe(struct platform_device *pdev) int i; struct device *dev = &pdev->dev; struct icnss_priv *priv; + const __be32 *addrp; + u64 prop_size = 0; + struct device_node *np; if (penv) { icnss_pr_err("Driver is already initialized\n"); @@ -4286,24 +4397,53 @@ static int icnss_probe(struct platform_device *pdev) } } - ret = of_property_read_u32(dev->of_node, "qcom,wlan-msa-memory", - &priv->msa_mem_size); + np = of_parse_phandle(dev->of_node, + "qcom,wlan-msa-fixed-region", 0); + if (np) { + addrp = of_get_address(np, 0, &prop_size, NULL); + if (!addrp) { + icnss_pr_err("Failed to get assigned-addresses or property\n"); + ret = -EINVAL; + goto out; + } + + priv->msa_pa = of_translate_address(np, addrp); + if (priv->msa_pa == OF_BAD_ADDR) { + icnss_pr_err("Failed to translate MSA PA from device-tree\n"); + ret = -EINVAL; + goto out; + } - if (ret || priv->msa_mem_size == 0) { - icnss_pr_err("Fail to get MSA Memory Size: %u, ret: %d\n", - priv->msa_mem_size, ret); - goto out; - } + priv->msa_va = memremap(priv->msa_pa, + (unsigned long)prop_size, MEMREMAP_WT); + if (!priv->msa_va) { + icnss_pr_err("MSA PA ioremap failed: phy addr: %pa\n", + &priv->msa_pa); + ret = -EINVAL; + goto out; + } + priv->msa_mem_size = prop_size; + } else { + ret = of_property_read_u32(dev->of_node, "qcom,wlan-msa-memory", + &priv->msa_mem_size); + if (ret || priv->msa_mem_size == 0) { + icnss_pr_err("Fail to get MSA Memory Size: %u ret: %d\n", + priv->msa_mem_size, ret); + goto out; + } - priv->msa_va = dmam_alloc_coherent(&pdev->dev, priv->msa_mem_size, - &priv->msa_pa, GFP_KERNEL); - if (!priv->msa_va) { - icnss_pr_err("DMA alloc failed for MSA\n"); - ret = -ENOMEM; - goto out; + priv->msa_va = dmam_alloc_coherent(&pdev->dev, + priv->msa_mem_size, &priv->msa_pa, GFP_KERNEL); + + if (!priv->msa_va) { + icnss_pr_err("DMA alloc failed for MSA\n"); + ret = -ENOMEM; + goto out; + } } - icnss_pr_dbg("MSA pa: %pa, MSA va: 0x%p\n", &priv->msa_pa, - priv->msa_va); + + icnss_pr_dbg("MSA pa: %pa, MSA va: 0x%p MSA Memory Size: 0x%x\n", + &priv->msa_pa, (void *)priv->msa_va, priv->msa_mem_size); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smmu_iova_base"); |
