ath10k: add bdf/cal indication support
PATCH 10/12 ath10k: add bdf/cal indication support
Add support for bdf download and cold boot
calibration trigger qmi message support.
--- drivers/net/wireless/ath/ath10k/qmi.c | 195 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 10 ++ 2 files changed, 205 insertions(+)
drivers/net/wireless/ath/ath10k/qmi.c +195 -0
@@ -28,6 +28,7 @@#include <linux/soc/qcom/qmi.h> #include <linux/qcom_scm.h> #include <linux/of.h> +#include <linux/firmware.h> #include "qmi.h" #include "qmi_svc_v01.h"
@@ -270,6 +271,179 @@ static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi)return ret; } +int ath10k_qmi_bdf_dnld_send_sync (struct ath10k_qmi *qmi) +{ +struct wlfw_bdf_download_resp_msg_v01 *resp; +struct wlfw_bdf_download_req_msg_v01 *req; +const struct firmware *fw_entry; +unsigned int remaining; +struct qmi_txn txn; +const u8 *temp; +int ret; + + req =kzalloc (sizeof (*req),GFP_KERNEL ); +if (!req) +return -ENOMEM ; + + resp =kzalloc (sizeof (*resp),GFP_KERNEL ); +if (!resp) { +kfree (req); +return -ENOMEM ; + } + + ret =request_firmware (&fw_entry,BDF_FILE_NAME , &qmi->pdev->dev); +if (ret <0 ) { +pr_err ("fail to load bdf: %s\n" ,BDF_FILE_NAME ); + goto err_req_fw; + } + + temp = fw_entry->data; + remaining = fw_entry->size; + +pr_debug ("downloading bdf: %s, size: %u\n" , +BDF_FILE_NAME , remaining); + +while (remaining) { + req->valid =1 ; + req->file_id_valid =1 ; + req->file_id =0 ; + req->total_size_valid =1 ; + req->total_size = fw_entry->size; + req->seg_id_valid =1 ; + req->data_valid =1 ; + req->end_valid =1 ; + +if (remaining >QMI_WLFW_MAX_DATA_SIZE_V01 ) { + req->data_len =QMI_WLFW_MAX_DATA_SIZE_V01 ; + }else { + req->data_len = remaining; + req->end =1 ; + } + +memcpy (req->data, temp, req->data_len); + + ret =qmi_txn_init (&qmi->qmi_hdl, &txn, + wlfw_bdf_download_resp_msg_v01_ei, + resp); +if (ret <0 ) { +pr_err ("fail to init txn for bdf download %d\n" , ret); + goto out; + } + + ret = +qmi_send_request (&qmi->qmi_hdl,NULL , &txn, +QMI_WLFW_BDF_DOWNLOAD_REQ_V01 , +WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN , + wlfw_bdf_download_req_msg_v01_ei, req); +if (ret <0 ) { +qmi_txn_cancel (&txn); + goto err_send; + } + + ret =qmi_txn_wait (&txn,WLFW_TIMEOUT *HZ ); + +if (ret <0 ) + goto err_send; + +if (resp->resp.result !=QMI_RESULT_SUCCESS_V01 ) { +pr_err ("bdf download failed, res:%d, err:%d\n" , + resp->resp.result, resp->resp.error); + ret = resp->resp.result; + goto err_send; + } + + remaining -= req->data_len; + temp += req->data_len; + req->seg_id++; + } + +pr_debug ("bdf download request completed\n" ); + +kfree (resp); +kfree (req); +return 0 ; + +err_send: +release_firmware (fw_entry); + +err_req_fw: +kfree (req); +kfree (resp); + +out: +return ret; +} + +int ath10k_qmi_send_cal_report_req (struct ath10k_qmi *qmi) +{ +struct wlfw_cal_report_resp_msg_v01 *resp; +struct wlfw_cal_report_req_msg_v01 *req; +struct qmi_txn txn; +int i, j =0 ; +int ret; + +pr_debug ("sending cal report\n" ); + + 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 (&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei, + resp); +if (ret <0 ) { +pr_err ("fail to init txn for bdf download req %d\n" , ret); + goto out; + } + +for (i =0 ; i <QMI_WLFW_MAX_NUM_CAL_V01 ; i++) { +if (qmi->cal_data[i].total_size && + qmi->cal_data[i].data) { + req->meta_data[j] = qmi->cal_data[i].cal_id; + j++; + } + } + req->meta_data_len = j; + + ret =qmi_send_request (&qmi->qmi_hdl,NULL , &txn, +QMI_WLFW_CAL_REPORT_REQ_V01 , +WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN , + wlfw_cal_report_req_msg_v01_ei, req); +if (ret <0 ) { +qmi_txn_cancel (&txn); +pr_err ("fail to send cal req %d\n" , ret); + goto out; + } + + ret =qmi_txn_wait (&txn,WLFW_TIMEOUT *HZ ); +if (ret <0 ) + goto out; + +if (resp->resp.result !=QMI_RESULT_SUCCESS_V01 ) { +pr_err ("qmi cal reoprt request rejected:" ); +pr_err ("resut:%d error:%d\n" , + resp->resp.result, resp->resp.error); + ret = resp->resp.result; + goto out; + } + +pr_debug ("cal report request completed\n" ); + +kfree (resp); +kfree (req); +return 0 ; + +out: +kfree (resp); +kfree (req); +return ret; +} +static int ath10k_qmi_cap_send_sync_msg (struct ath10k_qmi *qmi) {struct wlfw_cap_resp_msg_v01 *resp;
@@ -509,6 +683,7 @@ static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl, struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); qmi->msa_ready = true; +queue_work (qmi->event_wq, &qmi->work_msa_ready); }static struct qmi_msg_handler qmi_msg_handler[] = {
@@ -599,6 +774,24 @@ static void ath10k_qmi_event_server_exit(struct work_struct *work)pr_info ("wlan fw service disconnected\n" ); } +static void ath10k_qmi_event_msa_ready (struct work_struct *work) +{ + struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi, + work_msa_ready); +int ret; + + ret =ath10k_qmi_bdf_dnld_send_sync (qmi); +if (ret) + goto out; + + ret =ath10k_qmi_send_cal_report_req (qmi); +if (ret) + goto out; + +out: +return ; +} +static int ath10k_qmi_new_server (struct qmi_handle *qmi_hdl,struct qmi_service *service) {
@@ -649,6 +842,7 @@ static int ath10k_alloc_qmi_resources(struct ath10k_qmi *qmi)spin_lock_init (&qmi->event_lock);INIT_WORK (&qmi->work_svc_arrive, ath10k_qmi_event_server_arrive);INIT_WORK (&qmi->work_svc_exit, ath10k_qmi_event_server_exit); +INIT_WORK (&qmi->work_msa_ready, ath10k_qmi_event_msa_ready); ret =qmi_add_lookup (&qmi->qmi_hdl,WLFW_SERVICE_ID_V01 ,WLFW_SERVICE_VERS_V01 ,0 );
@@ -696,6 +890,7 @@ static void ath10k_remove_qmi_resources(struct ath10k_qmi *qmi) {cancel_work_sync (&qmi->work_svc_arrive);cancel_work_sync (&qmi->work_svc_exit); +cancel_work_sync (&qmi->work_msa_ready);destroy_workqueue (qmi->event_wq);qmi_handle_release (&qmi->qmi_hdl); qmi =NULL ;
drivers/net/wireless/ath/ath10k/qmi.h +10 -0
@@ -19,6 +19,8 @@#define MAX_NUM_MEMORY_REGIONS 2#define MAX_TIMESTAMP_LEN 32#define MAX_BUILD_ID_LEN 128 +#define BDF_FILE_NAME "bdwlan.bin" +#define MAX_NUM_CAL_V01 5enum ath10k_qmi_driver_event_type {ATH10K_QMI_EVENT_SERVER_ARRIVE ,
@@ -51,6 +53,12 @@ struct ath10k_qmi_fw_version_info {char fw_build_timestamp[MAX_TIMESTAMP_LEN +1 ]; }; +struct ath10k_qmi_cal_data { +u32 cal_id; +u32 total_size; +u8 *data; +}; +struct ath10k_qmi {struct platform_device *pdev;struct qmi_handle qmi_hdl;
@@ -59,6 +67,7 @@ struct ath10k_qmi {bool msa_ready;struct work_struct work_svc_arrive;struct work_struct work_svc_exit; +struct work_struct work_msa_ready;struct workqueue_struct *event_wq;spinlock_t event_lock;/* spinlock for fw ready status*/ u32 nr_mem_region;
@@ -72,5 +81,6 @@ struct ath10k_qmi {struct ath10k_qmi_soc_info soc_info;struct ath10k_qmi_fw_version_info fw_version_info;char fw_build_id[MAX_BUILD_ID_LEN +1 ]; + struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01]; };#endif /* _QMI_H_ */
Signature · 1 line
1.9.1
Hi Govind,
Quoted 38 lines · Govind Singh
Add support for bdf download and cold boot
calibration trigger qmi message support.Signed-off-by Govind Singh <[email protected]>--- drivers/net/wireless/ath/ath10k/qmi.c | 195 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 10 ++ 2 files changed, 205 insertions(+)drivers/net/wireless/ath/ath10k/qmi.c +14
-0@@ -28,6 +28,7 @@#include <linux/soc/qcom/qmi.h> #include <linux/qcom_scm.h> #include <linux/of.h> +#include <linux/firmware.h> #include "qmi.h" #include "qmi_svc_v01.h" @@ -270,6 +271,179 @@ static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi)return ret; } +int ath10k_qmi_bdf_dnld_send_sync (struct ath10k_qmi *qmi) +{ +struct wlfw_bdf_download_resp_msg_v01 *resp; +struct wlfw_bdf_download_req_msg_v01 *req; +const struct firmware *fw_entry; +unsigned int remaining; +struct qmi_txn txn; +const u8 *temp; +int ret; + + req =kzalloc (sizeof (*req),GFP_KERNEL ); +if (!req) +return -ENOMEM ;
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 296
Quoted 10 lines
drivers/net/wireless/ath/ath10k/qmi.c +10
-0+ + resp =kzalloc (sizeof (*resp),GFP_KERNEL ); +if (!resp) { +kfree (req); +return -ENOMEM ; + } + + ret =request_firmware (&fw_entry,BDF_FILE_NAME , &qmi->pdev->dev); +if (ret <0 ) { +pr_err ("fail to load bdf: %s\n" ,BDF_FILE_NAME );
Do we want to use the dev_* family print functions instead?
For example:dev_err(&qmi->pdev->dev,"fail to load bdf: %s\n", BDF_FILE_NAME);
Quoted 57 lines
drivers/net/wireless/ath/ath10k/qmi.c +57
-0+ goto err_req_fw; + } + + temp = fw_entry->data; + remaining = fw_entry->size; + +pr_debug ("downloading bdf: %s, size: %u\n" , +BDF_FILE_NAME , remaining); + +while (remaining) { + req->valid =1 ; + req->file_id_valid =1 ; + req->file_id =0 ; + req->total_size_valid =1 ; + req->total_size = fw_entry->size; + req->seg_id_valid =1 ; + req->data_valid =1 ; + req->end_valid =1 ; + +if (remaining >QMI_WLFW_MAX_DATA_SIZE_V01 ) { + req->data_len =QMI_WLFW_MAX_DATA_SIZE_V01 ; + }else { + req->data_len = remaining; + req->end =1 ; + } + +memcpy (req->data, temp, req->data_len); + + ret =qmi_txn_init (&qmi->qmi_hdl, &txn, + wlfw_bdf_download_resp_msg_v01_ei, + resp); +if (ret <0 ) { +pr_err ("fail to init txn for bdf download %d\n" , ret); + goto out; + } + + ret = +qmi_send_request (&qmi->qmi_hdl,NULL , &txn, +QMI_WLFW_BDF_DOWNLOAD_REQ_V01 , +WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN , + wlfw_bdf_download_req_msg_v01_ei, req); +if (ret <0 ) { +qmi_txn_cancel (&txn); + goto err_send; + } + + ret =qmi_txn_wait (&txn,WLFW_TIMEOUT *HZ ); + +if (ret <0 ) + goto err_send; + +if (resp->resp.result !=QMI_RESULT_SUCCESS_V01 ) { +pr_err ("bdf download failed, res:%d, err:%d\n" , + resp->resp.result, resp->resp.error); + ret = resp->resp.result; + goto err_send; + }
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 363
Quoted 10 lines
drivers/net/wireless/ath/ath10k/qmi.c +10
-0+ + remaining -= req->data_len; + temp += req->data_len; + req->seg_id++; + } + +pr_debug ("bdf download request completed\n" ); + +kfree (resp); +kfree (req);
release_firmware(fw_entry);
I think we need to release firmware before return?
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 375
Quoted 12 lines
drivers/net/wireless/ath/ath10k/qmi.c +12
-0+return 0 ; + +err_send: +release_firmware (fw_entry); + +err_req_fw: +kfree (req); +kfree (resp); + +out: +return ret; +}
Best regards
Marcus Folkesson
Quoted 22 lines · Govind Singh
Add support for bdf download and cold boot
calibration trigger qmi message support.Signed-off-by Govind Singh <[email protected]>--- drivers/net/wireless/ath/ath10k/qmi.c | 195 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 10 ++ 2 files changed, 205 insertions(+)drivers/net/wireless/ath/ath10k/qmi.c +1
-0@@ -28,6 +28,7 @@#include <linux/soc/qcom/qmi.h> #include <linux/qcom_scm.h> #include <linux/of.h> +#include <linux/firmware.h> #include "qmi.h" #include "qmi_svc_v01.h"
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 276
Quoted 6 lines
drivers/net/wireless/ath/ath10k/qmi.c +3
-0@@ -270,6 +271,179 @@ static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi)return ret; } +int ath10k_qmi_bdf_dnld_send_sync (struct ath10k_qmi *qmi) +{ +struct wlfw_bdf_download_resp_msg_v01 *resp;
4 bytes, use stack.
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 277
Quoted 1 line
drivers/net/wireless/ath/ath10k/qmi.c +1
-0+struct wlfw_bdf_download_req_msg_v01 *req;
And this is approx 7kB, so that makes sense to allocate on the heap.
Quoted 46 lines
drivers/net/wireless/ath/ath10k/qmi.c +46
-0+const struct firmware *fw_entry; +unsigned int remaining; +struct qmi_txn txn; +const u8 *temp; +int ret; + + req =kzalloc (sizeof (*req),GFP_KERNEL ); +if (!req) +return -ENOMEM ; + + resp =kzalloc (sizeof (*resp),GFP_KERNEL ); +if (!resp) { +kfree (req); +return -ENOMEM ; + } + + ret =request_firmware (&fw_entry,BDF_FILE_NAME , &qmi->pdev->dev); +if (ret <0 ) { +pr_err ("fail to load bdf: %s\n" ,BDF_FILE_NAME ); + goto err_req_fw; + } + + temp = fw_entry->data; + remaining = fw_entry->size; + +pr_debug ("downloading bdf: %s, size: %u\n" , +BDF_FILE_NAME , remaining); + +while (remaining) { + req->valid =1 ; + req->file_id_valid =1 ; + req->file_id =0 ; + req->total_size_valid =1 ; + req->total_size = fw_entry->size; + req->seg_id_valid =1 ; + req->data_valid =1 ; + req->end_valid =1 ; + +if (remaining >QMI_WLFW_MAX_DATA_SIZE_V01 ) { + req->data_len =QMI_WLFW_MAX_DATA_SIZE_V01 ; + }else { + req->data_len = remaining; + req->end =1 ; + } + +memcpy (req->data, temp, req->data_len);
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 333
Quoted 10 lines
drivers/net/wireless/ath/ath10k/qmi.c +10
-0+ + ret =qmi_txn_init (&qmi->qmi_hdl, &txn, + wlfw_bdf_download_resp_msg_v01_ei, + resp); +if (ret <0 ) { +pr_err ("fail to init txn for bdf download %d\n" , ret); + goto out; + } + + ret =
Don't indent wrapped lines like that.
Quoted 17 lines
drivers/net/wireless/ath/ath10k/qmi.c +17
-0+qmi_send_request (&qmi->qmi_hdl,NULL , &txn, +QMI_WLFW_BDF_DOWNLOAD_REQ_V01 , +WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN , + wlfw_bdf_download_req_msg_v01_ei, req); +if (ret <0 ) { +qmi_txn_cancel (&txn); + goto err_send; + } + + ret =qmi_txn_wait (&txn,WLFW_TIMEOUT *HZ ); + +if (ret <0 ) + goto err_send; + +if (resp->resp.result !=QMI_RESULT_SUCCESS_V01 ) { +pr_err ("bdf download failed, res:%d, err:%d\n" , + resp->resp.result, resp->resp.error);
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 360
Quoted 10 lines
drivers/net/wireless/ath/ath10k/qmi.c +10
-0+ ret = resp->resp.result; + goto err_send; + } + + remaining -= req->data_len; + temp += req->data_len; + req->seg_id++; + } + +pr_debug ("bdf download request completed\n" );
You're leaking fw_entry, consider merging the two exit paths.
Quoted 9 lines
drivers/net/wireless/ath/ath10k/qmi.c +9
-0+ +kfree (resp); +kfree (req); +return 0 ; + +err_send: +release_firmware (fw_entry); + +err_req_fw:
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 379
Quoted 10 lines
drivers/net/wireless/ath/ath10k/qmi.c +10
-0+kfree (req); +kfree (resp); + +out: +return ret; +} + +int ath10k_qmi_send_cal_report_req (struct ath10k_qmi *qmi) +{ +struct wlfw_cal_report_resp_msg_v01 *resp;
4 bytes
drivers/net/wireless/ath/ath10k/qmi.c static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) · line 380
Quoted 1 line
drivers/net/wireless/ath/ath10k/qmi.c +1
-0+struct wlfw_cal_report_req_msg_v01 *req;
26 bytes, use the stack for both
Quoted 4 lines
drivers/net/wireless/ath/ath10k/qmi.c +4
-0+struct qmi_txn txn; +int i, j =0 ; +int ret; +
[..]
Quoted 11 lines
static struct
qmi_msg_handlerqmi_msg_handler[] = {drivers/net/wireless/ath/ath10k/qmi.c +6
-0@@ -599,6 +774,24 @@ static void ath10k_qmi_event_server_exit(struct work_struct *work)pr_info ("wlan fw service disconnected\n" ); } +static void ath10k_qmi_event_msa_ready (struct work_struct *work) +{ + struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi, + work_msa_ready); +int ret; +
drivers/net/wireless/ath/ath10k/qmi.c static void ath10k_qmi_event_server_exit(struct work_struct *work) · line 792
Quoted 10 lines
drivers/net/wireless/ath/ath10k/qmi.c +10
-0+ ret =ath10k_qmi_bdf_dnld_send_sync (qmi); +if (ret) + goto out; + + ret =ath10k_qmi_send_cal_report_req (qmi); +if (ret) + goto out; + +out: +return ;
If this is your exit then just use return instead of goto above.
drivers/net/wireless/ath/ath10k/qmi.c static void ath10k_qmi_event_server_exit(struct work_struct *work) · line 794
Quoted 2 lines
drivers/net/wireless/ath/ath10k/qmi.c +2
-0+} +
Regards,
Bjorn