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:14:22 +0000 (09:14 +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 2146fda8da2fdbdece661ceb3e177ab7c5c2b83e..64d976d872b84ab50de574703d60b081a58ad8ca 100644 (file)
@@ -164,7 +164,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 b2cd7ef5fc3a9ba3b37351745d6fdedfda985cf9..6f25fd1bbd8f40fb30181613715e09b826cd530f 100644 (file)
@@ -206,7 +206,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 (trans->dbg_dest_tlv)
index b63d44b7cd7c7be1e6a0a3fe0081edc5ea4820b7..00f9566bcc2136ab588beb05fada23eeea2b60f1 100644 (file)
@@ -896,6 +896,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 747ca8b92cdcf7534cc099285e0a683b81244c5b..1d144985ea589d7a285c04279a70e5c09b570647 100644 (file)
@@ -1796,6 +1796,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 */
@@ -1914,6 +1916,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 2bc67219ed3efadd09597a28fe18e39ad5f1d736..31e72e1ff1e267ea5a57780b5b503e94d9b17cdd 100644 (file)
@@ -289,6 +289,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,