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 | 222 |
1 files changed, 133 insertions, 89 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index 3008a5246be8..df6341dfc4a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -1,71 +1,15 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless <linuxwifi@intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2005-2014, 2018-2021, 2024-2025 Intel Corporation + * Copyright (C) 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2015 Intel Deutschland GmbH + */ #ifndef __iwl_op_mode_h__ #define __iwl_op_mode_h__ #include <linux/netdevice.h> #include <linux/debugfs.h> +#include "iwl-dbg-tlv.h" struct iwl_op_mode; struct iwl_trans; @@ -73,7 +17,7 @@ struct sk_buff; struct iwl_device_cmd; struct iwl_rx_cmd_buffer; struct iwl_fw; -struct iwl_cfg; +struct iwl_rf_cfg; /** * DOC: Operational mode - what is it ? @@ -101,6 +45,63 @@ 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 + * @IWL_ERR_TYPE_TOP_RESET_BY_BT: TOP reset initiated by BT + * @IWL_ERR_TYPE_TOP_FATAL_ERROR: TOP fatal error + * @IWL_ERR_TYPE_TOP_RESET_FAILED: TOP reset failed + * @IWL_ERR_TYPE_DEBUGFS: error/reset indication from debugfs + */ +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, + IWL_ERR_TYPE_TOP_RESET_BY_BT, + IWL_ERR_TYPE_TOP_FATAL_ERROR, + IWL_ERR_TYPE_TOP_RESET_FAILED, + IWL_ERR_TYPE_DEBUGFS, +}; + +/** + * 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 @@ -120,30 +121,38 @@ struct iwl_cfg; * received on the RSS queue(s). The queue parameter indicates which of the * RSS queues received this frame; it will always be non-zero. * This method must not sleep. - * @async_cb: called when an ASYNC command with CMD_WANT_ASYNC_CALLBACK set - * completes. Must be atomic. * @queue_full: notifies that a HW queue is full. * Must be atomic and called with BH disabled. * @queue_not_full: notifies that a HW queue is not full any more. * Must be atomic and called with BH disabled. - * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that + * @hw_rf_kill: notifies of a change in the HW rf kill switch. True means that * the radio is killed. Return %true if the device should be stopped by * the transport immediately after the call. May sleep. + * Note that this must not return %true for newer devices using gen2 PCIe + * transport. * @free_skb: allows the transport layer to free skbs that haven't been * 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. - * @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... + * @dump: Op_mode needs to collect the firmware dump upon this handler + * being called. */ struct iwl_op_mode_ops { struct iwl_op_mode *(*start)(struct iwl_trans *trans, - const struct iwl_cfg *cfg, + const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir); void (*stop)(struct iwl_op_mode *op_mode); @@ -151,16 +160,23 @@ struct iwl_op_mode_ops { struct iwl_rx_cmd_buffer *rxb); void (*rx_rss)(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, unsigned int queue); - void (*async_cb)(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd); void (*queue_full)(struct iwl_op_mode *op_mode, int queue); 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); - 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); + void (*dump)(struct iwl_op_mode *op_mode); }; int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); @@ -169,13 +185,14 @@ void iwl_opmode_deregister(const char *name); /** * struct iwl_op_mode - operational mode * @ops: pointer to its own ops + * @op_mode_specific: per-opmode data * * This holds an implementation of the mac80211 / fw API. */ struct iwl_op_mode { const struct iwl_op_mode_ops *ops; - char op_mode_specific[0] __aligned(sizeof(void *)); + char op_mode_specific[] __aligned(sizeof(void *)); }; static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) @@ -199,13 +216,6 @@ static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode, op_mode->ops->rx_rss(op_mode, napi, rxb, queue); } -static inline void iwl_op_mode_async_cb(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd) -{ - if (op_mode->ops->async_cb) - op_mode->ops->async_cb(op_mode, cmd); -} - static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, int queue) { @@ -228,23 +238,34 @@ iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, bool state) static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) { + if (WARN_ON_ONCE(!op_mode)) + return; op_mode->ops->free_skb(op_mode, skb); } -static inline void iwl_op_mode_nic_error(struct iwl_op_mode *op_mode) +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); + 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 (WARN_ON(mode->type == IWL_ERR_TYPE_TOP_RESET_BY_BT)) + return; + + 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) @@ -253,4 +274,27 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) op_mode->ops->wimax_active(op_mode); } +static inline void iwl_op_mode_time_point(struct iwl_op_mode *op_mode, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data) +{ + if (!op_mode || !op_mode->ops || !op_mode->ops->time_point) + return; + 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); +} + +static inline void iwl_op_mode_dump(struct iwl_op_mode *op_mode) +{ + if (!op_mode || !op_mode->ops || !op_mode->ops->dump) + return; + op_mode->ops->dump(op_mode); +} + #endif /* __iwl_op_mode_h__ */ |
