Commit 8954e1eb authored by Shahar S Matityahu's avatar Shahar S Matityahu Committed by Luca Coelho

iwlwifi: trans: Clear persistence bit when starting the FW

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: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent f3f240f9
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH * Copyright(c) 2016 Intel Deutschland GmbH
* Copyright (C) 2018 Intel Corporation
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH * Copyright(c) 2016 Intel Deutschland GmbH
* Copyright (C) 2018 Intel Corporation
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -394,6 +396,7 @@ enum aux_misc_master1_en { ...@@ -394,6 +396,7 @@ enum aux_misc_master1_en {
#define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800
#define RSA_ENABLE 0xA24B08 #define RSA_ENABLE 0xA24B08
#define PREG_AUX_BUS_WPROT_0 0xA04CC0 #define PREG_AUX_BUS_WPROT_0 0xA04CC0
#define PREG_PRPH_WPROT_0 0xA04CE0
#define SB_CPU_1_STATUS 0xA01E30 #define SB_CPU_1_STATUS 0xA01E30
#define SB_CPU_2_STATUS 0xA01E34 #define SB_CPU_2_STATUS 0xA01E34
#define UMAG_SB_CPU_1_STATUS 0xA038C0 #define UMAG_SB_CPU_1_STATUS 0xA038C0
...@@ -420,4 +423,8 @@ enum { ...@@ -420,4 +423,8 @@ enum {
#define UREG_CHICK (0xA05C00) #define UREG_CHICK (0xA05C00)
#define UREG_CHICK_MSI_ENABLE BIT(24) #define UREG_CHICK_MSI_ENABLE BIT(24)
#define UREG_CHICK_MSIX_ENABLE BIT(25) #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__ */ #endif /* __iwl_prph_h__ */
...@@ -1729,6 +1729,7 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, ...@@ -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) 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); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 hpm;
int err; int err;
lockdep_assert_held(&trans_pcie->mutex); lockdep_assert_held(&trans_pcie->mutex);
...@@ -1739,6 +1740,17 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) ...@@ -1739,6 +1740,17 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
return err; 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); iwl_trans_pcie_sw_reset(trans);
err = iwl_pcie_apm_init(trans); err = iwl_pcie_apm_init(trans);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment