summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h96
1 files changed, 84 insertions, 12 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
index 1ca82f3e4ebf..34eca1a568ea 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2021, 2024 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015 Intel Deutschland GmbH
*/
@@ -45,6 +45,55 @@ struct iwl_cfg;
*/
/**
+ * 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
+ * @IWL_ERR_TYPE_CMD_QUEUE_FULL: command queue was full
+ */
+enum iwl_fw_error_type {
+ IWL_ERR_TYPE_IRQ,
+ IWL_ERR_TYPE_NMI_FORCED,
+ IWL_ERR_TYPE_RESET_HS_TIMEOUT,
+ IWL_ERR_TYPE_CMD_QUEUE_FULL,
+};
+
+/**
+ * enum iwl_fw_error_context - error dump context
+ * @IWL_ERR_CONTEXT_WORKER: regular from worker context,
+ * opmode must acquire locks and must also check
+ * for @IWL_ERR_CONTEXT_ABORT after acquiring locks
+ * @IWL_ERR_CONTEXT_FROM_OPMODE: context is in a call
+ * originating from the opmode, e.g. while resetting
+ * or stopping the device, so opmode must not acquire
+ * any locks
+ * @IWL_ERR_CONTEXT_ABORT: after lock acquisition, indicates
+ * that the dump already happened via another callback
+ * (currently only while stopping the device) via the
+ * @IWL_ERR_CONTEXT_FROM_OPMODE context, and this call
+ * must be aborted
+ */
+enum iwl_fw_error_context {
+ IWL_ERR_CONTEXT_WORKER,
+ IWL_ERR_CONTEXT_FROM_OPMODE,
+ IWL_ERR_CONTEXT_ABORT,
+};
+
+/**
+ * struct iwl_fw_error_dump_mode - error dump mode for callback
+ * @type: The reason for the dump, per &enum iwl_fw_error_type.
+ * @context: The context for the dump, may also indicate this
+ * call needs to be skipped. This MUST be checked before
+ * and after acquiring any locks in the op-mode!
+ */
+struct iwl_fw_error_dump_mode {
+ enum iwl_fw_error_type type;
+ enum iwl_fw_error_context context;
+};
+
+/**
* struct iwl_op_mode_ops - op_mode specific operations
*
* The op_mode exports its ops so that external components can start it and
@@ -77,14 +126,19 @@ struct iwl_cfg;
* reclaimed by the op_mode. This can happen when the driver is freed and
* 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.
- * @cmd_queue_full: Called when the command queue gets full. Must be atomic and
- * called with BH disabled.
+ * @nic_error: error notification. Must be atomic, the op mode should handle
+ * the error (e.g. abort notification waiters) and print the error if
+ * applicable
+ * @dump_error: NIC error dump collection (can sleep, synchronous)
+ * @sw_reset: (maybe) initiate a software reset, return %true if started
* @nic_config: configure NIC, called before firmware is started.
* May sleep
* @wimax_active: invoked when WiMax becomes active. May sleep
* @time_point: called when transport layer wants to collect debug data
+ * @device_powered_off: called upon resume from hibernation but not only.
+ * Op_mode needs to reset its internal state because the device did not
+ * survive the system state transition. The firmware is no longer running,
+ * etc...
*/
struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans,
@@ -100,13 +154,18 @@ 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 (*cmd_queue_full)(struct iwl_op_mode *op_mode);
+ void (*nic_error)(struct iwl_op_mode *op_mode,
+ enum iwl_fw_error_type type);
+ void (*dump_error)(struct iwl_op_mode *op_mode,
+ struct iwl_fw_error_dump_mode *mode);
+ bool (*sw_reset)(struct iwl_op_mode *op_mode,
+ enum iwl_fw_error_type type);
void (*nic_config)(struct iwl_op_mode *op_mode);
void (*wimax_active)(struct iwl_op_mode *op_mode);
void (*time_point)(struct iwl_op_mode *op_mode,
enum iwl_fw_ini_time_point tp_id,
union iwl_dbg_tlv_tp_data *tp_data);
+ void (*device_powered_off)(struct iwl_op_mode *op_mode);
};
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
@@ -172,20 +231,26 @@ 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)
+static inline void iwl_op_mode_dump_error(struct iwl_op_mode *op_mode,
+ struct iwl_fw_error_dump_mode *mode)
{
- op_mode->ops->cmd_queue_full(op_mode);
+ might_sleep();
+
+ if (op_mode->ops->dump_error)
+ op_mode->ops->dump_error(op_mode, mode);
}
static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode)
{
might_sleep();
- op_mode->ops->nic_config(op_mode);
+ if (op_mode->ops->nic_config)
+ op_mode->ops->nic_config(op_mode);
}
static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
@@ -203,4 +268,11 @@ static inline void iwl_op_mode_time_point(struct iwl_op_mode *op_mode,
op_mode->ops->time_point(op_mode, tp_id, tp_data);
}
+static inline void iwl_op_mode_device_powered_off(struct iwl_op_mode *op_mode)
+{
+ if (!op_mode || !op_mode->ops || !op_mode->ops->device_powered_off)
+ return;
+ op_mode->ops->device_powered_off(op_mode);
+}
+
#endif /* __iwl_op_mode_h__ */