diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/iwl-trans.h')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/iwl-trans.h | 346 | 
1 files changed, 223 insertions, 123 deletions
| diff --git a/sys/contrib/dev/iwlwifi/iwl-trans.h b/sys/contrib/dev/iwlwifi/iwl-trans.h index 7430d1b37541..557e601c0500 100644 --- a/sys/contrib/dev/iwlwifi/iwl-trans.h +++ b/sys/contrib/dev/iwlwifi/iwl-trans.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2025 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -113,16 +113,12 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)   *	the response. The caller needs to call iwl_free_resp when done.   * @CMD_SEND_IN_RFKILL: Send the command even if the NIC is in RF-kill.   * @CMD_BLOCK_TXQS: Block TXQs while the comment is executing. - * @CMD_SEND_IN_D3: Allow the command to be sent in D3 mode, relevant to - *	SUSPEND and RESUME commands. We are in D3 mode when we set - *	trans->system_pm_mode to IWL_PLAT_PM_MODE_D3.   */  enum CMD_MODE {  	CMD_ASYNC		= BIT(0),  	CMD_WANT_SKB		= BIT(1),  	CMD_SEND_IN_RFKILL	= BIT(2),  	CMD_BLOCK_TXQS		= BIT(3), -	CMD_SEND_IN_D3          = BIT(4),  };  #define CMD_MODE_BITS 5 @@ -313,6 +309,14 @@ enum iwl_d3_status {   * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation   * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once,   *	e.g. for testing + * @STATUS_IN_SW_RESET: device is undergoing reset, cleared by opmode + *	via iwl_trans_finish_sw_reset() + * @STATUS_RESET_PENDING: reset worker was scheduled, but didn't dump + *	the firmware state yet + * @STATUS_TRANS_RESET_IN_PROGRESS: reset is still in progress, don't + *	attempt another reset yet + * @STATUS_SUSPENDED: device is suspended, don't send commands that + *	aren't marked accordingly   */  enum iwl_trans_status {  	STATUS_SYNC_HCMD_ACTIVE, @@ -324,6 +328,10 @@ enum iwl_trans_status {  	STATUS_FW_ERROR,  	STATUS_TRANS_DEAD,  	STATUS_SUPPRESS_CMD_ERROR_ONCE, +	STATUS_IN_SW_RESET, +	STATUS_RESET_PENDING, +	STATUS_TRANS_RESET_IN_PROGRESS, +	STATUS_SUSPENDED,  };  static inline int @@ -395,11 +403,11 @@ struct iwl_dump_sanitize_ops {  /**   * struct iwl_trans_config - transport configuration   * - * @op_mode: pointer to the upper layer. + * These values should be set before iwl_trans_op_mode_enter(). + *   * @cmd_queue: the index of the command queue.   *	Must be set before start_fw.   * @cmd_fifo: the fifo for host commands - * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue.   * @no_reclaim_cmds: Some devices erroneously don't set the   *	SEQ_RX_FRAME bit on some notifications, this is the   *	list of such notifications to filter. Max length is @@ -407,8 +415,6 @@ struct iwl_dump_sanitize_ops {   * @n_no_reclaim_cmds: # of commands in list   * @rx_buf_size: RX buffer size needed for A-MSDUs   *	if unset 4k will be the RX buffer size - * @bc_table_dword: set to true if the BC table expects the byte count to be - *	in DWORD (as opposed to bytes)   * @scd_set_active: should the transport configure the SCD for HCMD queue   * @command_groups: array of command groups, each member is an array of the   *	commands in the group; for debugging only @@ -419,18 +425,24 @@ struct iwl_dump_sanitize_ops {   * @queue_alloc_cmd_ver: queue allocation command version, set to 0   *	for using the older SCD_QUEUE_CFG, set to the version of   *	SCD_QUEUE_CONFIG_CMD otherwise. + * @wide_cmd_header: true when ucode supports wide command header format + * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before + *	starting the firmware, used for tracing + * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the + *	start of the 802.11 header in the @rx_mpdu_cmd + * @dsbr_urm_fw_dependent: switch to URM based on fw settings + * @dsbr_urm_permanent: switch to URM permanently + * @mbx_addr_0_step: step address data 0 + * @mbx_addr_1_step: step address data 1 + * @ext_32khz_clock_valid: if true, the external 32 KHz clock can be used   */  struct iwl_trans_config { -	struct iwl_op_mode *op_mode; -  	u8 cmd_queue;  	u8 cmd_fifo; -	unsigned int cmd_q_wdg_timeout; -	const u8 *no_reclaim_cmds; -	unsigned int n_no_reclaim_cmds; +	u8 n_no_reclaim_cmds; +	u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];  	enum iwl_amsdu_size rx_buf_size; -	bool bc_table_dword;  	bool scd_set_active;  	const struct iwl_hcmd_arr *command_groups;  	int command_groups_size; @@ -438,6 +450,16 @@ struct iwl_trans_config {  	u8 cb_data_offs;  	bool fw_reset_handshake;  	u8 queue_alloc_cmd_ver; + +	bool wide_cmd_header; +	u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; + +	u8 dsbr_urm_fw_dependent:1, +	   dsbr_urm_permanent:1, +	   ext_32khz_clock_valid:1; + +	u32 mbx_addr_0_step; +	u32 mbx_addr_1_step;  };  struct iwl_trans_dump_data { @@ -523,23 +545,6 @@ enum iwl_trans_state {   */  /** - * enum iwl_plat_pm_mode - platform power management mode - * - * This enumeration describes the device's platform power management - * behavior when in system-wide suspend (i.e WoWLAN). - * - * @IWL_PLAT_PM_MODE_DISABLED: power management is disabled for this - *	device.  In system-wide suspend mode, it means that the all - *	connections will be closed automatically by mac80211 before - *	the platform is suspended. - * @IWL_PLAT_PM_MODE_D3: the device goes into D3 mode (i.e. WoWLAN). - */ -enum iwl_plat_pm_mode { -	IWL_PLAT_PM_MODE_DISABLED, -	IWL_PLAT_PM_MODE_D3, -}; - -/**   * enum iwl_ini_cfg_state   * @IWL_INI_CFG_STATE_NOT_LOADED: no debug cfg was given   * @IWL_INI_CFG_STATE_LOADED: debug cfg was found and loaded @@ -643,8 +648,6 @@ struct iwl_pc_data {   * @n_dest_reg: num of reg_ops in %dbg_dest_tlv   * @rec_on: true iff there is a fw debug recording currently active   * @dest_tlv: points to the destination TLV for debug - * @conf_tlv: array of pointers to configuration TLVs for debug - * @trigger_tlv: array of pointers to triggers TLVs for debug   * @lmac_error_event_table: addrs of lmacs error tables   * @umac_error_event_table: addr of umac error table   * @tcm_error_event_table: address(es) of TCM error table(s) @@ -679,8 +682,6 @@ struct iwl_trans_debug {  	bool rec_on;  	const struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv; -	const struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX]; -	struct iwl_fw_dbg_trigger_tlv * const *trigger_tlv;  	u32 lmac_error_event_table[2];  	u32 umac_error_event_table; @@ -833,91 +834,90 @@ struct iwl_txq {  };  /** + * struct iwl_trans_info - transport info for outside use + * @name: the device name + * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. + *	0 indicates that frag SKBs (NETIF_F_SG) aren't supported. + * @hw_rev: the revision data of the HW + * @hw_rev_step: The mac step of the HW + * @hw_rf_id: the device RF ID + * @hw_cnv_id: the device CNV ID + * @hw_crf_id: the device CRF ID + * @hw_wfpm_id: the device wfpm ID + * @hw_id: the ID of the device / sub-device + *	Bits 0:15 represent the sub-device ID + *	Bits 16:31 represent the device ID. + * @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*), + *	only valid for discrete (not integrated) NICs + * @num_rxqs: number of RX queues allocated by the transport + */ +struct iwl_trans_info { +	const char *name; +	u32 max_skb_frags; +	u32 hw_rev; +	u32 hw_rev_step; +	u32 hw_rf_id; +	u32 hw_crf_id; +	u32 hw_cnv_id; +	u32 hw_wfpm_id; +	u32 hw_id; +	u8 pcie_link_speed; +	u8 num_rxqs; +}; + +/**   * struct iwl_trans - transport common data   *   * @csme_own: true if we couldn't get ownership on the device   * @op_mode: pointer to the op_mode - * @trans_cfg: the trans-specific configuration part + * @mac_cfg: the trans-specific configuration part   * @cfg: pointer to the configuration   * @drv: pointer to iwl_drv + * @conf: configuration set by the opmode before enter   * @state: current device state   * @status: a bit-mask of transport status flags   * @dev: pointer to struct device * that represents the device - * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. - *	0 indicates that frag SKBs (NETIF_F_SG) aren't supported. - * @hw_rf_id: a u32 with the device RF ID - * @hw_cnv_id: a u32 with the device CNV ID - * @hw_crf_id: a u32 with the device CRF ID - * @hw_wfpm_id: a u32 with the device wfpm ID - * @hw_id: a u32 with the ID of the device / sub-device. - *	Set during transport allocation. - * @hw_id_str: a string with info about HW ID. Set during transport allocation. - * @sku_id: the SKU identifier (for PNVM matching) + * @info: device information for use by other layers   * @pnvm_loaded: indicates PNVM was loaded - * @hw_rev: the revision data of the HW - * @hw_rev_step: The mac step of the HW   * @pm_support: set to true in start_hw if link pm is supported   * @ltr_enabled: set to true if the LTR is enabled   * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed   * @reduce_power_loaded: indicates reduced power section was loaded   * @failed_to_load_reduce_power_image: set to true if pnvm loading failed - * @command_groups: pointer to command group name list array - * @command_groups_size: array size of @command_groups - * @wide_cmd_header: true when ucode supports wide command header format - * @wait_command_queue: wait queue for sync commands - * @num_rx_queues: number of RX queues allocated by the transport; - *	the transport must set this before calling iwl_drv_start() - * @iml_len: the length of the image loader - * @iml: a pointer to the image loader itself   * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.   *	The user should use iwl_trans_{alloc,free}_tx_cmd.   * @dev_cmd_pool_name: name for the TX command allocation pool   * @dbgfs_dir: iwlwifi debugfs base dir for this device   * @sync_cmd_lockdep_map: lockdep map for checking sync commands - * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before - *	starting the firmware, used for tracing - * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the - *	start of the 802.11 header in the @rx_mpdu_cmd   * @dbg: additional debug data, see &struct iwl_trans_debug   * @init_dram: FW initialization DMA data - * @system_pm_mode: the system-wide power management mode in use. - *	This mode is set dynamically, depending on the WoWLAN values - *	configured from the userspace at runtime. - * @name: the device name - * @mbx_addr_0_step: step address data 0 - * @mbx_addr_1_step: step address data 1 - * @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*), - *	only valid for discrete (not integrated) NICs - * @invalid_tx_cmd: invalid TX command buffer   * @reduced_cap_sku: reduced capability supported SKU - * @no_160: device not supporting 160 MHz   * @step_urm: STEP is in URM, no support for MCS>9 in 320 MHz + * @restart: restart worker data + * @restart.wk: restart worker + * @restart.mode: reset/restart error mode information + * @restart.during_reset: error occurred during previous software reset   * @trans_specific: data for the specific transport this is allocated for/with + * @request_top_reset: TOP reset was requested, used by the reset + *	worker that should be scheduled (with appropriate reason) + * @do_top_reset: indication to the (PCIe) transport/context-info + *	to do the TOP reset   */  struct iwl_trans {  	bool csme_own;  	struct iwl_op_mode *op_mode; -	const struct iwl_cfg_trans_params *trans_cfg; -	const struct iwl_cfg *cfg; +	const struct iwl_mac_cfg *mac_cfg; +	const struct iwl_rf_cfg *cfg;  	struct iwl_drv *drv; +	struct iwl_trans_config conf;  	enum iwl_trans_state state;  	unsigned long status;  	struct device *dev; -	u32 max_skb_frags; -	u32 hw_rev; -	u32 hw_rev_step; -	u32 hw_rf_id; -	u32 hw_crf_id; -	u32 hw_cnv_id; -	u32 hw_wfpm_id; -	u32 hw_id; -	char hw_id_str[52]; -	u32 sku_id[3]; -	bool reduced_cap_sku; -	u8 no_160:1, step_urm:1; -	u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; +	const struct iwl_trans_info info; +	bool reduced_cap_sku; +	bool step_urm;  	bool pm_support;  	bool ltr_enabled; @@ -926,16 +926,6 @@ struct iwl_trans {  	u8 reduce_power_loaded:1;  	u8 failed_to_load_reduce_power_image:1; -	const struct iwl_hcmd_arr *command_groups; -	int command_groups_size; -	bool wide_cmd_header; - -	wait_queue_head_t wait_command_queue; -	u8 num_rx_queues; - -	size_t iml_len; -	u8 *iml; -  	/* The following fields are internal only */  	struct kmem_cache *dev_cmd_pool;  	char dev_cmd_pool_name[50]; @@ -949,15 +939,14 @@ struct iwl_trans {  	struct iwl_trans_debug dbg;  	struct iwl_self_init_dram init_dram; -	enum iwl_plat_pm_mode system_pm_mode; - -	const char *name; -	u32 mbx_addr_0_step; -	u32 mbx_addr_1_step; - -	u8 pcie_link_speed; +	struct { +		struct delayed_work wk; +		struct iwl_fw_error_dump_mode mode; +		bool during_reset; +	} restart; -	struct iwl_dma_ptr invalid_tx_cmd; +	u8 request_top_reset:1, +	   do_top_reset:1;  	/* pointer to trans specific struct */  	/*Ensure that this pointer will always be aligned to sizeof pointer */ @@ -965,19 +954,18 @@ struct iwl_trans {  };  const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id); -int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans); -void iwl_trans_configure(struct iwl_trans *trans, -			 const struct iwl_trans_config *trans_cfg); +void iwl_trans_op_mode_enter(struct iwl_trans *trans, +			     struct iwl_op_mode *op_mode);  int iwl_trans_start_hw(struct iwl_trans *trans);  void iwl_trans_op_mode_leave(struct iwl_trans *trans); -void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr); +void iwl_trans_fw_alive(struct iwl_trans *trans); -int iwl_trans_start_fw(struct iwl_trans *trans, const struct fw_img *fw, -		       bool run_in_rfkill); +int iwl_trans_start_fw(struct iwl_trans *trans, const struct iwl_fw *fw, +		       enum iwl_ucode_type ucode_type, bool run_in_rfkill);  void iwl_trans_stop_device(struct iwl_trans *trans); @@ -1089,12 +1077,13 @@ int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs,  void iwl_trans_debugfs_cleanup(struct iwl_trans *trans);  #endif -#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize)		      \ -	do {								      \ -		if (__builtin_constant_p(bufsize))			      \ -			BUILD_BUG_ON((bufsize) % sizeof(u32));		      \ -		iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\ -	} while (0) +#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize)	\ +	({							\ +		if (__builtin_constant_p(bufsize))		\ +			BUILD_BUG_ON((bufsize) % sizeof(u32));	\ +		iwl_trans_read_mem(trans, addr, buf,		\ +				   (bufsize) / sizeof(u32));	\ +	})  int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr,  			    u64 src_addr, u32 byte_cnt); @@ -1120,7 +1109,7 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,  void iwl_trans_set_pmi(struct iwl_trans *trans, bool state); -int iwl_trans_sw_reset(struct iwl_trans *trans, bool retake_ownership); +int iwl_trans_sw_reset(struct iwl_trans *trans);  void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg,  			     u32 mask, u32 value); @@ -1134,7 +1123,31 @@ 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_schedule_reset(struct iwl_trans *trans, +					    enum iwl_fw_error_type type) +{ +	if (test_bit(STATUS_TRANS_DEAD, &trans->status)) +		return; +	/* clear this on device init, not cleared on any unbind/reprobe */ +	if (test_and_set_bit(STATUS_TRANS_RESET_IN_PROGRESS, &trans->status)) +		return; + +	trans->restart.mode.type = type; +	trans->restart.mode.context = IWL_ERR_CONTEXT_WORKER; + +	set_bit(STATUS_RESET_PENDING, &trans->status); + +	/* +	 * keep track of whether or not this happened while resetting, +	 * by the timer the worker runs it might have finished +	 */ +	trans->restart.during_reset = test_bit(STATUS_IN_SW_RESET, +					       &trans->status); +	queue_delayed_work(system_unbound_wq, &trans->restart.wk, 0); +} + +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; @@ -1142,10 +1155,27 @@ 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); +		iwl_trans_schedule_reset(trans, type);  	}  } +static inline void iwl_trans_opmode_sw_reset(struct iwl_trans *trans, +					     enum iwl_fw_error_type type) +{ +	if (WARN_ON_ONCE(!trans->op_mode)) +		return; + +	set_bit(STATUS_IN_SW_RESET, &trans->status); + +	if (WARN_ON(type == IWL_ERR_TYPE_TOP_RESET_BY_BT)) +		return; + +	if (!trans->op_mode->ops->sw_reset || +	    !trans->op_mode->ops->sw_reset(trans->op_mode, type)) +		clear_bit(STATUS_IN_SW_RESET, &trans->status); +} +  static inline bool iwl_trans_fw_running(struct iwl_trans *trans)  {  	return trans->state == IWL_TRANS_FW_ALIVE; @@ -1178,13 +1208,19 @@ static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans)  void iwl_trans_interrupts(struct iwl_trans *trans, bool enable); +static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans) +{ +	clear_bit(STATUS_IN_SW_RESET, &trans->status); +} +  /*****************************************************   * transport helper functions   *****************************************************/  struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, -			  struct device *dev, -			  const struct iwl_cfg_trans_params *cfg_trans); -int iwl_trans_init(struct iwl_trans *trans); +				  struct device *dev, +				  const struct iwl_mac_cfg *mac_cfg, +				  unsigned int txcmd_size, +				  unsigned int txcmd_align);  void iwl_trans_free(struct iwl_trans *trans);  static inline bool iwl_trans_is_hw_error_value(u32 val) @@ -1192,14 +1228,78 @@ static inline bool iwl_trans_is_hw_error_value(u32 val)  	return ((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50);  } +void iwl_trans_free_restart_list(void); + +static inline u16 iwl_trans_get_num_rbds(struct iwl_trans *trans) +{ +	u16 result = trans->cfg->num_rbds; + +	/* +	 * Since AX210 family (So/Ty) the device cannot put mutliple +	 * frames into the same buffer, so double the value for them. +	 */ +	if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +		return 2 * result; +	return result; +} + +static inline void iwl_trans_suppress_cmd_error_once(struct iwl_trans *trans) +{ +	set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &trans->status); +} + +static inline bool iwl_trans_device_enabled(struct iwl_trans *trans) +{ +	return test_bit(STATUS_DEVICE_ENABLED, &trans->status); +} + +static inline bool iwl_trans_is_dead(struct iwl_trans *trans) +{ +	return test_bit(STATUS_TRANS_DEAD, &trans->status); +} +  /*****************************************************   * PCIe handling   *****************************************************/  int __must_check iwl_pci_register_driver(void);  void iwl_pci_unregister_driver(void); -void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan); + +/* Note: order matters */ +enum iwl_reset_mode { +	/* upper level modes: */ +	IWL_RESET_MODE_SW_RESET, +	IWL_RESET_MODE_REPROBE, +	/* TOP reset doesn't require PCIe remove */ +	IWL_RESET_MODE_TOP_RESET, +	/* PCIE level modes: */ +	IWL_RESET_MODE_REMOVE_ONLY, +	IWL_RESET_MODE_RESCAN, +	IWL_RESET_MODE_FUNC_RESET, +	IWL_RESET_MODE_PROD_RESET, + +	/* keep last - special backoff value */ +	IWL_RESET_MODE_BACKOFF, +}; + +void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode); +void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans);  int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans,  			     struct iwl_host_cmd *cmd); +/* Internal helper */ +static inline void iwl_trans_set_info(struct iwl_trans *trans, +				      struct iwl_trans_info *info) +{ +	struct iwl_trans_info *write; + +	write = (void *)(uintptr_t)&trans->info; +	*write = *info; +} + +static inline u16 iwl_trans_get_device_id(struct iwl_trans *trans) +{ +	return u32_get_bits(trans->info.hw_id, GENMASK(31, 16)); +} +  #endif /* __iwl_trans_h__ */ | 
