diff --git a/icnss2/main.c b/icnss2/main.c index a7841244b8..856aa61141 100644 --- a/icnss2/main.c +++ b/icnss2/main.c @@ -4753,7 +4753,7 @@ static int icnss_probe(struct platform_device *pdev) init_completion(&priv->smp2p_soc_wake_wait); icnss_runtime_pm_init(priv); - icnss_aop_mbox_init(priv); + icnss_aop_interface_init(priv); set_bit(ICNSS_COLD_BOOT_CAL, &priv->state); priv->bdf_download_support = true; register_trace_android_vh_rproc_recovery_set(rproc_restart_level_notifier, NULL); @@ -4865,8 +4865,6 @@ static int icnss_remove(struct platform_device *pdev) priv->device_id == WCN6450_DEVICE_ID) { icnss_genl_exit(); icnss_runtime_pm_deinit(priv); - if (!IS_ERR_OR_NULL(priv->mbox_chan)) - mbox_free_channel(priv->mbox_chan); unregister_trace_android_vh_rproc_recovery_set(rproc_restart_level_notifier, NULL); complete_all(&priv->smp2p_soc_wake_wait); icnss_destroy_ramdump_device(priv->m3_dump_phyareg); @@ -4876,6 +4874,7 @@ static int icnss_remove(struct platform_device *pdev) icnss_destroy_ramdump_device(priv->m3_dump_phyapdmem); if (priv->soc_wake_wq) destroy_workqueue(priv->soc_wake_wq); + icnss_aop_interface_deinit(priv); } class_destroy(priv->icnss_ramdump_class); diff --git a/icnss2/main.h b/icnss2/main.h index 5cf658f3f1..2e2ae332a0 100644 --- a/icnss2/main.h +++ b/icnss2/main.h @@ -12,6 +12,10 @@ #include #include #include +#if IS_ENABLED(CONFIG_MSM_QMP) +#include +#include +#endif #ifdef CONFIG_CNSS_OUT_OF_TREE #include "icnss2.h" #else @@ -485,6 +489,10 @@ struct icnss_priv { bool root_pd_shutdown; struct mbox_client mbox_client_data; struct mbox_chan *mbox_chan; +#if IS_ENABLED(CONFIG_MSM_QMP) + struct qmp *qmp; +#endif + bool use_direct_qmp; u32 wlan_en_delay_ms; u32 wlan_en_delay_ms_user; struct class *icnss_ramdump_class; @@ -542,7 +550,8 @@ int icnss_get_iova_ipa(struct icnss_priv *priv, u64 *addr, u64 *size); int icnss_update_cpr_info(struct icnss_priv *priv); void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name, char *name); -int icnss_aop_mbox_init(struct icnss_priv *priv); +int icnss_aop_interface_init(struct icnss_priv *priv); +void icnss_aop_interface_deinit(struct icnss_priv *priv); void icnss_recovery_timeout_hdlr(struct timer_list *t); void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t); #endif diff --git a/icnss2/power.c b/icnss2/power.c index d45fb8adaf..1094f9d8fa 100644 --- a/icnss2/power.c +++ b/icnss2/power.c @@ -5,9 +5,6 @@ */ #include #include -#if IS_ENABLED(CONFIG_MSM_QMP) -#include -#endif #include #include #include @@ -736,7 +733,18 @@ void icnss_put_resources(struct icnss_priv *priv) icnss_put_vreg(priv); } -int icnss_aop_mbox_init(struct icnss_priv *priv) + +#if IS_ENABLED(CONFIG_MSM_QMP) +/** + * icnss_aop_interface_init: Initialize AOP interface: either mbox channel or direct QMP + * @priv: Pointer to icnss platform data + * + * Device tree file should have either mbox or qmp configured, but not both. + * Based on device tree configuration setup mbox channel or QMP + * + * Return: 0 for success, otherwise error code +*/ +int icnss_aop_interface_init(struct icnss_priv *priv) { struct mbox_client *mbox = &priv->mbox_client_data; struct mbox_chan *chan; @@ -756,19 +764,50 @@ int icnss_aop_mbox_init(struct icnss_priv *priv) mbox->knows_txdone = false; priv->mbox_chan = NULL; + priv->qmp = NULL; + priv->use_direct_qmp = false; + /* First try to get mbox channel, if it fails then try qmp_get + * In device tree file there should be either mboxes or qmp, + * cannot have both properties at the same time. + */ chan = mbox_request_channel(mbox, 0); if (IS_ERR(chan)) { ret = PTR_ERR(chan); - icnss_pr_err("Failed to get mbox channel with err %d\n", ret); - return ret; + icnss_pr_dbg("Failed to get mbox channel with err %d\n", ret); + priv->qmp = qmp_get(&priv->pdev->dev); + if (IS_ERR(priv->qmp)) { + icnss_pr_err("Failed to get qmp\n"); + return PTR_ERR(priv->qmp); + } else { + priv->use_direct_qmp = true; + icnss_pr_dbg("QMP initialized\n"); + } + } else { + priv->mbox_chan = chan; + icnss_pr_dbg("Mbox channel initialized\n"); + } + return ret; +} + +/** + * cnss_aop_interface_deinit: Cleanup AOP interface + * @priv: Pointer to icnss platform data + * + * Cleanup mbox channel or QMP whichever was configured during initialization. + * + * Return: None + */ +void icnss_aop_interface_deinit(struct icnss_priv *priv) +{ + if (!IS_ERR_OR_NULL(priv->mbox_chan)) + mbox_free_channel(priv->mbox_chan); + + if (!IS_ERR_OR_NULL(priv->qmp)) { + qmp_put(priv->qmp); + priv->use_direct_qmp = false; } - priv->mbox_chan = chan; - - icnss_pr_dbg("Mbox channel initialized\n"); - return 0; } -#if IS_ENABLED(CONFIG_MSM_QMP) static int icnss_aop_set_vreg_param(struct icnss_priv *priv, const char *vreg_name, enum icnss_vreg_param param, @@ -786,21 +825,38 @@ static int icnss_aop_set_vreg_param(struct icnss_priv *priv, snprintf(mbox_msg, ICNSS_MBOX_MSG_MAX_LEN, "{class: wlan_pdc, res: %s.%s, %s: %d}", vreg_name, vreg_param_str[param], tcs_seq_str[seq], val); + if (priv->use_direct_qmp) { + icnss_pr_dbg("Sending AOP QMP msg: %s\n", mbox_msg); + ret = qmp_send(priv->qmp, mbox_msg, ICNSS_MBOX_MSG_MAX_LEN); + if (ret < 0) + icnss_pr_err("Failed to send AOP QMP msg: %s\n", mbox_msg); + else + ret = 0; + } else { + icnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg); + pkt.size = ICNSS_MBOX_MSG_MAX_LEN; + pkt.data = mbox_msg; - icnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg); - pkt.size = ICNSS_MBOX_MSG_MAX_LEN; - pkt.data = mbox_msg; - - ret = mbox_send_message(priv->mbox_chan, &pkt); - if (ret < 0) - icnss_pr_err("Failed to send AOP mbox msg: %s,ret: %d\n", - mbox_msg, ret); - else - ret = 0; + ret = mbox_send_message(priv->mbox_chan, &pkt); + if (ret < 0) + icnss_pr_err("Failed to send AOP mbox msg: %s,ret: %d\n", + mbox_msg, ret); + else + ret = 0; + } return ret; } #else +int icnss_aop_interface_init(struct icnss_priv *priv) +{ + return 0; +} + +void icnss_aop_interface_deinit(struct icnss_priv *priv) +{ +} + static int icnss_aop_set_vreg_param(struct icnss_priv *priv, const char *vreg_name, enum icnss_vreg_param param, @@ -814,8 +870,8 @@ int icnss_update_cpr_info(struct icnss_priv *priv) { struct icnss_cpr_info *cpr_info = &priv->cpr_info; - if (!cpr_info->vreg_ol_cpr || !priv->mbox_chan) { - icnss_pr_dbg("Mbox channel / OL CPR Vreg not configured\n"); + if (!cpr_info->vreg_ol_cpr || (!priv->mbox_chan && !priv->qmp)) { + icnss_pr_dbg("Mbox channel / QMP / OL CPR Vreg not configured\n"); return 0; }