Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b52c22b authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cnss2: check wlfw mac before switching to mission mode"

parents 1f664fd1 5d1ad5c4
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -2130,6 +2130,13 @@ static const struct of_device_id cnss_of_match_table[] = {
};
MODULE_DEVICE_TABLE(of, cnss_of_match_table);

static inline bool
cnss_use_nv_mac(struct cnss_plat_data *plat_priv)
{
	return of_property_read_bool(plat_priv->plat_dev->dev.of_node,
				     "use-nv-mac");
}

static int cnss_probe(struct platform_device *plat_dev)
{
	int ret = 0;
@@ -2162,6 +2169,7 @@ static int cnss_probe(struct platform_device *plat_dev)
	plat_priv->plat_dev = plat_dev;
	plat_priv->device_id = device_id->driver_data;
	plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id);
	plat_priv->use_nv_mac = cnss_use_nv_mac(plat_priv);
	cnss_set_plat_priv(plat_dev, plat_priv);
	platform_set_drvdata(plat_dev, plat_priv);
	INIT_LIST_HEAD(&plat_priv->vreg_list);
+1 −0
Original line number Diff line number Diff line
@@ -361,6 +361,7 @@ struct cnss_plat_data {
	u64 dynamic_feature;
	void *get_info_cb_ctx;
	int (*get_info_cb)(void *ctx, void *event, int event_len);
	u8 use_nv_mac;
};

#ifdef CONFIG_ARCH_QCOM
+131 −0
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@

#define QMI_WLFW_MAX_RECV_BUF_SIZE	SZ_8K

#define QMI_WLFW_MAC_READY_TIMEOUT_MS	50
#define QMI_WLFW_MAC_READY_MAX_RETRY	200

static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode)
{
	switch (mode) {
@@ -690,6 +693,131 @@ int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
	return ret;
}

static int cnss_wlfw_wlan_mac_req_send_sync(struct cnss_plat_data *plat_priv,
					    u8 *mac, u32 mac_len)
{
	struct wlfw_mac_addr_req_msg_v01 *req;
	struct wlfw_mac_addr_resp_msg_v01 *resp;
	struct qmi_txn txn;
	int ret;
	u8 is_query;

	if (!plat_priv)
		return -ENODEV;

	/* NULL mac && zero mac_len means querying the status of MAC in FW */
	if ((mac && mac_len != QMI_WLFW_MAC_ADDR_SIZE_V01) ||
	    (!mac && mac_len != 0))
		return -EINVAL;

	req = kzalloc(sizeof(*req), GFP_KERNEL);
	if (!req)
		return -ENOMEM;

	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
	if (!resp) {
		kfree(req);
		return -ENOMEM;
	}

	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
			   wlfw_mac_addr_resp_msg_v01_ei, resp);
	if (ret < 0) {
		cnss_pr_err("Failed to initialize txn for mac req, err: %d\n",
			    ret);
		ret = -EIO;
		goto out;
	}

	is_query = !mac;
	if (!is_query) {
		/* DO NOT print this for mac query, that might be too many */
		cnss_pr_dbg("Sending WLAN mac req [%pM], state: 0x%lx\n",
			    mac, plat_priv->driver_state);
		memcpy(req->mac_addr, mac, mac_len);

		/* 0 - query status of wlfw MAC; 1 - set wlfw MAC */
		req->mac_addr_valid = 1;
	}

	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
			       QMI_WLFW_MAC_ADDR_REQ_V01,
			       WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN,
			       wlfw_mac_addr_req_msg_v01_ei, req);
	if (ret < 0) {
		qmi_txn_cancel(&txn);
		cnss_pr_err("Failed to send mac req, err: %d\n", ret);

		ret = -EIO;
		goto out;
	}

	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
	if (ret < 0) {
		cnss_pr_err("Failed to wait for resp of mac req, err: %d\n",
			    ret);

		ret = -EIO;
		goto out;
	}

	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
		cnss_pr_err("WLAN mac req failed, result: %d, err: %d\n",
			    resp->resp.result);

		ret = -EIO;
		goto out;
	}

	if (resp->resp.error != QMI_ERR_NONE_V01) {
		ret = ((resp->resp.error == QMI_ERR_NETWORK_NOT_READY_V01 &&
			is_query) ? -EAGAIN : -EIO);
		if (ret != -EAGAIN)
			cnss_pr_err("Got error resp for mac req, err: %d\n",
				    resp->resp.error);
		goto out;
	}

	cnss_pr_dbg("WLAN mac req completed\n");

out:
	kfree(req);
	kfree(resp);
	return ret;
}

static void cnss_wait_for_wlfw_mac_ready(struct cnss_plat_data *plat_priv)
{
	int ret, retry = 0;

	if (!plat_priv)
		return;

	cnss_pr_dbg("Checking wlfw mac, state: 0x%lx\n",
		    plat_priv->driver_state);
	do {
		/* query the current status of WLAN MAC */
		ret = cnss_wlfw_wlan_mac_req_send_sync(plat_priv, NULL, 0);
		if (!ret) {
			cnss_pr_dbg("wlfw mac is ready\n");
			break;
		}

		if (ret != -EAGAIN) {
			cnss_pr_err("failed to query wlfw mac, error: %d\n",
				    ret);
			break;
		}

		if (++retry >= QMI_WLFW_MAC_READY_MAX_RETRY) {
			cnss_pr_err("Timeout to wait for wlfw mac ready\n");
			break;
		}

		msleep(QMI_WLFW_MAC_READY_TIMEOUT_MS);
	} while (true);
}

int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
				  enum cnss_driver_mode mode)
{
@@ -701,6 +829,9 @@ int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
	if (!plat_priv)
		return -ENODEV;

	if (mode == CNSS_MISSION && plat_priv->use_nv_mac)
		cnss_wait_for_wlfw_mac_ready(plat_priv);

	cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n",
		    cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state);

+1 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ struct qmi_elem_info {
#define QMI_ERR_INTERNAL_V01			3
#define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01	5
#define QMI_ERR_INVALID_ID_V01			41
#define QMI_ERR_NETWORK_NOT_READY_V01		53
#define QMI_ERR_ENCODING_V01			58
#define QMI_ERR_DISABLED_V01			69
#define QMI_ERR_INCOMPATIBLE_STATE_V01		90