From ae5cef9b7e0b7edfb6e3b163b7eb0fa35a99efaa Mon Sep 17 00:00:00 2001 From: Krupali Dhanvijay Date: Mon, 16 Jan 2023 20:39:50 +0530 Subject: [PATCH] cnss2: Add API to send WFC mode to WLAN FW Add and export API to host driver to send WFC(WiFi Calling) mode to WLAN FW. Change-Id: I92d3d0baad9afc6fdf66f66b847a4e8a90a54341 CRs-Fixed: 3346550 Signed-off-by: Krupali Dhanvijay --- drivers/net/wireless/cnss2/main.c | 21 ++++++++++ drivers/net/wireless/cnss2/qmi.c | 68 ++++++++++++++++++++++++++++++- drivers/net/wireless/cnss2/qmi.h | 8 ++++ include/net/cnss2.h | 10 +++++ 4 files changed, 106 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 10c25a806f05..f10b55aa7d28 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -3134,6 +3134,27 @@ cnss_is_converged_dt(struct cnss_plat_data *plat_priv) return of_property_read_bool(plat_priv->plat_dev->dev.of_node, "qcom,converged-dt"); } + +int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + int ret = 0; + + if (!plat_priv) + return -ENODEV; + + /* If IMS server is connected, return success without QMI send */ + if (test_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state)) { + cnss_pr_dbg("Ignore host request as IMS server is connected"); + return ret; + } + + ret = cnss_wlfw_send_host_wfc_call_status(plat_priv, cfg); + + return ret; +} +EXPORT_SYMBOL(cnss_set_wfc_mode); + static int cnss_probe(struct platform_device *plat_dev) { int ret = 0; diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 7fdda4a58eff..6fa987c08c12 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1957,6 +1957,72 @@ out: return ret; } +int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, + struct cnss_wfc_cfg cfg) +{ + struct wlfw_wfc_call_status_req_msg_v01 *req; + struct wlfw_wfc_call_status_resp_msg_v01 *resp; + struct qmi_txn txn; + int ret = 0; + + if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { + cnss_pr_err("Drop host WFC indication as FW not initialized\n"); + return -EINVAL; + } + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) { + kfree(req); + return -ENOMEM; + } + + req->wfc_call_active_valid = 1; + req->wfc_call_active = cfg.mode; + cnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n", + plat_priv->driver_state); + ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, + wlfw_wfc_call_status_resp_msg_v01_ei, resp); + if (ret < 0) { + cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n", + ret); + goto out; + } + + cnss_pr_dbg("Send WFC Mode: %d\n", cfg.mode); + ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, + QMI_WLFW_WFC_CALL_STATUS_REQ_V01, + WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_wfc_call_status_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n", + ret); + goto out; + } + + ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); + if (ret < 0) { + cnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n", + ret); + goto out; + } + + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { + cnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n", + resp->resp.result, resp->resp.error); + ret = -EINVAL; + goto out; + } + ret = 0; +out: + kfree(req); + kfree(resp); + return ret; +} + static int cnss_wlfw_wfc_call_status_send_sync (struct cnss_plat_data *plat_priv, const struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg) diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h index 53368ac6303e..88ff44d0e7c4 100644 --- a/drivers/net/wireless/cnss2/qmi.h +++ b/drivers/net/wireless/cnss2/qmi.h @@ -82,6 +82,8 @@ int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_n u32 total_size); int wlfw_qdss_trace_send_start(struct cnss_plat_data *plat_priv); int wlfw_qdss_trace_send_stop(struct cnss_plat_data *plat_priv, unsigned long long option); +int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, + struct cnss_wfc_cfg cfg); #else #define QMI_WLFW_TIMEOUT_MS 10000 @@ -285,6 +287,12 @@ int wlfw_qdss_trace_send_stop(struct cnss_plat_data *plat_priv, unsigned long lo { return 0; } + +int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, + struct cnss_wfc_cfg cfg) +{ + return 0; +} #endif /* CONFIG_CNSS2_QMI */ #ifdef CONFIG_CNSS2_DEBUG diff --git a/include/net/cnss2.h b/include/net/cnss2.h index dbb0ea5978fb..92a78971710b 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -92,6 +92,15 @@ enum cnss_bus_event_type { BUS_EVENT_INVALID = 0xFFFF, }; +enum cnss_wfc_mode { + CNSS_WFC_MODE_OFF, + CNSS_WFC_MODE_ON, +}; + +struct cnss_wfc_cfg { + enum cnss_wfc_mode mode; +}; + struct cnss_hang_event { void *hang_event_data; u16 hang_event_data_len; @@ -281,4 +290,5 @@ extern int cnss_get_mem_segment_info(enum cnss_remote_mem_type type, extern int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb, uint32_t len, uint8_t slotid); extern int cnss_reset_afcmem(struct device *dev, uint8_t slotid); +extern int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg); #endif /* _NET_CNSS2_H */