wifi: iwlwifi: pcie: add support for the reset handshake in MSI
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 24 Apr 2025 12:38:18 +0000 (15:38 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 25 Apr 2025 09:26:32 +0000 (11:26 +0200)
Add the proper case in the MSI interrupt handler and read the non-MSIx
interrupt cause register in case of timeout.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250424153620.758cdfbb78dc.Ia359071e6148218c26f18e783a8130c681d77df7@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c

index be9e464..f259747 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2018-2024 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2025 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2016 Intel Deutschland GmbH
  */
 #define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
 #define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
 #define CSR_INT_BIT_SW_RX        (1 << 3)  /* Rx, command responses */
+#define CSR_INT_BIT_RESET_DONE   (1 << 2)  /* reset handshake with firmware is done */
 #define CSR_INT_BIT_WAKEUP       (1 << 1)  /* NIC controller waking up (pwr mgmt) */
 #define CSR_INT_BIT_ALIVE        (1 << 0)  /* uCode interrupts once it initializes */
 
-#define CSR_INI_SET_MASK       (CSR_INT_BIT_FH_RX   | \
-                                CSR_INT_BIT_HW_ERR  | \
-                                CSR_INT_BIT_FH_TX   | \
-                                CSR_INT_BIT_SW_ERR  | \
-                                CSR_INT_BIT_RF_KILL | \
-                                CSR_INT_BIT_SW_RX   | \
-                                CSR_INT_BIT_WAKEUP  | \
-                                CSR_INT_BIT_ALIVE   | \
+#define CSR_INI_SET_MASK       (CSR_INT_BIT_FH_RX      | \
+                                CSR_INT_BIT_HW_ERR     | \
+                                CSR_INT_BIT_FH_TX      | \
+                                CSR_INT_BIT_SW_ERR     | \
+                                CSR_INT_BIT_RF_KILL    | \
+                                CSR_INT_BIT_SW_RX      | \
+                                CSR_INT_BIT_WAKEUP     | \
+                                CSR_INT_BIT_RESET_DONE | \
+                                CSR_INT_BIT_ALIVE      | \
                                 CSR_INT_BIT_RX_PERIODIC)
 
 /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
index 4a4f8de..337324e 100644 (file)
@@ -1947,6 +1947,13 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                handled |= CSR_INT_BIT_ALIVE;
        }
 
+       if (inta & CSR_INT_BIT_RESET_DONE) {
+               IWL_DEBUG_ISR(trans, "Reset flow completed\n");
+               trans_pcie->fw_reset_state = FW_RESET_OK;
+               handled |= CSR_INT_BIT_RESET_DONE;
+               wake_up(&trans_pcie->fw_reset_waitq);
+       }
+
        /* Safely ignore these bits for debug checks below */
        inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
 
@@ -1968,7 +1975,12 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                IWL_ERR(trans, "Microcode SW error detected. "
                        " Restarting 0x%X.\n", inta);
                isr_stats->sw++;
-               iwl_pcie_irq_handle_error(trans);
+               if (trans_pcie->fw_reset_state == FW_RESET_REQUESTED) {
+                       trans_pcie->fw_reset_state = FW_RESET_ERROR;
+                       wake_up(&trans_pcie->fw_reset_waitq);
+               } else {
+                       iwl_pcie_irq_handle_error(trans);
+               }
                handled |= CSR_INT_BIT_SW_ERR;
        }
 
index cfd9420..08409e2 100644 (file)
@@ -117,13 +117,23 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans)
                                 trans_pcie->fw_reset_state != FW_RESET_REQUESTED,
                                 FW_RESET_TIMEOUT);
        if (!ret || trans_pcie->fw_reset_state == FW_RESET_ERROR) {
-               u32 inta_hw = iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD);
+               bool reset_done;
+               u32 inta_hw;
+
+               if (trans_pcie->msix_enabled) {
+                       inta_hw = iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD);
+                       reset_done =
+                               inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE;
+               } else {
+                       inta_hw = iwl_read32(trans, CSR_INT_MASK);
+                       reset_done = inta_hw & CSR_INT_BIT_RESET_DONE;
+               }
 
                IWL_ERR(trans,
-                       "timeout waiting for FW reset ACK (inta_hw=0x%x)\n",
-                       inta_hw);
+                       "timeout waiting for FW reset ACK (inta_hw=0x%x, reset_done %d)\n",
+                       inta_hw, reset_done);
 
-               if (!(inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE)) {
+               if (!reset_done) {
                        struct iwl_fw_error_dump_mode mode = {
                                .type = IWL_ERR_TYPE_RESET_HS_TIMEOUT,
                                .context = IWL_ERR_CONTEXT_FROM_OPMODE,