From 017791027b3c010d840ba23c5cc68a7f1ae2c10a Mon Sep 17 00:00:00 2001 From: Manikandan Mohan Date: Thu, 30 Jul 2020 09:37:41 -0700 Subject: [PATCH] cnss2: Add support for PCIE gen switch Add support for PCIE gen switch request from wlan driver using QMI message to FW. Change-Id: I6ea4ee234a38162cb9093d36d580c872b4d62644 Signed-off-by: Manikandan Mohan --- android/abi_gki_aarch64_qcom_internal | 1 + drivers/net/wireless/cnss2/main.c | 20 +++++++++ drivers/net/wireless/cnss2/main.h | 2 + drivers/net/wireless/cnss2/qmi.c | 62 +++++++++++++++++++++++++++ drivers/net/wireless/cnss2/qmi.h | 4 ++ include/net/cnss2.h | 2 +- 6 files changed, 90 insertions(+), 1 deletion(-) diff --git a/android/abi_gki_aarch64_qcom_internal b/android/abi_gki_aarch64_qcom_internal index 962660efeeb6..df3d80b6aea4 100644 --- a/android/abi_gki_aarch64_qcom_internal +++ b/android/abi_gki_aarch64_qcom_internal @@ -49,6 +49,7 @@ cnss_get_user_msi_assignment cnss_get_msi_irq cnss_get_msi_address + cnss_set_pcie_gen_speed register_cld_cmd_cb deregister_cld_cmd_cb cld80211_get_genl_family diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index fbd5b3ba9fcf..987e4f2384cf 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -318,6 +318,24 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode) } EXPORT_SYMBOL(cnss_set_fw_log_mode); +int cnss_set_pcie_gen_speed(struct device *dev, u8 pcie_gen_speed) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + + if (plat_priv->device_id != QCA6490_DEVICE_ID || + !plat_priv->fw_pcie_gen_switch) + return -ENOTSUPP; + + if (pcie_gen_speed < QMI_PCIE_GEN_SPEED_1_V01 || + pcie_gen_speed > QMI_PCIE_GEN_SPEED_3_V01) + return -EINVAL; + + cnss_pr_dbg("WLAN provided PCIE gen speed: %d\n", pcie_gen_speed); + plat_priv->pcie_gen_speed = pcie_gen_speed; + return 0; +} +EXPORT_SYMBOL(cnss_set_pcie_gen_speed); + static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv) { int ret = 0; @@ -395,6 +413,8 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv) set_bit(CNSS_FW_READY, &plat_priv->driver_state); clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state); + cnss_wlfw_send_pcie_gen_speed_sync(plat_priv); + if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) { clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state); clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 6e57871810f1..ace23b7ac4f7 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -407,6 +407,8 @@ struct cnss_plat_data { u8 use_nv_mac; u8 set_wlaon_pwr_ctrl; struct cnss_tcs_info tcs_info; + bool fw_pcie_gen_switch; + u8 pcie_gen_speed; }; #ifdef CONFIG_ARCH_QCOM diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 30b13b1651f9..5418290653f5 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -452,6 +452,10 @@ int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv) if (resp->otp_version_valid) plat_priv->otp_version = resp->otp_version; + if (resp->fw_caps_valid) + plat_priv->fw_pcie_gen_switch = + !!(resp->fw_caps & QMI_WLFW_HOST_PCIE_GEN_SWITCH_V01); + cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, fw_version: 0x%x, fw_build_timestamp: %s, fw_build_id: %s, otp_version: 0x%x\n", plat_priv->chip_info.chip_id, plat_priv->chip_info.chip_family, @@ -1287,6 +1291,64 @@ out: return ret; } +int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv) +{ + struct wlfw_pcie_gen_switch_req_msg_v01 req; + struct wlfw_pcie_gen_switch_resp_msg_v01 resp; + struct qmi_txn txn; + int ret = 0; + + if (!plat_priv) + return -ENODEV; + + if (plat_priv->pcie_gen_speed == QMI_PCIE_GEN_SPEED_INVALID_V01 || + !plat_priv->fw_pcie_gen_switch) { + cnss_pr_dbg("PCIE Gen speed not setup\n"); + return 0; + } + + cnss_pr_dbg("Sending PCIE Gen speed: %d state: 0x%lx\n", + plat_priv->pcie_gen_speed, plat_priv->driver_state); + req.pcie_speed = (enum wlfw_pcie_gen_speed_v01) + plat_priv->pcie_gen_speed; + + ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, + wlfw_pcie_gen_switch_resp_msg_v01_ei, &resp); + if (ret < 0) { + cnss_pr_err("Failed to initialize txn for PCIE speed switch err: %d\n", + ret); + goto out; + } + + ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, + QMI_WLFW_PCIE_GEN_SWITCH_REQ_V01, + WLFW_PCIE_GEN_SWITCH_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_pcie_gen_switch_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + cnss_pr_err("Failed to send PCIE speed switch, err: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); + if (ret < 0) { + cnss_pr_err("Failed to wait for PCIE Gen switch resp, err: %d\n", + ret); + goto out; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + cnss_pr_err("PCIE Gen Switch req failed, Speed: %d, result: %d, err: %d\n", + plat_priv->pcie_gen_speed, resp.resp.result, + resp.resp.error); + ret = -resp.resp.result; + } +out: + /* Reset PCIE Gen speed after one time use */ + plat_priv->pcie_gen_speed = QMI_PCIE_GEN_SPEED_INVALID_V01; + return ret; +} + int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv) { struct wlfw_antenna_switch_req_msg_v01 *req; diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h index 60967e7843e9..798492a2ffb2 100644 --- a/drivers/net/wireless/cnss2/qmi.h +++ b/drivers/net/wireless/cnss2/qmi.h @@ -67,6 +67,7 @@ int coex_antenna_switch_to_mdm_send_sync_msg(struct cnss_plat_data *plat_priv); int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv); int cnss_register_ims_service(struct cnss_plat_data *plat_priv); void cnss_unregister_ims_service(struct cnss_plat_data *plat_priv); +int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv); #else #define QMI_WLFW_TIMEOUT_MS 10000 @@ -217,6 +218,9 @@ int cnss_register_ims_service(struct cnss_plat_data *plat_priv) static inline void cnss_unregister_ims_service(struct cnss_plat_data *plat_priv) {} +static inline +int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv) {} + #endif /* CONFIG_CNSS2_QMI */ #endif /* _CNSS_QMI_H */ diff --git a/include/net/cnss2.h b/include/net/cnss2.h index ecec0832af77..6700fd18a554 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -237,5 +237,5 @@ extern int cnss_athdiag_write(struct device *dev, uint32_t offset, uint32_t mem_type, uint32_t data_len, uint8_t *input); extern int cnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode); - +extern int cnss_set_pcie_gen_speed(struct device *dev, u8 pcie_gen_speed); #endif /* _NET_CNSS2_H */