mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
cnss2: check wlfw mac before switching to mission mode
To make sure WLAN MAC address has already been well configured in firmware before switching to mission mode, send QMI message to WLAN firmware to query the current MAC status, and wait for 10 seconds at most if it's not ready. A new DTS property 'use-nv-mac' is also added: if 'use-nv-mac' is defined in WLAN dts node, the MAC checking will be performed; otherwise, it won't. Change-Id: I1e751d84fb304cb95ea0f989f6939bc7ba5a3ecc Signed-off-by: Yu Wang <yyuwang@codeaurora.org>
This commit is contained in:
parent
2a1334dded
commit
65569d506c
4 changed files with 141 additions and 0 deletions
|
|
@ -2095,6 +2095,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;
|
||||
|
|
@ -2127,6 +2134,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);
|
||||
|
|
|
|||
|
|
@ -372,6 +372,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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -692,6 +695,131 @@ out:
|
|||
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)
|
||||
{
|
||||
|
|
@ -703,6 +831,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue