iwlwifi: trans: Clear persistence bit when starting the FW
authorShahar S Matityahu <shahar.s.matityahu@intel.com>
Wed, 4 Jul 2018 12:31:36 +0000 (15:31 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Sun, 11 Nov 2018 09:06:15 +0000 (11:06 +0200)
In D3 suspend flow in 9260 gen2 HW, the NIC receives two PERST signals.
The first PERST is expected and indicates the device on coming resume flow.
The second PERST causes FW restart FW restart.
In order to avoid this issue, the FW set the persistence bit on.
Once this bit is set, the FW ignores reset attempts.
The problem is when the FW gets assert during D3 and then the persistence
bit is set and causes the FW to ignore reset.
To handle this issue, the FW opens the preg bit which allows access
to the persistence bit, so that the driver clear the persistence bit
and reset the NIC.

The flow is as follows:
the driver checks if the persistence bit is set.
If the bit is set, the driver checks if he can clear the bit.
If the driver can not clear the bit then there is no point to continue
configuring the NIC since it will fail.

The fix was added is in start HW flow instead of the resume flow since in
general, if the persistence bit is set, the driver can not start the FW.
So it is good to check it when we start configuring the NIC.

The driver does not need to close the preg bit since the FW close it
during the start flow.

Signed-off-by: Shahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index 0f51c7bea8d0b96d625453aa9e4aab2c4aaa5b3f..2084c63dc670a89537a2a6dc6a6ab69ff73d0c0d 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * Copyright(c) 2016        Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * Copyright(c) 2016        Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -394,6 +396,7 @@ enum aux_misc_master1_en {
 #define AUX_MISC_MASTER1_SMPHR_STATUS  0xA20800
 #define RSA_ENABLE                     0xA24B08
 #define PREG_AUX_BUS_WPROT_0           0xA04CC0
+#define PREG_PRPH_WPROT_0              0xA04CE0
 #define SB_CPU_1_STATUS                        0xA01E30
 #define SB_CPU_2_STATUS                        0xA01E34
 #define UMAG_SB_CPU_1_STATUS           0xA038C0
@@ -420,4 +423,8 @@ enum {
 #define UREG_CHICK             (0xA05C00)
 #define UREG_CHICK_MSI_ENABLE  BIT(24)
 #define UREG_CHICK_MSIX_ENABLE BIT(25)
+
+#define HPM_DEBUG                      0xA03440
+#define PERSISTENCE_BIT                        BIT(12)
+#define PREG_WFPM_ACCESS               BIT(12)
 #endif                         /* __iwl_prph_h__ */
index 5bafb3f46eb8ace3c5668f64133f7bb83a2630e3..890b51b223a1897fcfc09fe777dcbfc1fe4ee3cc 100644 (file)
@@ -1729,6 +1729,7 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
 static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 hpm;
        int err;
 
        lockdep_assert_held(&trans_pcie->mutex);
@@ -1739,6 +1740,17 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
                return err;
        }
 
+       hpm = iwl_trans_read_prph(trans, HPM_DEBUG);
+       if (hpm != 0xa5a5a5a0 && (hpm & PERSISTENCE_BIT)) {
+               if (iwl_trans_read_prph(trans, PREG_PRPH_WPROT_0) &
+                   PREG_WFPM_ACCESS) {
+                       IWL_ERR(trans,
+                               "Error, can not clear persistence bit\n");
+                       return -EPERM;
+               }
+               iwl_trans_write_prph(trans, HPM_DEBUG, hpm & ~PERSISTENCE_BIT);
+       }
+
        iwl_trans_pcie_sw_reset(trans);
 
        err = iwl_pcie_apm_init(trans);