Commit eee7f196 authored by Zhaoyang Liu's avatar Zhaoyang Liu Committed by Kalle Valo

mwifiex: add firmware dump support for SD8997

This patch adds firmware dump feature for SD8997 chipset.
The difference here is only one memory type is needed
to save all firmware information. Device dump information
will be uploaded to usersapace file.
Signed-off-by: default avatarZhaoyang Liu <liuzy@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 6d85ef00
...@@ -51,6 +51,10 @@ static unsigned long iface_work_flags; ...@@ -51,6 +51,10 @@ static unsigned long iface_work_flags;
static struct semaphore add_remove_card_sem; static struct semaphore add_remove_card_sem;
static struct memory_type_mapping generic_mem_type_map[] = {
{"DUMP", NULL, 0, 0xDD},
};
static struct memory_type_mapping mem_type_mapping_tbl[] = { static struct memory_type_mapping mem_type_mapping_tbl[] = {
{"ITCM", NULL, 0, 0xF0}, {"ITCM", NULL, 0, 0xF0},
{"DTCM", NULL, 0, 0xF1}, {"DTCM", NULL, 0, 0xF1},
...@@ -108,6 +112,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) ...@@ -108,6 +112,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size;
card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;
card->can_dump_fw = data->can_dump_fw; card->can_dump_fw = data->can_dump_fw;
card->fw_dump_enh = data->fw_dump_enh;
card->can_auto_tdls = data->can_auto_tdls; card->can_auto_tdls = data->can_auto_tdls;
card->can_ext_scan = data->can_ext_scan; card->can_ext_scan = data->can_ext_scan;
} }
...@@ -1969,8 +1974,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) ...@@ -1969,8 +1974,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
adapter->dev = &func->dev; adapter->dev = &func->dev;
strcpy(adapter->fw_name, card->firmware); strcpy(adapter->fw_name, card->firmware);
if (card->fw_dump_enh) {
adapter->mem_type_mapping_tbl = generic_mem_type_map;
adapter->num_mem_types = 1;
} else {
adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
}
return 0; return 0;
} }
...@@ -2163,8 +2173,8 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, ...@@ -2163,8 +2173,8 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
int ret, tries; int ret, tries;
u8 ctrl_data = 0; u8 ctrl_data = 0;
sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl, sdio_writeb(card->func, card->reg->fw_dump_host_ready,
&ret); card->reg->fw_dump_ctrl, &ret);
if (ret) { if (ret) {
mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n"); mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n");
return RDWR_STATUS_FAILURE; return RDWR_STATUS_FAILURE;
...@@ -2180,10 +2190,10 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, ...@@ -2180,10 +2190,10 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
break; break;
if (doneflag && ctrl_data == doneflag) if (doneflag && ctrl_data == doneflag)
return RDWR_STATUS_DONE; return RDWR_STATUS_DONE;
if (ctrl_data != FW_DUMP_HOST_READY) { if (ctrl_data != card->reg->fw_dump_host_ready) {
mwifiex_dbg(adapter, WARN, mwifiex_dbg(adapter, WARN,
"The ctrl reg was changed, re-try again!\n"); "The ctrl reg was changed, re-try again\n");
sdio_writeb(card->func, FW_DUMP_HOST_READY, sdio_writeb(card->func, card->reg->fw_dump_host_ready,
card->reg->fw_dump_ctrl, &ret); card->reg->fw_dump_ctrl, &ret);
if (ret) { if (ret) {
mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); mwifiex_dbg(adapter, ERROR, "SDIO write err\n");
...@@ -2192,7 +2202,7 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, ...@@ -2192,7 +2202,7 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
} }
usleep_range(100, 200); usleep_range(100, 200);
} }
if (ctrl_data == FW_DUMP_HOST_READY) { if (ctrl_data == card->reg->fw_dump_host_ready) {
mwifiex_dbg(adapter, ERROR, mwifiex_dbg(adapter, ERROR,
"Fail to pull ctrl_data\n"); "Fail to pull ctrl_data\n");
return RDWR_STATUS_FAILURE; return RDWR_STATUS_FAILURE;
...@@ -2325,9 +2335,128 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) ...@@ -2325,9 +2335,128 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
sdio_release_host(card->func); sdio_release_host(card->func);
} }
static void mwifiex_sdio_generic_fw_dump(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
struct memory_type_mapping *entry = &generic_mem_type_map[0];
unsigned int reg, reg_start, reg_end;
u8 start_flag = 0, done_flag = 0;
u8 *dbg_ptr, *end_ptr;
enum rdwr_status stat;
int ret = -1, tries;
if (!card->fw_dump_enh)
return;
if (entry->mem_ptr) {
vfree(entry->mem_ptr);
entry->mem_ptr = NULL;
}
entry->mem_size = 0;
mwifiex_pm_wakeup_card(adapter);
sdio_claim_host(card->func);
mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
reg_start = card->reg->fw_dump_start;
reg_end = card->reg->fw_dump_end;
for (reg = reg_start; reg <= reg_end; reg++) {
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
start_flag = sdio_readb(card->func, reg, &ret);
if (ret) {
mwifiex_dbg(adapter, ERROR,
"SDIO read err\n");
goto done;
}
if (start_flag == 0)
break;
if (tries == MAX_POLL_TRIES) {
mwifiex_dbg(adapter, ERROR,
"FW not ready to dump\n");
ret = -1;
goto done;
}
}
usleep_range(100, 200);
}
entry->mem_ptr = vmalloc(0xf0000 + 1);
if (!entry->mem_ptr) {
ret = -1;
goto done;
}
dbg_ptr = entry->mem_ptr;
entry->mem_size = 0xf0000;
end_ptr = dbg_ptr + entry->mem_size;
done_flag = entry->done_flag;
mwifiex_dbg(adapter, DUMP,
"Start %s output, please wait...\n", entry->mem_name);
while (true) {
stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
for (reg = reg_start; reg <= reg_end; reg++) {
*dbg_ptr = sdio_readb(card->func, reg, &ret);
if (ret) {
mwifiex_dbg(adapter, ERROR,
"SDIO read err\n");
goto done;
}
dbg_ptr++;
if (dbg_ptr >= end_ptr) {
u8 *tmp_ptr;
tmp_ptr = vmalloc(entry->mem_size + 0x4000 + 1);
if (!tmp_ptr)
goto done;
memcpy(tmp_ptr, entry->mem_ptr,
entry->mem_size);
vfree(entry->mem_ptr);
entry->mem_ptr = tmp_ptr;
tmp_ptr = NULL;
dbg_ptr = entry->mem_ptr + entry->mem_size;
entry->mem_size += 0x4000;
end_ptr = entry->mem_ptr + entry->mem_size;
}
}
if (stat == RDWR_STATUS_DONE) {
entry->mem_size = dbg_ptr - entry->mem_ptr;
mwifiex_dbg(adapter, DUMP, "dump %s done size=0x%x\n",
entry->mem_name, entry->mem_size);
ret = 0;
break;
}
}
mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
done:
if (ret) {
mwifiex_dbg(adapter, ERROR, "firmware dump failed\n");
if (entry->mem_ptr) {
vfree(entry->mem_ptr);
entry->mem_ptr = NULL;
}
entry->mem_size = 0;
}
sdio_release_host(card->func);
}
static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter) static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter)
{ {
struct sdio_mmc_card *card = adapter->card;
mwifiex_drv_info_dump(adapter); mwifiex_drv_info_dump(adapter);
if (card->fw_dump_enh)
mwifiex_sdio_generic_fw_dump(adapter);
else
mwifiex_sdio_fw_dump(adapter); mwifiex_sdio_fw_dump(adapter);
mwifiex_upload_device_dump(adapter); mwifiex_upload_device_dump(adapter);
} }
......
...@@ -223,6 +223,7 @@ struct mwifiex_sdio_card_reg { ...@@ -223,6 +223,7 @@ struct mwifiex_sdio_card_reg {
u8 cmd_cfg_1; u8 cmd_cfg_1;
u8 cmd_cfg_2; u8 cmd_cfg_2;
u8 cmd_cfg_3; u8 cmd_cfg_3;
u8 fw_dump_host_ready;
u8 fw_dump_ctrl; u8 fw_dump_ctrl;
u8 fw_dump_start; u8 fw_dump_start;
u8 fw_dump_end; u8 fw_dump_end;
...@@ -258,6 +259,7 @@ struct sdio_mmc_card { ...@@ -258,6 +259,7 @@ struct sdio_mmc_card {
bool supports_sdio_new_mode; bool supports_sdio_new_mode;
bool has_control_mask; bool has_control_mask;
bool can_dump_fw; bool can_dump_fw;
bool fw_dump_enh;
bool can_auto_tdls; bool can_auto_tdls;
bool can_ext_scan; bool can_ext_scan;
...@@ -279,6 +281,7 @@ struct mwifiex_sdio_device { ...@@ -279,6 +281,7 @@ struct mwifiex_sdio_device {
bool supports_sdio_new_mode; bool supports_sdio_new_mode;
bool has_control_mask; bool has_control_mask;
bool can_dump_fw; bool can_dump_fw;
bool fw_dump_enh;
bool can_auto_tdls; bool can_auto_tdls;
bool can_ext_scan; bool can_ext_scan;
}; };
...@@ -354,6 +357,7 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { ...@@ -354,6 +357,7 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {
.cmd_cfg_1 = 0xb9, .cmd_cfg_1 = 0xb9,
.cmd_cfg_2 = 0xba, .cmd_cfg_2 = 0xba,
.cmd_cfg_3 = 0xbb, .cmd_cfg_3 = 0xbb,
.fw_dump_host_ready = 0xee,
.fw_dump_ctrl = 0xe2, .fw_dump_ctrl = 0xe2,
.fw_dump_start = 0xe3, .fw_dump_start = 0xe3,
.fw_dump_end = 0xea, .fw_dump_end = 0xea,
...@@ -404,6 +408,10 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8997 = { ...@@ -404,6 +408,10 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8997 = {
.cmd_cfg_1 = 0xc5, .cmd_cfg_1 = 0xc5,
.cmd_cfg_2 = 0xc6, .cmd_cfg_2 = 0xc6,
.cmd_cfg_3 = 0xc7, .cmd_cfg_3 = 0xc7,
.fw_dump_host_ready = 0xcc,
.fw_dump_ctrl = 0xf0,
.fw_dump_start = 0xf1,
.fw_dump_end = 0xf8,
.func1_dump_reg_start = 0x10, .func1_dump_reg_start = 0x10,
.func1_dump_reg_end = 0x17, .func1_dump_reg_end = 0x17,
.func1_scratch_reg = 0xe8, .func1_scratch_reg = 0xe8,
...@@ -532,7 +540,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { ...@@ -532,7 +540,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX,
.supports_sdio_new_mode = true, .supports_sdio_new_mode = true,
.has_control_mask = false, .has_control_mask = false,
.can_dump_fw = false, .can_dump_fw = true,
.fw_dump_enh = true,
.can_auto_tdls = false, .can_auto_tdls = false,
.can_ext_scan = true, .can_ext_scan = true,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment