Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ath10k: Fix HOST capability QMI incompatibility

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>

authored by

Bjorn Andersson and committed by
Kalle Valo
7165ef89 b10f3267

+51 -3
+6
Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
··· 81 81 Definition: Name of external front end module used. Some valid FEM names 82 82 for example: "microsemi-lx5586", "sky85703-11" 83 83 and "sky85803" etc. 84 + - qcom,snoc-host-cap-8bit-quirk: 85 + Usage: Optional 86 + Value type: <empty> 87 + Definition: Quirk specifying that the firmware expects the 8bit version 88 + of the host capability QMI request 89 + 84 90 85 91 Example (to supply PCI based wifi block details): 86 92
+10 -3
drivers/net/wireless/ath/ath10k/qmi.c
··· 581 581 { 582 582 struct wlfw_host_cap_resp_msg_v01 resp = {}; 583 583 struct wlfw_host_cap_req_msg_v01 req = {}; 584 + struct qmi_elem_info *req_ei; 584 585 struct ath10k *ar = qmi->ar; 586 + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 585 587 struct qmi_txn txn; 586 588 int ret; 587 589 588 590 req.daemon_support_valid = 1; 589 591 req.daemon_support = 0; 590 592 591 - ret = qmi_txn_init(&qmi->qmi_hdl, &txn, 592 - wlfw_host_cap_resp_msg_v01_ei, &resp); 593 + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei, 594 + &resp); 593 595 if (ret < 0) 594 596 goto out; 597 + 598 + if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags)) 599 + req_ei = wlfw_host_cap_8bit_req_msg_v01_ei; 600 + else 601 + req_ei = wlfw_host_cap_req_msg_v01_ei; 595 602 596 603 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, 597 604 QMI_WLFW_HOST_CAP_REQ_V01, 598 605 WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, 599 - wlfw_host_cap_req_msg_v01_ei, &req); 606 + req_ei, &req); 600 607 if (ret < 0) { 601 608 qmi_txn_cancel(&txn); 602 609 ath10k_err(ar, "failed to send host capability request: %d\n", ret);
+22
drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
··· 1988 1988 {} 1989 1989 }; 1990 1990 1991 + struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = { 1992 + { 1993 + .data_type = QMI_OPT_FLAG, 1994 + .elem_len = 1, 1995 + .elem_size = sizeof(u8), 1996 + .array_type = NO_ARRAY, 1997 + .tlv_type = 0x10, 1998 + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, 1999 + daemon_support_valid), 2000 + }, 2001 + { 2002 + .data_type = QMI_UNSIGNED_1_BYTE, 2003 + .elem_len = 1, 2004 + .elem_size = sizeof(u8), 2005 + .array_type = NO_ARRAY, 2006 + .tlv_type = 0x10, 2007 + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, 2008 + daemon_support), 2009 + }, 2010 + {} 2011 + }; 2012 + 1991 2013 struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { 1992 2014 { 1993 2015 .data_type = QMI_STRUCT,
+1
drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
··· 575 575 576 576 #define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189 577 577 extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; 578 + extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[]; 578 579 579 580 struct wlfw_host_cap_resp_msg_v01 { 580 581 struct qmi_response_type_v01 resp;
+11
drivers/net/wireless/ath/ath10k/snoc.c
··· 1261 1261 return ret; 1262 1262 } 1263 1263 1264 + static void ath10k_snoc_quirks_init(struct ath10k *ar) 1265 + { 1266 + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 1267 + struct device *dev = &ar_snoc->dev->dev; 1268 + 1269 + if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk")) 1270 + set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags); 1271 + } 1272 + 1264 1273 int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) 1265 1274 { 1266 1275 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); ··· 1686 1677 ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; 1687 1678 ar->ce_priv = &ar_snoc->ce; 1688 1679 msa_size = drv_data->msa_size; 1680 + 1681 + ath10k_snoc_quirks_init(ar); 1689 1682 1690 1683 ret = ath10k_snoc_resource_init(ar); 1691 1684 if (ret) {
+1
drivers/net/wireless/ath/ath10k/snoc.h
··· 63 63 ATH10K_SNOC_FLAG_REGISTERED, 64 64 ATH10K_SNOC_FLAG_UNREGISTERING, 65 65 ATH10K_SNOC_FLAG_RECOVERY, 66 + ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, 66 67 }; 67 68 68 69 struct ath10k_snoc {