diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h | 96 |
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__ */ |