iwlwifi: fix access to prph when transport is stopped
authorSara Sharon <sara.sharon@intel.com>
Mon, 20 Nov 2017 11:25:05 +0000 (13:25 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Sat, 25 Nov 2017 15:12:56 +0000 (17:12 +0200)
When getting HW rfkill we get stop_device being called from
two paths.
One path is the IRQ calling stop device, and updating op
mode and stack.
As a result, cfg80211 is running rfkill sync work that shuts
down all devices (second path).
In the second path, we eventually get to iwl_mvm_stop_device
which calls iwl_fw_dump_conf_clear->iwl_fw_dbg_stop_recording,
that access periphery registers.
The device may be stopped at this point from the first path,
which will result with a failure to access those registers.
Simply checking for the trans status is insufficient, since
the race will still exist, only minimized.
Instead, move the stop from iwl_fw_dump_conf_clear (which is
getting called only from stop path) to the transport stop
device function, where the access is always safe.
This has the added value, of actually stopping dbgc before
stopping device even when the stop is initiated from the
transport.

Fixes: 1efc3843a4ee ("iwlwifi: stop dbgc recording before stopping DMA")
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/dbg.h
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index 9c889a32fe2424941d9bceb89b8cd1f593e4f3ab..223fb77a3aa9d64456244dd4c5156b8885cec6fd 100644 (file)
@@ -209,8 +209,6 @@ static inline void iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt)
 
 static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
 {
-       iwl_fw_dbg_stop_recording(fwrt);
-
        fwrt->dump.conf = FW_DBG_INVALID;
 }
 
index c59f4581e97271cc35d07bed98876d300384fa9c..ac05fd1e74c4c80308caf5b630ffd29a6968f888 100644 (file)
@@ -49,6 +49,7 @@
  *
  *****************************************************************************/
 #include "iwl-trans.h"
+#include "iwl-prph.h"
 #include "iwl-context-info.h"
 #include "internal.h"
 
@@ -156,6 +157,11 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
 
        trans_pcie->is_down = true;
 
+       /* Stop dbgc before stopping device */
+       iwl_write_prph(trans, DBGC_IN_SAMPLE, 0);
+       udelay(100);
+       iwl_write_prph(trans, DBGC_OUT_CTRL, 0);
+
        /* tell the device to stop sending interrupts */
        iwl_disable_interrupts(trans);
 
index 3dee95e6a4757b0be6136775876c6123c6afec39..4541c86881d604e16093eef51cb7ba48afb3685b 100644 (file)
@@ -1227,6 +1227,15 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 
        trans_pcie->is_down = true;
 
+       /* Stop dbgc before stopping device */
+       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+               iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       } else {
+               iwl_write_prph(trans, DBGC_IN_SAMPLE, 0);
+               udelay(100);
+               iwl_write_prph(trans, DBGC_OUT_CTRL, 0);
+       }
+
        /* tell the device to stop sending interrupts */
        iwl_disable_interrupts(trans);