]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.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)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 14 Aug 2019 09:18:49 +0000 (11:18 +0200)
BugLink: https://bugs.launchpad.net/bugs/1839036
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>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
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 5ef216f3a60b98255b55ac034965b974b9bf8ada..beb5b63bbe1bbd7383fff4d478cc413c644c26a8 100644 (file)
@@ -256,7 +256,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 c2592da0f0601bdce4cf957dd5a2bb57522bce73..8783d853d40aa46f45fb80ecf1a7f86b07fc46d2 100644 (file)
@@ -658,6 +658,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 void iwl_pcie_sw_reset(struct iwl_trans *trans)
 {
        /* Reset entire device - do controller reset (results in SHRD_HW_RST) */
index 12e32312709a537cb1d3763ce8be1f6f597012a2..6523c69c79c08a45a5a4b340811225285a03d2c9 100644 (file)
@@ -1692,6 +1692,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 */
@@ -1810,6 +1812,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 ac05fd1e74c4c80308caf5b630ffd29a6968f888..f374b213623cc52388ab1d7c323d34faa05e0798 100644 (file)
@@ -280,6 +280,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,