]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iwlwifi: fix RF-Kill interrupt while FW load for gen2 devices
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 20 May 2019 12:18:24 +0000 (15:18 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Jul 2019 07:12:57 +0000 (09:12 +0200)
commit ed3e4c6d3cd8f093a3636cb05492429fe2af228d upstream.

Newest devices have a new firmware load mechanism. This
mechanism is called the context info. It means that the
driver doesn't need to load the sections of the firmware.
The driver rather prepares a place in DRAM, with pointers
to the relevant sections of the firmware, and the firmware
loads itself.
At the end of the process, the firmware sends the ALIVE
interrupt. This is different from the previous scheme in
which the driver expected the FH_TX interrupt after each
section being transferred over the DMA.

In order to support this new flow, we enabled all the
interrupts. This broke the assumption that we have in the
code that the RF-Kill interrupt can't interrupt the firmware
load flow.

Change the context info flow to enable only the ALIVE
interrupt, and re-enable all the other interrupts only
after the firmware is alive. Then, we won't see the RF-Kill
interrupt until then. Getting the RF-Kill interrupt while
loading the firmware made us kill the firmware while it is
loading and we ended up dumping garbage instead of the firmware
state.

Re-enable the ALIVE | RX interrupts from the ISR when we
get the ALIVE interrupt to be able to get the RX interrupt
that comes immediately afterwards for the ALIVE
notification. This is needed for non MSI-X only.

Cc: stable@vger.kernel.org
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c

index 1e36459948db02916ddc4abb796dd779a191b9f9..504c535309d59815e4100d181057dad1a6972654 100644 (file)
@@ -168,7 +168,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
 
        memcpy(iml_img, trans->iml, trans->iml_len);
 
-       iwl_enable_interrupts(trans);
+       iwl_enable_fw_load_int_ctx_info(trans);
 
        /* kick FW self load */
        iwl_write64(trans, CSR_CTXT_INFO_ADDR,
index 9274e317cc777b041ef8553445e15fcc6165c6b9..eeb349134056c645fd291fb0118b1ea9fefb5a9d 100644 (file)
@@ -222,7 +222,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
 
        trans_pcie->ctxt_info = ctxt_info;
 
-       iwl_enable_interrupts(trans);
+       iwl_enable_fw_load_int_ctx_info(trans);
 
        /* Configure debug, if exists */
        if (iwl_pcie_dbg_on(trans))
index 2afce5c4132253c6bdf3854b0b6fdd43513e5e02..98128024b95ea41c84f4f82b6e538e69972837f8 100644 (file)
@@ -894,6 +894,33 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
        }
 }
 
+static inline void iwl_enable_fw_load_int_ctx_info(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       IWL_DEBUG_ISR(trans, "Enabling ALIVE interrupt only\n");
+
+       if (!trans_pcie->msix_enabled) {
+               /*
+                * When we'll receive the ALIVE interrupt, the ISR will call
+                * iwl_enable_fw_load_int_ctx_info again to set the ALIVE
+                * interrupt (which is not really needed anymore) but also the
+                * RX interrupt which will allow us to receive the ALIVE
+                * notification (which is Rx) and continue the flow.
+                */
+               trans_pcie->inta_mask =  CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX;
+               iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+       } else {
+               iwl_enable_hw_int_msk_msix(trans,
+                                          MSIX_HW_INT_CAUSES_REG_ALIVE);
+               /*
+                * Leave all the FH causes enabled to get the ALIVE
+                * notification.
+                */
+               iwl_enable_fh_int_msk_msix(trans, trans_pcie->fh_init_mask);
+       }
+}
+
 static inline u16 iwl_pcie_get_cmd_index(const struct iwl_txq *q, u32 index)
 {
        return index & (q->n_window - 1);
index 82d31ea4ba0d122614847f63561f627a76e8ac2a..8c124debf53a268a399aa9ffde0250e5ecb25db2 100644 (file)
@@ -1850,6 +1850,8 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                         */
                        iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
                }
+
+               handled |= CSR_INT_BIT_ALIVE;
        }
 
        /* Safely ignore these bits for debug checks below */
@@ -1968,6 +1970,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
        /* Re-enable RF_KILL if it occurred */
        else if (handled & CSR_INT_BIT_RF_KILL)
                iwl_enable_rfkill_int(trans);
+       /* Re-enable the ALIVE / Rx interrupt if it occurred */
+       else if (handled & (CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX))
+               iwl_enable_fw_load_int_ctx_info(trans);
        spin_unlock(&trans_pcie->irq_lock);
 
 out:
index 9c203ca75de9069e9ce4a769d18b3af402ab7076..8e0b40c4f4a4675a02220a5c96ec93de8762c30b 100644 (file)
@@ -272,6 +272,15 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
         * paging memory cannot be freed included since FW will still use it
         */
        iwl_pcie_ctxt_info_free(trans);
+
+       /*
+        * Re-enable all the interrupts, including the RF-Kill one, now that
+        * the firmware is alive.
+        */
+       iwl_enable_interrupts(trans);
+       mutex_lock(&trans_pcie->mutex);
+       iwl_pcie_check_hw_rf_kill(trans);
+       mutex_unlock(&trans_pcie->mutex);
 }
 
 int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,