]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: differentiate NIC error types
authorJohannes Berg <johannes.berg@intel.com>
Fri, 27 Dec 2024 08:00:56 +0000 (10:00 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 13 Jan 2025 13:01:51 +0000 (14:01 +0100)
Instead of differentiating only sync/async, differentiate
the type of error, and document that only reset handshake
timeout (IWL_ERR_TYPE_RESET_HS_TIMEOUT) needs sync handling.

The special sync handling is somewhat temporary, the idea
is to later split the nic_error() method into error dump,
synchronizing the dump, and SW reset methods, and the type
is mostly in order to unify command queue full handling
into that new architecture as well.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20241227095718.aed9c9e4fac0.I2288042bec4728a75b61cb7f6ded5214bfa3ce85@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/dvm/main.c
drivers/net/wireless/intel/iwlwifi/iwl-io.c
drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c

index 769b75c3fa5b911827e51f8f0d2668a34d5c4de9..2c4363662efd3438a46722036a36f4a022941ea5 100644 (file)
@@ -1942,7 +1942,8 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
        }
 }
 
-static void iwl_nic_error(struct iwl_op_mode *op_mode, bool sync)
+static void iwl_nic_error(struct iwl_op_mode *op_mode,
+                         enum iwl_fw_error_type type)
 {
        struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
index 060becfd64f364716c9dbbeb7f6a6687ae800ed1..0653ca8b974a85d6b31c513f2f3b7f9f7e454893 100644 (file)
@@ -526,5 +526,5 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr,
        if (interrupts_enabled)
                iwl_trans_interrupts(trans, true);
 
-       iwl_trans_fw_error(trans, false);
+       iwl_trans_fw_error(trans, IWL_ERR_TYPE_NMI_FORCED);
 }
index 8ef5ed2db051772ff835bce70de403e25f33b897..8febc949b610475f54319e7788eb1deecdc36c61 100644 (file)
@@ -44,6 +44,20 @@ struct iwl_cfg;
  *     5) The driver layer stops the op_mode
  */
 
+/**
+ * enum iwl_fw_error_type - FW error types/sources
+ * @IWL_ERR_TYPE_IRQ: "normal" FW error through an IRQ
+ * @IWL_ERR_TYPE_NMI_FORCED: NMI was forced by driver
+ * @IWL_ERR_TYPE_RESET_HS_TIMEOUT: reset handshake timed out,
+ *     any debug collection must happen synchronously as
+ *     the device will be shut down
+ */
+enum iwl_fw_error_type {
+       IWL_ERR_TYPE_IRQ,
+       IWL_ERR_TYPE_NMI_FORCED,
+       IWL_ERR_TYPE_RESET_HS_TIMEOUT,
+};
+
 /**
  * struct iwl_op_mode_ops - op_mode specific operations
  *
@@ -78,7 +92,7 @@ struct iwl_cfg;
  *     there are Tx packets pending in the transport layer.
  *     Must be atomic
  * @nic_error: error notification. Must be atomic and must be called with BH
- *     disabled, unless the sync parameter is true.
+ *     disabled, unless the type is IWL_ERR_TYPE_RESET_HS_TIMEOUT
  * @cmd_queue_full: Called when the command queue gets full. Must be atomic and
  *     called with BH disabled.
  * @nic_config: configure NIC, called before firmware is started.
@@ -104,7 +118,8 @@ struct iwl_op_mode_ops {
        void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue);
        bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
        void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
-       void (*nic_error)(struct iwl_op_mode *op_mode, bool sync);
+       void (*nic_error)(struct iwl_op_mode *op_mode,
+                         enum iwl_fw_error_type type);
        void (*cmd_queue_full)(struct iwl_op_mode *op_mode);
        void (*nic_config)(struct iwl_op_mode *op_mode);
        void (*wimax_active)(struct iwl_op_mode *op_mode);
@@ -177,9 +192,10 @@ static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
        op_mode->ops->free_skb(op_mode, skb);
 }
 
-static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode, bool sync)
+static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode,
+                                        enum iwl_fw_error_type type)
 {
-       op_mode->ops->nic_error(op_mode, sync);
+       op_mode->ops->nic_error(op_mode, type);
 }
 
 static inline void iwl_op_mode_cmd_queue_full(struct iwl_op_mode *op_mode)
index c70da7281551a2b8e3e1344ed215ed516123f1e0..56b551fd215622ec9029bd44495d5a6cf18ed321 100644 (file)
@@ -1120,7 +1120,8 @@ bool _iwl_trans_grab_nic_access(struct iwl_trans *trans);
 void __releases(nic_access)
 iwl_trans_release_nic_access(struct iwl_trans *trans);
 
-static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync)
+static inline void iwl_trans_fw_error(struct iwl_trans *trans,
+                                     enum iwl_fw_error_type type)
 {
        if (WARN_ON_ONCE(!trans->op_mode))
                return;
@@ -1128,7 +1129,7 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync)
        /* prevent double restarts due to the same erroneous FW */
        if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status)) {
                trans->state = IWL_TRANS_NO_FW;
-               iwl_op_mode_nic_error(trans->op_mode, sync);
+               iwl_op_mode_nic_error(trans->op_mode, type);
        }
 }
 
index 0deaf6ed899481aa14cf1c82eb87f2e61fce90bc..e21199313278e3c389d6a4aece71b68361c57f78 100644 (file)
@@ -2108,7 +2108,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
        }
 }
 
-static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync)
+static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode,
+                             enum iwl_fw_error_type type)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
@@ -2117,13 +2118,9 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync)
                                &mvm->status))
                iwl_mvm_dump_nic_error_log(mvm);
 
-       if (sync) {
+       /* reset HS timeout is during shutdown, so collect right now */
+       if (type == IWL_ERR_TYPE_RESET_HS_TIMEOUT) {
                iwl_fw_error_collect(&mvm->fwrt, true);
-               /*
-                * Currently, the only case for sync=true is during
-                * shutdown, so just stop in this case. If/when that
-                * changes, we need to be a bit smarter here.
-                */
                return;
        }
 
index afb88eab8174b78fd06cc010b13e529a42855e52..02fef6baf2e3e122fc94bb45ee1c80f4b337eab5 100644 (file)
@@ -1702,7 +1702,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
 
        /* The STATUS_FW_ERROR bit is set in this function. This must happen
         * before we wake up the command caller, to ensure a proper cleanup. */
-       iwl_trans_fw_error(trans, false);
+       iwl_trans_fw_error(trans, IWL_ERR_TYPE_IRQ);
 
        clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
        wake_up(&trans->wait_command_queue);
index 8903a5692dfbbddc98be75af6959ab6560f272c4..469ef32a3e26d67ff1f508df38d456b0cc994d89 100644 (file)
@@ -124,7 +124,7 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans)
                        inta_hw);
 
                if (!(inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE))
-                       iwl_trans_fw_error(trans, true);
+                       iwl_trans_fw_error(trans, IWL_ERR_TYPE_RESET_HS_TIMEOUT);
        }
 
        trans_pcie->fw_reset_state = FW_RESET_IDLE;