]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
mwifiex: Add quirk to disable deep sleep with certain hardware revision
authorJonas Dreßler <verdre@v0yd.nl>
Wed, 3 Nov 2021 20:17:59 +0000 (21:17 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 26 Nov 2021 16:29:38 +0000 (18:29 +0200)
The 88W8897 PCIe+USB card in the hardware revision 20 apparently has a
hardware issue where the card wakes up from deep sleep randomly and very
often, somewhat depending on the card activity, maybe the hardware has a
floating wakeup pin or something. This was found by comparing two MS
Surface Book 2 devices, where one devices wifi card experienced spurious
wakeups, while the other one didn't.

Those continuous wakeups prevent the card from entering host sleep when
the computer suspends. And because the host won't answer to events from
the card anymore while it's suspended, the firmwares internal power
saving state machine seems to get confused and the card can't sleep
anymore at all after that.

Since we can't work around that hardware bug in the firmware, let's
get the hardware revision string from the firmware and match it with
known bad revisions. Then disable auto deep sleep for those revisions,
which makes sure we no longer get those spurious wakeups.

Signed-off-by: Jonas Dreßler <verdre@v0yd.nl>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20211103201800.13531-3-verdre@v0yd.nl
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c

index 19b996c6a2605af90416d979f599636ba9bac630..ace7371c477394b396994ceb4b02a1cc1c92f0df 100644 (file)
@@ -226,6 +226,23 @@ exit_rx_proc:
        return 0;
 }
 
+static void maybe_quirk_fw_disable_ds(struct mwifiex_adapter *adapter)
+{
+       struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+       struct mwifiex_ver_ext ver_ext;
+
+       if (test_and_set_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &adapter->work_flags))
+               return;
+
+       memset(&ver_ext, 0, sizeof(ver_ext));
+       ver_ext.version_str_sel = 1;
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
+                            HostCmd_ACT_GEN_GET, 0, &ver_ext, false)) {
+               mwifiex_dbg(priv->adapter, MSG,
+                           "Checking hardware revision failed.\n");
+       }
+}
+
 /*
  * The main process.
  *
@@ -356,6 +373,7 @@ process_start:
                        if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) {
                                adapter->hw_status = MWIFIEX_HW_STATUS_READY;
                                mwifiex_init_fw_complete(adapter);
+                               maybe_quirk_fw_disable_ds(adapter);
                        }
                }
 
index 65609ea2327e13af39acf990c2fae0ab7e7caf45..eabd0e0a9f56be3384fa9ed51d7932e0d6672a25 100644 (file)
@@ -524,6 +524,7 @@ enum mwifiex_adapter_work_flags {
        MWIFIEX_IS_SUSPENDED,
        MWIFIEX_IS_HS_CONFIGURED,
        MWIFIEX_IS_HS_ENABLING,
+       MWIFIEX_IS_REQUESTING_FW_VEREXT,
 };
 
 struct mwifiex_band_config {
index 20b69a37f9e1596b34e48ea7e76e6b483edb8e56..6c7b0b9bc4e9f59a6135158d51e75d83214f77e9 100644 (file)
@@ -708,6 +708,26 @@ static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
 {
        struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
 
+       if (test_and_clear_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &priv->adapter->work_flags)) {
+               if (strncmp(ver_ext->version_str, "ChipRev:20, BB:9b(10.00), RF:40(21)",
+                           MWIFIEX_VERSION_STR_LENGTH) == 0) {
+                       struct mwifiex_ds_auto_ds auto_ds = {
+                               .auto_ds = DEEP_SLEEP_OFF,
+                       };
+
+                       mwifiex_dbg(priv->adapter, MSG,
+                                   "Bad HW revision detected, disabling deep sleep\n");
+
+                       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+                                            DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, false)) {
+                               mwifiex_dbg(priv->adapter, MSG,
+                                           "Disabling deep sleep failed.\n");
+                       }
+               }
+
+               return 0;
+       }
+
        if (version_ext) {
                version_ext->version_str_sel = ver_ext->version_str_sel;
                memcpy(version_ext->version_str, ver_ext->version_str,