ath10k: Fix HOST capability QMI incompatibility
authorBjorn Andersson <bjorn.andersson@linaro.org>
Thu, 25 Jul 2019 06:31:08 +0000 (23:31 -0700)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 17 Sep 2019 14:03:13 +0000 (17:03 +0300)
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>
Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
drivers/net/wireless/ath/ath10k/qmi.c
drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
drivers/net/wireless/ath/ath10k/snoc.c
drivers/net/wireless/ath/ath10k/snoc.h

index ae661e65354e7865faf170c42fa6e10ed05c35a8..f9499b20d8405df42dec81072b0f6d2a9551f6c2 100644 (file)
@@ -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):
 
index 3b63b6257c433e2d99fde9df026879c20994b570..545ac1f069970a2bc9c8671a687e62997a742026 100644 (file)
@@ -581,22 +581,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);
index 1fe05c6218c3e487f582ad1256def964720bc9c6..86fcf4e1de5f800640a99138d5324dc42e71884d 100644 (file)
@@ -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,
index bca1186e1560891538077ae22f72a57106891fa2..4d107e1364a80acc0f148a9ea779055bad1cff1d 100644 (file)
@@ -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;
index b491361e6ed4540f2b53ee782d5a2c5ec8b2ef0b..fc15a0037f0e662bdae360187a1260ef53f11e3d 100644 (file)
@@ -1261,6 +1261,15 @@ out:
        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);
@@ -1678,6 +1687,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);
index d62f53501fbbfcb4052ab531418a118672e01a98..9db823e46314daaf2a7e192b5af97b065046e4e6 100644 (file)
@@ -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 {