Skip to content

Commit

Permalink
ath10k: download firmware via diag Copy Engine for QCA6174 and QCA9377.
Browse files Browse the repository at this point in the history
Downloading firmware via BMI protocol takes too long time. For example,
a ~700K bytes firmware takes about 500ms to download via BMI protocol.
This is too long especially in suspend and resume scenario where firmware
is re-downloaded unless WoWLAN is enabled. Downloading firmware via diag CE
can reduce the time to ~40ms for a ~700K bytes firmware binary.

Ath10k driver parses the firmware to segments and downloads the segments
to the specified address directly. If the firmware is compressed or has
unsupported segments, ath10k driver will try BMI download again.

It's tested with QCA6174 hw3.2 and
firmware-6.bin_WLAN.RM.4.4.1-00111-QCARMSWP-1. QCA9377 is also affected.

Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Carl Huang authored and Kalle Valo committed Sep 6, 2018
1 parent bc346c9 commit 39501ea
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 6 deletions.
23 changes: 23 additions & 0 deletions drivers/net/wireless/ath/ath10k/bmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,26 @@ int ath10k_bmi_fast_download(struct ath10k *ar,

return ret;
}

int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
{
struct bmi_cmd cmd;
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
int ret;

if (ar->bmi.done_sent) {
ath10k_warn(ar, "bmi set start command disallowed\n");
return -EBUSY;
}

cmd.id = __cpu_to_le32(BMI_SET_APP_START);
cmd.set_app_start.addr = __cpu_to_le32(address);

ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
if (ret) {
ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
return ret;
}

return 0;
}
31 changes: 31 additions & 0 deletions drivers/net/wireless/ath/ath10k/bmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,35 @@ struct bmi_target_info {
u32 type;
};

struct bmi_segmented_file_header {
__le32 magic_num;
__le32 file_flags;
u8 data[];
};

struct bmi_segmented_metadata {
__le32 addr;
__le32 length;
u8 data[];
};

#define BMI_SGMTFILE_MAGIC_NUM 0x544d4753 /* "SGMT" */
#define BMI_SGMTFILE_FLAG_COMPRESS 1

/* Special values for bmi_segmented_metadata.length (all have high bit set) */

/* end of segmented data */
#define BMI_SGMTFILE_DONE 0xffffffff

/* Board Data segment */
#define BMI_SGMTFILE_BDDATA 0xfffffffe

/* set beginning address */
#define BMI_SGMTFILE_BEGINADDR 0xfffffffd

/* immediate function execution */
#define BMI_SGMTFILE_EXEC 0xfffffffc

/* in jiffies */
#define BMI_COMMUNICATION_TIMEOUT_HZ (3 * HZ)

Expand Down Expand Up @@ -244,4 +273,6 @@ int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
const void *buffer, u32 length);
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val);
int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val);
int ath10k_bmi_set_start(struct ath10k *ar, u32 address);

#endif /* _BMI_H_ */
36 changes: 30 additions & 6 deletions drivers/net/wireless/ath/ath10k/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA988X_HW_2_0_VERSION,
Expand Down Expand Up @@ -127,6 +128,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA9887_HW_1_0_VERSION,
Expand Down Expand Up @@ -161,6 +163,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
Expand Down Expand Up @@ -194,6 +197,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
Expand Down Expand Up @@ -227,6 +231,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_3_0_VERSION,
Expand Down Expand Up @@ -260,6 +265,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_3_2_VERSION,
Expand Down Expand Up @@ -296,6 +302,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = true,
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
Expand Down Expand Up @@ -335,6 +342,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA9984_HW_1_0_DEV_VERSION,
Expand Down Expand Up @@ -381,6 +389,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
Expand Down Expand Up @@ -424,6 +433,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
Expand Down Expand Up @@ -457,6 +467,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
Expand Down Expand Up @@ -492,6 +503,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = true,
},
{
.id = QCA4019_HW_1_0_DEV_VERSION,
Expand Down Expand Up @@ -532,6 +544,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
.fw_diag_ce_download = false,
},
{
.id = WCN3990_HW_1_0_DEV_VERSION,
Expand All @@ -556,6 +569,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.shadow_reg_support = true,
.rri_on_ddr = true,
.hw_filter_reset_required = false,
.fw_diag_ce_download = false,
},
};

Expand Down Expand Up @@ -955,14 +969,24 @@ static int ath10k_download_fw(struct ath10k *ar)
"boot uploading firmware image %pK len %d\n",
data, data_len);

ret = ath10k_bmi_fast_download(ar, address, data, data_len);
if (ret) {
ath10k_err(ar, "failed to download firmware: %d\n",
ret);
return ret;
/* Check if device supports to download firmware via
* diag copy engine. Downloading firmware via diag CE
* greatly reduces the time to download firmware.
*/
if (ar->hw_params.fw_diag_ce_download) {
ret = ath10k_hw_diag_fast_download(ar, address,
data, data_len);
if (ret == 0)
/* firmware upload via diag ce was successful */
return 0;

ath10k_warn(ar,
"failed to upload firmware via diag ce, trying BMI: %d",
ret);
}

return ret;
return ath10k_bmi_fast_download(ar, address,
data, data_len);
}

static void ath10k_core_free_board_files(struct ath10k *ar)
Expand Down
Loading

0 comments on commit 39501ea

Please sign in to comment.