| From c14453371338c74cfc043885ef14755a723b32d3 Mon Sep 17 00:00:00 2001 |
| From: Bjorn Andersson <bjorn.andersson@linaro.org> |
| Date: Wed, 24 Jul 2019 23:31:08 -0700 |
| Subject: [PATCH] ath10k: Fix HOST capability QMI incompatibility |
| |
| commit 7165ef890a4c44cf16db66b82fd78448f4bde6ba upstream. |
| |
| The introduction of 768ec4c012ac ("ath10k: update HOST capability QMI |
| message") served the purpose of supporting the new and extended HOST |
| capability QMI message. |
| |
| But while the new message adds a slew of optional members it changes the |
| data type of the "daemon_support" member, which means that older |
| versions of the firmware will fail to decode the incoming request |
| message. |
| |
| There is no way to detect this breakage from Linux and there's no way to |
| recover from sending the wrong message (i.e. we can't just try one |
| format and then fallback to the other), so a quirk is introduced in |
| DeviceTree to indicate to the driver that the firmware requires the 8bit |
| version of this message. |
| |
| Cc: stable@vger.kernel.org |
| Fixes: 768ec4c012ac ("ath10k: update HOST capability qmi message") |
| Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> |
| Acked-by: Rob Herring <robh@kernel.org> |
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt |
| index ae661e65354e..f9499b20d840 100644 |
| --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt |
| +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt |
| @@ -81,6 +81,12 @@ Optional properties: |
| Definition: Name of external front end module used. Some valid FEM names |
| for example: "microsemi-lx5586", "sky85703-11" |
| and "sky85803" etc. |
| +- qcom,snoc-host-cap-8bit-quirk: |
| + Usage: Optional |
| + Value type: <empty> |
| + Definition: Quirk specifying that the firmware expects the 8bit version |
| + of the host capability QMI request |
| + |
| |
| Example (to supply PCI based wifi block details): |
| |
| diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c |
| index 8f8f717a23ee..eed2626a0d74 100644 |
| --- a/drivers/net/wireless/ath/ath10k/qmi.c |
| +++ b/drivers/net/wireless/ath/ath10k/qmi.c |
| @@ -580,22 +580,29 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) |
| { |
| struct wlfw_host_cap_resp_msg_v01 resp = {}; |
| struct wlfw_host_cap_req_msg_v01 req = {}; |
| + struct qmi_elem_info *req_ei; |
| struct ath10k *ar = qmi->ar; |
| + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); |
| struct qmi_txn txn; |
| int ret; |
| |
| req.daemon_support_valid = 1; |
| req.daemon_support = 0; |
| |
| - ret = qmi_txn_init(&qmi->qmi_hdl, &txn, |
| - wlfw_host_cap_resp_msg_v01_ei, &resp); |
| + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei, |
| + &resp); |
| if (ret < 0) |
| goto out; |
| |
| + if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags)) |
| + req_ei = wlfw_host_cap_8bit_req_msg_v01_ei; |
| + else |
| + req_ei = wlfw_host_cap_req_msg_v01_ei; |
| + |
| ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, |
| QMI_WLFW_HOST_CAP_REQ_V01, |
| WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, |
| - wlfw_host_cap_req_msg_v01_ei, &req); |
| + req_ei, &req); |
| if (ret < 0) { |
| qmi_txn_cancel(&txn); |
| ath10k_err(ar, "failed to send host capability request: %d\n", ret); |
| diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c |
| index 1fe05c6218c3..86fcf4e1de5f 100644 |
| --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c |
| +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c |
| @@ -1988,6 +1988,28 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { |
| {} |
| }; |
| |
| +struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = { |
| + { |
| + .data_type = QMI_OPT_FLAG, |
| + .elem_len = 1, |
| + .elem_size = sizeof(u8), |
| + .array_type = NO_ARRAY, |
| + .tlv_type = 0x10, |
| + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, |
| + daemon_support_valid), |
| + }, |
| + { |
| + .data_type = QMI_UNSIGNED_1_BYTE, |
| + .elem_len = 1, |
| + .elem_size = sizeof(u8), |
| + .array_type = NO_ARRAY, |
| + .tlv_type = 0x10, |
| + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, |
| + daemon_support), |
| + }, |
| + {} |
| +}; |
| + |
| struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { |
| { |
| .data_type = QMI_STRUCT, |
| diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h |
| index bca1186e1560..4d107e1364a8 100644 |
| --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h |
| +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h |
| @@ -575,6 +575,7 @@ struct wlfw_host_cap_req_msg_v01 { |
| |
| #define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189 |
| extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; |
| +extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[]; |
| |
| struct wlfw_host_cap_resp_msg_v01 { |
| struct qmi_response_type_v01 resp; |
| diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c |
| index 873cb4ce419b..c0fc96c29bf1 100644 |
| --- a/drivers/net/wireless/ath/ath10k/snoc.c |
| +++ b/drivers/net/wireless/ath/ath10k/snoc.c |
| @@ -1246,6 +1246,15 @@ static int ath10k_snoc_resource_init(struct ath10k *ar) |
| return ret; |
| } |
| |
| +static void ath10k_snoc_quirks_init(struct ath10k *ar) |
| +{ |
| + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); |
| + struct device *dev = &ar_snoc->dev->dev; |
| + |
| + if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk")) |
| + set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags); |
| +} |
| + |
| int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) |
| { |
| struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); |
| @@ -1663,6 +1672,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev) |
| ar->ce_priv = &ar_snoc->ce; |
| msa_size = drv_data->msa_size; |
| |
| + ath10k_snoc_quirks_init(ar); |
| + |
| ret = ath10k_snoc_resource_init(ar); |
| if (ret) { |
| ath10k_warn(ar, "failed to initialize resource: %d\n", ret); |
| diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h |
| index d62f53501fbb..9db823e46314 100644 |
| --- a/drivers/net/wireless/ath/ath10k/snoc.h |
| +++ b/drivers/net/wireless/ath/ath10k/snoc.h |
| @@ -63,6 +63,7 @@ enum ath10k_snoc_flags { |
| ATH10K_SNOC_FLAG_REGISTERED, |
| ATH10K_SNOC_FLAG_UNREGISTERING, |
| ATH10K_SNOC_FLAG_RECOVERY, |
| + ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, |
| }; |
| |
| struct ath10k_snoc { |
| -- |
| 2.7.4 |
| |