Loading drivers/net/wireless/cnss2/main.c +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading drivers/net/wireless/cnss2/main.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/net/wireless/cnss2/qmi.c +131 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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) { Loading @@ -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); Loading include/linux/soc/qcom/qmi.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/net/wireless/cnss2/main.c +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading
drivers/net/wireless/cnss2/main.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/net/wireless/cnss2/qmi.c +131 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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) { Loading @@ -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); Loading
include/linux/soc/qcom/qmi.h +1 −0 Original line number Diff line number Diff line Loading @@ -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