aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/marvell/mwifiex/pcie.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/marvell/mwifiex/pcie.c')
-rw-r--r--drivers/net/wireless/marvell/mwifiex/pcie.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 8ee9609ef974..9fcd070f2463 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -368,6 +368,8 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+
+ card->pci_reset_ongoing = true;
}
/*
@@ -396,6 +398,8 @@ static void mwifiex_pcie_reset_done(struct pci_dev *pdev)
dev_err(&pdev->dev, "reinit failed: %d\n", ret);
else
mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
+
+ card->pci_reset_ongoing = false;
}
static const struct pci_error_handlers mwifiex_pcie_err_handler = {
@@ -1066,7 +1070,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- u32 tmp;
+ u32 *cookie;
card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
&card->sleep_cookie_pbase);
@@ -1075,13 +1079,11 @@ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
"pci_alloc_consistent failed!\n");
return -ENOMEM;
}
+ cookie = (u32 *)card->sleep_cookie_vbase;
/* Init val of Sleep Cookie */
- tmp = FW_AWAKE_COOKIE;
- put_unaligned(tmp, card->sleep_cookie_vbase);
+ *cookie = FW_AWAKE_COOKIE;
- mwifiex_dbg(adapter, INFO,
- "alloc_scook: sleep cookie=0x%x\n",
- get_unaligned(card->sleep_cookie_vbase));
+ mwifiex_dbg(adapter, INFO, "alloc_scook: sleep cookie=0x%x\n", *cookie);
return 0;
}
@@ -1314,6 +1316,14 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
ret = -1;
goto done_unmap;
}
+
+ /* The firmware (latest version 15.68.19.p21) of the 88W8897 PCIe+USB card
+ * seems to crash randomly after setting the TX ring write pointer when
+ * ASPM powersaving is enabled. A workaround seems to be keeping the bus
+ * busy by reading a random register afterwards.
+ */
+ mwifiex_read_reg(adapter, PCI_VENDOR_ID, &rx_val);
+
if ((mwifiex_pcie_txbd_not_full(card)) &&
tx_param->next_pkt_len) {
/* have more packets and TxBD still can hold more */
@@ -2980,7 +2990,19 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter)
int ret;
u32 fw_status;
- cancel_work_sync(&card->work);
+ /* Perform the cancel_work_sync() only when we're not resetting
+ * the card. It's because that function never returns if we're
+ * in reset path. If we're here when resetting the card, it means
+ * that we failed to reset the card (reset failure path).
+ */
+ if (!card->pci_reset_ongoing) {
+ mwifiex_dbg(adapter, MSG, "performing cancel_work_sync()...\n");
+ cancel_work_sync(&card->work);
+ mwifiex_dbg(adapter, MSG, "cancel_work_sync() done\n");
+ } else {
+ mwifiex_dbg(adapter, MSG,
+ "skipped cancel_work_sync() because we're in card reset failure path\n");
+ }
ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
if (fw_status == FIRMWARE_READY_PCIE) {