diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/sdio.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/sdio.c | 111 |
1 files changed, 107 insertions, 4 deletions
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 933dae137850..91e36cda9543 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -107,6 +107,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; card->supports_fw_dump = data->supports_fw_dump; card->auto_tdls = data->auto_tdls; + card->can_ext_scan = data->can_ext_scan; } sdio_claim_host(func); @@ -282,6 +283,9 @@ static int mwifiex_sdio_suspend(struct device *dev) #define SDIO_DEVICE_ID_MARVELL_8897 (0x912d) /* Device ID for SD8887 */ #define SDIO_DEVICE_ID_MARVELL_8887 (0x9135) +/* Device ID for SD8801 */ +#define SDIO_DEVICE_ID_MARVELL_8801 (0x9139) + /* WLAN IDs */ static const struct sdio_device_id mwifiex_ids[] = { @@ -295,6 +299,8 @@ static const struct sdio_device_id mwifiex_ids[] = { .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887), .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801), + .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, {}, }; @@ -986,8 +992,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, offset += txlen; } while (true); - dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", - offset); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", offset); ret = 0; done: @@ -1882,6 +1888,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) } adapter->auto_tdls = card->auto_tdls; + adapter->ext_scan = card->can_ext_scan; return ret; } @@ -1958,8 +1965,8 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) pr_err("Resetting card...\n"); mmc_remove_host(target); - /* 20ms delay is based on experiment with sdhci controller */ - mdelay(20); + /* 200ms delay is based on experiment with sdhci controller */ + mdelay(200); target->rescan_entered = 0; /* rescan non-removable cards */ mmc_add_host(target); } @@ -2023,6 +2030,8 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) u32 memory_size; static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL }; + mwifiex_dump_drv_info(adapter); + if (!card->supports_fw_dump) return; @@ -2166,6 +2175,99 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) schedule_work(&adapter->iface_work); } +/* Function to dump SDIO function registers and SDIO scratch registers in case + * of FW crash + */ +static int +mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) +{ + char *p = drv_buf; + struct sdio_mmc_card *cardp = adapter->card; + int ret = 0; + u8 count, func, data, index = 0, size = 0; + u8 reg, reg_start, reg_end; + char buf[256], *ptr; + + if (!p) + return 0; + + dev_info(adapter->dev, "SDIO register DUMP START\n"); + + mwifiex_pm_wakeup_card(adapter); + + sdio_claim_host(cardp->func); + + for (count = 0; count < 5; count++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + + switch (count) { + case 0: + /* Read the registers of SDIO function0 */ + func = count; + reg_start = 0; + reg_end = 9; + break; + case 1: + /* Read the registers of SDIO function1 */ + func = count; + reg_start = cardp->reg->func1_dump_reg_start; + reg_end = cardp->reg->func1_dump_reg_end; + break; + case 2: + index = 0; + func = 1; + reg_start = cardp->reg->func1_spec_reg_table[index++]; + size = cardp->reg->func1_spec_reg_num; + reg_end = cardp->reg->func1_spec_reg_table[size-1]; + break; + default: + /* Read the scratch registers of SDIO function1 */ + if (count == 4) + mdelay(100); + func = 1; + reg_start = cardp->reg->func1_scratch_reg; + reg_end = reg_start + MWIFIEX_SDIO_SCRATCH_SIZE; + } + + if (count != 2) + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", + func, reg_start, reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + data = sdio_f0_readb(cardp->func, reg, &ret); + else + data = sdio_readb(cardp->func, reg, &ret); + + if (count == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) { + ptr += sprintf(ptr, "%02x ", data); + } else { + ptr += sprintf(ptr, "ERR"); + break; + } + + if (count == 2 && reg < reg_end) + reg = cardp->reg->func1_spec_reg_table[index++]; + else + reg++; + } + + dev_info(adapter->dev, "%s\n", buf); + p += sprintf(p, "%s\n", buf); + } + + sdio_release_host(cardp->func); + + dev_info(adapter->dev, "SDIO register DUMP END\n"); + + return p - drv_buf; +} + static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, @@ -2188,6 +2290,7 @@ static struct mwifiex_if_ops sdio_ops = { .card_reset = mwifiex_sdio_card_reset, .iface_work = mwifiex_sdio_work, .fw_dump = mwifiex_sdio_fw_dump, + .reg_dump = mwifiex_sdio_reg_dump, }; /* |