Commit 7165ef89 authored by Bjorn Andersson's avatar Bjorn Andersson Committed by Kalle Valo
Browse files

ath10k: Fix HOST capability QMI incompatibility



The introduction of 768ec4c0 ("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: 768ec4c0 ("ath10k: update HOST capability qmi message")
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Acked-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent b10f3267
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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):

+10 −3
Original line number Diff line number Diff line
@@ -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);
+22 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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;
+11 −0
Original line number Diff line number Diff line
@@ -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);
Loading