diff options
Diffstat (limited to 'drivers/net/wireless/intel')
53 files changed, 1896 insertions, 522 deletions
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index b0f23cf1a621..0812db8936f1 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -418,17 +418,6 @@ static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)  	write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);  } -static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr) -{ -	write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, -		       addr & IPW_REG_INDIRECT_ADDR_MASK); -} - -static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val) -{ -	write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val); -} -  static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,  				    const u8 * buf)  { diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 5b483de18c81..d382f2017325 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -2995,20 +2995,6 @@ static void ipw_remove_current_network(struct ipw_priv *priv)  	spin_unlock_irqrestore(&priv->ieee->lock, flags);  } -/* - * Check that card is still alive. - * Reads debug register from domain0. - * If card is present, pre-defined value should - * be found there. - * - * @param priv - * @return 1 if card is present, 0 otherwise - */ -static inline int ipw_alive(struct ipw_priv *priv) -{ -	return ipw_read32(priv, 0x90) == 0xd55555d5; -} -  /* timeout in msec, attempted in 10-msec quanta */  static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,  			       int timeout) @@ -3441,7 +3427,7 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv,  			dma_unmap_single(&priv->pci_dev->dev,  					 rxq->pool[i].dma_addr,  					 IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); -			dev_kfree_skb(rxq->pool[i].skb); +			dev_kfree_skb_irq(rxq->pool[i].skb);  			rxq->pool[i].skb = NULL;  		}  		list_add_tail(&rxq->pool[i].list, &rxq->rx_used); @@ -9870,7 +9856,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,  /* Rebase the WE IOCTLs to zero for the handler array */  static iw_handler ipw_wx_handlers[] = { -	IW_HANDLER(SIOCGIWNAME, (iw_handler)cfg80211_wext_giwname), +	IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),  	IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq),  	IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq),  	IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode), @@ -11397,9 +11383,14 @@ static int ipw_wdev_init(struct net_device *dev)  	set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);  	/* With that information in place, we can now register the wiphy... */ -	if (wiphy_register(wdev->wiphy)) -		rc = -EIO; +	rc = wiphy_register(wdev->wiphy); +	if (rc) +		goto out; + +	return 0;  out: +	kfree(priv->ieee->a_band.channels); +	kfree(priv->ieee->bg_band.channels);  	return rc;  } diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 7352d5b2095f..9eaf5ec133f9 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -1202,8 +1202,6 @@ il3945_rx_handle(struct il_priv *il)  		D_RX("r = %d, i = %d\n", r, i);  	while (i != r) { -		int len; -  		rxb = rxq->queue[i];  		/* If an RXB doesn't have a Rx queue slot associated with it, @@ -1217,10 +1215,6 @@ il3945_rx_handle(struct il_priv *il)  			       PAGE_SIZE << il->hw_params.rx_page_order,  			       DMA_FROM_DEVICE);  		pkt = rxb_addr(rxb); - -		len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; -		len += sizeof(u32);	/* account for status word */ -  		reclaim = il_need_reclaim(il, pkt);  		/* Based on type of command response or notification, @@ -3378,10 +3372,12 @@ static DEVICE_ATTR(dump_errors, 0200, NULL, il3945_dump_error_log);   *   *****************************************************************************/ -static void +static int  il3945_setup_deferred_work(struct il_priv *il)  {  	il->workqueue = create_singlethread_workqueue(DRV_NAME); +	if (!il->workqueue) +		return -ENOMEM;  	init_waitqueue_head(&il->wait_command_queue); @@ -3398,6 +3394,8 @@ il3945_setup_deferred_work(struct il_priv *il)  	timer_setup(&il->watchdog, il_bg_watchdog, 0);  	tasklet_setup(&il->irq_tasklet, il3945_irq_tasklet); + +	return 0;  }  static void @@ -3435,6 +3433,7 @@ static const struct attribute_group il3945_attribute_group = {  static struct ieee80211_ops il3945_mac_ops __ro_after_init = {  	.tx = il3945_mac_tx, +	.wake_tx_queue = ieee80211_handle_wake_tx_queue,  	.start = il3945_mac_start,  	.stop = il3945_mac_stop,  	.add_interface = il_mac_add_interface, @@ -3717,7 +3716,10 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	}  	il_set_rxon_channel(il, &il->bands[NL80211_BAND_2GHZ].channels[5]); -	il3945_setup_deferred_work(il); +	err = il3945_setup_deferred_work(il); +	if (err) +		goto out_remove_sysfs; +  	il3945_setup_handlers(il);  	il_power_initialize(il); @@ -3729,7 +3731,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	err = il3945_setup_mac(il);  	if (err) -		goto out_remove_sysfs; +		goto out_destroy_workqueue;  	il_dbgfs_register(il, DRV_NAME); @@ -3738,9 +3740,10 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	return 0; -out_remove_sysfs: +out_destroy_workqueue:  	destroy_workqueue(il->workqueue);  	il->workqueue = NULL; +out_remove_sysfs:  	sysfs_remove_group(&pdev->dev.kobj, &il3945_attribute_group);  out_release_irq:  	free_irq(il->pci_dev->irq, il); diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 943de47170c7..0a4aa3c678c1 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4020,7 +4020,7 @@ il4965_hdl_alive(struct il_priv *il, struct il_rx_buf *rxb)  	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {  		D_INFO("Initialization Alive received.\n"); -		memcpy(&il->card_alive_init, &pkt->u.alive_frame, +		memcpy(&il->card_alive_init, &pkt->u.raw,  		       sizeof(struct il_init_alive_resp));  		pwork = &il->init_alive_start;  	} else { @@ -6211,10 +6211,12 @@ out:  	mutex_unlock(&il->mutex);  } -static void +static int  il4965_setup_deferred_work(struct il_priv *il)  {  	il->workqueue = create_singlethread_workqueue(DRV_NAME); +	if (!il->workqueue) +		return -ENOMEM;  	init_waitqueue_head(&il->wait_command_queue); @@ -6233,6 +6235,8 @@ il4965_setup_deferred_work(struct il_priv *il)  	timer_setup(&il->watchdog, il_bg_watchdog, 0);  	tasklet_setup(&il->irq_tasklet, il4965_irq_tasklet); + +	return 0;  }  static void @@ -6304,6 +6308,7 @@ il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,  static const struct ieee80211_ops il4965_mac_ops = {  	.tx = il4965_mac_tx, +	.wake_tx_queue = ieee80211_handle_wake_tx_queue,  	.start = il4965_mac_start,  	.stop = il4965_mac_stop,  	.add_interface = il_mac_add_interface, @@ -6617,7 +6622,10 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		goto out_disable_msi;  	} -	il4965_setup_deferred_work(il); +	err = il4965_setup_deferred_work(il); +	if (err) +		goto out_free_irq; +  	il4965_setup_handlers(il);  	/********************************************* @@ -6655,6 +6663,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  out_destroy_workqueue:  	destroy_workqueue(il->workqueue);  	il->workqueue = NULL; +out_free_irq:  	free_irq(il->pci_dev->irq, il);  out_disable_msi:  	pci_disable_msi(il->pci_dev); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 341c17fe2af4..96002121bb8b 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5174,7 +5174,7 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)  	memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));  	/* new association get rid of ibss beacon skb */ -	dev_kfree_skb(il->beacon_skb); +	dev_consume_skb_irq(il->beacon_skb);  	il->beacon_skb = NULL;  	il->timestamp = 0; @@ -5293,7 +5293,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)  	}  	spin_lock_irqsave(&il->lock, flags); -	dev_kfree_skb(il->beacon_skb); +	dev_consume_skb_irq(il->beacon_skb);  	il->beacon_skb = skb;  	timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 110fda65bd21..3bdd6774716d 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -10,7 +10,7 @@  #include "fw/api/txq.h"  /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX	72 +#define IWL_22000_UCODE_API_MAX	74  /* Lowest firmware API version supported */  #define IWL_22000_UCODE_API_MIN	39 @@ -172,6 +172,13 @@ static const struct iwl_ht_params iwl_22000_ht_params = {  		      BIT(NL80211_BAND_6GHZ),  }; +static const struct iwl_ht_params iwl_gl_a_ht_params = { +	.stbc = false, /* we explicitly disable STBC for GL step A */ +	.ldpc = true, +	.ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | +		      BIT(NL80211_BAND_6GHZ), +}; +  #define IWL_DEVICE_22000_COMMON						\  	.ucode_api_max = IWL_22000_UCODE_API_MAX,			\  	.ucode_api_min = IWL_22000_UCODE_API_MIN,			\ @@ -249,7 +256,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = {  		},							\  	} -#define IWL_DEVICE_BZ							\ +#define IWL_DEVICE_BZ_COMMON						\  	.ucode_api_max = IWL_22000_UCODE_API_MAX,			\  	.ucode_api_min = IWL_22000_UCODE_API_MIN,			\  	.led_mode = IWL_LED_RF_STATE,					\ @@ -261,12 +268,10 @@ static const struct iwl_ht_params iwl_22000_ht_params = {  	.dccm2_len = IWL_22000_DCCM2_LEN,				\  	.smem_offset = IWL_22000_SMEM_OFFSET,				\  	.smem_len = IWL_22000_SMEM_LEN,					\ -	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,	\  	.apmg_not_supported = true,					\  	.trans.mq_rx_supported = true,					\  	.vht_mu_mimo_supported = true,					\  	.mac_addr_from_csr = 0x30,					\ -	.ht_params = &iwl_22000_ht_params,				\  	.nvm_ver = IWL_22000_NVM_VERSION,				\  	.trans.use_tfh = true,						\  	.trans.rf_id = true,						\ @@ -313,6 +318,14 @@ static const struct iwl_ht_params iwl_22000_ht_params = {  		},							\  	} +#define IWL_DEVICE_BZ							\ +	IWL_DEVICE_BZ_COMMON,						\ +	.ht_params = &iwl_22000_ht_params + +#define IWL_DEVICE_GL_A							\ +	IWL_DEVICE_BZ_COMMON,						\ +	.ht_params = &iwl_gl_a_ht_params +  const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = {  	.mq_rx_supported = true,  	.use_tfh = true, @@ -901,6 +914,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = {  	.fw_name_pre = IWL_BZ_A_HR_B_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -908,6 +922,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = {  	.fw_name_pre = IWL_BZ_A_GF_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -915,6 +930,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = {  	.fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -922,6 +938,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = {  	.fw_name_pre = IWL_BZ_A_MR_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -929,6 +946,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm_a0 = {  	.fw_name_pre = IWL_BZ_A_FM_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -936,13 +954,15 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = {  	.fw_name_pre = IWL_BZ_A_FM4_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  };  const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = {  	.fw_name_pre = IWL_GL_A_FM_A_FW_PRE,  	.uhb_supported = true, -	IWL_DEVICE_BZ, +	IWL_DEVICE_GL_A, +	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -950,6 +970,7 @@ const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = {  	.fw_name_pre = IWL_GL_B_FM_B_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -957,6 +978,7 @@ const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = {  	.fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -964,6 +986,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0 = {  	.fw_name_pre = IWL_BNJ_A_FM_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -971,6 +994,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = {  	.fw_name_pre = IWL_BNJ_A_FM4_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -978,6 +1002,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = {  	.fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -985,6 +1010,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = {  	.fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -992,6 +1018,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = {  	.fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  }; @@ -999,6 +1026,7 @@ const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = {  	.fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE,  	.uhb_supported = true,  	IWL_DEVICE_BZ, +	.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,  	.num_rbds = IWL_NUM_RBDS_AX210_HE,  };  MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index f4070fddc8c7..b1939ff275b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -1571,6 +1571,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,  const struct ieee80211_ops iwlagn_hw_ops = {  	.tx = iwlagn_mac_tx, +	.wake_tx_queue = ieee80211_handle_wake_tx_queue,  	.start = iwlagn_mac_start,  	.stop = iwlagn_mac_stop,  #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index e6d64152c81a..a02e5a67b706 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1106,6 +1106,11 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c          int i, j, num_sub_bands;          s8 *gain; +	/* many firmware images for JF lie about this */ +	if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == +	    CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) +		return -EOPNOTSUPP; +          if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {                  IWL_DEBUG_RADIO(fwrt,                                  "PPAG capability not supported by FW, command not sent.\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 0b052c2e563a..28c87a480246 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -153,6 +153,7 @@ enum iwl_legacy_cmds {  	/**  	 * @TXPATH_FLUSH: &struct iwl_tx_path_flush_cmd +	 *	response in &struct iwl_tx_path_flush_cmd_rsp  	 */  	TXPATH_FLUSH = 0x1e, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 43619acc29fd..8b38a0073077 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -72,13 +72,18 @@ enum iwl_data_path_subcmd_ids {  	SCD_QUEUE_CONFIG_CMD = 0x17,  	/** +	 * @SEC_KEY_CMD: security key command, uses &struct iwl_sec_key_cmd +	 */ +	SEC_KEY_CMD = 0x18, + +	/**  	 * @MONITOR_NOTIF: Datapath monitoring notification, using  	 *	&struct iwl_datapath_monitor_notif  	 */  	MONITOR_NOTIF = 0xF4,  	/** -	 * @RX_NO_DATA_NOTIF: &struct iwl_rx_no_data +	 * @RX_NO_DATA_NOTIF: &struct iwl_rx_no_data or &struct iwl_rx_no_data_ver_3  	 */  	RX_NO_DATA_NOTIF = 0xF5, @@ -377,9 +382,11 @@ enum iwl_scd_queue_cfg_operation {   * @u.add.cb_size: size code   * @u.add.bc_dram_addr: byte-count table IOVA   * @u.add.tfdq_dram_addr: TFD queue IOVA - * @u.remove.queue: queue ID for removal - * @u.modify.sta_mask: new station mask for modify - * @u.modify.queue: queue ID to modify + * @u.remove.sta_mask: station mask of queue to remove + * @u.remove.tid: TID of queue to remove + * @u.modify.old_sta_mask: old station mask for modify + * @u.modify.tid: TID of queue to modify + * @u.modify.new_sta_mask: new station mask for modify   */  struct iwl_scd_queue_cfg_cmd {  	__le32 operation; @@ -394,13 +401,89 @@ struct iwl_scd_queue_cfg_cmd {  			__le64 tfdq_dram_addr;  		} __packed add; /* TX_QUEUE_CFG_CMD_ADD_API_S_VER_1 */  		struct { -			__le32 queue; +			__le32 sta_mask; +			__le32 tid;  		} __packed remove; /* TX_QUEUE_CFG_CMD_REMOVE_API_S_VER_1 */  		struct { -			__le32 sta_mask; -			__le32 queue; +			__le32 old_sta_mask; +			__le32 tid; +			__le32 new_sta_mask;  		} __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1 */  	} __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */  } __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */ +/** + * enum iwl_sec_key_flags - security key command key flags + * @IWL_SEC_KEY_FLAG_CIPHER_MASK: cipher mask + * @IWL_SEC_KEY_FLAG_CIPHER_WEP: WEP cipher + * @IWL_SEC_KEY_FLAG_CIPHER_CCMP: CCMP/CMAC cipher + * @IWL_SEC_KEY_FLAG_CIPHER_TKIP: TKIP cipher + * @IWL_SEC_KEY_FLAG_CIPHER_GCMP: GCMP/GMAC cipher + * @IWL_SEC_KEY_FLAG_NO_TX: don't install for TX + * @IWL_SEC_KEY_FLAG_KEY_SIZE: large key size (WEP-104, GCMP-256, GMAC-256) + * @IWL_SEC_KEY_FLAG_MFP: MFP is in used for this key + * @IWL_SEC_KEY_FLAG_MCAST_KEY: this is a multicast key + * @IWL_SEC_KEY_FLAG_SPP_AMSDU: SPP A-MSDU should be used + */ +enum iwl_sec_key_flags { +	IWL_SEC_KEY_FLAG_CIPHER_MASK	= 0x07, +	IWL_SEC_KEY_FLAG_CIPHER_WEP	= 0x01, +	IWL_SEC_KEY_FLAG_CIPHER_CCMP	= 0x02, +	IWL_SEC_KEY_FLAG_CIPHER_TKIP	= 0x03, +	IWL_SEC_KEY_FLAG_CIPHER_GCMP	= 0x05, +	IWL_SEC_KEY_FLAG_NO_TX		= 0x08, +	IWL_SEC_KEY_FLAG_KEY_SIZE	= 0x10, +	IWL_SEC_KEY_FLAG_MFP		= 0x20, +	IWL_SEC_KEY_FLAG_MCAST_KEY	= 0x40, +	IWL_SEC_KEY_FLAG_SPP_AMSDU	= 0x80, +}; + +#define IWL_SEC_WEP_KEY_OFFSET	3 + +/** + * struct iwl_sec_key_cmd - security key command + * @action: action from &enum iwl_ctxt_action + * @u.add.sta_mask: station mask for the new key + * @u.add.key_id: key ID (0-7) for the new key + * @u.add.key_flags: key flags per &enum iwl_sec_key_flags + * @u.add.key: key material. WEP keys should start from &IWL_SEC_WEP_KEY_OFFSET. + * @u.add.tkip_mic_rx_key: TKIP MIC RX key + * @u.add.tkip_mic_tx_key: TKIP MIC TX key + * @u.add.rx_seq: RX sequence counter value + * @u.add.tx_seq: TX sequence counter value + * @u.modify.old_sta_mask: old station mask + * @u.modify.new_sta_mask: new station mask + * @u.modify.key_id: key ID + * @u.modify.key_flags: new key flags + * @u.remove.sta_mask: station mask + * @u.remove.key_id: key ID + * @u.remove.key_flags: key flags + */ +struct iwl_sec_key_cmd { +	__le32 action; +	union { +		struct { +			__le32 sta_mask; +			__le32 key_id; +			__le32 key_flags; +			u8 key[32]; +			u8 tkip_mic_rx_key[8]; +			u8 tkip_mic_tx_key[8]; +			__le64 rx_seq; +			__le64 tx_seq; +		} __packed add; /* SEC_KEY_ADD_CMD_API_S_VER_1 */ +		struct { +			__le32 old_sta_mask; +			__le32 new_sta_mask; +			__le32 key_id; +			__le32 key_flags; +		} __packed modify; /* SEC_KEY_MODIFY_CMD_API_S_VER_1 */ +		struct { +			__le32 sta_mask; +			__le32 key_id; +			__le32 key_flags; +		} __packed remove; /* SEC_KEY_REMOVE_CMD_API_S_VER_1 */ +	} __packed u; /* SEC_KEY_OPERATION_API_U_VER_1 */ +} __packed; /* SEC_KEY_CMD_API_S_VER_1 */ +  #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 9b7caf968346..e3eda251c728 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation   * Copyright (C) 2017 Intel Deutschland GmbH   */  #ifndef __iwl_fw_api_mac_h__ @@ -398,7 +398,7 @@ struct iwl_he_backoff_conf {   * @IWL_HE_PKT_EXT_64QAM: 64-QAM   * @IWL_HE_PKT_EXT_256QAM: 256-QAM   * @IWL_HE_PKT_EXT_1024QAM: 1024-QAM - * @IWL_HE_PKT_EXT_RESERVED: reserved value + * @IWL_HE_PKT_EXT_4096QAM: 4096-QAM, for EHT only   * @IWL_HE_PKT_EXT_NONE: not defined   */  enum iwl_he_pkt_ext_constellations { @@ -408,7 +408,7 @@ enum iwl_he_pkt_ext_constellations {  	IWL_HE_PKT_EXT_64QAM,  	IWL_HE_PKT_EXT_256QAM,  	IWL_HE_PKT_EXT_1024QAM, -	IWL_HE_PKT_EXT_RESERVED, +	IWL_HE_PKT_EXT_4096QAM,  	IWL_HE_PKT_EXT_NONE,  }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index e66f77924f83..2f7d8558becd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -13,10 +13,12 @@  #define PHY_BAND_6 (2)  /* Supported channel width, vary if there is VHT support */ -#define PHY_VHT_CHANNEL_MODE20	(0x0) -#define PHY_VHT_CHANNEL_MODE40	(0x1) -#define PHY_VHT_CHANNEL_MODE80	(0x2) -#define PHY_VHT_CHANNEL_MODE160	(0x3) +#define IWL_PHY_CHANNEL_MODE20	0x0 +#define IWL_PHY_CHANNEL_MODE40	0x1 +#define IWL_PHY_CHANNEL_MODE80	0x2 +#define IWL_PHY_CHANNEL_MODE160	0x3 +/* and 320 MHz for EHT */ +#define IWL_PHY_CHANNEL_MODE320	0x4  /*   * Control channel position: @@ -24,20 +26,17 @@   * For VHT - bit-2 marks if the control is lower/upper relative to center-freq   *   bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0.   *                                   center_freq - *                                        | - * 40Mhz                          |_______|_______| - * 80Mhz                  |_______|_______|_______|_______| - * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| - * code      011     010     001     000  |  100     101     110    111 + * For EHT - bit-3 is used for extended distance + *                                                | + * 40Mhz                                     |____|____| + * 80Mhz                                |____|____|____|____| + * 160Mhz                     |____|____|____|____|____|____|____|____| + * 320MHz |____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____| + * code    1011 1010 1001 1000 0011 0010 0001 0000 0100 0101 0110 0111 1100 1101 1110 1111   */ -#define PHY_VHT_CTRL_POS_1_BELOW  (0x0) -#define PHY_VHT_CTRL_POS_2_BELOW  (0x1) -#define PHY_VHT_CTRL_POS_3_BELOW  (0x2) -#define PHY_VHT_CTRL_POS_4_BELOW  (0x3) -#define PHY_VHT_CTRL_POS_1_ABOVE  (0x4) -#define PHY_VHT_CTRL_POS_2_ABOVE  (0x5) -#define PHY_VHT_CTRL_POS_3_ABOVE  (0x6) -#define PHY_VHT_CTRL_POS_4_ABOVE  (0x7) +#define IWL_PHY_CTRL_POS_ABOVE		0x4 +#define IWL_PHY_CTRL_POS_OFFS_EXT	0x8 +#define IWL_PHY_CTRL_POS_OFFS_MSK	0x3  /*   * struct iwl_fw_channel_info_v1 - channel information diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 687f804c46b7..ddacd5b45aea 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -36,14 +36,14 @@ enum iwl_tlc_mng_cfg_flags {   * @IWL_TLC_MNG_CH_WIDTH_40MHZ: 40MHZ channel   * @IWL_TLC_MNG_CH_WIDTH_80MHZ: 80MHZ channel   * @IWL_TLC_MNG_CH_WIDTH_160MHZ: 160MHZ channel - * @IWL_TLC_MNG_CH_WIDTH_LAST: maximum value + * @IWL_TLC_MNG_CH_WIDTH_320MHZ: 320MHZ channel   */  enum iwl_tlc_mng_cfg_cw {  	IWL_TLC_MNG_CH_WIDTH_20MHZ,  	IWL_TLC_MNG_CH_WIDTH_40MHZ,  	IWL_TLC_MNG_CH_WIDTH_80MHZ,  	IWL_TLC_MNG_CH_WIDTH_160MHZ, -	IWL_TLC_MNG_CH_WIDTH_LAST = IWL_TLC_MNG_CH_WIDTH_160MHZ, +	IWL_TLC_MNG_CH_WIDTH_320MHZ,  };  /** @@ -64,8 +64,7 @@ enum iwl_tlc_mng_cfg_chains {   * @IWL_TLC_MNG_MODE_HT: enable HT   * @IWL_TLC_MNG_MODE_VHT: enable VHT   * @IWL_TLC_MNG_MODE_HE: enable HE - * @IWL_TLC_MNG_MODE_INVALID: invalid value - * @IWL_TLC_MNG_MODE_NUM: a count of possible modes + * @IWL_TLC_MNG_MODE_EHT: enable EHT   */  enum iwl_tlc_mng_cfg_mode {  	IWL_TLC_MNG_MODE_CCK = 0, @@ -74,8 +73,7 @@ enum iwl_tlc_mng_cfg_mode {  	IWL_TLC_MNG_MODE_HT,  	IWL_TLC_MNG_MODE_VHT,  	IWL_TLC_MNG_MODE_HE, -	IWL_TLC_MNG_MODE_INVALID, -	IWL_TLC_MNG_MODE_NUM = IWL_TLC_MNG_MODE_INVALID, +	IWL_TLC_MNG_MODE_EHT,  };  /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 74a01888715b..1c4e84932058 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -273,7 +273,7 @@ enum iwl_rx_mpdu_mac_info {  };  /* TSF overload low dword */ -enum iwl_rx_phy_data0 { +enum iwl_rx_phy_he_data0 {  	/* info type: HE any */  	IWL_RX_PHY_DATA0_HE_BEAM_CHNG				= 0x00000001,  	IWL_RX_PHY_DATA0_HE_UPLINK				= 0x00000002, @@ -289,6 +289,25 @@ enum iwl_rx_phy_data0 {  	IWL_RX_PHY_DATA0_HE_DELIM_EOF				= 0x80000000,  }; +/* TSF overload low dword */ +enum iwl_rx_phy_eht_data0 { +	/* info type: EHT any */ +	/* 1 bits reserved */ +	IWL_RX_PHY_DATA0_EHT_UPLINK				= BIT(1), +	IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK			= 0x000000fc, +	IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK			= 0x00000f00, +	IWL_RX_PHY_DATA0_EHT_PS160				= BIT(12), +	IWL_RX_PHY_DATA0_EHT_TXOP_DUR_MASK			= 0x000fe000, +	IWL_RX_PHY_DATA0_EHT_LDPC_EXT_SYM			= BIT(20), +	IWL_RX_PHY_DATA0_EHT_PRE_FEC_PAD_MASK			= 0x00600000, +	IWL_RX_PHY_DATA0_EHT_PE_DISAMBIG			= BIT(23), +	IWL_RX_PHY_DATA0_EHT_BW320_SLOT				= BIT(24), +	IWL_RX_PHY_DATA0_EHT_SIGA_CRC_OK			= BIT(25), +	IWL_RX_PHY_DATA0_EHT_PHY_VER				= 0x1c000000, +	/* 2 bits reserved */ +	IWL_RX_PHY_DATA0_EHT_DELIM_EOF				= BIT(31), +}; +  enum iwl_rx_phy_info_type {  	IWL_RX_PHY_INFO_TYPE_NONE				= 0,  	IWL_RX_PHY_INFO_TYPE_CCK				= 1, @@ -301,19 +320,26 @@ enum iwl_rx_phy_info_type {  	IWL_RX_PHY_INFO_TYPE_HE_TB				= 8,  	IWL_RX_PHY_INFO_TYPE_HE_MU_EXT				= 9,  	IWL_RX_PHY_INFO_TYPE_HE_TB_EXT				= 10, +	IWL_RX_PHY_INFO_TYPE_EHT_MU				= 11, +	IWL_RX_PHY_INFO_TYPE_EHT_TB				= 12, +	IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT				= 13, +	IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT				= 14,  };  /* TSF overload high dword */ -enum iwl_rx_phy_data1 { +enum iwl_rx_phy_common_data1 {  	/*  	 * check this first - if TSF overload is set,  	 * see &enum iwl_rx_phy_info_type  	 */  	IWL_RX_PHY_DATA1_INFO_TYPE_MASK				= 0xf0000000, -	/* info type: HT/VHT/HE any */ +	/* info type: HT/VHT/HE/EHT any */  	IWL_RX_PHY_DATA1_LSIG_LEN_MASK				= 0x0fff0000, +}; +/* TSF overload high dword For HE rates*/ +enum iwl_rx_phy_he_data1 {  	/* info type: HE MU/MU-EXT */  	IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION			= 0x00000001,  	IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK	= 0x0000001e, @@ -329,8 +355,23 @@ enum iwl_rx_phy_data1 {  	IWL_RX_PHY_DATA1_HE_TB_LOW_SS_MASK			= 0x0000000e,  }; +/* TSF overload high dword For EHT-MU/TB rates*/ +enum iwl_rx_phy_eht_data1 { +	/* info type: EHT-MU */ +	IWL_RX_PHY_DATA1_EHT_MU_NUM_SIG_SYM_USIGA2	= 0x0000001f, +	/* info type: EHT-TB */ +	IWL_RX_PHY_DATA1_EHT_TB_PILOT_TYPE		= BIT(0), +	IWL_RX_PHY_DATA1_EHT_TB_LOW_SS			= 0x0000001e, + +	/* info type: EHT any */ +	/* number of EHT-LTF symbols 0 - 1 EHT-LTF, 1 - 2 EHT-LTFs, 2 - 4 EHT-LTFs, +	 * 3 - 6 EHT-LTFs, 4 - 8 EHT-LTFs */ +	IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM		= 0x000000e0, +	IWL_RX_PHY_DATA1_EHT_RU_ALLOC			= 0x0000ff00, +}; +  /* goes into Metadata DW 7 */ -enum iwl_rx_phy_data2 { +enum iwl_rx_phy_he_data2 {  	/* info type: HE MU-EXT */  	/* the a1/a2/... is what the PHY/firmware calls the values */  	IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0		= 0x000000ff, /* a1 */ @@ -346,7 +387,7 @@ enum iwl_rx_phy_data2 {  };  /* goes into Metadata DW 8 */ -enum iwl_rx_phy_data3 { +enum iwl_rx_phy_he_data3 {  	/* info type: HE MU-EXT */  	IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1		= 0x000000ff, /* c1 */  	IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3		= 0x0000ff00, /* c2 */ @@ -355,7 +396,7 @@ enum iwl_rx_phy_data3 {  };  /* goes into Metadata DW 4 high 16 bits */ -enum iwl_rx_phy_data4 { +enum iwl_rx_phy_he_he_data4 {  	/* info type: HE MU-EXT */  	IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU			= 0x0001,  	IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU			= 0x0002, @@ -366,6 +407,51 @@ enum iwl_rx_phy_data4 {  	IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK	= 0x0600,  }; +/* goes into Metadata DW 7 */ +enum iwl_rx_phy_eht_data2 { +	/* info type: EHT-MU-EXT */ +	/* OFDM_RX_VECTOR_COMMON_RU_ALLOC_0_OUT */ +	IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A1	= 0x000001ff, +	IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A2	= 0x0003fe00, +	IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A3	= 0x01fc0000, + +	/* info type: EHT-TB-EXT */ +	IWL_RX_PHY_DATA2_EHT_TB_EXT_TRIG_SIGA1	= 0xffffffff, +}; + +/* goes into Metadata DW 8 */ +enum iwl_rx_phy_eht_data3 { +	/* info type: EHT-MU-EXT */ +	/* OFDM_RX_VECTOR_COMMON_RU_ALLOC_1_OUT */ +	IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B1	= 0x000001ff, +	IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B2	= 0x0003fe00, +	IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B3	= 0x01fc0000, +}; + +/* goes into Metadata DW 4 */ +enum iwl_rx_phy_eht_data4 { +	/* info type: EHT-MU-EXT */ +	/* OFDM_RX_VECTOR_COMMON_RU_ALLOC_2_OUT */ +	IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_C1	= 0x000001ff, +	IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_C2	= 0x0003fe00, +	IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_C3	= 0x01fc0000, +	IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS	= 0x18000000, +}; + +/* goes into Metadata DW 16 */ +enum iwl_rx_phy_data5 { +	/* info type: EHT any */ +	IWL_RX_PHY_DATA5_EHT_TYPE_AND_COMP		= 0x00000003, +	/* info type: EHT-TB */ +	IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE1		= 0x0000003c, +	IWL_RX_PHY_DATA5_EHT_TB_SPATIAL_REUSE2		= 0x000003c0, +	/* info type: EHT-MU */ +	IWL_RX_PHY_DATA5_EHT_MU_PUNC_CH_CODE		= 0x0000007c, +	IWL_RX_PHY_DATA5_EHT_MU_STA_ID_USR		= 0x0003ff80, +	IWL_RX_PHY_DATA5_EHT_MU_NUM_USR_NON_OFDMA	= 0x001c0000, +	IWL_RX_PHY_DATA5_EHT_MU_SPATIAL_CONF_USR_FIELD	= 0x0fe00000, +}; +  /**   * struct iwl_rx_mpdu_desc_v1 - RX MPDU descriptor   */ @@ -440,7 +526,9 @@ struct iwl_rx_mpdu_desc_v1 {  			/**  			 * @phy_data1: valid only if  			 * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set, -			 * see &enum iwl_rx_phy_data1. +			 * see &enum iwl_rx_phy_common_data1 or +			 *     &enum iwl_rx_phy_he_data1 or +			 *     &enum iwl_rx_phy_eht_data1.  			 */  			__le32 phy_data1;  		}; @@ -540,11 +628,18 @@ struct iwl_rx_mpdu_desc_v3 {  			__le32 phy_data1;  		};  	}; -	/* DW16 & DW17 */ +	/* DW16 */ +	/** +	 * @phy_data5: valid only if +	 * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set, +	 * see &enum iwl_rx_phy_data5. +	 */ +	__le32 phy_data5; +	/* DW17 */  	/**  	 * @reserved: reserved  	 */ -	__le32 reserved[2]; +	__le32 reserved[1];  } __packed; /* RX_MPDU_RES_START_API_S_VER_3,  	       RX_MPDU_RES_START_API_S_VER_5 */ @@ -639,12 +734,14 @@ struct iwl_rx_mpdu_desc {  #define RX_NO_DATA_INFO_ERR_UNSUPPORTED_RATE	2  #define RX_NO_DATA_INFO_ERR_NO_DELIM		3  #define RX_NO_DATA_INFO_ERR_BAD_MAC_HDR	4 +#define RX_NO_DATA_INFO_LOW_ENERGY		5  #define RX_NO_DATA_FRAME_TIME_POS	0  #define RX_NO_DATA_FRAME_TIME_MSK	(0xfffff << RX_NO_DATA_FRAME_TIME_POS)  #define RX_NO_DATA_RX_VEC0_HE_NSTS_MSK	0x03800000  #define RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK	0x38000000 +#define RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK	0x00f00000  /**   * struct iwl_rx_no_data - RX no data descriptor @@ -654,7 +751,8 @@ struct iwl_rx_mpdu_desc {   * @on_air_rise_time: GP2 during on air rise   * @fr_time: frame time   * @rate: rate/mcs of frame - * @phy_info: &enum iwl_rx_phy_data0 and &enum iwl_rx_phy_info_type + * @phy_info: &enum iwl_rx_phy_he_data0 or &enum iwl_rx_phy_eht_data0 + *	      based on &enum iwl_rx_phy_info_type   * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type.   *	for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT   *	for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT @@ -670,6 +768,33 @@ struct iwl_rx_no_data {  } __packed; /* RX_NO_DATA_NTFY_API_S_VER_1,  	       RX_NO_DATA_NTFY_API_S_VER_2 */ +/** + * struct iwl_rx_no_data_ver_3 - RX no data descriptor + * @info: 7:0 frame type, 15:8 RX error type + * @rssi: 7:0 energy chain-A, + *	15:8 chain-B, measured at FINA time (FINA_ENERGY), 16:23 channel + * @on_air_rise_time: GP2 during on air rise + * @fr_time: frame time + * @rate: rate/mcs of frame + * @phy_info: &enum iwl_rx_phy_eht_data0 and &enum iwl_rx_phy_info_type + * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type. + *	for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT + *	for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT + *	for EHT: OFDM_RX_VECTOR_USIG_A1_OUT, OFDM_RX_VECTOR_USIG_A2_OUT, + *	OFDM_RX_VECTOR_EHT_OUT, OFDM_RX_VECTOR_EHT_USER_FIELD_OUT + */ +struct iwl_rx_no_data_ver_3 { +	__le32 info; +	__le32 rssi; +	__le32 on_air_rise_time; +	__le32 fr_time; +	__le32 rate; +	__le32 phy_info[2]; +	__le32 rx_vec[4]; +} __packed; /* RX_NO_DATA_NTFY_API_S_VER_1, +	       RX_NO_DATA_NTFY_API_S_VER_2 +	       RX_NO_DATA_NTFY_API_S_VER_3 */ +  struct iwl_frame_release {  	u8 baid;  	u8 reserved; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index b90f1e9ce691..792f7fee1840 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation   * Copyright (C) 2013-2014 Intel Mobile Communications GmbH   * Copyright (C) 2015-2017 Intel Deutschland GmbH   */ @@ -157,7 +157,8 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu  			base = fwrt->fw->inst_errlog_ptr;  	} -	if (base < 0x400000) { +	if ((fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && !base) || +	    (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ && base < 0x400000)) {  		IWL_ERR(fwrt,  			"Not valid error log pointer 0x%08X for %s uCode\n",  			base, @@ -376,7 +377,7 @@ static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)  		return;  	} -	error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); +	error = iwl_read_umac_prph(trans, error);  	IWL_ERR(trans, "IML/ROM dump:\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/rs.c b/drivers/net/wireless/intel/iwlwifi/fw/rs.c index a835214611ce..e128d2e07f38 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/rs.c @@ -218,6 +218,8 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)  		type = "HT";  	else if (format == RATE_MCS_HE_MSK)  		type = "HE"; +	else if (format == RATE_MCS_EHT_MSK) +		type = "EHT";  	else  		type = "Unknown"; /* shouldn't happen */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 6d408cd0f517..0b6f694cf30d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright(c) 2021 Intel Corporation + * Copyright(c) 2021-2022 Intel Corporation   */  #include "iwl-drv.h" @@ -246,6 +246,63 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)  	return data;  } +static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data, +			       struct iwl_trans *trans) +{ +	if (common_step_data->revision != 1) +		return -EINVAL; + +	trans->mbx_addr_0_step = (u32)common_step_data->revision | +		(u32)common_step_data->cnvi_eq_channel << 8 | +		(u32)common_step_data->cnvr_eq_channel << 16 | +		(u32)common_step_data->radio1 << 24; +	trans->mbx_addr_1_step = (u32)common_step_data->radio2; +	return 0; +} + +void iwl_uefi_get_step_table(struct iwl_trans *trans) +{ +	struct uefi_cnv_common_step_data *data; +	unsigned long package_size; +	efi_status_t status; +	int ret; + +	if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) +		return; + +	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) +		return; + +	/* TODO: we hardcode a maximum length here, because reading +	 * from the UEFI is not working.  To implement this properly, +	 * we have to call efivar_entry_size(). +	 */ +	package_size = IWL_HARDCODED_STEP_SIZE; + +	data = kmalloc(package_size, GFP_KERNEL); +	if (!data) +		return; + +	status = efi.get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, +				  NULL, &package_size, data); +	if (status != EFI_SUCCESS) { +		IWL_DEBUG_FW(trans, +			     "STEP UEFI variable not found 0x%lx\n", status); +		goto out_free; +	} + +	IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n", +		     package_size); + +	ret = iwl_uefi_step_parse(data, trans); +	if (ret < 0) +		IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n"); + +out_free: +	kfree(data); +} +IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); +  #ifdef CONFIG_ACPI  static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data,  			       struct iwl_fw_runtime *fwrt) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 09d2a971b3a0..17089bc74cf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright(c) 2021 Intel Corporation + * Copyright(c) 2021-2022 Intel Corporation   */  #ifndef __iwl_fw_uefi__  #define __iwl_fw_uefi__ @@ -8,6 +8,7 @@  #define IWL_UEFI_OEM_PNVM_NAME		L"UefiCnvWlanOemSignedPnvm"  #define IWL_UEFI_REDUCED_POWER_NAME	L"UefiCnvWlanReducedPower"  #define IWL_UEFI_SGOM_NAME		L"UefiCnvWlanSarGeoOffsetMapping" +#define IWL_UEFI_STEP_NAME		L"UefiCnvCommonSTEP"  /*   * TODO: we have these hardcoded values that the caller must pass, @@ -18,6 +19,7 @@  #define IWL_HARDCODED_PNVM_SIZE		4096  #define IWL_HARDCODED_REDUCE_POWER_SIZE	32768  #define IWL_HARDCODED_SGOM_SIZE		339 +#define IWL_HARDCODED_STEP_SIZE		6  struct pnvm_sku_package {  	u8 rev; @@ -32,6 +34,15 @@ struct uefi_cnv_wlan_sgom_data {  	u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1];  } __packed; +struct uefi_cnv_common_step_data { +	u8 revision; +	u8 step_mode; +	u8 cnvi_eq_channel; +	u8 cnvr_eq_channel; +	u8 radio1; +	u8 radio2; +} __packed; +  /*   * This is known to be broken on v4.19 and to work on v5.4.  Until we   * figure out why this is the case and how to make it work, simply @@ -40,6 +51,7 @@ struct uefi_cnv_wlan_sgom_data {  #ifdef CONFIG_EFI  void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len);  void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); +void iwl_uefi_get_step_table(struct iwl_trans *trans);  #else /* CONFIG_EFI */  static inline  void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) @@ -52,6 +64,11 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)  {  	return ERR_PTR(-EOPNOTSUPP);  } + +static inline +void iwl_uefi_get_step_table(struct iwl_trans *trans) +{ +}  #endif /* CONFIG_EFI */  #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index b84884034c74..3f7278014009 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -141,12 +141,27 @@ struct iwl_prph_scratch_uefi_cfg {  } __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */  /* + * struct iwl_prph_scratch_step_cfg - prph scratch step configuration + * @mbx_addr_0: [0:7] revision, + *		[8:15] cnvi_to_cnvr length, + *		[16:23] cnvr_to_cnvi channel length, + *		[24:31] radio1 reserved + * @mbx_addr_1: [0:7] radio2 reserved + */ + +struct iwl_prph_scratch_step_cfg { +	__le32 mbx_addr_0; +	__le32 mbx_addr_1; +} __packed; + +/*   * struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config   * @version: version information of context info and HW   * @control: control flags of FH configurations   * @pnvm_cfg: ror configuration   * @hwm_cfg: hwm configuration   * @rbd_cfg: default RX queue configuration + * @step_cfg: step configuration   */  struct iwl_prph_scratch_ctrl_cfg {  	struct iwl_prph_scratch_version version; @@ -155,6 +170,7 @@ struct iwl_prph_scratch_ctrl_cfg {  	struct iwl_prph_scratch_hwm_cfg hwm_cfg;  	struct iwl_prph_scratch_rbd_cfg rbd_cfg;  	struct iwl_prph_scratch_uefi_cfg reduce_power_cfg; +	struct iwl_prph_scratch_step_cfg step_cfg;  } __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */  /* @@ -165,7 +181,7 @@ struct iwl_prph_scratch_ctrl_cfg {   */  struct iwl_prph_scratch {  	struct iwl_prph_scratch_ctrl_cfg ctrl_cfg; -	__le32 reserved[12]; +	__le32 reserved[10];  	struct iwl_context_info_dram dram;  } __packed; /* PERIPH_SCRATCH_S */ @@ -265,5 +281,6 @@ int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,  					  const void *data, u32 len);  int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,  						  const void *data, u32 len); - +int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, +					  u32 mbx_addr_0_step, u32 mbx_addr_1_step);  #endif /* __iwl_context_info_file_gen3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 3237d4b528b5..48e7376a5fea 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -371,7 +371,7 @@ void iwl_dbg_tlv_del_timers(struct iwl_trans *trans)  	struct iwl_dbg_tlv_timer_node *node, *tmp;  	list_for_each_entry_safe(node, tmp, timer_list, list) { -		del_timer_sync(&node->timer); +		timer_shutdown_sync(&node->timer);  		list_del(&node->list);  		kfree(node);  	} @@ -590,6 +590,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,  		if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)  			return -EIO;  		num_frags = 1; +	} else if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ && +			   alloc_id > IWL_FW_INI_ALLOCATION_ID_DBGC3) { +		return -EIO;  	}  	remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size), @@ -789,7 +792,7 @@ static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt)  	dram_info->second_word = cpu_to_le32(DRAM_INFO_SECOND_MAGIC_WORD);  	for (i = IWL_FW_INI_ALLOCATION_ID_DBGC1; -	     i <= IWL_FW_INI_ALLOCATION_ID_DBGC3; i++) { +	     i < IWL_FW_INI_ALLOCATION_NUM; i++) {  		ret = iwl_dbg_tlv_update_dram(fwrt, i, dram_info);  		if (!ret)  			dram_alloc = true; @@ -1324,7 +1327,7 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt)  			     "WRT: removing allocation id %d from region id %d\n",  			     le32_to_cpu(reg->dram_alloc_id), i); -		failed_alloc &= ~le32_to_cpu(reg->dram_alloc_id); +		failed_alloc &= ~BIT(le32_to_cpu(reg->dram_alloc_id));  		fwrt->trans->dbg.unsupported_region_msk |= BIT(i);  		kfree(*active_reg); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index a2203f661321..4c977ba9cd85 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -163,7 +163,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw,  static int iwl_request_firmware(struct iwl_drv *drv, bool first)  {  	const struct iwl_cfg *cfg = drv->trans->cfg; -	char tag[8];  	if (drv->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000 &&  	    (drv->trans->hw_rev_step != SILICON_B_STEP && @@ -174,13 +173,10 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)  		return -EINVAL;  	} -	if (first) { +	if (first)  		drv->fw_index = cfg->ucode_api_max; -		sprintf(tag, "%d", drv->fw_index); -	} else { +	else  		drv->fw_index--; -		sprintf(tag, "%d", drv->fw_index); -	}  	if (drv->fw_index < cfg->ucode_api_min) {  		IWL_ERR(drv, "no suitable firmware found!\n"); @@ -200,8 +196,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)  		return -ENOENT;  	} -	snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", -		 cfg->fw_name_pre, tag); +	snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%d.ucode", +		 cfg->fw_name_pre, drv->fw_index);  	IWL_DEBUG_FW_INFO(drv, "attempting to load firmware '%s'\n",  			  drv->firmware_name); @@ -1971,3 +1967,6 @@ MODULE_PARM_DESC(remove_when_gone,  module_param_named(disable_11ax, iwlwifi_mod_params.disable_11ax, bool,  		   S_IRUGO);  MODULE_PARM_DESC(disable_11ax, "Disable HE capabilities (default: false)"); + +module_param_named(disable_11be, iwlwifi_mod_params.disable_11be, bool, 0444); +MODULE_PARM_DESC(disable_11be, "Disable EHT capabilities (default: false)"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index 0efffb6eeb1e..baa643386018 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -1,6 +1,6 @@  /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */  /* - * Copyright (C) 2005-2014, 2018 Intel Corporation + * Copyright (C) 2005-2014, 2018, 2020-2022 Intel Corporation   * Copyright (C) 2015 Intel Mobile Communications GmbH   */  #ifndef __iwl_eeprom_parse_h__ @@ -31,6 +31,7 @@ struct iwl_nvm_data {  	bool sku_cap_amt_enable;  	bool sku_cap_ipan_enable;  	bool sku_cap_mimo_disabled; +	bool sku_cap_11be_enable;  	u16 radio_cfg_type;  	u8 radio_cfg_step; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index d0b4d02bdab9..1cf26ab4f488 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -62,6 +62,7 @@ enum iwl_uapsd_disable {   * @disable_11ac: disable VHT capabilities, default = false.   * @remove_when_gone: remove an inaccessible device from the PCIe bus.   * @enable_ini: enable new FW debug infratructure (INI TLVs) + * @disable_11be: disable EHT capabilities, default = false.   */  struct iwl_mod_params {  	int swcrypto; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 9040da3dcce3..aa8e08487b52 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -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-2022 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -546,7 +546,7 @@ static const u8 iwl_vendor_caps[] = {  	0x00  }; -static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { +static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = {  	{  		.types_mask = BIT(NL80211_IFTYPE_STATION),  		.he_cap = { @@ -571,10 +571,6 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {  					IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU |  					IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS |  					IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, -				.phy_cap_info[0] = -					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | -					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | -					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G,  				.phy_cap_info[1] =  					IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |  					IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | @@ -631,6 +627,78 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {  			 */  			.ppe_thres = {0x61, 0x1c, 0xc7, 0x71},  		}, +		.eht_cap = { +			.has_eht = true, +			.eht_cap_elem = { +				.mac_cap_info[0] = +					IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | +					IEEE80211_EHT_MAC_CAP0_OM_CONTROL | +					IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | +					IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2, +				.phy_cap_info[0] = +					IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | +					IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | +					IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | +					IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | +					IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, +				.phy_cap_info[1] = +					IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK  | +					IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | +					IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, +				.phy_cap_info[3] = +					IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | +					IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | +					IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | +					IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | +					IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | +					IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | +					IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, + +				.phy_cap_info[4] = +					IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | +					IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | +					IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI, +				.phy_cap_info[5] = +					IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | +					IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | +					IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | +					IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT, +				.phy_cap_info[6] = +					IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | +					IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, +				.phy_cap_info[8] = +					IEEE80211_EHT_PHY_CAP8_RX_1024QAM_WIDER_BW_DL_OFDMA | +					IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA, +			}, + +			/* For all MCS and bandwidth, set 2 NSS for both Tx and +			 * Rx - note we don't set the only_20mhz, but due to this +			 * being a union, it gets set correctly anyway. +			 */ +			.eht_mcs_nss_supp = { +				.bw._80 = { +					.rx_tx_mcs9_max_nss = 0x22, +					.rx_tx_mcs11_max_nss = 0x22, +					.rx_tx_mcs13_max_nss = 0x22, +				}, +				.bw._160 = { +					.rx_tx_mcs9_max_nss = 0x22, +					.rx_tx_mcs11_max_nss = 0x22, +					.rx_tx_mcs13_max_nss = 0x22, +				}, +				.bw._320 = { +					.rx_tx_mcs9_max_nss = 0x22, +					.rx_tx_mcs11_max_nss = 0x22, +					.rx_tx_mcs13_max_nss = 0x22, +				}, +			}, + +			/* +			 * PPE thresholds for NSS = 2, and RU index bitmap set +			 * to 0xc. +			 */ +			.eht_ppe_thres = {0xc1, 0x0e, 0xe0 } +		},  	},  	{  		.types_mask = BIT(NL80211_IFTYPE_AP), @@ -644,9 +712,6 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {  					IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,  				.mac_cap_info[3] =  					IEEE80211_HE_MAC_CAP3_OMI_CONTROL, -				.phy_cap_info[0] = -					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | -					IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G,  				.phy_cap_info[1] =  					IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD,  				.phy_cap_info[2] = @@ -687,6 +752,49 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {  			 */  			.ppe_thres = {0x61, 0x1c, 0xc7, 0x71},  		}, +		.eht_cap = { +			.has_eht = true, +			.eht_cap_elem = { +				.mac_cap_info[0] = +					IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | +					IEEE80211_EHT_MAC_CAP0_OM_CONTROL | +					IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | +					IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2, +				.phy_cap_info[0] = +					IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | +					IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI, +				.phy_cap_info[5] = +					IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT, +			}, + +			/* For all MCS and bandwidth, set 2 NSS for both Tx and +			 * Rx - note we don't set the only_20mhz, but due to this +			 * being a union, it gets set correctly anyway. +			 */ +			.eht_mcs_nss_supp = { +				.bw._80 = { +					.rx_tx_mcs9_max_nss = 0x22, +					.rx_tx_mcs11_max_nss = 0x22, +					.rx_tx_mcs13_max_nss = 0x22, +				}, +				.bw._160 = { +					.rx_tx_mcs9_max_nss = 0x22, +					.rx_tx_mcs11_max_nss = 0x22, +					.rx_tx_mcs13_max_nss = 0x22, +				}, +				.bw._320 = { +					.rx_tx_mcs9_max_nss = 0x22, +					.rx_tx_mcs11_max_nss = 0x22, +					.rx_tx_mcs13_max_nss = 0x22, +				}, +			}, + +			/* +			 * PPE thresholds for NSS = 2, and RU index bitmap set +			 * to 0xc. +			 */ +			.eht_ppe_thres = {0xc1, 0x0e, 0xe0 } +		},  	},  }; @@ -738,6 +846,7 @@ static void iwl_init_he_6ghz_capa(struct iwl_trans *trans,  static void  iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, +			 struct iwl_nvm_data *data,  			 struct ieee80211_supported_band *sband,  			 struct ieee80211_sband_iftype_data *iftype_data,  			 u8 tx_chains, u8 rx_chains, @@ -745,6 +854,9 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,  {  	bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); +	if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) +		iftype_data->eht_cap.has_eht = false; +  	/* Advertise an A-MPDU exponent extension based on  	 * operating band  	 */ @@ -755,9 +867,30 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,  		iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |=  			IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; -	if (is_ap && iwlwifi_mod_params.nvm_file) +	switch (sband->band) { +	case NL80211_BAND_2GHZ:  		iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= -			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; +			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; +		iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] |= +			u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454, +				       IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); +		break; +	case NL80211_BAND_6GHZ: +		if (!is_ap || iwlwifi_mod_params.nvm_file) +			iftype_data->eht_cap.eht_cap_elem.phy_cap_info[0] |= +				IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; +		fallthrough; +	case NL80211_BAND_5GHZ: +		iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= +			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; +		if (!is_ap || iwlwifi_mod_params.nvm_file) +			iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= +				IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; +		break; +	default: +		WARN_ON(1); +		break; +	}  	if ((tx_chains & rx_chains) == ANT_AB) {  		iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= @@ -765,19 +898,44 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,  		iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |=  			IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |  			IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; -		if (!is_ap) +		if (!is_ap) {  			iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |=  				IEEE80211_HE_PHY_CAP7_MAX_NC_2; -	} else if (!is_ap) { -		/* If not 2x2, we need to indicate 1x1 in the -		 * Midamble RX Max NSTS - but not for AP mode -		 */ -		iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &= -			~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; -		iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= -			~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; -		iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= -			IEEE80211_HE_PHY_CAP7_MAX_NC_1; + +			if (iftype_data->eht_cap.has_eht) { +				/* +				 * Set the number of sounding dimensions for each +				 * bandwidth to 1 to indicate the maximal supported +				 * value of TXVECTOR parameter NUM_STS of 2 +				 */ +				iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] |= 0x49; + +				/* +				 * Set the MAX NC to 1 to indicate sounding feedback of +				 * 2 supported by the beamfomee. +				 */ +				iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] |= 0x10; +			} +		} +	} else { +		if (iftype_data->eht_cap.has_eht) { +			struct ieee80211_eht_mcs_nss_supp *mcs_nss = +				&iftype_data->eht_cap.eht_mcs_nss_supp; + +			memset(mcs_nss, 0x11, sizeof(*mcs_nss)); +		} + +		if (!is_ap) { +			/* If not 2x2, we need to indicate 1x1 in the +			 * Midamble RX Max NSTS - but not for AP mode +			 */ +			iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &= +				~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; +			iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= +				~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; +			iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= +				IEEE80211_HE_PHY_CAP7_MAX_NC_1; +		}  	}  	switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { @@ -792,6 +950,29 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,  		break;  	} +	if (CSR_HW_REV_TYPE(trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && +	    iftype_data->eht_cap.has_eht) { +		iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] &= +			~(IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | +			  IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | +			  IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2); +		iftype_data->eht_cap.eht_cap_elem.phy_cap_info[3] &= +			~(IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | +			  IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | +			  IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | +			  IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | +			  IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | +			  IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK); +		iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] &= +			~(IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | +			  IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP); +		iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] &= +			~IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK; +		iftype_data->eht_cap.eht_cap_elem.phy_cap_info[6] &= +			~(IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | +			  IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP); +	} +  	if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT))  		iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |=  			IEEE80211_HE_MAC_CAP2_BCAST_TWT; @@ -816,8 +997,8 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,  	if (WARN_ON(sband->iftype_data))  		return; -	BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_capa)); -	BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_capa)); +	BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_eht_capa)); +	BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_eht_capa));  	switch (sband->band) {  	case NL80211_BAND_2GHZ: @@ -832,13 +1013,13 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,  		return;  	} -	memcpy(iftype_data, iwl_he_capa, sizeof(iwl_he_capa)); +	memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa));  	sband->iftype_data = iftype_data; -	sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa); +	sband->n_iftype_data = ARRAY_SIZE(iwl_he_eht_capa);  	for (i = 0; i < sband->n_iftype_data; i++) -		iwl_nvm_fixup_sband_iftd(trans, sband, &iftype_data[i], +		iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i],  					 tx_chains, rx_chains, fw);  	iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains); @@ -1783,6 +1964,8 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,  		!!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED);  	nvm->sku_cap_mimo_disabled =  		!!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); +	if (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) +		nvm->sku_cap_11be_enable = true;  	/* Initialize PHY sku data */  	nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 157d1f31c487..62ce116d3783 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -368,6 +368,7 @@ enum {  #define CNVR_AUX_MISC_CHIP				0xA2B800  #define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM		0xA29890  #define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR	0xA29938 +#define CNVI_SCU_SEQ_DATA_DW9				0xA27488  #define PREG_AUX_BUS_WPROT_0		0xA04CC0 @@ -377,6 +378,7 @@ enum {  #define PREG_PRPH_WPROT_22000		0xA04D00  #define SB_MODIFY_CFG_FLAG		0xA03088 +#define SB_CFG_RESIDES_IN_OTP_MASK	0x10  #define SB_CPU_1_STATUS			0xA01E30  #define SB_CPU_2_STATUS			0xA01E34  #define UMAG_SB_CPU_1_STATUS		0xA038C0 @@ -500,4 +502,7 @@ enum {  #define REG_OTP_MINOR 0xA0333C +#define WFPM_LMAC2_PD_NOTIFICATION 0xA033CC +#define WFPM_LMAC2_PD_RE_READ BIT(31) +  #endif				/* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index d659ccd065f7..9aced3e44bc2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -976,6 +976,8 @@ struct iwl_trans_txqs {   * @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_crf_id a u32 with the device CRF ID + * @hw_cdb_id a u32 with the device CDB 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. @@ -999,6 +1001,8 @@ struct iwl_trans_txqs {   *	This mode is set dynamically, depending on the WoWLAN values   *	configured from the userspace at runtime.   * @iwl_trans_txqs: transport tx queues data. + * @mbx_addr_0_step: step address data 0 + * @mbx_addr_1_step: step address data 1   */  struct iwl_trans {  	bool csme_own; @@ -1015,6 +1019,8 @@ struct iwl_trans {  	u32 hw_rev;  	u32 hw_rev_step;  	u32 hw_rf_id; +	u32 hw_crf_id; +	u32 hw_cdb_id;  	u32 hw_id;  	char hw_id_str[52];  	u32 sku_id[3]; @@ -1053,6 +1059,8 @@ struct iwl_trans {  	const char *name;  	struct iwl_trans_txqs txqs; +	u32 mbx_addr_0_step; +	u32 mbx_addr_1_step;  	/* pointer to trans specific struct */  	/*Ensure that this pointer will always be aligned to sizeof pointer */ @@ -1542,5 +1550,6 @@ void iwl_trans_free(struct iwl_trans *trans);  ******************************************************/  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);  #endif /* __iwl_trans_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h index 67122cfa2292..ae66192feefe 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h +++ b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0-only */  /*   * Copyright (C) 2021 Intel Corporation   */ @@ -13,7 +13,7 @@  /**   * DOC: Introduction   * - * iwlmei is the kernel module that is in charge of the commnunication between + * iwlmei is the kernel module that is in charge of the communication between   * the iwlwifi driver and the CSME firmware's WLAN driver. This communication   * uses the SAP protocol defined in another file.   * iwlwifi can request or release ownership on the WiFi device through iwlmei. @@ -220,6 +220,7 @@ struct iwl_mei_nvm {  /**   * enum iwl_mei_pairwise_cipher - cipher for UCAST key   * @IWL_MEI_CIPHER_NONE: none + * @IWL_MEI_CIPHER_TKIP: tkip   * @IWL_MEI_CIPHER_CCMP: ccmp   * @IWL_MEI_CIPHER_GCMP: gcmp   * @IWL_MEI_CIPHER_GCMP_256: gcmp 256 @@ -228,6 +229,7 @@ struct iwl_mei_nvm {   */  enum iwl_mei_pairwise_cipher {  	IWL_MEI_CIPHER_NONE	= 0, +	IWL_MEI_CIPHER_TKIP	= 2,  	IWL_MEI_CIPHER_CCMP	= 4,  	IWL_MEI_CIPHER_GCMP	= 8,  	IWL_MEI_CIPHER_GCMP_256 = 9, @@ -346,7 +348,7 @@ void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill);  /**   * iwl_mei_set_nic_info() - set mac address   * @mac_address: mac address to set - * @nvm_address: NVM mac adsress to set + * @nvm_address: NVM mac address to set   *   * This function must be called upon mac address change.   */ @@ -446,9 +448,25 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,  void iwl_mei_host_disassociated(void);  /** - * iwl_mei_device_down() - must be called when the device is down + * iwl_mei_device_state() - must be called when the device changes up/down state + * @up: true if the device is up, false otherwise.   */ -void iwl_mei_device_down(void); +void iwl_mei_device_state(bool up); + +/** + * iwl_mei_pldr_req() - must be called before loading the fw + * + * Return: 0 if the PLDR flow was successful and the fw can be loaded, negative + *	value otherwise. + */ +int iwl_mei_pldr_req(void); + +/** + * iwl_mei_alive_notif() - must be called when alive notificaiton is received + * @success: true if received alive notification, false if waiting for the + *	notificaiton timed out. + */ +void iwl_mei_alive_notif(bool success);  #else @@ -497,7 +515,13 @@ static inline void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_  static inline void iwl_mei_host_disassociated(void)  {} -static inline void iwl_mei_device_down(void) +static inline void iwl_mei_device_state(bool up) +{} + +static inline int iwl_mei_pldr_req(void) +{ return 0; } + +static inline void iwl_mei_alive_notif(bool success)  {}  #endif /* CONFIG_IWLMEI */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c index 357f14626cf4..67dfb77fedf7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/main.c +++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c @@ -147,9 +147,15 @@ struct iwl_mei_filters {   *	to send CSME_OWNERSHIP_CONFIRMED when the driver completes its down   *	flow.   * @link_prot_state: true when we are in link protection PASSIVE + * @device_down: true if the device is down. Used to remember to send + *	CSME_OWNERSHIP_CONFIRMED when the driver is already down.   * @csa_throttle_end_wk: used when &csa_throttled is true + * @pldr_wq: the wait queue for PLDR flow + * @pldr_active: PLDR flow is in progress   * @data_q_lock: protects the access to the data queues which are   *	accessed without the mutex. + * @netdev_work: used to defer registering and unregistering of the netdev to + *	avoid taking the rtnl lock in the SAP messages handlers.   * @sap_seq_no: the sequence number for the SAP messages   * @seq_no: the sequence number for the SAP messages   * @dbgfs_dir: the debugfs dir entry @@ -167,8 +173,12 @@ struct iwl_mei {  	bool csa_throttled;  	bool csme_taking_ownership;  	bool link_prot_state; +	bool device_down;  	struct delayed_work csa_throttle_end_wk; +	wait_queue_head_t pldr_wq; +	bool pldr_active;  	spinlock_t data_q_lock; +	struct work_struct netdev_work;  	atomic_t sap_seq_no;  	atomic_t seq_no; @@ -588,13 +598,38 @@ static rx_handler_result_t iwl_mei_rx_handler(struct sk_buff **pskb)  	return res;  } +static void iwl_mei_netdev_work(struct work_struct *wk) +{ +	struct iwl_mei *mei = +		container_of(wk, struct iwl_mei, netdev_work); +	struct net_device *netdev; + +	/* +	 * First take rtnl and only then the mutex to avoid an ABBA +	 * with iwl_mei_set_netdev() +	 */ +	rtnl_lock(); +	mutex_lock(&iwl_mei_mutex); + +	netdev = rcu_dereference_protected(iwl_mei_cache.netdev, +					   lockdep_is_held(&iwl_mei_mutex)); +	if (netdev) { +		if (mei->amt_enabled) +			netdev_rx_handler_register(netdev, iwl_mei_rx_handler, +						   mei); +		else +			netdev_rx_handler_unregister(netdev); +	} + +	mutex_unlock(&iwl_mei_mutex); +	rtnl_unlock(); +} +  static void  iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,  			   const struct iwl_sap_me_msg_start_ok *rsp,  			   ssize_t len)  { -	struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); -  	if (len != sizeof(*rsp)) {  		dev_err(&cldev->dev,  			"got invalid SAP_ME_MSG_START_OK from CSME firmware\n"); @@ -613,13 +648,10 @@ iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,  	mutex_lock(&iwl_mei_mutex);  	set_bit(IWL_MEI_STATUS_SAP_CONNECTED, &iwl_mei_status); -	/* wifi driver has registered already */ -	if (iwl_mei_cache.ops) { -		iwl_mei_send_sap_msg(mei->cldev, -				     SAP_MSG_NOTIF_WIFIDR_UP); -		iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv); -	} - +	/* +	 * We'll receive AMT_STATE SAP message in a bit and +	 * that will continue the flow +	 */  	mutex_unlock(&iwl_mei_mutex);  } @@ -712,6 +744,13 @@ static void iwl_mei_set_init_conf(struct iwl_mei *mei)  		.val = cpu_to_le32(iwl_mei_cache.rf_kill),  	}; +	/* wifi driver has registered already */ +	if (iwl_mei_cache.ops) { +		iwl_mei_send_sap_msg(mei->cldev, +				     SAP_MSG_NOTIF_WIFIDR_UP); +		iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv); +	} +  	iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WHO_OWNS_NIC);  	if (iwl_mei_cache.conn_info) { @@ -738,38 +777,23 @@ static void iwl_mei_handle_amt_state(struct mei_cl_device *cldev,  				     const struct iwl_sap_msg_dw *dw)  {  	struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); -	struct net_device *netdev; -	/* -	 * First take rtnl and only then the mutex to avoid an ABBA -	 * with iwl_mei_set_netdev() -	 */ -	rtnl_lock();  	mutex_lock(&iwl_mei_mutex); -	netdev = rcu_dereference_protected(iwl_mei_cache.netdev, -					   lockdep_is_held(&iwl_mei_mutex)); -  	if (mei->amt_enabled == !!le32_to_cpu(dw->val))  		goto out;  	mei->amt_enabled = dw->val; -	if (mei->amt_enabled) { -		if (netdev) -			netdev_rx_handler_register(netdev, iwl_mei_rx_handler, mei); - +	if (mei->amt_enabled)  		iwl_mei_set_init_conf(mei); -	} else { -		if (iwl_mei_cache.ops) -			iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false); -		if (netdev) -			netdev_rx_handler_unregister(netdev); -	} +	else if (iwl_mei_cache.ops) +		iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false); + +	schedule_work(&mei->netdev_work);  out:  	mutex_unlock(&iwl_mei_mutex); -	rtnl_unlock();  }  static void iwl_mei_handle_nic_owner(struct mei_cl_device *cldev, @@ -798,14 +822,18 @@ static void iwl_mei_handle_csme_taking_ownership(struct mei_cl_device *cldev,  	mei->got_ownership = false; -	/* -	 * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi driver -	 * is finished taking the device down. -	 */ -	mei->csme_taking_ownership = true; +	if (iwl_mei_cache.ops && !mei->device_down) { +		/* +		 * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi +		 * driver is finished taking the device down. +		 */ +		mei->csme_taking_ownership = true; -	if (iwl_mei_cache.ops)  		iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true); +	} else { +		iwl_mei_send_sap_msg(cldev, +				     SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED); +	}  }  static void iwl_mei_handle_nvm(struct mei_cl_device *cldev, @@ -857,6 +885,15 @@ static void iwl_mei_handle_rx_host_own_req(struct mei_cl_device *cldev,  		iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false);  } +static void iwl_mei_handle_pldr_ack(struct mei_cl_device *cldev, +				    const struct iwl_sap_pldr_ack_data *ack) +{ +	struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + +	mei->pldr_active = le32_to_cpu(ack->status) == SAP_PLDR_STATUS_SUCCESS; +	wake_up_all(&mei->pldr_wq); +} +  static void iwl_mei_handle_ping(struct mei_cl_device *cldev,  				const struct iwl_sap_hdr *hdr)  { @@ -937,6 +974,8 @@ static void iwl_mei_handle_sap_msg(struct mei_cl_device *cldev,  			iwl_mei_handle_can_release_ownership, 0);  	SAP_MSG_HANDLER(CSME_TAKING_OWNERSHIP,  			iwl_mei_handle_csme_taking_ownership, 0); +	SAP_MSG_HANDLER(PLDR_ACK, iwl_mei_handle_pldr_ack, +			sizeof(struct iwl_sap_pldr_ack_data));  	default:  	/*  	 * This is not really an error, there are message that we decided @@ -1313,10 +1352,17 @@ out:  }  EXPORT_SYMBOL_GPL(iwl_mei_get_nvm); -int iwl_mei_get_ownership(void) +#define IWL_MEI_PLDR_NUM_RETRIES	3 + +int iwl_mei_pldr_req(void)  {  	struct iwl_mei *mei;  	int ret; +	struct iwl_sap_pldr_data msg = { +		.hdr.type = cpu_to_le16(SAP_MSG_NOTIF_PLDR), +		.hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), +	}; +	int i;  	mutex_lock(&iwl_mei_mutex); @@ -1338,22 +1384,34 @@ int iwl_mei_get_ownership(void)  		goto out;  	} -	if (mei->got_ownership) { -		ret = 0; -		goto out; +	for (i = 0; i < IWL_MEI_PLDR_NUM_RETRIES; i++) { +		ret = iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); +		mutex_unlock(&iwl_mei_mutex); +		if (ret) +			return ret; + +		ret = wait_event_timeout(mei->pldr_wq, mei->pldr_active, HZ / 2); +		if (ret) +			break; + +		/* Take the mutex for the next iteration */ +		mutex_lock(&iwl_mei_mutex);  	} -	ret = iwl_mei_send_sap_msg(mei->cldev, -				   SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP);  	if (ret) -		goto out; +		return 0; +	ret = -ETIMEDOUT; +out:  	mutex_unlock(&iwl_mei_mutex); +	return ret; +} +EXPORT_SYMBOL_GPL(iwl_mei_pldr_req); -	ret = wait_event_timeout(mei->get_ownership_wq, -				 mei->got_ownership, HZ / 2); -	if (!ret) -		return -ETIMEDOUT; +int iwl_mei_get_ownership(void) +{ +	struct iwl_mei *mei; +	int ret;  	mutex_lock(&iwl_mei_mutex); @@ -1370,14 +1428,59 @@ int iwl_mei_get_ownership(void)  		goto out;  	} -	ret = !mei->got_ownership; +	if (!mei->amt_enabled) { +		ret = 0; +		goto out; +	} + +	if (mei->got_ownership) { +		ret = 0; +		goto out; +	} +	ret = iwl_mei_send_sap_msg(mei->cldev, +				   SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP); +	if (ret) +		goto out; + +	mutex_unlock(&iwl_mei_mutex); + +	ret = wait_event_timeout(mei->get_ownership_wq, +				 mei->got_ownership, HZ / 2); +	return (!ret) ? -ETIMEDOUT : 0;  out:  	mutex_unlock(&iwl_mei_mutex);  	return ret;  }  EXPORT_SYMBOL_GPL(iwl_mei_get_ownership); +void iwl_mei_alive_notif(bool success) +{ +	struct iwl_mei *mei; +	struct iwl_sap_pldr_end_data msg = { +		.hdr.type = cpu_to_le16(SAP_MSG_NOTIF_PLDR_END), +		.hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), +		.status = success ? cpu_to_le32(SAP_PLDR_STATUS_SUCCESS) : +			cpu_to_le32(SAP_PLDR_STATUS_FAILURE), +	}; + +	mutex_lock(&iwl_mei_mutex); + +	if (!iwl_mei_is_connected()) +		goto out; + +	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); +	if (!mei || !mei->pldr_active) +		goto out; + +	mei->pldr_active = false; + +	iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); +out: +	mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_alive_notif); +  void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,  			     const struct iwl_mei_colloc_info *colloc_info)  { @@ -1413,10 +1516,7 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,  	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); -	if (!mei) -		goto out; - -	if (!mei->amt_enabled) +	if (!mei && !mei->amt_enabled)  		goto out;  	iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); @@ -1435,7 +1535,7 @@ void iwl_mei_host_disassociated(void)  	struct iwl_sap_notif_host_link_down msg = {  		.hdr.type = cpu_to_le16(SAP_MSG_NOTIF_HOST_LINK_DOWN),  		.hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), -		.type = HOST_LINK_DOWN_TYPE_LONG, +		.type = HOST_LINK_DOWN_TYPE_TEMPORARY,  	};  	mutex_lock(&iwl_mei_mutex); @@ -1445,7 +1545,7 @@ void iwl_mei_host_disassociated(void)  	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); -	if (!mei) +	if (!mei && !mei->amt_enabled)  		goto out;  	iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); @@ -1481,7 +1581,7 @@ void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill)  	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); -	if (!mei) +	if (!mei && !mei->amt_enabled)  		goto out;  	iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); @@ -1510,7 +1610,7 @@ void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address)  	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); -	if (!mei) +	if (!mei && !mei->amt_enabled)  		goto out;  	iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); @@ -1538,7 +1638,7 @@ void iwl_mei_set_country_code(u16 mcc)  	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); -	if (!mei) +	if (!mei && !mei->amt_enabled)  		goto out;  	iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); @@ -1564,7 +1664,7 @@ void iwl_mei_set_power_limit(const __le16 *power_limit)  	mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); -	if (!mei) +	if (!mei && !mei->amt_enabled)  		goto out;  	memcpy(msg.sar_chain_info_table, power_limit, sizeof(msg.sar_chain_info_table)); @@ -1616,7 +1716,7 @@ out:  }  EXPORT_SYMBOL_GPL(iwl_mei_set_netdev); -void iwl_mei_device_down(void) +void iwl_mei_device_state(bool up)  {  	struct iwl_mei *mei; @@ -1630,7 +1730,9 @@ void iwl_mei_device_down(void)  	if (!mei)  		goto out; -	if (!mei->csme_taking_ownership) +	mei->device_down = !up; + +	if (up || !mei->csme_taking_ownership)  		goto out;  	iwl_mei_send_sap_msg(mei->cldev, @@ -1639,7 +1741,7 @@ void iwl_mei_device_down(void)  out:  	mutex_unlock(&iwl_mei_mutex);  } -EXPORT_SYMBOL_GPL(iwl_mei_device_down); +EXPORT_SYMBOL_GPL(iwl_mei_device_state);  int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)  { @@ -1669,8 +1771,9 @@ int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)  		/* we have already a SAP connection */  		if (iwl_mei_is_connected()) { -			iwl_mei_send_sap_msg(mei->cldev, -					     SAP_MSG_NOTIF_WIFIDR_UP); +			if (mei->amt_enabled) +				iwl_mei_send_sap_msg(mei->cldev, +						     SAP_MSG_NOTIF_WIFIDR_UP);  			ops->rfkill(priv, mei->link_prot_state);  		}  	} @@ -1817,10 +1920,13 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,  	INIT_DELAYED_WORK(&mei->csa_throttle_end_wk,  			  iwl_mei_csa_throttle_end_wk);  	init_waitqueue_head(&mei->get_ownership_wq); +	init_waitqueue_head(&mei->pldr_wq);  	spin_lock_init(&mei->data_q_lock); +	INIT_WORK(&mei->netdev_work, iwl_mei_netdev_work);  	mei_cldev_set_drvdata(cldev, mei);  	mei->cldev = cldev; +	mei->device_down = true;  	do {  		ret = iwl_mei_alloc_shared_mem(cldev); @@ -1857,7 +1963,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,  	iwl_mei_dbgfs_register(mei);  	/* -	 * We now have a Rx function in place, start the SAP procotol +	 * We now have a Rx function in place, start the SAP protocol  	 * we expect to get the SAP_ME_MSG_START_OK response later on.  	 */  	mutex_lock(&iwl_mei_mutex); @@ -1884,6 +1990,7 @@ free:  }  #define SEND_SAP_MAX_WAIT_ITERATION 10 +#define IWLMEI_DEVICE_DOWN_WAIT_ITERATION 50  static void iwl_mei_remove(struct mei_cl_device *cldev)  { @@ -1894,8 +2001,26 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)  	 * We are being removed while the bus is active, it means we are  	 * going to suspend/ shutdown, so the NIC will disappear.  	 */ -	if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops) -		iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv); +	if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops) { +		unsigned int iter = IWLMEI_DEVICE_DOWN_WAIT_ITERATION; +		bool down = false; + +		/* +		 * In case of suspend, wait for the mac to stop and don't remove +		 * the interface. This will allow the interface to come back +		 * on resume. +		 */ +		while (!down && iter--) { +			mdelay(1); + +			mutex_lock(&iwl_mei_mutex); +			down = mei->device_down; +			mutex_unlock(&iwl_mei_mutex); +		} + +		if (!down) +			iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv); +	}  	if (rcu_access_pointer(iwl_mei_cache.netdev)) {  		struct net_device *dev; @@ -1921,29 +2046,32 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)  	mutex_lock(&iwl_mei_mutex); -	/* -	 * Tell CSME that we are going down so that it won't access the -	 * memory anymore, make sure this message goes through immediately. -	 */ -	mei->csa_throttled = false; -	iwl_mei_send_sap_msg(mei->cldev, -			     SAP_MSG_NOTIF_HOST_GOES_DOWN); +	if (mei->amt_enabled) { +		/* +		 * Tell CSME that we are going down so that it won't access the +		 * memory anymore, make sure this message goes through immediately. +		 */ +		mei->csa_throttled = false; +		iwl_mei_send_sap_msg(mei->cldev, +				     SAP_MSG_NOTIF_HOST_GOES_DOWN); -	for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) { -		if (!iwl_mei_host_to_me_data_pending(mei)) -			break; +		for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) { +			if (!iwl_mei_host_to_me_data_pending(mei)) +				break; -		msleep(5); -	} +			msleep(20); +		} -	/* -	 * If we couldn't make sure that CSME saw the HOST_GOES_DOWN message, -	 * it means that it will probably keep reading memory that we are going -	 * to unmap and free, expect IOMMU error messages. -	 */ -	if (i == SEND_SAP_MAX_WAIT_ITERATION) -		dev_err(&mei->cldev->dev, -			"Couldn't get ACK from CSME on HOST_GOES_DOWN message\n"); +		/* +		 * If we couldn't make sure that CSME saw the HOST_GOES_DOWN +		 * message, it means that it will probably keep reading memory +		 * that we are going to unmap and free, expect IOMMU error +		 * messages. +		 */ +		if (i == SEND_SAP_MAX_WAIT_ITERATION) +			dev_err(&mei->cldev->dev, +				"Couldn't get ACK from CSME on HOST_GOES_DOWN message\n"); +	}  	mutex_unlock(&iwl_mei_mutex); @@ -1976,6 +2104,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)  	 */  	cancel_work_sync(&mei->send_csa_msg_wk);  	cancel_delayed_work_sync(&mei->csa_throttle_end_wk); +	cancel_work_sync(&mei->netdev_work);  	/*  	 * If someone waits for the ownership, let him know that we are going @@ -1983,6 +2112,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)  	 * the device.  	 */  	wake_up_all(&mei->get_ownership_wq); +	wake_up_all(&mei->pldr_wq);  	mutex_lock(&iwl_mei_mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mei/net.c b/drivers/net/wireless/intel/iwlwifi/mei/net.c index 3472167c8370..eac46d1a397a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/net.c +++ b/drivers/net/wireless/intel/iwlwifi/mei/net.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0-only  /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation   */  #include <uapi/linux/if_ether.h> @@ -337,10 +337,14 @@ rx_handler_result_t iwl_mei_rx_filter(struct sk_buff *orig_skb,  	if (!*pass_to_csme)  		return RX_HANDLER_PASS; -	if (ret == RX_HANDLER_PASS) +	if (ret == RX_HANDLER_PASS) {  		skb = skb_copy(orig_skb, GFP_ATOMIC); -	else + +		if (!skb) +			return RX_HANDLER_PASS; +	} else {  		skb = orig_skb; +	}  	/* CSME wants the MAC header as well, push it back */  	skb_push(skb, skb->data - skb_mac_header(skb)); diff --git a/drivers/net/wireless/intel/iwlwifi/mei/sap.h b/drivers/net/wireless/intel/iwlwifi/mei/sap.h index be1456dea484..3b56637b9697 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/sap.h +++ b/drivers/net/wireless/intel/iwlwifi/mei/sap.h @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0-only */  /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021 - 2022 Intel Corporation   */  #ifndef __sap_h__ @@ -25,7 +25,7 @@   *   * Since this messaging system cannot support high amounts of   * traffic, iwlwifi and the CSME firmware's WLAN driver have an - * addtional communication pipe to exchange information. The body + * additional communication pipe to exchange information. The body   * of the message is copied to a shared area and the message that   * goes over the ME interface just signals the other side   * that a new message is waiting in the shared area. The ME @@ -55,7 +55,7 @@  /**   * DOC: Host and driver state messages   * - * In order to let CSME konw about the host state and the host driver state, + * In order to let CSME know about the host state and the host driver state,   * the host sends messages that let CSME know about the host's state.   * When the host driver is loaded, the host sends %SAP_MSG_NOTIF_WIFIDR_UP.   * When the host driver is unloaded, the host sends %SAP_MSG_NOTIF_WIFIDR_DOWN. @@ -76,7 +76,7 @@   * DOC: Ownership   *   * The device can be controlled either by the CSME firmware or - * by the host driver: iwlwifi. There is a negotiaion between + * by the host driver: iwlwifi. There is a negotiation between   * those two entities to determine who controls (or owns) the   * device. Since the CSME can control the device even when the   * OS is not working or even missing, the CSME can request the @@ -136,7 +136,7 @@ enum iwl_sap_me_msg_id {   * struct iwl_sap_me_msg_hdr - the header of the ME message   * @type: the type of the message, see &enum iwl_sap_me_msg_id.   * @seq_num: a sequence number used for debug only. - * @len: the length of the mssage. + * @len: the length of the message.   */  struct iwl_sap_me_msg_hdr {  	__le32 type; @@ -203,6 +203,7 @@ struct iwl_sap_me_msg_start_ok {   * @SAP_MSG_NOTIF_NIC_OWNER: Payload is a DW. See &enum iwl_sap_nic_owner.   * @SAP_MSG_NOTIF_CSME_CONN_STATUS: See &struct iwl_sap_notif_conn_status.   * @SAP_MSG_NOTIF_NVM: See &struct iwl_sap_nvm. + * @SAP_MSG_NOTIF_PLDR_ACK: See &struct iwl_sap_pldr_ack_data.   * @SAP_MSG_NOTIF_FROM_CSME_MAX: Not used.   *   * @SAP_MSG_NOTIF_FROM_HOST_MIN: Not used. @@ -226,6 +227,8 @@ struct iwl_sap_me_msg_start_ok {   * @SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED: No payload.   * @SAP_MSG_NOTIF_SAR_LIMITS: See &struct iwl_sap_notif_sar_limits.   * @SAP_MSG_NOTIF_GET_NVM: No payload. Triggers %SAP_MSG_NOTIF_NVM. + * @SAP_MSG_NOTIF_PLDR: See &struct iwl_sap_pldr_data. + * @SAP_MSG_NOTIF_PLDR_END: See &struct iwl_sap_pldr_end_data.   * @SAP_MSG_NOTIF_FROM_HOST_MAX: Not used.   *   * @SAP_MSG_DATA_MIN: Not used. @@ -258,6 +261,8 @@ enum iwl_sap_msg {  	SAP_MSG_NOTIF_NIC_OWNER				= 511,  	SAP_MSG_NOTIF_CSME_CONN_STATUS			= 512,  	SAP_MSG_NOTIF_NVM				= 513, +	/* 514 - 517 not supported */ +	SAP_MSG_NOTIF_PLDR_ACK				= 518,  	SAP_MSG_NOTIF_FROM_CSME_MAX,  	SAP_MSG_NOTIF_FROM_HOST_MIN			= 1000, @@ -279,6 +284,9 @@ enum iwl_sap_msg {  	SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED		= 1015,  	SAP_MSG_NOTIF_SAR_LIMITS			= 1016,  	SAP_MSG_NOTIF_GET_NVM				= 1017, +	/* 1018 - 1023 not supported */ +	SAP_MSG_NOTIF_PLDR				= 1024, +	SAP_MSG_NOTIF_PLDR_END				= 1025,  	SAP_MSG_NOTIF_FROM_HOST_MAX,  	SAP_MSG_DATA_MIN				= 2000, @@ -334,12 +342,14 @@ enum iwl_sap_wifi_auth_type {  /**   * enum iwl_sap_wifi_cipher_alg   * @SAP_WIFI_CIPHER_ALG_NONE: TBD + * @SAP_WIFI_CIPHER_ALG_TKIP: TBD   * @SAP_WIFI_CIPHER_ALG_CCMP: TBD   * @SAP_WIFI_CIPHER_ALG_GCMP: TBD   * @SAP_WIFI_CIPHER_ALG_GCMP_256: TBD   */  enum iwl_sap_wifi_cipher_alg {  	SAP_WIFI_CIPHER_ALG_NONE	= IWL_MEI_CIPHER_NONE, +	SAP_WIFI_CIPHER_ALG_TKIP	= IWL_MEI_CIPHER_TKIP,  	SAP_WIFI_CIPHER_ALG_CCMP	= IWL_MEI_CIPHER_CCMP,  	SAP_WIFI_CIPHER_ALG_GCMP	= IWL_MEI_CIPHER_GCMP,  	SAP_WIFI_CIPHER_ALG_GCMP_256	= IWL_MEI_CIPHER_GCMP_256, @@ -730,4 +740,47 @@ struct iwl_sap_cb_data {  	u8 payload[];  }; +/** + * struct iwl_sap_pldr_data - payload of %SAP_MSG_NOTIF_PLDR + * @hdr: The SAP header. + * @version: SAP message version + */ +struct iwl_sap_pldr_data { +	struct iwl_sap_hdr hdr; +	__le32 version; +} __packed; + +/** + * enum iwl_sap_pldr_status - + * @SAP_PLDR_STATUS_SUCCESS: PLDR started/ended successfully + * @SAP_PLDR_STATUS_FAILURE: PLDR failed to start/end + */ +enum iwl_sap_pldr_status { +	SAP_PLDR_STATUS_SUCCESS	= 0, +	SAP_PLDR_STATUS_FAILURE	= 1, +}; + +/* + * struct iwl_sap_pldr_end_data - payload of %SAP_MSG_NOTIF_PLDR_END + * @hdr: The SAP header. + * @version: SAP message version + * @status: PLDR end status + */ +struct iwl_sap_pldr_end_data { +	struct iwl_sap_hdr hdr; +	__le32 version; +	__le32 status; +} __packed; + +/* + * struct iwl_sap_pldr_ack_data - payload of %SAP_MSG_NOTIF_PLDR_ACK + * @version: SAP message version + * @status: CSME accept/refuse to the PLDR request + */ +struct iwl_sap_pldr_ack_data { +	struct iwl_sap_hdr hdr; +	__le32 version; +	__le32 status; +} __packed; +  #endif /* __sap_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h b/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h index 83639c6225ca..15cb0bb4e9dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0-only */  /*   * Copyright(c) 2021        Intel Corporation   */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace.h b/drivers/net/wireless/intel/iwlwifi/mei/trace.h index 45ecb22ec84a..20ff836733bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/trace.h +++ b/drivers/net/wireless/intel/iwlwifi/mei/trace.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only +/* SPDX-License-Identifier: GPL-2.0-only */  /*   * Copyright(c) 2021        Intel Corporation   */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 11e814b7cad0..b28fcf0cf9cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -7,6 +7,7 @@ iwlmvm-y += power.o coex.o  iwlmvm-y += tt.o offloading.o tdls.o  iwlmvm-y += ftm-responder.o ftm-initiator.o  iwlmvm-y += rfi.o +iwlmvm-y += mld-key.o  iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o  iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o  iwlmvm-$(CONFIG_PM) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 919b1f478b4c..c5ad34b063df 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -599,6 +599,11 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw,  	switch (key->cipher) {  	default:  		return; +	case WLAN_CIPHER_SUITE_TKIP: +		if (!sta) +			data->kek_kck_cmd->gtk_cipher = +				cpu_to_le32(STA_KEY_FLG_TKIP); +		return;  	case WLAN_CIPHER_SUITE_BIP_GMAC_256:  	case WLAN_CIPHER_SUITE_BIP_GMAC_128:  		data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); @@ -610,13 +615,13 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw,  		if (!sta)  			data->kek_kck_cmd->gtk_cipher =  				cpu_to_le32(STA_KEY_FLG_CCM); -		break; +		return;  	case WLAN_CIPHER_SUITE_GCMP:  	case WLAN_CIPHER_SUITE_GCMP_256:  		if (!sta)  			data->kek_kck_cmd->gtk_cipher =  				cpu_to_le32(STA_KEY_FLG_GCMP); -		break; +		return;  	}  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 78d8b37eb71a..3779ac040ba0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -438,13 +438,6 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,  	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);  } -static inline char *iwl_dbgfs_is_match(char *name, char *buf) -{ -	int len = strlen(name); - -	return !strncmp(name, buf, len) ? buf + len : NULL; -} -  static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,  						 char __user *user_buf,  						 size_t count, loff_t *ppos) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 1e8123140973..85b99316d029 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -324,12 +324,12 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file,  		pos += scnprintf(buf + pos, bufsz - pos,  				 "Use geographic profile %d\n", tbl_idx);  		pos += scnprintf(buf + pos, bufsz - pos, -				 "2.4GHz:\n\tChain A offset: %hhu dBm\n\tChain B offset: %hhu dBm\n\tmax tx power: %hhu dBm\n", +				 "2.4GHz:\n\tChain A offset: %u dBm\n\tChain B offset: %u dBm\n\tmax tx power: %u dBm\n",  				 mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[0],  				 mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[1],  				 mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].max);  		pos += scnprintf(buf + pos, bufsz - pos, -				 "5.2GHz:\n\tChain A offset: %hhu dBm\n\tChain B offset: %hhu dBm\n\tmax tx power: %hhu dBm\n", +				 "5.2GHz:\n\tChain A offset: %u dBm\n\tChain B offset: %u dBm\n\tmax tx power: %u dBm\n",  				 mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[0],  				 mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[1],  				 mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].max); @@ -1069,7 +1069,7 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file,  		pos += scnprintf(buf + pos, bufsz - pos, "A");  	if (mvm->scan_rx_ant & ANT_B)  		pos += scnprintf(buf + pos, bufsz - pos, "B"); -	pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant); +	pos += scnprintf(buf + pos, bufsz - pos, " (%x)\n", mvm->scan_rx_ant);  	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);  } @@ -1248,7 +1248,7 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)  	mvmvif = iwl_mvm_vif_from_mac80211(vif);  	info = IEEE80211_SKB_CB(beacon); -	rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif); +	rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);  	beacon_cmd.flags =  		cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, rate)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 8c5b97fb1941..05f3136b1c43 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1010,11 +1010,10 @@ static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,  static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,  				      struct cfg80211_pmsr_result *res)  { -	struct iwl_mvm_smooth_entry *resp; +	struct iwl_mvm_smooth_entry *resp = NULL, *iter;  	s64 rtt_avg, rtt = res->ftm.rtt_avg;  	u32 undershoot, overshoot;  	u8 alpha; -	bool found;  	if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH)  		return; @@ -1028,15 +1027,14 @@ static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,  		return;  	} -	found = false; -	list_for_each_entry(resp, &mvm->ftm_initiator.smooth.resp, list) { -		if (!memcmp(res->addr, resp->addr, ETH_ALEN)) { -			found = true; +	list_for_each_entry(iter, &mvm->ftm_initiator.smooth.resp, list) { +		if (!memcmp(res->addr, iter->addr, ETH_ALEN)) { +			resp = iter;  			break;  		}  	} -	if (!found) { +	if (!resp) {  		resp = kzalloc(sizeof(*resp), GFP_KERNEL);  		if (!resp)  			return; @@ -1208,7 +1206,7 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  	}  	IWL_DEBUG_INFO(mvm, "Range response received\n"); -	IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n", +	IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %u\n",  		       mvm->ftm_initiator.req->cookie, num_of_aps);  	for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) { @@ -1300,7 +1298,7 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)  		if (fw_has_api(&mvm->fw->ucode_capa,  			       IWL_UCODE_TLV_API_FTM_RTT_ACCURACY)) -			IWL_DEBUG_INFO(mvm, "RTT confidence: %hhu\n", +			IWL_DEBUG_INFO(mvm, "RTT confidence: %u\n",  				       fw_ap->rttConfidence);  		iwl_mvm_debug_range_resp(mvm, i, &result); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f041e77af059..0c6b49fcb00d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -122,6 +122,9 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  	u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,  					      UCODE_ALIVE_NTFY, 0);  	u32 i; +	struct iwl_trans *trans = mvm->trans; +	enum iwl_device_family device_family = trans->trans_cfg->device_family; +  	if (version == 6) {  		struct iwl_alive_ntf_v6 *palive; @@ -230,7 +233,8 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,  	if (umac_error_table) {  		if (umac_error_table >= -		    mvm->trans->cfg->min_umac_error_event_table) { +		    mvm->trans->cfg->min_umac_error_event_table || +		    device_family >= IWL_DEVICE_FAMILY_BZ) {  			iwl_fw_umac_set_alive_err_table(mvm->trans,  							umac_error_table);  		} else { @@ -354,6 +358,20 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  	 */  	ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait,  				    MVM_UCODE_ALIVE_TIMEOUT); + +	if (mvm->trans->trans_cfg->device_family == +	    IWL_DEVICE_FAMILY_AX210) { +		/* print these registers regardless of alive fail/success */ +		IWL_INFO(mvm, "WFPM_UMAC_PD_NOTIFICATION: 0x%x\n", +			 iwl_read_umac_prph(mvm->trans, WFPM_ARC1_PD_NOTIFICATION)); +		IWL_INFO(mvm, "WFPM_LMAC2_PD_NOTIFICATION: 0x%x\n", +			 iwl_read_umac_prph(mvm->trans, WFPM_LMAC2_PD_NOTIFICATION)); +		IWL_INFO(mvm, "WFPM_AUTH_KEY_0: 0x%x\n", +			 iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG)); +		IWL_INFO(mvm, "CNVI_SCU_SEQ_DATA_DW9: 0x%x\n", +			 iwl_read_prph(mvm->trans, CNVI_SCU_SEQ_DATA_DW9)); +	} +  	if (ret) {  		struct iwl_trans *trans = mvm->trans; @@ -390,7 +408,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  						UREG_LMAC2_CURRENT_PC));  		} -		if (ret == -ETIMEDOUT) +		if (ret == -ETIMEDOUT && !mvm->pldr_sync)  			iwl_fw_dbg_error_collect(&mvm->fwrt,  						 FW_DBG_TRIGGER_ALIVE_TIMEOUT); @@ -404,6 +422,9 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,  		return -EIO;  	} +	/* if reached this point, Alive notification was received */ +	iwl_mei_alive_notif(true); +  	ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait);  	if (ret) {  		IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); @@ -1456,6 +1477,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  	struct ieee80211_channel *chan;  	struct cfg80211_chan_def chandef;  	struct ieee80211_supported_band *sband = NULL; +	u32 sb_cfg;  	lockdep_assert_held(&mvm->mutex); @@ -1463,15 +1485,23 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  	if (ret)  		return ret; +	sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG); +	mvm->pldr_sync = !(sb_cfg & SB_CFG_RESIDES_IN_OTP_MASK); +	if (mvm->pldr_sync && iwl_mei_pldr_req()) +		return -EBUSY; +  	ret = iwl_mvm_load_rt_fw(mvm);  	if (ret) {  		IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); -		if (ret != -ERFKILL) +		if (ret != -ERFKILL && !mvm->pldr_sync)  			iwl_fw_dbg_error_collect(&mvm->fwrt,  						 FW_DBG_TRIGGER_DRIVER);  		goto error;  	} +	/* FW loaded successfully */ +	mvm->pldr_sync = false; +  	iwl_get_shared_mem_conf(&mvm->fwrt);  	ret = iwl_mvm_sf_update(mvm, NULL, false); @@ -1665,6 +1695,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)  			iwl_rfi_send_config_cmd(mvm, NULL);  	} +	iwl_mvm_mei_device_state(mvm, true); +  	IWL_DEBUG_INFO(mvm, "RT uCode started.\n");  	return 0;   error: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index de0c545d50fd..aa791dbc3066 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -788,14 +788,40 @@ static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)  	return ie - beacon;  } -u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, -				    struct ieee80211_vif *vif) +static u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, +					   struct ieee80211_tx_info *info, +					   struct ieee80211_vif *vif)  { +	struct ieee80211_supported_band *sband; +	unsigned long basic = vif->bss_conf.basic_rates; +	u16 lowest_cck = IWL_RATE_COUNT, lowest_ofdm = IWL_RATE_COUNT;  	u8 rate; -	if (info->band == NL80211_BAND_2GHZ && !vif->p2p) -		rate = IWL_FIRST_CCK_RATE; -	else -		rate = IWL_FIRST_OFDM_RATE; +	u32 i; + +	sband = mvm->hw->wiphy->bands[info->band]; +	for_each_set_bit(i, &basic, BITS_PER_LONG) { +		u16 hw = sband->bitrates[i].hw_value; + +		if (hw >= IWL_FIRST_OFDM_RATE) { +			if (lowest_ofdm > hw) +				lowest_ofdm = hw; +		} else if (lowest_cck > hw) { +			lowest_cck = hw; +		} +	} + +	if (info->band == NL80211_BAND_2GHZ && !vif->p2p) { +		if (lowest_cck != IWL_RATE_COUNT) +			rate = lowest_cck; +		else if (lowest_ofdm != IWL_RATE_COUNT) +			rate = lowest_ofdm; +		else +			rate = IWL_RATE_1M_INDEX; +	} else if (lowest_ofdm != IWL_RATE_COUNT) { +		rate = lowest_ofdm; +	} else { +		rate = IWL_RATE_6M_INDEX; +	}  	return rate;  } @@ -812,6 +838,24 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)  	return flags;  } +u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm, +				    struct ieee80211_tx_info *info, +				    struct ieee80211_vif *vif) +{ +	struct ieee80211_supported_band *sband = +		mvm->hw->wiphy->bands[info->band]; +	u32 legacy = vif->bss_conf.beacon_tx_rate.control[info->band].legacy; + +	/* if beacon rate was configured try using it */ +	if (hweight32(legacy) == 1) { +		u32 rate = ffs(legacy) - 1; + +		return sband->bitrates[rate].hw_value; +	} + +	return iwl_mvm_mac_ctxt_get_lowest_rate(mvm, info, vif); +} +  static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,  				    struct ieee80211_vif *vif,  				    struct sk_buff *beacon, @@ -842,7 +886,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,  		cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<  			    RATE_MCS_ANT_POS); -	rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif); +	rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);  	tx->rate_n_flags |=  		cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate)); @@ -926,7 +970,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(beacon);  	struct iwl_mac_beacon_cmd beacon_cmd = {}; -	u8 rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif); +	u8 rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);  	u16 flags;  	struct ieee80211_chanctx_conf *ctx;  	int channel; @@ -1099,7 +1143,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,  			iwl_mvm_mac_ap_iterator, &data);  		if (data.beacon_device_ts) { -			u32 rand = prandom_u32_max(64 - 36) + 36; +			u32 rand = get_random_u32_inclusive(36, 63);  			mvmvif->ap_beacon_time = data.beacon_device_ts +  				ieee80211_tu_to_usec(data.beacon_int * rand /  						     100); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8464c9b7baf1..565522466eba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -374,6 +374,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  		hw->wiphy->n_cipher_suites++;  	} +	wiphy_ext_feature_set(hw->wiphy, +			      NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); +  	if (fw_has_capa(&mvm->fw->ucode_capa,  			IWL_UCODE_TLV_CAPA_FTM_CALIBRATED)) {  		wiphy_ext_feature_set(hw->wiphy, @@ -1065,6 +1068,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)  		if (!ret)  			break; +		/* +		 * In PLDR sync PCI re-enumeration is needed. no point to retry +		 * mac start before that. +		 */ +		if (mvm->pldr_sync) { +			iwl_mei_alive_notif(false); +			iwl_trans_pcie_remove(mvm->trans, true); +			break; +		} +  		IWL_ERR(mvm, "mac start retry %d\n", retry);  	}  	clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status); @@ -1822,7 +1835,8 @@ static u8 iwl_mvm_he_get_ppe_val(u8 *ppe, u8 ppe_pos_bit)  static void iwl_mvm_parse_ppe(struct iwl_mvm *mvm,  			      struct iwl_he_pkt_ext_v2 *pkt_ext, u8 nss, -			      u8 ru_index_bitmap, u8 *ppe, u8 ppe_pos_bit) +			      u8 ru_index_bitmap, u8 *ppe, u8 ppe_pos_bit, +			      bool inheritance)  {  	int i; @@ -1848,14 +1862,25 @@ static void iwl_mvm_parse_ppe(struct iwl_mvm *mvm,  		     bw++) {  			ru_index_tmp >>= 1; -			if (!(ru_index_tmp & 1)) -				continue; +			/* +			* According to the 11be spec, if for a specific BW the PPE Thresholds +			* isn't present - it should inherit the thresholds from the last +			* BW for which we had PPE Thresholds. In 11ax though, we don't have +			* this inheritance - continue in this case +			*/ +			if (!(ru_index_tmp & 1)) { +				if (inheritance) +					goto set_thresholds; +				else +					continue; +			}  			high_th = iwl_mvm_he_get_ppe_val(ppe, ppe_pos_bit);  			ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE;  			low_th = iwl_mvm_he_get_ppe_val(ppe, ppe_pos_bit);  			ppe_pos_bit += IEEE80211_PPE_THRES_INFO_PPET_SIZE; +set_thresholds:  			pkt_ext->pkt_ext_qam_th[i][bw][0] = low_th;  			pkt_ext->pkt_ext_qam_th[i][bw][1] = high_th;  		} @@ -1864,7 +1889,8 @@ static void iwl_mvm_parse_ppe(struct iwl_mvm *mvm,  static void iwl_mvm_set_pkt_ext_from_he_ppe(struct iwl_mvm *mvm,  					    struct ieee80211_sta *sta, -					    struct iwl_he_pkt_ext_v2 *pkt_ext) +					    struct iwl_he_pkt_ext_v2 *pkt_ext, +					    bool inheritance)  {  	u8 nss = (sta->deflink.he_cap.ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) + 1;  	u8 *ppe = &sta->deflink.he_cap.ppe_thres[0]; @@ -1874,7 +1900,8 @@ static void iwl_mvm_set_pkt_ext_from_he_ppe(struct iwl_mvm *mvm,  	/* Starting after PPE header */  	u8 ppe_pos_bit = IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE; -	iwl_mvm_parse_ppe(mvm, pkt_ext, nss, ru_index_bitmap, ppe, ppe_pos_bit); +	iwl_mvm_parse_ppe(mvm, pkt_ext, nss, ru_index_bitmap, ppe, ppe_pos_bit, +			  inheritance);  }  static void iwl_mvm_set_pkt_ext_from_nominal_padding(struct iwl_he_pkt_ext_v2 *pkt_ext, @@ -1885,16 +1912,18 @@ static void iwl_mvm_set_pkt_ext_from_nominal_padding(struct iwl_he_pkt_ext_v2 *p  	int high_th = -1;  	int i; +	/* all the macros are the same for EHT and HE */  	switch (nominal_padding) { -	case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US: +	case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US:  		low_th = IWL_HE_PKT_EXT_NONE;  		high_th = IWL_HE_PKT_EXT_NONE;  		break; -	case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US: +	case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US:  		low_th = IWL_HE_PKT_EXT_BPSK;  		high_th = IWL_HE_PKT_EXT_NONE;  		break; -	case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US: +	case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US: +	case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US:  		low_th = IWL_HE_PKT_EXT_NONE;  		high_th = IWL_HE_PKT_EXT_BPSK;  		break; @@ -1917,6 +1946,31 @@ static void iwl_mvm_set_pkt_ext_from_nominal_padding(struct iwl_he_pkt_ext_v2 *p  	}  } +static void iwl_mvm_get_optimal_ppe_info(struct iwl_he_pkt_ext_v2 *pkt_ext, +					 u8 nominal_padding) +{ +	int i; + +	for (i = 0; i < MAX_HE_SUPP_NSS; i++) { +		u8 bw; + +		for (bw = 0; bw < ARRAY_SIZE(pkt_ext->pkt_ext_qam_th[i]); +		     bw++) { +			u8 *qam_th = &pkt_ext->pkt_ext_qam_th[i][bw][0]; + +			if (nominal_padding > +			    IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US && +			    qam_th[1] == IWL_HE_PKT_EXT_NONE) +				qam_th[1] = IWL_HE_PKT_EXT_4096QAM; +			else if (nominal_padding == +				 IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US && +				 qam_th[0] == IWL_HE_PKT_EXT_NONE && +				 qam_th[1] == IWL_HE_PKT_EXT_NONE) +				qam_th[0] = IWL_HE_PKT_EXT_4096QAM; +		} +	} +} +  static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,  			       struct ieee80211_vif *vif, u8 sta_id)  { @@ -1940,6 +1994,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,  	struct ieee80211_chanctx_conf *chanctx_conf;  	const struct ieee80211_supported_band *sband;  	void *cmd; +	u8 nominal_padding;  	if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_MBSSID_HE))  		ver = 1; @@ -2029,22 +2084,96 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,  	memset(&sta_ctxt_cmd.pkt_ext, IWL_HE_PKT_EXT_NONE,  	       sizeof(sta_ctxt_cmd.pkt_ext)); -	/* If PPE Thresholds exist, parse them into a FW-familiar format. */ -	if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[6] & -		IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { -		iwl_mvm_set_pkt_ext_from_he_ppe(mvm, sta, -						&sta_ctxt_cmd.pkt_ext); -		flags |= STA_CTXT_HE_PACKET_EXT; -	/* PPE Thresholds doesn't exist - set the API PPE values -	* according to Common Nominal Packet Padding fiels. */ -	} else { -		u8 nominal_padding = -			u8_get_bits(sta->deflink.he_cap.he_cap_elem.phy_cap_info[9], -				    IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); -		if (nominal_padding != IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED) +	if (sta->deflink.eht_cap.has_eht) { +		nominal_padding = +			u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], +				    IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); + +		/* If PPE Thresholds exists, parse them into a FW-familiar format. */ +		if (sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5] & +		    IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) { +			u8 nss = (sta->deflink.eht_cap.eht_ppe_thres[0] & +				IEEE80211_EHT_PPE_THRES_NSS_MASK) + 1; +			u8 *ppe = &sta->deflink.eht_cap.eht_ppe_thres[0]; +			u8 ru_index_bitmap = +				u16_get_bits(*ppe, +					     IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); +			 /* Starting after PPE header */ +			u8 ppe_pos_bit = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE; + +			iwl_mvm_parse_ppe(mvm, +					  &sta_ctxt_cmd.pkt_ext, +					  nss, ru_index_bitmap, ppe, +					  ppe_pos_bit, true); +			flags |= STA_CTXT_HE_PACKET_EXT; +		/* EHT PPE Thresholds doesn't exist - set the API according to HE PPE Tresholds*/ +		} else if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[6] & +			   IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { +			struct iwl_he_pkt_ext_v2 *pkt_ext = +				&sta_ctxt_cmd.pkt_ext; + +			/* +			* Even though HE Capabilities IE doesn't contain PPE +			* Thresholds for BW 320Mhz, thresholds for this BW will +			* be filled in with the same values as 160Mhz, due to +			* the inheritance, as required. +			*/ +			iwl_mvm_set_pkt_ext_from_he_ppe(mvm, sta, pkt_ext, +							true); + +			/* +			* According to the requirements, for MCSs 12-13 the maximum value between +			* HE PPE Threshold and Common Nominal Packet Padding needs to be taken +			*/ +			iwl_mvm_get_optimal_ppe_info(pkt_ext, nominal_padding); + +			flags |= STA_CTXT_HE_PACKET_EXT; + +		/* +		* if PPE Thresholds doesn't present in both EHT IE and HE IE - +		* take the Thresholds from Common Nominal Packet Padding field +		*/ +		} else {  			iwl_mvm_set_pkt_ext_from_nominal_padding(&sta_ctxt_cmd.pkt_ext,  								 nominal_padding,  								 &flags); +		} +	} else if (sta->deflink.he_cap.has_he) { +		/* If PPE Thresholds exist, parse them into a FW-familiar format. */ +		if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[6] & +			IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { +			iwl_mvm_set_pkt_ext_from_he_ppe(mvm, sta, +							&sta_ctxt_cmd.pkt_ext, +							false); +			flags |= STA_CTXT_HE_PACKET_EXT; +		/* +		* PPE Thresholds doesn't exist - set the API PPE values +		* according to Common Nominal Packet Padding field. +		*/ +		} else { +			nominal_padding = +				u8_get_bits(sta->deflink.he_cap.he_cap_elem.phy_cap_info[9], +					    IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); +			if (nominal_padding != IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED) +				iwl_mvm_set_pkt_ext_from_nominal_padding(&sta_ctxt_cmd.pkt_ext, +									 nominal_padding, +									 &flags); +		} +	} + +	for (i = 0; i < MAX_HE_SUPP_NSS; i++) { +		int bw; + +		for (bw = 0; +		     bw < ARRAY_SIZE(sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i]); +		     bw++) { +			u8 *qam_th = +				&sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw][0]; + +			IWL_DEBUG_HT(mvm, +				     "PPE table: nss[%d] bw[%d] PPET8 = %d, PPET16 = %d\n", +				     i, bw, qam_th[0], qam_th[1]); +		}  	}  	if (sta->deflink.he_cap.he_cap_elem.mac_cap_info[2] & @@ -2192,8 +2321,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  	 * interface was added.  	 */  	if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { -		if (vif->bss_conf.he_support && -		    !iwlwifi_mod_params.disable_11ax) +		if ((vif->bss_conf.he_support && +		     !iwlwifi_mod_params.disable_11ax) || +		    (vif->bss_conf.eht_support && +		     !iwlwifi_mod_params.disable_11be))  			iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id);  		iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); @@ -2201,8 +2332,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  	/* Update MU EDCA params */  	if (changes & BSS_CHANGED_QOS && mvmvif->associated && -	    vif->cfg.assoc && vif->bss_conf.he_support && -	    !iwlwifi_mod_params.disable_11ax) +	    vif->cfg.assoc && +	    ((vif->bss_conf.he_support && +	      !iwlwifi_mod_params.disable_11ax) || +	     (vif->bss_conf.eht_support && +	      !iwlwifi_mod_params.disable_11be)))  		iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id);  	/* @@ -2306,6 +2440,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  			 */  			if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,  				      &mvm->status)) { +				/* first remove remaining keys */ +				iwl_mvm_sec_key_remove_ap(mvm, vif); +  				/*  				 * Remove AP station now that  				 * the MAC is unassoc @@ -3059,6 +3196,9 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,  		return;  	switch (mvm_sta->pairwise_cipher) { +	case WLAN_CIPHER_SUITE_TKIP: +		conn_info.pairwise_cipher = IWL_MEI_CIPHER_TKIP; +		break;  	case WLAN_CIPHER_SUITE_CCMP:  		conn_info.pairwise_cipher = IWL_MEI_CIPHER_CCMP;  		break; @@ -3209,8 +3349,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,  			vif->bss_conf.he_support = sta->deflink.he_cap.has_he;  			mvmvif->ap_assoc_sta_count++;  			iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); -			if (vif->bss_conf.he_support && -			    !iwlwifi_mod_params.disable_11ax) +			if ((vif->bss_conf.he_support && +			     !iwlwifi_mod_params.disable_11ax) || +			    (vif->bss_conf.eht_support && +			     !iwlwifi_mod_params.disable_11be))  				iwl_mvm_cfg_he_sta(mvm, vif, mvm_sta->sta_id);  		} else if (vif->type == NL80211_IFTYPE_STATION) {  			vif->bss_conf.he_support = sta->deflink.he_cap.has_he; @@ -3461,6 +3603,8 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  	struct iwl_mvm_sta *mvmsta = NULL;  	struct iwl_mvm_key_pn *ptk_pn;  	int keyidx = key->keyidx; +	u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); +	u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);  	int ret, i;  	u8 key_offset; @@ -3600,7 +3744,12 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  			mvmsta->pairwise_cipher = key->cipher;  		IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); -		ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset); + +		if (sec_key_ver) +			ret = iwl_mvm_sec_key_add(mvm, vif, sta, key); +		else +			ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset); +  		if (ret) {  			IWL_WARN(mvm, "set key failed\n");  			key->hw_key_idx = STA_KEY_IDX_INVALID; @@ -3653,7 +3802,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  		}  		IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); -		ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); +		if (sec_key_ver) +			ret = iwl_mvm_sec_key_del(mvm, vif, sta, key); +		else +			ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);  		break;  	default:  		ret = -EINVAL; @@ -3758,7 +3910,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,  	/* Set the channel info data */  	iwl_mvm_set_chan_info(mvm, &aux_roc_req.channel_info, channel->hw_value,  			      iwl_mvm_phy_band_from_nl80211(channel->band), -			      PHY_VHT_CHANNEL_MODE20, +			      IWL_PHY_CHANNEL_MODE20,  			      0);  	/* Set the time and duration */ @@ -4964,6 +5116,9 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)  	case RATE_MCS_CHAN_WIDTH_160:  		rinfo->bw = RATE_INFO_BW_160;  		break; +	case RATE_MCS_CHAN_WIDTH_320: +		rinfo->bw = RATE_INFO_BW_320; +		break;  	}  	if (format == RATE_MCS_CCK_MSK || @@ -5024,6 +5179,10 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)  		rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;  	switch (format) { +	case RATE_MCS_EHT_MSK: +		/* TODO: GI/LTF/RU. How does the firmware encode them? */ +		rinfo->flags |= RATE_INFO_FLAGS_EHT_MCS; +		break;  	case RATE_MCS_HE_MSK:  		gi_ltf = u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c new file mode 100644 index 000000000000..e27c893502f7 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2022 Intel Corporation + */ +#include <linux/kernel.h> +#include <net/mac80211.h> +#include "mvm.h" +#include "fw/api/context.h" +#include "fw/api/datapath.h" + +static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, +				    struct ieee80211_vif *vif, +				    struct ieee80211_sta *sta, +				    struct ieee80211_key_conf *keyconf) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + +	if (vif->type == NL80211_IFTYPE_AP && +	    !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) +		return BIT(mvmvif->mcast_sta.sta_id); + +	if (sta) { +		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + +		return BIT(mvmsta->sta_id); +	} + +	if (vif->type == NL80211_IFTYPE_STATION && +	    mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) +		return BIT(mvmvif->ap_sta_id); + +	/* invalid */ +	return 0; +} + +static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, +				 struct ieee80211_vif *vif, +				 struct ieee80211_sta *sta, +				 struct ieee80211_key_conf *keyconf) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	u32 flags = 0; + +	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) +		flags |= IWL_SEC_KEY_FLAG_MCAST_KEY; + +	switch (keyconf->cipher) { +	case WLAN_CIPHER_SUITE_WEP104: +		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE; +		fallthrough; +	case WLAN_CIPHER_SUITE_WEP40: +		flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP; +		break; +	case WLAN_CIPHER_SUITE_TKIP: +		flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP; +		break; +	case WLAN_CIPHER_SUITE_AES_CMAC: +	case WLAN_CIPHER_SUITE_CCMP: +		flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP; +		break; +	case WLAN_CIPHER_SUITE_GCMP_256: +	case WLAN_CIPHER_SUITE_BIP_GMAC_256: +		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE; +		fallthrough; +	case WLAN_CIPHER_SUITE_GCMP: +	case WLAN_CIPHER_SUITE_BIP_GMAC_128: +		flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP; +		break; +	} + +	rcu_read_lock(); +	if (!sta && vif->type == NL80211_IFTYPE_STATION && +	    mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) { +		u8 sta_id = mvmvif->ap_sta_id; + +		sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id], +					    lockdep_is_held(&mvm->mutex)); +	} + +	if (!IS_ERR_OR_NULL(sta) && sta->mfp) +		flags |= IWL_SEC_KEY_FLAG_MFP; +	rcu_read_unlock(); + +	return flags; +} + +static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, +				 u32 key_flags, u32 keyidx, u32 flags) +{ +	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); +	struct iwl_sec_key_cmd cmd = { +		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), +		.u.remove.sta_mask = cpu_to_le32(sta_mask), +		.u.remove.key_id = cpu_to_le32(keyidx), +		.u.remove.key_flags = cpu_to_le32(key_flags), +	}; + +	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd); +} + +int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, +			struct ieee80211_vif *vif, +			struct ieee80211_sta *sta, +			struct ieee80211_key_conf *keyconf) +{ +	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); +	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); +	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); +	struct iwl_sec_key_cmd cmd = { +		.action = cpu_to_le32(FW_CTXT_ACTION_ADD), +		.u.add.sta_mask = cpu_to_le32(sta_mask), +		.u.add.key_id = cpu_to_le32(keyconf->keyidx), +		.u.add.key_flags = cpu_to_le32(key_flags), +		.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)), +	}; +	int ret; + +	if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key))) +		return -EINVAL; + +	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || +	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) +		memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key, +		       keyconf->keylen); +	else +		memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen); + +	if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) { +		memcpy(cmd.u.add.tkip_mic_rx_key, +		       keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, +		       8); +		memcpy(cmd.u.add.tkip_mic_tx_key, +		       keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, +		       8); +	} + +	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd); +	if (ret) +		return ret; + +	/* +	 * For WEP, the same key is used for multicast and unicast so need to +	 * upload it again. If this fails, remove the original as well. +	 */ +	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || +	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { +		cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY); +		ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd); +		if (ret) +			__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, +					      keyconf->keyidx, 0); +	} + +	return ret; +} + +static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, +				struct ieee80211_vif *vif, +				struct ieee80211_sta *sta, +				struct ieee80211_key_conf *keyconf, +				u32 flags) +{ +	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); +	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); +	int ret; + +	ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx, +				    flags); +	if (ret) +		return ret; + +	/* For WEP, delete the key again as unicast */ +	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || +	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { +		key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY; +		ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, +					    keyconf->keyidx, flags); +	} + +	return ret; +} + +int iwl_mvm_sec_key_del(struct iwl_mvm *mvm, +			struct ieee80211_vif *vif, +			struct ieee80211_sta *sta, +			struct ieee80211_key_conf *keyconf) +{ +	return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0); +} + +static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw, +					   struct ieee80211_vif *vif, +					   struct ieee80211_sta *sta, +					   struct ieee80211_key_conf *key, +					   void *data) +{ +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + +	if (key->hw_key_idx == STA_KEY_IDX_INVALID) +		return; + +	if (sta) +		return; + +	_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC); +	key->hw_key_idx = STA_KEY_IDX_INVALID; +} + +void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, +			       struct ieee80211_vif *vif) +{ +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); +	u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0); + +	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION || +		    mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)) +		return; + +	if (!sec_key_ver) +		return; + +	ieee80211_iter_keys_rcu(mvm->hw, vif, +				iwl_mvm_sec_key_remove_ap_iter, +				NULL); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 97cba526e465..90bc95d96a78 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -501,7 +501,7 @@ struct iwl_mvm_tt_mgmt {   * @tzone: thermal zone device data  */  struct iwl_mvm_thermal_device { -	s16 temp_trips[IWL_MAX_DTS_TRIPS]; +	struct thermal_trip trips[IWL_MAX_DTS_TRIPS];  	u8 fw_trips_index[IWL_MAX_DTS_TRIPS];  	struct thermal_zone_device *tzone;  }; @@ -1105,6 +1105,8 @@ struct iwl_mvm {  	unsigned long last_reset_or_resume_time_jiffies;  	bool sta_remove_requires_queue_remove; + +	bool pldr_sync;  };  /* Extract MVM priv from op_mode and _hw */ @@ -1644,7 +1646,8 @@ int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,  int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,  				     struct sk_buff *beacon,  				     void *data, int len); -u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, +u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm, +				    struct ieee80211_tx_info *info,  				    struct ieee80211_vif *vif);  u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw,  				      u8 rate_idx); @@ -2079,6 +2082,18 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,  			     struct dentry *dir);  #endif +/* new MLD related APIs */ +int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, +			struct ieee80211_vif *vif, +			struct ieee80211_sta *sta, +			struct ieee80211_key_conf *keyconf); +int iwl_mvm_sec_key_del(struct iwl_mvm *mvm, +			struct ieee80211_vif *vif, +			struct ieee80211_sta *sta, +			struct ieee80211_key_conf *keyconf); +void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, +			       struct ieee80211_vif *vif); +  int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm,  			    struct iwl_rfi_lut_entry *rfi_table);  struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm); @@ -2201,10 +2216,10 @@ static inline void iwl_mvm_mei_host_disassociated(struct iwl_mvm *mvm)  		iwl_mei_host_disassociated();  } -static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm) +static inline void iwl_mvm_mei_device_state(struct iwl_mvm *mvm, bool up)  {  	if (mvm->mei_registered) -		iwl_mei_device_down(); +		iwl_mei_device_state(up);  }  static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d2d42cd48af2..f4e9446d9dc2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -92,6 +92,12 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  	radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >>  			 FW_PHY_CFG_RADIO_DASH_POS; +	IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, +		       radio_cfg_step, radio_cfg_dash); + +	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) +		return; +  	/* SKU control */  	reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev); @@ -127,9 +133,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)  				CSR_HW_IF_CONFIG_REG_D3_DEBUG,  				reg_val); -	IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, -		       radio_cfg_step, radio_cfg_dash); -  	/*  	 * W/A : NIC is stuck in a reset state after Early PCIe power off  	 * (PCIe power is lost before PERST# is asserted), causing ME FW @@ -547,6 +550,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {  	HCMD_NAME(TLC_MNG_CONFIG_CMD),  	HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD),  	HCMD_NAME(SCD_QUEUE_CONFIG_CMD), +	HCMD_NAME(SEC_KEY_CMD),  	HCMD_NAME(MONITOR_NOTIF),  	HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST),  	HCMD_NAME(STA_PM_NOTIF), @@ -1076,6 +1080,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	static const u8 no_reclaim_cmds[] = {  		TX_CMD,  	}; +	u32 max_agg;  	size_t scan_size;  	u32 min_backoff;  	struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused; @@ -1097,12 +1102,17 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	if (!hw)  		return NULL; -	hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; +	if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) +		max_agg = IEEE80211_MAX_AMPDU_BUF_EHT; +	else +		max_agg = IEEE80211_MAX_AMPDU_BUF_HE; + +	hw->max_rx_aggregation_subframes = max_agg;  	if (cfg->max_tx_agg_size)  		hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;  	else -		hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; +		hw->max_tx_aggregation_subframes = max_agg;  	op_mode = hw->priv; @@ -1118,6 +1128,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	iwl_mvm_get_acpi_tables(mvm);  	iwl_uefi_get_sgom_table(trans, &mvm->fwrt); +	iwl_uefi_get_step_table(trans);  	mvm->init_status = 0; @@ -1375,7 +1386,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)  	iwl_trans_stop_device(mvm->trans);  	iwl_free_fw_paging(&mvm->fwrt);  	iwl_fw_dump_conf_clear(&mvm->fwrt); -	iwl_mvm_mei_device_down(mvm); +	iwl_mvm_mei_device_state(mvm, false);  }  static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) @@ -1881,6 +1892,9 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync)  {  	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); +	if (mvm->pldr_sync) +		return; +  	if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) &&  	    !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE,  				&mvm->status)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index a3cefbc43e80..06f4203fb989 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -14,16 +14,18 @@ u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef)  	switch (chandef->width) {  	case NL80211_CHAN_WIDTH_20_NOHT:  	case NL80211_CHAN_WIDTH_20: -		return PHY_VHT_CHANNEL_MODE20; +		return IWL_PHY_CHANNEL_MODE20;  	case NL80211_CHAN_WIDTH_40: -		return PHY_VHT_CHANNEL_MODE40; +		return IWL_PHY_CHANNEL_MODE40;  	case NL80211_CHAN_WIDTH_80: -		return PHY_VHT_CHANNEL_MODE80; +		return IWL_PHY_CHANNEL_MODE80;  	case NL80211_CHAN_WIDTH_160: -		return PHY_VHT_CHANNEL_MODE160; +		return IWL_PHY_CHANNEL_MODE160; +	case NL80211_CHAN_WIDTH_320: +		return IWL_PHY_CHANNEL_MODE320;  	default:  		WARN(1, "Invalid channel width=%u", chandef->width); -		return PHY_VHT_CHANNEL_MODE20; +		return IWL_PHY_CHANNEL_MODE20;  	}  } @@ -33,34 +35,32 @@ u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef)   */  u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef)  { -	switch (chandef->chan->center_freq - chandef->center_freq1) { -	case -70: -		return PHY_VHT_CTRL_POS_4_BELOW; -	case -50: -		return PHY_VHT_CTRL_POS_3_BELOW; -	case -30: -		return PHY_VHT_CTRL_POS_2_BELOW; -	case -10: -		return PHY_VHT_CTRL_POS_1_BELOW; -	case  10: -		return PHY_VHT_CTRL_POS_1_ABOVE; -	case  30: -		return PHY_VHT_CTRL_POS_2_ABOVE; -	case  50: -		return PHY_VHT_CTRL_POS_3_ABOVE; -	case  70: -		return PHY_VHT_CTRL_POS_4_ABOVE; -	default: -		WARN(1, "Invalid channel definition"); -		fallthrough; -	case 0: +	int offs = chandef->chan->center_freq - chandef->center_freq1; +	int abs_offs = abs(offs); +	u8 ret; + +	if (offs == 0) {  		/*  		 * The FW is expected to check the control channel position only  		 * when in HT/VHT and the channel width is not 20MHz. Return  		 * this value as the default one.  		 */ -		return PHY_VHT_CTRL_POS_1_BELOW; +		return 0;  	} + +	/* this results in a value 0-7, i.e. fitting into 0b0111 */ +	ret = (abs_offs - 10) / 20; +	/* +	 * But we need the value to be in 0b1011 because 0b0100 is +	 * IWL_PHY_CTRL_POS_ABOVE, so shift bit 2 up to land in +	 * IWL_PHY_CTRL_POS_OFFS_EXT (0b1000) +	 */ +	ret = (ret & IWL_PHY_CTRL_POS_OFFS_MSK) | +	      ((ret & BIT(2)) << 1); +	/* and add the above bit */ +	ret |= (offs > 0) * IWL_PHY_CTRL_POS_ABOVE; + +	return ret;  }  /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 2e9081cb6627..f30eeab5505b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -9,9 +9,11 @@  #include "iwl-op-mode.h"  #include "mvm.h" -static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta) +static u8 rs_fw_bw_from_sta_bw(const struct ieee80211_sta *sta)  {  	switch (sta->deflink.bandwidth) { +	case IEEE80211_STA_RX_BW_320: +		return IWL_TLC_MNG_CH_WIDTH_320MHZ;  	case IEEE80211_STA_RX_BW_160:  		return IWL_TLC_MNG_CH_WIDTH_160MHZ;  	case IEEE80211_STA_RX_BW_80: @@ -238,6 +240,122 @@ rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,  	}  } +static u8 rs_fw_eht_max_nss(u8 rx_nss, u8 tx_nss) +{ +	u8 tx = u8_get_bits(tx_nss, IEEE80211_EHT_MCS_NSS_TX); +	u8 rx = u8_get_bits(rx_nss, IEEE80211_EHT_MCS_NSS_RX); +	/* the max nss that can be used, +	 * is the min with our tx capa and the peer rx capa. +	 */ +	return min(tx, rx); +} + +#define MAX_NSS_MCS(mcs_num, rx, tx) \ +	rs_fw_eht_max_nss((rx)->rx_tx_mcs ##mcs_num## _max_nss, \ +			  (tx)->rx_tx_mcs ##mcs_num## _max_nss) + +static void rs_fw_set_eht_mcs_nss(__le16 ht_rates[][3], +				  enum IWL_TLC_MCS_PER_BW bw, +				  u8 max_nss, u16 mcs_msk) +{ +	if (max_nss >= 2) +		ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le16(mcs_msk); + +	if (max_nss >= 1) +		ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le16(mcs_msk); +} + +static const +struct ieee80211_eht_mcs_nss_supp_bw * +rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw, +		     const struct ieee80211_eht_mcs_nss_supp *eht_mcs) +{ +	switch (bw) { +	case IWL_TLC_MCS_PER_BW_80: +		return &eht_mcs->bw._80; +	case IWL_TLC_MCS_PER_BW_160: +		return &eht_mcs->bw._160; +	case IWL_TLC_MCS_PER_BW_320: +		return &eht_mcs->bw._320; +	default: +		return NULL; +	} +} + +static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta, +					struct ieee80211_supported_band *sband, +					struct iwl_tlc_config_cmd_v4 *cmd) +{ +	/* peer RX mcs capa */ +	const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs = +		&sta->deflink.eht_cap.eht_mcs_nss_supp; +	/* our TX mcs capa */ +	const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs = +		&sband->iftype_data->eht_cap.eht_mcs_nss_supp; + +	enum IWL_TLC_MCS_PER_BW bw; +	struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_rx_20; +	struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_tx_20; + +	/* peer is 20Mhz only */ +	if (!(sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & +	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { +		mcs_rx_20 = eht_rx_mcs->only_20mhz; +	} else { +		mcs_rx_20.rx_tx_mcs7_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs9_max_nss; +		mcs_rx_20.rx_tx_mcs9_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs9_max_nss; +		mcs_rx_20.rx_tx_mcs11_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs11_max_nss; +		mcs_rx_20.rx_tx_mcs13_max_nss = eht_rx_mcs->bw._80.rx_tx_mcs13_max_nss; +	} + +	/* nic is 20Mhz only */ +	if (!(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[0] & +	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { +		mcs_tx_20 = eht_tx_mcs->only_20mhz; +	} else { +		mcs_tx_20.rx_tx_mcs7_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs9_max_nss; +		mcs_tx_20.rx_tx_mcs9_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs9_max_nss; +		mcs_tx_20.rx_tx_mcs11_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs11_max_nss; +		mcs_tx_20.rx_tx_mcs13_max_nss = eht_tx_mcs->bw._80.rx_tx_mcs13_max_nss; +	} + +	/* rates for 20/40/80 bw */ +	bw = IWL_TLC_MCS_PER_BW_80; +	rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +			      MAX_NSS_MCS(7, &mcs_rx_20, &mcs_tx_20), GENMASK(7, 0)); +	rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +			      MAX_NSS_MCS(9, &mcs_rx_20, &mcs_tx_20), GENMASK(9, 8)); +	rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +			      MAX_NSS_MCS(11, &mcs_rx_20, &mcs_tx_20), GENMASK(11, 10)); +	rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +			      MAX_NSS_MCS(13, &mcs_rx_20, &mcs_tx_20), GENMASK(13, 12)); + +	/* rate for 160/320 bw */ +	for (bw = IWL_TLC_MCS_PER_BW_160; bw <= IWL_TLC_MCS_PER_BW_320; bw++) { +		const struct ieee80211_eht_mcs_nss_supp_bw *mcs_rx = +			rs_fw_rs_mcs2eht_mcs(bw, eht_rx_mcs); +		const struct ieee80211_eht_mcs_nss_supp_bw *mcs_tx = +			rs_fw_rs_mcs2eht_mcs(bw, eht_tx_mcs); + +		/* got unsuppored index for bw */ +		if (!mcs_rx || !mcs_tx) +			continue; + +		rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +				      MAX_NSS_MCS(9, mcs_rx, mcs_tx), GENMASK(9, 0)); +		rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +				      MAX_NSS_MCS(11, mcs_rx, mcs_tx), GENMASK(11, 10)); +		rs_fw_set_eht_mcs_nss(cmd->ht_rates, bw, +				      MAX_NSS_MCS(13, mcs_rx, mcs_tx), GENMASK(13, 12)); +	} + +	/* the station support only a single receive chain */ +	if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC || +	    sta->deflink.rx_nss < 2) +		memset(cmd->ht_rates[IWL_TLC_NSS_2], 0, +		       sizeof(cmd->ht_rates[IWL_TLC_NSS_2])); +} +  static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,  				 struct ieee80211_supported_band *sband,  				 struct iwl_tlc_config_cmd_v4 *cmd) @@ -258,7 +376,10 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,  	cmd->mode = IWL_TLC_MNG_MODE_NON_HT;  	/* HT/VHT rates */ -	if (he_cap->has_he) { +	if (sta->deflink.eht_cap.has_eht) { +		cmd->mode = IWL_TLC_MNG_MODE_EHT; +		rs_fw_eht_set_enabled_rates(sta, sband, cmd); +	} else if (he_cap->has_he) {  		cmd->mode = IWL_TLC_MNG_MODE_HE;  		rs_fw_he_set_enabled_rates(sta, sband, cmd);  	} else if (vht_cap->vht_supported) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 1aadccd8841f..549dbe0be223 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -10,37 +10,11 @@  #include "mvm.h"  #include "fw-api.h" -static void *iwl_mvm_skb_get_hdr(struct sk_buff *skb) -{ -	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); -	u8 *data = skb->data; - -	/* Alignment concerns */ -	BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4); -	BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4); -	BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) % 4); -	BUILD_BUG_ON(sizeof(struct ieee80211_vendor_radiotap) % 4); - -	if (rx_status->flag & RX_FLAG_RADIOTAP_HE) -		data += sizeof(struct ieee80211_radiotap_he); -	if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU) -		data += sizeof(struct ieee80211_radiotap_he_mu); -	if (rx_status->flag & RX_FLAG_RADIOTAP_LSIG) -		data += sizeof(struct ieee80211_radiotap_lsig); -	if (rx_status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { -		struct ieee80211_vendor_radiotap *radiotap = (void *)data; - -		data += sizeof(*radiotap) + radiotap->len + radiotap->pad; -	} - -	return data; -} -  static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,  				   int queue, struct ieee80211_sta *sta)  {  	struct iwl_mvm_sta *mvmsta; -	struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); +	struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);  	struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);  	struct iwl_mvm_key_pn *ptk_pn;  	int res; @@ -179,6 +153,10 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb,  	if (unlikely(headlen < hdrlen))  		return -EINVAL; +	/* Since data doesn't move data while putting data on skb and that is +	 * the only way we use, data + len is the next place that hdr would be put +	 */ +	skb_set_mac_header(skb, skb->len);  	skb_put_data(skb, hdr, hdrlen);  	skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); @@ -936,7 +914,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  			    struct iwl_rx_mpdu_desc *desc)  {  	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); -	struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); +	struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);  	struct iwl_mvm_sta *mvm_sta;  	struct iwl_mvm_baid_data *baid_data;  	struct iwl_mvm_reorder_buffer *buffer; @@ -1346,6 +1324,10 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,  	case IWL_RX_PHY_INFO_TYPE_HT:  	case IWL_RX_PHY_INFO_TYPE_VHT_SU:  	case IWL_RX_PHY_INFO_TYPE_VHT_MU: +	case IWL_RX_PHY_INFO_TYPE_EHT_MU: +	case IWL_RX_PHY_INFO_TYPE_EHT_TB: +	case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT: +	case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT:  		return;  	case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT:  		he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | @@ -1690,6 +1672,9 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,  	case RATE_MCS_CHAN_WIDTH_160:  		rx_status->bw = RATE_INFO_BW_160;  		break; +	case RATE_MCS_CHAN_WIDTH_320: +		rx_status->bw = RATE_INFO_BW_320; +		break;  	}  	/* must be before L-SIG data */ @@ -1726,6 +1711,9 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,  		rx_status->he_dcm =  			!!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK);  		break; +	case RATE_MCS_EHT_MSK: +		rx_status->encoding = RX_ENC_EHT; +		break;  	}  	switch (format) { @@ -1736,6 +1724,7 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,  		break;  	case RATE_MCS_VHT_MSK:  	case RATE_MCS_HE_MSK: +	case RATE_MCS_EHT_MSK:  		rx_status->nss =  			u32_get_bits(rate_n_flags, RATE_MCS_NSS_MSK) + 1;  		rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK; @@ -1747,10 +1736,13 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,  		rx_status->rate_idx = rate; -		if (WARN_ONCE(rate < 0 || rate > 0xFF, -			      "Invalid rate flags 0x%x, band %d,\n", -			      rate_n_flags, rx_status->band)) +		if ((rate < 0 || rate > 0xFF)) {  			rx_status->rate_idx = 0; +			if (net_ratelimit()) +				IWL_ERR(mvm, "Invalid rate flags 0x%x, band %d,\n", +					rate_n_flags, rx_status->band); +		} +  		break;  		}  	} @@ -2063,23 +2055,31 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  {  	struct ieee80211_rx_status *rx_status;  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_rx_no_data *desc = (void *)pkt->data; -	u32 rssi = le32_to_cpu(desc->rssi); -	u32 info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK; +	struct iwl_rx_no_data_ver_3 *desc = (void *)pkt->data; +	u32 rssi; +	u32 info_type;  	struct ieee80211_sta *sta = NULL;  	struct sk_buff *skb; -	struct iwl_mvm_rx_phy_data phy_data = { -		.d0 = desc->phy_info[0], -		.d1 = desc->phy_info[1], -		.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD, -		.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time), -		.rate_n_flags = le32_to_cpu(desc->rate), -		.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK), -		.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK), -		.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK), -	}; +	struct iwl_mvm_rx_phy_data phy_data;  	u32 format; +	if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) +		return; + +	if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(struct iwl_rx_no_data))) +		return; + +	rssi = le32_to_cpu(desc->rssi); +	info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK; +	phy_data.d0 = desc->phy_info[0]; +	phy_data.d1 = desc->phy_info[1]; +	phy_data.phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD; +	phy_data.gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time); +	phy_data.rate_n_flags = le32_to_cpu(desc->rate); +	phy_data.energy_a = u32_get_bits(rssi, RX_NO_DATA_CHAIN_A_MSK); +	phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK); +	phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK); +  	if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,  				    RX_NO_DATA_NOTIF, 0) < 2) {  		IWL_DEBUG_DROP(mvm, "Got an old rate format. Old rate: 0x%x\n", @@ -2091,11 +2091,17 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  	format = phy_data.rate_n_flags & RATE_MCS_MOD_TYPE_MSK; -	if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc))) -		return; - -	if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) -		return; +	if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, +				    RX_NO_DATA_NOTIF, 0) >= 3) { +		if (unlikely(iwl_rx_packet_payload_len(pkt) < +		    sizeof(struct iwl_rx_no_data_ver_3))) +		/* invalid len for ver 3 */ +			return; +	} else { +		if (format == RATE_MCS_EHT_MSK) +			/* no support for EHT before version 3 API */ +			return; +	}  	/* Dont use dev_alloc_skb(), we'll have enough headroom once  	 * ieee80211_hdr pulled. @@ -2132,6 +2138,16 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  	iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue); +	/* no more radio tap info should be put after this point. +	 * +	 * We mark it as mac header, for upper layers to know where +	 * all radio tap header ends. +	 * +	 * Since data doesn't move data while putting data on skb and that is +	 * the only way we use, data + len is the next place that hdr would be put +	 */ +	skb_set_mac_header(skb, skb->len); +  	/*  	 * Override the nss from the rx_vec since the rate_n_flags has  	 * only 2 bits for the nss which gives a max of 4 ss but there @@ -2148,6 +2164,10 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,  			le32_get_bits(desc->rx_vec[0],  				      RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1;  		break; +	case RATE_MCS_EHT_MSK: +		rx_status->nss = +			le32_get_bits(desc->rx_vec[2], +				      RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK) + 1;  	}  	rcu_read_lock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index cbd8053a9e35..69634fb82a9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -316,7 +316,7 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,  }  static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, -			       u16 *queueptr, u8 tid) +			       int sta_id, u16 *queueptr, u8 tid)  {  	int queue = *queueptr;  	struct iwl_scd_txq_cfg_cmd cmd = { @@ -333,7 +333,8 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  					     SCD_QUEUE_CONFIG_CMD);  			struct iwl_scd_queue_cfg_cmd remove_cmd = {  				.operation = cpu_to_le32(IWL_SCD_QUEUE_REMOVE), -				.u.remove.queue = cpu_to_le32(queue), +				.u.remove.tid = cpu_to_le32(tid), +				.u.remove.sta_mask = cpu_to_le32(BIT(sta_id)),  			};  			ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, @@ -531,7 +532,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,  		iwl_mvm_invalidate_sta_queue(mvm, queue,  					     disable_agg_tids, false); -	ret = iwl_mvm_disable_txq(mvm, old_sta, &queue_tmp, tid); +	ret = iwl_mvm_disable_txq(mvm, old_sta, sta_id, &queue_tmp, tid);  	if (ret) {  		IWL_ERR(mvm,  			"Failed to free inactive queue %d (ret=%d)\n", @@ -1408,7 +1409,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,  out_err:  	queue_tmp = queue; -	iwl_mvm_disable_txq(mvm, sta, &queue_tmp, tid); +	iwl_mvm_disable_txq(mvm, sta, mvmsta->sta_id, &queue_tmp, tid);  	return ret;  } @@ -1854,7 +1855,8 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,  		if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE)  			continue; -		iwl_mvm_disable_txq(mvm, sta, &mvm_sta->tid_data[i].txq_id, i); +		iwl_mvm_disable_txq(mvm, sta, mvm_sta->sta_id, +				    &mvm_sta->tid_data[i].txq_id, i);  		mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE;  	} @@ -1954,6 +1956,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,  		if (vif->cfg.assoc)  			return ret; +		/* first remove remaining keys */ +		iwl_mvm_sec_key_remove_ap(mvm, vif); +  		/* unassoc - go ahead - remove the AP STA now */  		mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;  	} @@ -2062,7 +2067,7 @@ static int iwl_mvm_add_int_sta_with_queue(struct iwl_mvm *mvm, int macidx,  	ret = iwl_mvm_add_int_sta_common(mvm, sta, addr, macidx, maccolor);  	if (ret) {  		if (!iwl_mvm_has_new_tx_api(mvm)) -			iwl_mvm_disable_txq(mvm, NULL, queue, +			iwl_mvm_disable_txq(mvm, NULL, sta->sta_id, queue,  					    IWL_MAX_TID_COUNT);  		return ret;  	} @@ -2135,7 +2140,8 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA))  		return -EINVAL; -	iwl_mvm_disable_txq(mvm, NULL, &mvm->snif_queue, IWL_MAX_TID_COUNT); +	iwl_mvm_disable_txq(mvm, NULL, mvm->snif_sta.sta_id, +			    &mvm->snif_queue, IWL_MAX_TID_COUNT);  	ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);  	if (ret)  		IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2152,7 +2158,8 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm)  	if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA))  		return -EINVAL; -	iwl_mvm_disable_txq(mvm, NULL, &mvm->aux_queue, IWL_MAX_TID_COUNT); +	iwl_mvm_disable_txq(mvm, NULL, mvm->aux_sta.sta_id, +			    &mvm->aux_queue, IWL_MAX_TID_COUNT);  	ret = iwl_mvm_rm_sta_common(mvm, mvm->aux_sta.sta_id);  	if (ret)  		IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2269,7 +2276,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,  	}  	queue = *queueptr; -	iwl_mvm_disable_txq(mvm, NULL, queueptr, IWL_MAX_TID_COUNT); +	iwl_mvm_disable_txq(mvm, NULL, mvmvif->bcast_sta.sta_id, +			    queueptr, IWL_MAX_TID_COUNT);  	if (iwl_mvm_has_new_tx_api(mvm))  		return; @@ -2504,7 +2512,8 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true); -	iwl_mvm_disable_txq(mvm, NULL, &mvmvif->cab_queue, 0); +	iwl_mvm_disable_txq(mvm, NULL, mvmvif->mcast_sta.sta_id, +			    &mvmvif->cab_queue, 0);  	ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);  	if (ret) @@ -2826,7 +2835,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		/* synchronize all rx queues so we can safely delete */  		iwl_mvm_free_reorder(mvm, baid_data); -		del_timer_sync(&baid_data->session_timer); +		timer_shutdown_sync(&baid_data->session_timer);  		RCU_INIT_POINTER(mvm->baid_map[baid], NULL);  		kfree_rcu(baid_data, rcu_head);  		IWL_DEBUG_HT(mvm, "BAID %d is free\n", baid); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index ed8ba81a6043..e403a240a82f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -376,12 +376,11 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,  static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,  					   struct iwl_time_event_notif *notif)  { -	struct iwl_mvm_time_event_data *te_data, *tmp; -	bool aux_roc_te = false; +	struct iwl_mvm_time_event_data *aux_roc_te = NULL, *te_data; -	list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) { +	list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {  		if (le32_to_cpu(notif->unique_id) == te_data->uid) { -			aux_roc_te = true; +			aux_roc_te = te_data;  			break;  		}  	} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 69cf3a372759..232c200af38f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -573,11 +573,11 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)  	 * and uncompressed, the FW should get it compressed and sorted  	 */ -	/* compress temp_trips to cmd array, remove uninitialized values*/ +	/* compress trips to cmd array, remove uninitialized values*/  	for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) { -		if (mvm->tz_device.temp_trips[i] != S16_MIN) { +		if (mvm->tz_device.trips[i].temperature != INT_MIN) {  			cmd.thresholds[idx++] = -				cpu_to_le16(mvm->tz_device.temp_trips[i]); +				cpu_to_le16((s16)(mvm->tz_device.trips[i].temperature / 1000));  		}  	}  	cmd.num_temps = cpu_to_le32(idx); @@ -593,8 +593,8 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)  	 */  	for (i = 0; i < idx; i++) {  		for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) { -			if (le16_to_cpu(cmd.thresholds[i]) == -				mvm->tz_device.temp_trips[j]) +			if ((int)(le16_to_cpu(cmd.thresholds[i]) * 1000) == +			    mvm->tz_device.trips[j].temperature)  				mvm->tz_device.fw_trips_index[i] = j;  		}  	} @@ -638,37 +638,12 @@ out:  	return ret;  } -static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device, -				       int trip, int *temp) -{ -	struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata; - -	if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) -		return -EINVAL; - -	*temp = mvm->tz_device.temp_trips[trip] * 1000; - -	return 0; -} - -static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device, -				       int trip, enum thermal_trip_type *type) -{ -	if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) -		return -EINVAL; - -	*type = THERMAL_TRIP_PASSIVE; - -	return 0; -} -  static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,  				       int trip, int temp)  {  	struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;  	struct iwl_mvm_thermal_device *tzone; -	int i, ret; -	s16 temperature; +	int ret;  	mutex_lock(&mvm->mutex); @@ -678,40 +653,17 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,  		goto out;  	} -	if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) { -		ret = -EINVAL; -		goto out; -	} -  	if ((temp / 1000) > S16_MAX) {  		ret = -EINVAL;  		goto out;  	} -	temperature = (s16)(temp / 1000);  	tzone = &mvm->tz_device; -  	if (!tzone) {  		ret = -EIO;  		goto out;  	} -	/* no updates*/ -	if (tzone->temp_trips[trip] == temperature) { -		ret = 0; -		goto out; -	} - -	/* already existing temperature */ -	for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) { -		if (tzone->temp_trips[i] == temperature) { -			ret = -EINVAL; -			goto out; -		} -	} - -	tzone->temp_trips[trip] = temperature; -  	ret = iwl_mvm_send_temp_report_ths_cmd(mvm);  out:  	mutex_unlock(&mvm->mutex); @@ -720,8 +672,6 @@ out:  static  struct thermal_zone_device_ops tzone_ops = {  	.get_temp = iwl_mvm_tzone_get_temp, -	.get_trip_temp = iwl_mvm_tzone_get_trip_temp, -	.get_trip_type = iwl_mvm_tzone_get_trip_type,  	.set_trip_temp = iwl_mvm_tzone_set_trip_temp,  }; @@ -743,7 +693,8 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)  	BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);  	sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF); -	mvm->tz_device.tzone = thermal_zone_device_register(name, +	mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name, +							mvm->tz_device.trips,  							IWL_MAX_DTS_TRIPS,  							IWL_WRITABLE_TRIPS_MSK,  							mvm, &tzone_ops, @@ -766,8 +717,10 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)  	/* 0 is a valid temperature,  	 * so initialize the array with S16_MIN which invalid temperature  	 */ -	for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) -		mvm->tz_device.temp_trips[i] = S16_MIN; +	for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) { +		mvm->tz_device.trips[i].temperature = INT_MIN; +		mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE; +	}  }  static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 86d20e13bf47..9813d7fa1800 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation   * Copyright (C) 2013-2015 Intel Mobile Communications GmbH   * Copyright (C) 2016-2017 Intel Deutschland GmbH   */ @@ -183,7 +183,10 @@ static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,  			   struct ieee80211_tx_info *info,  			   bool amsdu)  { -	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) +	if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ || +	    (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_BZ && +	     CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && +	     mvm->trans->hw_rev_step == SILICON_A_STEP))  		return iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu);  	return iwl_mvm_tx_csum_bz(mvm, skb, amsdu);  } @@ -1104,8 +1107,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,  	spin_lock(&mvmsta->lock);  	/* nullfunc frames should go to the MGMT queue regardless of QOS, -	 * the condition of !ieee80211_is_qos_nullfunc(fc) keeps the default -	 * assignment of MGMT TID +	 * the conditions of !ieee80211_is_qos_nullfunc(fc) and +	 * !ieee80211_is_data_qos(fc) keep the default assignment of MGMT TID  	 */  	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {  		tid = ieee80211_get_tid(hdr); @@ -1130,7 +1133,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,  			/* update the tx_cmd hdr as it was already copied */  			tx_cmd->hdr->seq_ctrl = hdr->seq_ctrl;  		} -	} else if (ieee80211_is_data(fc) && !ieee80211_is_data_qos(fc)) { +	} else if (ieee80211_is_data(fc) && !ieee80211_is_data_qos(fc) && +		   !ieee80211_is_nullfunc(fc)) {  		tid = IWL_TID_NON_QOS;  	} @@ -1171,9 +1175,15 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,  	/* From now on, we cannot access info->control */  	iwl_mvm_skb_prepare_status(skb, dev_cmd); +	/* +	 * The IV is introduced by the HW for new tx api, and it is not present +	 * in the skb, hence, don't tell iwl_mvm_mei_tx_copy_to_csme about the +	 * IV for those devices. +	 */  	if (ieee80211_is_data(fc))  		iwl_mvm_mei_tx_copy_to_csme(mvm, skb, -					    info->control.hw_key ? +					    info->control.hw_key && +					    !iwl_mvm_has_new_tx_api(mvm) ?  					    info->control.hw_key->iv_len : 0);  	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id)) @@ -1206,6 +1216,7 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,  	struct sk_buff_head mpdus_skbs;  	unsigned int payload_len;  	int ret; +	struct sk_buff *orig_skb = skb;  	if (WARN_ON_ONCE(!mvmsta))  		return -1; @@ -1238,8 +1249,17 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,  		ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta);  		if (ret) { +			/* Free skbs created as part of TSO logic that have not yet been dequeued */  			__skb_queue_purge(&mpdus_skbs); -			return ret; +			/* skb here is not necessarily same as skb that entered this method, +			 * so free it explicitly. +			 */ +			if (skb == orig_skb) +				ieee80211_free_txskb(mvm->hw, skb); +			else +				kfree_skb(skb); +			/* there was error, but we consumed skb one way or another, so return 0 */ +			return 0;  		}  	} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 75fd386b048e..cb60ba40fe97 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -136,6 +136,10 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,  				      &control_flags);  	prph_sc_ctrl->control.control_flags = cpu_to_le32(control_flags); +	/* initialize the Step equalizer data */ +	prph_sc_ctrl->step_cfg.mbx_addr_0 = cpu_to_le32(trans->mbx_addr_0_step); +	prph_sc_ctrl->step_cfg.mbx_addr_1 = cpu_to_le32(trans->mbx_addr_1_step); +  	/* allocate ucode sections in dram and set addresses */  	ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram);  	if (ret) @@ -343,3 +347,4 @@ int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,  	return 0;  } + diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 4f699862e7f7..99768d6a6032 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1350,15 +1350,13 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {  };  /* - * In case that there is no OTP on the NIC, get the rf id and cdb info - * from the prph registers. + * Read rf id and cdb info from prph register and store it   */  static int get_crf_id(struct iwl_trans *iwl_trans)  {  	int ret = 0;  	u32 sd_reg_ver_addr; -	u32 cdb = 0; -	u32 val; +	u32 val = 0;  	if (iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)  		sd_reg_ver_addr = SD_REG_VER_GEN2; @@ -1377,10 +1375,26 @@ static int get_crf_id(struct iwl_trans *iwl_trans)  	iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val);  	/* Read crf info */ -	val = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr); +	iwl_trans->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr);  	/* Read cdb info (also contains the jacket info if needed in the future */ -	cdb = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); +	iwl_trans->hw_cdb_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); + +	iwl_trans_release_nic_access(iwl_trans); + +out: +	return ret; +} + +/* + * In case that there is no OTP on the NIC, map the rf id and cdb info + * from the prph registers. + */ +static int map_crf_id(struct iwl_trans *iwl_trans) +{ +	int ret = 0; +	u32 val = iwl_trans->hw_crf_id; +	u32 cdb = iwl_trans->hw_cdb_id;  	/* Map between crf id to rf id */  	switch (REG_CRF_ID_TYPE(val)) { @@ -1410,7 +1424,7 @@ static int get_crf_id(struct iwl_trans *iwl_trans)  		IWL_ERR(iwl_trans,  			"Can find a correct rfid for crf id 0x%x\n",  			REG_CRF_ID_TYPE(val)); -		goto out_release; +		goto out;  	} @@ -1423,8 +1437,6 @@ static int get_crf_id(struct iwl_trans *iwl_trans)  	IWL_INFO(iwl_trans, "Detected RF 0x%x from crf id 0x%x\n",  		 iwl_trans->hw_rf_id, REG_CRF_ID_TYPE(val)); -out_release: -	iwl_trans_release_nic_access(iwl_trans);  out:  	return ret; @@ -1544,6 +1556,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	}  	iwl_trans->hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); +	get_crf_id(iwl_trans);  	/*  	 * The RF_ID is set to zero in blank OTP so read version to @@ -1552,7 +1565,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	 */  	if (iwl_trans->trans_cfg->rf_id &&  	    iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && -	    !CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && get_crf_id(iwl_trans)) { +	    !CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && map_crf_id(iwl_trans)) {  		ret = -EINVAL;  		goto out_free_trans;  	} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index bd50f52a1aad..0a9af1ad1f20 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2052,6 +2052,7 @@ static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)  struct iwl_trans_pcie_removal {  	struct pci_dev *pdev;  	struct work_struct work; +	bool rescan;  };  static void iwl_trans_pcie_removal_wk(struct work_struct *wk) @@ -2060,18 +2061,61 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk)  		container_of(wk, struct iwl_trans_pcie_removal, work);  	struct pci_dev *pdev = removal->pdev;  	static char *prop[] = {"EVENT=INACCESSIBLE", NULL}; +	struct pci_bus *bus = pdev->bus;  	dev_err(&pdev->dev, "Device gone - attempting removal\n");  	kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop);  	pci_lock_rescan_remove();  	pci_dev_put(pdev);  	pci_stop_and_remove_bus_device(pdev); +	if (removal->rescan) +		pci_rescan_bus(bus->parent);  	pci_unlock_rescan_remove();  	kfree(removal);  	module_put(THIS_MODULE);  } +void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan) +{ +	struct iwl_trans_pcie_removal *removal; + +	if (test_bit(STATUS_TRANS_DEAD, &trans->status)) +		return; + +	IWL_ERR(trans, "Device gone - scheduling removal!\n"); + +	/* +	 * get a module reference to avoid doing this +	 * while unloading anyway and to avoid +	 * scheduling a work with code that's being +	 * removed. +	 */ +	if (!try_module_get(THIS_MODULE)) { +		IWL_ERR(trans, +			"Module is being unloaded - abort\n"); +		return; +	} + +	removal = kzalloc(sizeof(*removal), GFP_ATOMIC); +	if (!removal) { +		module_put(THIS_MODULE); +		return; +	} +	/* +	 * we don't need to clear this flag, because +	 * the trans will be freed and reallocated. +	 */ +	set_bit(STATUS_TRANS_DEAD, &trans->status); + +	removal->pdev = to_pci_dev(trans->dev); +	removal->rescan = rescan; +	INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk); +	pci_dev_get(removal->pdev); +	schedule_work(&removal->work); +} +EXPORT_SYMBOL(iwl_trans_pcie_remove); +  /*   * This version doesn't disable BHs but rather assumes they're   * already disabled. @@ -2131,47 +2175,12 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)  		iwl_trans_pcie_dump_regs(trans); -		if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) { -			struct iwl_trans_pcie_removal *removal; - -			if (test_bit(STATUS_TRANS_DEAD, &trans->status)) -				goto err; - -			IWL_ERR(trans, "Device gone - scheduling removal!\n"); - -			/* -			 * get a module reference to avoid doing this -			 * while unloading anyway and to avoid -			 * scheduling a work with code that's being -			 * removed. -			 */ -			if (!try_module_get(THIS_MODULE)) { -				IWL_ERR(trans, -					"Module is being unloaded - abort\n"); -				goto err; -			} - -			removal = kzalloc(sizeof(*removal), GFP_ATOMIC); -			if (!removal) { -				module_put(THIS_MODULE); -				goto err; -			} -			/* -			 * we don't need to clear this flag, because -			 * the trans will be freed and reallocated. -			*/ -			set_bit(STATUS_TRANS_DEAD, &trans->status); - -			removal->pdev = to_pci_dev(trans->dev); -			INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk); -			pci_dev_get(removal->pdev); -			schedule_work(&removal->work); -		} else { +		if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) +			iwl_trans_pcie_remove(trans, false); +		else  			iwl_write32(trans, CSR_RESET,  				    CSR_RESET_REG_FLAG_FORCE_NMI); -		} -err:  		spin_unlock(&trans_pcie->reg_lock);  		return false;  	}  |