--- zzzz-none-000/linux-3.10.107/drivers/bluetooth/btmrvl_sdio.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/bluetooth/btmrvl_sdio.c 2021-02-04 17:41:59.000000000 +0000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,24 @@ #define VERSION "1.0" +static struct memory_type_mapping mem_type_mapping_tbl[] = { + {"ITCM", NULL, 0, 0xF0}, + {"DTCM", NULL, 0, 0xF1}, + {"SQRAM", NULL, 0, 0xF2}, + {"APU", NULL, 0, 0xF3}, + {"CIU", NULL, 0, 0xF4}, + {"ICU", NULL, 0, 0xF5}, + {"MAC", NULL, 0, 0xF6}, + {"EXT7", NULL, 0, 0xF7}, + {"EXT8", NULL, 0, 0xF8}, + {"EXT9", NULL, 0, 0xF9}, + {"EXT10", NULL, 0, 0xFA}, + {"EXT11", NULL, 0, 0xFB}, + {"EXT12", NULL, 0, 0xFC}, + {"EXT13", NULL, 0, 0xFD}, + {"EXTLAST", NULL, 0, 0xFE}, +}; + /* The btmrvl_sdio_remove() callback function is called * when user removes this module from kernel space or ejects * the card from the slot. The driver handles these 2 cases @@ -64,6 +83,7 @@ .io_port_0 = 0x00, .io_port_1 = 0x01, .io_port_2 = 0x02, + .int_read_to_clear = false, }; static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .cfg = 0x00, @@ -80,9 +100,30 @@ .io_port_0 = 0x78, .io_port_1 = 0x79, .io_port_2 = 0x7a, + .int_read_to_clear = false, }; -static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { +static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = { + .cfg = 0x00, + .host_int_mask = 0x08, + .host_intstatus = 0x0C, + .card_status = 0x5C, + .sq_read_base_addr_a0 = 0x6C, + .sq_read_base_addr_a1 = 0x6D, + .card_revision = 0xC8, + .card_fw_status0 = 0x88, + .card_fw_status1 = 0x89, + .card_rx_len = 0x8A, + .card_rx_unit = 0x8B, + .io_port_0 = 0xE4, + .io_port_1 = 0xE5, + .io_port_2 = 0xE6, + .int_read_to_clear = true, + .host_int_rsr = 0x04, + .card_misc_cfg = 0xD8, +}; + +static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { .cfg = 0x00, .host_int_mask = 0x02, .host_intstatus = 0x03, @@ -97,52 +138,113 @@ .io_port_0 = 0xd8, .io_port_1 = 0xd9, .io_port_2 = 0xda, + .int_read_to_clear = true, + .host_int_rsr = 0x01, + .card_misc_cfg = 0xcc, + .fw_dump_ctrl = 0xe2, + .fw_dump_start = 0xe3, + .fw_dump_end = 0xea, +}; + +static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = { + .cfg = 0x00, + .host_int_mask = 0x08, + .host_intstatus = 0x0c, + .card_status = 0x5c, + .sq_read_base_addr_a0 = 0xf8, + .sq_read_base_addr_a1 = 0xf9, + .card_revision = 0xc8, + .card_fw_status0 = 0xe8, + .card_fw_status1 = 0xe9, + .card_rx_len = 0xea, + .card_rx_unit = 0xeb, + .io_port_0 = 0xe4, + .io_port_1 = 0xe5, + .io_port_2 = 0xe6, + .int_read_to_clear = true, + .host_int_rsr = 0x04, + .card_misc_cfg = 0xD8, + .fw_dump_ctrl = 0xf0, + .fw_dump_start = 0xf1, + .fw_dump_end = 0xf8, }; static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { .helper = "mrvl/sd8688_helper.bin", .firmware = "mrvl/sd8688.bin", .reg = &btmrvl_reg_8688, + .support_pscan_win_report = false, .sd_blksz_fw_dl = 64, + .supports_fw_dump = false, }; static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { .helper = NULL, .firmware = "mrvl/sd8787_uapsta.bin", .reg = &btmrvl_reg_87xx, + .support_pscan_win_report = false, .sd_blksz_fw_dl = 256, + .supports_fw_dump = false, }; static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .helper = NULL, .firmware = "mrvl/sd8797_uapsta.bin", .reg = &btmrvl_reg_87xx, + .support_pscan_win_report = false, + .sd_blksz_fw_dl = 256, + .supports_fw_dump = false, +}; + +static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = { + .helper = NULL, + .firmware = "mrvl/sd8887_uapsta.bin", + .reg = &btmrvl_reg_8887, + .support_pscan_win_report = true, .sd_blksz_fw_dl = 256, + .supports_fw_dump = false, }; static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", - .reg = &btmrvl_reg_88xx, + .reg = &btmrvl_reg_8897, + .support_pscan_win_report = true, .sd_blksz_fw_dl = 256, + .supports_fw_dump = true, +}; + +static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = { + .helper = NULL, + .firmware = "mrvl/sd8997_uapsta.bin", + .reg = &btmrvl_reg_8997, + .support_pscan_win_report = true, + .sd_blksz_fw_dl = 256, + .supports_fw_dump = true, }; static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8688 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), - .driver_data = (unsigned long) &btmrvl_sdio_sd8688 }, + .driver_data = (unsigned long)&btmrvl_sdio_sd8688 }, /* Marvell SD8787 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), - .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, + .driver_data = (unsigned long)&btmrvl_sdio_sd8787 }, /* Marvell SD8787 Bluetooth AMP device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B), - .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, + .driver_data = (unsigned long)&btmrvl_sdio_sd8787 }, /* Marvell SD8797 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), - .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, + .driver_data = (unsigned long)&btmrvl_sdio_sd8797 }, + /* Marvell SD8887 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136), + .driver_data = (unsigned long)&btmrvl_sdio_sd8887 }, /* Marvell SD8897 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), - .driver_data = (unsigned long) &btmrvl_sdio_sd8897 }, + .driver_data = (unsigned long)&btmrvl_sdio_sd8897 }, + /* Marvell SD8997 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142), + .driver_data = (unsigned long)&btmrvl_sdio_sd8997 }, { } /* Terminating entry */ }; @@ -486,7 +588,7 @@ if (firmwarelen - offset < txlen) txlen = firmwarelen - offset; - tx_blocks = (txlen + blksz_dl - 1) / blksz_dl; + tx_blocks = DIV_ROUND_UP(txlen, blksz_dl); memcpy(fwbuf, &firmware[offset], txlen); } @@ -506,7 +608,7 @@ offset += txlen; } while (true); - BT_DBG("FW download over, size %d bytes", offset); + BT_INFO("FW download over, size %d bytes", offset); ret = 0; @@ -552,8 +654,9 @@ /* Allocate buffer */ skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC); - if (skb == NULL) { + if (!skb) { BT_ERR("No free skb"); + ret = -ENOMEM; goto exit; } @@ -596,15 +699,14 @@ case HCI_SCODATA_PKT: case HCI_EVENT_PKT: bt_cb(skb)->pkt_type = type; - skb->dev = (void *)hdev; skb_put(skb, buf_len); skb_pull(skb, SDIO_HEADER_LEN); if (type == HCI_EVENT_PKT) { if (btmrvl_check_evtpkt(priv, skb)) - hci_recv_frame(skb); + hci_recv_frame(hdev, skb); } else { - hci_recv_frame(skb); + hci_recv_frame(hdev, skb); } hdev->stat.byte_rx += buf_len; @@ -612,12 +714,11 @@ case MRVL_VENDOR_PKT: bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; - skb->dev = (void *)hdev; skb_put(skb, buf_len); skb_pull(skb, SDIO_HEADER_LEN); if (btmrvl_process_event(priv, skb)) - hci_recv_frame(skb); + hci_recv_frame(hdev, skb); hdev->stat.byte_rx += buf_len; break; @@ -668,46 +769,81 @@ return 0; } -static void btmrvl_sdio_interrupt(struct sdio_func *func) +static int btmrvl_sdio_read_to_clear(struct btmrvl_sdio_card *card, u8 *ireg) { - struct btmrvl_private *priv; - struct btmrvl_sdio_card *card; - ulong flags; - u8 ireg = 0; + struct btmrvl_adapter *adapter = card->priv->adapter; int ret; - card = sdio_get_drvdata(func); - if (!card || !card->priv) { - BT_ERR("sbi_interrupt(%p) card or priv is " - "NULL, card=%p\n", func, card); - return; + ret = sdio_readsb(card->func, adapter->hw_regs, 0, SDIO_BLOCK_SIZE); + if (ret) { + BT_ERR("sdio_readsb: read int hw_regs failed: %d", ret); + return ret; } - priv = card->priv; + *ireg = adapter->hw_regs[card->reg->host_intstatus]; + BT_DBG("hw_regs[%#x]=%#x", card->reg->host_intstatus, *ireg); - ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); + return 0; +} + +static int btmrvl_sdio_write_to_clear(struct btmrvl_sdio_card *card, u8 *ireg) +{ + int ret; + + *ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); if (ret) { - BT_ERR("sdio_readb: read int status register failed"); - return; + BT_ERR("sdio_readb: read int status failed: %d", ret); + return ret; } - if (ireg != 0) { + if (*ireg) { /* * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS * Clear the interrupt status register and re-enable the * interrupt. */ - BT_DBG("ireg = 0x%x", ireg); + BT_DBG("int_status = 0x%x", *ireg); - sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | - UP_LD_HOST_INT_STATUS), - card->reg->host_intstatus, &ret); + sdio_writeb(card->func, ~(*ireg) & (DN_LD_HOST_INT_STATUS | + UP_LD_HOST_INT_STATUS), + card->reg->host_intstatus, &ret); if (ret) { - BT_ERR("sdio_writeb: clear int status register failed"); - return; + BT_ERR("sdio_writeb: clear int status failed: %d", ret); + return ret; } } + return 0; +} + +static void btmrvl_sdio_interrupt(struct sdio_func *func) +{ + struct btmrvl_private *priv; + struct btmrvl_sdio_card *card; + ulong flags; + u8 ireg = 0; + int ret; + + card = sdio_get_drvdata(func); + if (!card || !card->priv) { + BT_ERR("sbi_interrupt(%p) card or priv is NULL, card=%p", + func, card); + return; + } + + priv = card->priv; + + if (priv->surprise_removed) + return; + + if (card->reg->int_read_to_clear) + ret = btmrvl_sdio_read_to_clear(card, &ireg); + else + ret = btmrvl_sdio_write_to_clear(card, &ireg); + + if (ret) + return; + spin_lock_irqsave(&priv->driver_lock, flags); sdio_ireg |= ireg; spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -778,6 +914,30 @@ BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); + if (card->reg->int_read_to_clear) { + reg = sdio_readb(func, card->reg->host_int_rsr, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + reg = sdio_readb(func, card->reg->card_misc_cfg, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + } + sdio_set_drvdata(func, card); sdio_release_host(func); @@ -872,7 +1032,7 @@ } blksz = SDIO_BLOCK_SIZE; - buf_block_len = (nb + blksz - 1) / blksz; + buf_block_len = DIV_ROUND_UP(nb, blksz); sdio_claim_host(card->func); @@ -946,8 +1106,6 @@ } } - sdio_release_host(card->func); - /* * winner or not, with this test the FW synchronizes when the * module can continue its initialization @@ -957,6 +1115,8 @@ return -ETIMEDOUT; } + sdio_release_host(card->func); + return 0; done: @@ -985,6 +1145,282 @@ return ret; } +static void btmrvl_sdio_dump_regs(struct btmrvl_private *priv) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret = 0; + unsigned int reg, reg_start, reg_end; + char buf[256], *ptr; + u8 loop, func, data; + int MAX_LOOP = 2; + + btmrvl_sdio_wakeup_fw(priv); + sdio_claim_host(card->func); + + for (loop = 0; loop < MAX_LOOP; loop++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + + if (loop == 0) { + /* Read the registers of SDIO function0 */ + func = loop; + reg_start = 0; + reg_end = 9; + } else { + func = 2; + reg_start = 0; + reg_end = 0x09; + } + + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", + func, reg_start, reg_end); + for (reg = reg_start; reg <= reg_end; reg++) { + if (func == 0) + data = sdio_f0_readb(card->func, reg, &ret); + else + data = sdio_readb(card->func, reg, &ret); + + if (!ret) { + ptr += sprintf(ptr, "%02x ", data); + } else { + ptr += sprintf(ptr, "ERR"); + break; + } + } + + BT_INFO("%s", buf); + } + + sdio_release_host(card->func); +} + +/* This function read/write firmware */ +static enum +rdwr_status btmrvl_sdio_rdwr_firmware(struct btmrvl_private *priv, + u8 doneflag) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret, tries; + u8 ctrl_data = 0; + + sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl, + &ret); + + if (ret) { + BT_ERR("SDIO write err"); + return RDWR_STATUS_FAILURE; + } + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl, + &ret); + + if (ret) { + BT_ERR("SDIO read err"); + return RDWR_STATUS_FAILURE; + } + + if (ctrl_data == FW_DUMP_DONE) + break; + if (doneflag && ctrl_data == doneflag) + return RDWR_STATUS_DONE; + if (ctrl_data != FW_DUMP_HOST_READY) { + BT_INFO("The ctrl reg was changed, re-try again!"); + sdio_writeb(card->func, FW_DUMP_HOST_READY, + card->reg->fw_dump_ctrl, &ret); + if (ret) { + BT_ERR("SDIO write err"); + return RDWR_STATUS_FAILURE; + } + } + usleep_range(100, 200); + } + + if (ctrl_data == FW_DUMP_HOST_READY) { + BT_ERR("Fail to pull ctrl_data"); + return RDWR_STATUS_FAILURE; + } + + return RDWR_STATUS_SUCCESS; +} + +/* This function dump sdio register and memory data */ +static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret = 0; + unsigned int reg, reg_start, reg_end; + enum rdwr_status stat; + u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr; + u8 dump_num = 0, idx, i, read_reg, doneflag = 0; + u32 memory_size, fw_dump_len = 0; + + /* dump sdio register first */ + btmrvl_sdio_dump_regs(priv); + + if (!card->supports_fw_dump) { + BT_ERR("Firmware dump not supported for this card!"); + return; + } + + for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } + + btmrvl_sdio_wakeup_fw(priv); + sdio_claim_host(card->func); + + BT_INFO("== btmrvl firmware dump start =="); + + stat = btmrvl_sdio_rdwr_firmware(priv, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg = card->reg->fw_dump_start; + /* Read the number of the memories which will dump */ + dump_num = sdio_readb(card->func, reg, &ret); + + if (ret) { + BT_ERR("SDIO read memory length err"); + goto done; + } + + /* Read the length of every memory which will dump */ + for (idx = 0; idx < dump_num; idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + stat = btmrvl_sdio_rdwr_firmware(priv, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + memory_size = 0; + reg = card->reg->fw_dump_start; + for (i = 0; i < 4; i++) { + read_reg = sdio_readb(card->func, reg, &ret); + if (ret) { + BT_ERR("SDIO read err"); + goto done; + } + memory_size |= (read_reg << i*8); + reg++; + } + + if (memory_size == 0) { + BT_INFO("Firmware dump finished!"); + sdio_writeb(card->func, FW_DUMP_READ_DONE, + card->reg->fw_dump_ctrl, &ret); + if (ret) { + BT_ERR("SDIO Write MEMDUMP_FINISH ERR"); + goto done; + } + break; + } + + BT_INFO("%s_SIZE=0x%x", entry->mem_name, memory_size); + entry->mem_ptr = vzalloc(memory_size + 1); + entry->mem_size = memory_size; + if (!entry->mem_ptr) { + BT_ERR("Vzalloc %s failed", entry->mem_name); + goto done; + } + + fw_dump_len += (strlen("========Start dump ") + + strlen(entry->mem_name) + + strlen("========\n") + + (memory_size + 1) + + strlen("\n========End dump========\n")); + + dbg_ptr = entry->mem_ptr; + end_ptr = dbg_ptr + memory_size; + + doneflag = entry->done_flag; + BT_INFO("Start %s output, please wait...", + entry->mem_name); + + do { + stat = btmrvl_sdio_rdwr_firmware(priv, doneflag); + 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++) { + *dbg_ptr = sdio_readb(card->func, reg, &ret); + if (ret) { + BT_ERR("SDIO read err"); + goto done; + } + if (dbg_ptr < end_ptr) + dbg_ptr++; + else + BT_ERR("Allocated buffer not enough"); + } + + if (stat != RDWR_STATUS_DONE) { + continue; + } else { + BT_INFO("%s done: size=0x%tx", + entry->mem_name, + dbg_ptr - entry->mem_ptr); + break; + } + } while (1); + } + + BT_INFO("== btmrvl firmware dump end =="); + +done: + sdio_release_host(card->func); + + if (fw_dump_len == 0) + return; + + fw_dump_data = vzalloc(fw_dump_len+1); + if (!fw_dump_data) { + BT_ERR("Vzalloc fw_dump_data fail!"); + return; + } + fw_dump_ptr = fw_dump_data; + + /* Dump all the memory data into single file, a userspace script will + be used to split all the memory data to multiple files*/ + BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump start"); + for (idx = 0; idx < dump_num; idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + strcpy(fw_dump_ptr, "========Start dump "); + fw_dump_ptr += strlen("========Start dump "); + + strcpy(fw_dump_ptr, entry->mem_name); + fw_dump_ptr += strlen(entry->mem_name); + + strcpy(fw_dump_ptr, "========\n"); + fw_dump_ptr += strlen("========\n"); + + memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size); + fw_dump_ptr += entry->mem_size; + + strcpy(fw_dump_ptr, "\n========End dump========\n"); + fw_dump_ptr += strlen("\n========End dump========\n"); + + vfree(mem_type_mapping_tbl[idx].mem_ptr); + mem_type_mapping_tbl[idx].mem_ptr = NULL; + } + } + + /* fw_dump_data will be free in device coredump release function + after 5 min*/ + dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL); + BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end"); +} + static int btmrvl_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -1007,6 +1443,8 @@ card->firmware = data->firmware; card->reg = data->reg; card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; + card->support_pscan_win_report = data->support_pscan_win_report; + card->supports_fw_dump = data->supports_fw_dump; } if (btmrvl_sdio_register_dev(card) < 0) { @@ -1038,6 +1476,7 @@ priv->hw_host_to_card = btmrvl_sdio_host_to_card; priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; priv->hw_process_int_status = btmrvl_sdio_process_int_status; + priv->firmware_dump = btmrvl_sdio_dump_firmware; if (btmrvl_register_hdev(priv)) { BT_ERR("Register hdev failed!"); @@ -1045,12 +1484,6 @@ goto disable_host_int; } - priv->btmrvl_dev.psmode = 1; - btmrvl_enable_ps(priv); - - priv->btmrvl_dev.gpio_gap = 0xffff; - btmrvl_send_hscfg_cmd(priv); - return 0; disable_host_int: @@ -1076,6 +1509,7 @@ btmrvl_sdio_disable_host_int(card); } BT_DBG("unregester dev"); + card->priv->surprise_removed = true; btmrvl_sdio_unregister_dev(card); btmrvl_remove_card(card->priv); } @@ -1110,6 +1544,10 @@ } priv = card->priv; + hcidev = priv->btmrvl_dev.hcidev; + BT_DBG("%s: SDIO suspend", hcidev->name); + hci_suspend_dev(hcidev); + skb_queue_purge(&priv->adapter->tx_queue); if (priv->adapter->hs_state != HS_ACTIVATED) { if (btmrvl_enable_hs(priv)) { @@ -1117,10 +1555,6 @@ return -EBUSY; } } - hcidev = priv->btmrvl_dev.hcidev; - BT_DBG("%s: SDIO suspend", hcidev->name); - hci_suspend_dev(hcidev); - skb_queue_purge(&priv->adapter->tx_queue); priv->adapter->is_suspended = true; @@ -1162,13 +1596,13 @@ return 0; } - priv->adapter->is_suspended = false; - hcidev = priv->btmrvl_dev.hcidev; - BT_DBG("%s: SDIO resume", hcidev->name); - hci_resume_dev(hcidev); priv->hw_wakeup_firmware(priv); priv->adapter->hs_state = HS_DEACTIVATED; + hcidev = priv->btmrvl_dev.hcidev; BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name); + priv->adapter->is_suspended = false; + BT_DBG("%s: SDIO resume", hcidev->name); + hci_resume_dev(hcidev); return 0; } @@ -1221,4 +1655,6 @@ MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8997_uapsta.bin");