forked from Minki/linux
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: Zhaoyang Liu <liuzy@marvell.com> Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
6d85ef00d9
commit
eee7f1961b
@ -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)
|
|||||||
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)
|
|||||||
adapter->dev = &func->dev;
|
adapter->dev = &func->dev;
|
||||||
|
|
||||||
strcpy(adapter->fw_name, card->firmware);
|
strcpy(adapter->fw_name, card->firmware);
|
||||||
adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
|
if (card->fw_dump_enh) {
|
||||||
adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
|
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->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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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,10 +2335,129 @@ done:
|
|||||||
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);
|
||||||
mwifiex_sdio_fw_dump(adapter);
|
if (card->fw_dump_enh)
|
||||||
|
mwifiex_sdio_generic_fw_dump(adapter);
|
||||||
|
else
|
||||||
|
mwifiex_sdio_fw_dump(adapter);
|
||||||
mwifiex_upload_device_dump(adapter);
|
mwifiex_upload_device_dump(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
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 = {
|
|||||||
.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 = {
|
|||||||
.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 = {
|
|||||||
.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,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user