diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 69 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 21 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 11 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 8 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 10 | 
13 files changed, 114 insertions, 27 deletions
| diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 00e6737dda72..a47635c32c11 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  obj-$(CONFIG_IWLMVM)   += iwlmvm.o  iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o  iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 5de19ea10575..b205a7bfb828 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2167,7 +2167,7 @@ out:  	 * 1. We are not using a unified image  	 * 2. We are using a unified image but had an error while exiting D3  	 */ -	set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); +	set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);  	set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);  	/*  	 * When switching images we return 1, which causes mac80211 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 15f2d826bb4b..a9ac872226fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1077,6 +1077,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)  	mvm->vif_count = 0;  	mvm->rx_ba_sessions = 0;  	mvm->fwrt.dump.conf = FW_DBG_INVALID; +	mvm->monitor_on = false;  	/* keep statistics ticking */  	iwl_mvm_accu_radio_stats(mvm); @@ -1437,6 +1438,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,  		mvm->p2p_device_vif = vif;  	} +	if (vif->type == NL80211_IFTYPE_MONITOR) +		mvm->monitor_on = true; +  	iwl_mvm_vif_dbgfs_register(mvm, vif);  	goto out_unlock; @@ -1526,6 +1530,9 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,  	iwl_mvm_power_update_mac(mvm);  	iwl_mvm_mac_ctxt_remove(mvm, vif); +	if (vif->type == NL80211_IFTYPE_MONITOR) +		mvm->monitor_on = false; +  out_release:  	mutex_unlock(&mvm->mutex);  } @@ -1546,6 +1553,11 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,  	struct iwl_mvm_mc_iter_data *data = _data;  	struct iwl_mvm *mvm = data->mvm;  	struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd; +	struct iwl_host_cmd hcmd = { +		.id = MCAST_FILTER_CMD, +		.flags = CMD_ASYNC, +		.dataflags[0] = IWL_HCMD_DFL_NOCOPY, +	};  	int ret, len;  	/* if we don't have free ports, mcast frames will be dropped */ @@ -1560,7 +1572,10 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,  	memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);  	len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4); -	ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd); +	hcmd.len[0] = len; +	hcmd.data[0] = cmd; + +	ret = iwl_mvm_send_cmd(mvm, &hcmd);  	if (ret)  		IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);  } @@ -1635,6 +1650,12 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,  	if (!cmd)  		goto out; +	if (changed_flags & FIF_ALLMULTI) +		cmd->pass_all = !!(*total_flags & FIF_ALLMULTI); + +	if (cmd->pass_all) +		cmd->count = 0; +  	iwl_mvm_recalc_multicast(mvm);  out:  	mutex_unlock(&mvm->mutex); @@ -2563,7 +2584,7 @@ static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm,  			 * queues, so we should never get a second deferred  			 * frame for the RA/TID.  			 */ -			iwl_mvm_start_mac_queues(mvm, info->hw_queue); +			iwl_mvm_start_mac_queues(mvm, BIT(info->hw_queue));  			ieee80211_free_txskb(mvm->hw, skb);  		}  	} @@ -3975,6 +3996,43 @@ out_unlock:  	return ret;  } +static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop) +{ +	if (drop) { +		if (iwl_mvm_has_new_tx_api(mvm)) +			/* TODO new tx api */ +			WARN_ONCE(1, +				  "Need to implement flush TX queue\n"); +		else +			iwl_mvm_flush_tx_path(mvm, +				iwl_mvm_flushable_queues(mvm) & queues, +				0); +	} else { +		if (iwl_mvm_has_new_tx_api(mvm)) { +			struct ieee80211_sta *sta; +			int i; + +			mutex_lock(&mvm->mutex); + +			for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { +				sta = rcu_dereference_protected( +						mvm->fw_id_to_mac_id[i], +						lockdep_is_held(&mvm->mutex)); +				if (IS_ERR_OR_NULL(sta)) +					continue; + +				iwl_mvm_wait_sta_queues_empty(mvm, +						iwl_mvm_sta_from_mac80211(sta)); +			} + +			mutex_unlock(&mvm->mutex); +		} else { +			iwl_trans_wait_tx_queues_empty(mvm->trans, +						       queues); +		} +	} +} +  static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,  			      struct ieee80211_vif *vif, u32 queues, bool drop)  { @@ -3985,7 +4043,12 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,  	int i;  	u32 msk = 0; -	if (!vif || vif->type != NL80211_IFTYPE_STATION) +	if (!vif) { +		iwl_mvm_flush_no_vif(mvm, queues, drop); +		return; +	} + +	if (vif->type != NL80211_IFTYPE_STATION)  		return;  	/* Make sure we're done with the deferred traffic before flushing */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 83303bac0e4b..949e63418299 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1015,6 +1015,9 @@ struct iwl_mvm {  	bool drop_bcn_ap_mode;  	struct delayed_work cs_tx_unblock_dwork; + +	/* does a monitor vif exist (only one can exist hence bool) */ +	bool monitor_on;  #ifdef CONFIG_ACPI  	struct iwl_mvm_sar_profile sar_profiles[IWL_MVM_SAR_PROFILE_NUM];  	struct iwl_mvm_geo_profile geo_profiles[IWL_NUM_GEO_PROFILES]; @@ -1159,7 +1162,7 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)  	 * Enable LAR only if it is supported by the FW (TLV) &&  	 * enabled in the NVM  	 */ -	if (mvm->cfg->ext_nvm) +	if (mvm->cfg->nvm_type == IWL_NVM_EXT)  		return nvm_lar && tlv_lar;  	else  		return tlv_lar; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 422aa6be9932..fb25b6f29323 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -295,18 +295,24 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  	const __be16 *hw;  	const __le16 *sw, *calib, *regulatory, *mac_override, *phy_sku;  	bool lar_enabled; +	int regulatory_type;  	/* Checking for required sections */ -	if (!mvm->trans->cfg->ext_nvm) { +	if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) {  		if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||  		    !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {  			IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");  			return NULL;  		}  	} else { +		if (mvm->trans->cfg->nvm_type == IWL_NVM_SDP) +			regulatory_type = NVM_SECTION_TYPE_REGULATORY_SDP; +		else +			regulatory_type = NVM_SECTION_TYPE_REGULATORY; +  		/* SW and REGULATORY sections are mandatory */  		if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || -		    !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { +		    !mvm->nvm_sections[regulatory_type].data) {  			IWL_ERR(mvm,  				"Can't parse empty family 8000 OTP/NVM sections\n");  			return NULL; @@ -330,11 +336,14 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)  	hw = (const __be16 *)sections[mvm->cfg->nvm_hw_section_num].data;  	sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;  	calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; -	regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;  	mac_override =  		(const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;  	phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data; +	regulatory = mvm->trans->cfg->nvm_type == IWL_NVM_SDP ? +		(const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY_SDP].data : +		(const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; +  	lar_enabled = !iwlwifi_mod_params.lar_disable &&  		      fw_has_capa(&mvm->fw->ucode_capa,  				  IWL_UCODE_TLV_CAPA_LAR_SUPPORT); @@ -394,7 +403,7 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)  	IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");  	/* Maximal size depends on NVM version */ -	if (!mvm->trans->cfg->ext_nvm) +	if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT)  		max_section_size = IWL_MAX_NVM_SECTION_SIZE;  	else  		max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; @@ -465,7 +474,7 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)  			break;  		} -		if (!mvm->trans->cfg->ext_nvm) { +		if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) {  			section_size =  				2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));  			section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); @@ -740,7 +749,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)  	struct ieee80211_regdomain *regd;  	char mcc[3]; -	if (mvm->cfg->ext_nvm) { +	if (mvm->cfg->nvm_type == IWL_NVM_EXT) {  		tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,  				      IWL_UCODE_TLV_CAPA_LAR_SUPPORT);  		nvm_lar = mvm->nvm_data->lar_enabled; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index ba7bd049d3d4..0fe723ca844e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -661,7 +661,8 @@ static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,  	    (lq_sta->tx_agg_tid_en & BIT(tid)) &&  	    (tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD)) {  		IWL_DEBUG_RATE(mvm, "try to aggregate tid %d\n", tid); -		rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta); +		if (rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta) == 0) +			tid_data->state = IWL_AGG_QUEUED;  	}  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 184c749766f2..2d14a58cbdd7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -244,7 +244,9 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,  		return 0;  	default: -		IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); +		/* Expected in monitor (not having the keys) */ +		if (!mvm->monitor_on) +			IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);  	}  	return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 67ffd9774712..248699c2c4bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -277,7 +277,9 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,  		stats->flag |= RX_FLAG_DECRYPTED;  		return 0;  	default: -		IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status); +		/* Expected in monitor (not having the keys) */ +		if (!mvm->monitor_on) +			IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status);  	}  	return 0; @@ -672,11 +674,12 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,  	 * If there was a significant jump in the nssn - adjust.  	 * If the SN is smaller than the NSSN it might need to first go into  	 * the reorder buffer, in which case we just release up to it and the -	 * rest of the function will take of storing it and releasing up to the -	 * nssn +	 * rest of the function will take care of storing it and releasing up to +	 * the nssn  	 */  	if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, -				buffer->buf_size)) { +				buffer->buf_size) || +	    !ieee80211_sn_less(sn, buffer->head_sn + buffer->buf_size)) {  		u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;  		iwl_mvm_release_frames(mvm, sta, napi, buffer, min_sn); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 50983615dce6..774122fed454 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -555,7 +555,7 @@ static int iwl_mvm_lmac_scan_abort(struct iwl_mvm *mvm)  	struct iwl_host_cmd cmd = {  		.id = SCAN_OFFLOAD_ABORT_CMD,  	}; -	u32 status; +	u32 status = CAN_ABORT_STATUS;  	ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);  	if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 411a2055dc45..c4a343534c5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1285,7 +1285,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,  {  	struct iwl_mvm_add_sta_cmd cmd;  	int ret; -	u32 status; +	u32 status = ADD_STA_SUCCESS;  	lockdep_assert_held(&mvm->mutex); @@ -2385,8 +2385,10 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))  		return -EINVAL; -	if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) { -		IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n", +	if (mvmsta->tid_data[tid].state != IWL_AGG_QUEUED && +	    mvmsta->tid_data[tid].state != IWL_AGG_OFF) { +		IWL_ERR(mvm, +			"Start AGG when state is not IWL_AGG_QUEUED or IWL_AGG_OFF %d!\n",  			mvmsta->tid_data[tid].state);  		return -ENXIO;  	} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index d13893806513..aedabe101cf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -281,6 +281,7 @@ struct iwl_mvm_vif;   * These states relate to a specific RA / TID.   *   * @IWL_AGG_OFF: aggregation is not used + * @IWL_AGG_QUEUED: aggregation start work has been queued   * @IWL_AGG_STARTING: aggregation are starting (between start and oper)   * @IWL_AGG_ON: aggregation session is up   * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the @@ -290,6 +291,7 @@ struct iwl_mvm_vif;   */  enum iwl_mvm_agg_state {  	IWL_AGG_OFF = 0, +	IWL_AGG_QUEUED,  	IWL_AGG_STARTING,  	IWL_AGG_ON,  	IWL_EMPTYING_HW_QUEUE_ADDBA, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 8876c2abc440..1232f63278eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -529,6 +529,7 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)  	lockdep_assert_held(&mvm->mutex); +	status = 0;  	ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,  						       CTDP_CONFIG_CMD),  					  sizeof(cmd), &cmd, &status); @@ -630,7 +631,7 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,  	if (!iwl_mvm_firmware_running(mvm) ||  	    mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { -		ret = -EIO; +		ret = -ENODATA;  		goto out;  	} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 172b5e63d3fb..6f2e2af23219 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -564,8 +564,8 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,  	case NL80211_IFTYPE_AP:  	case NL80211_IFTYPE_ADHOC:  		/* -		 * Handle legacy hostapd as well, where station will be added -		 * only just before sending the association response. +		 * Non-bufferable frames use the broadcast station, thus they +		 * use the probe queue.  		 * Also take care of the case where we send a deauth to a  		 * station that we don't have, or similarly an association  		 * response (with non-success status) for a station we can't @@ -573,9 +573,9 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,  		 * Also, disassociate frames might happen, particular with  		 * reason 7 ("Class 3 frame received from nonassociated STA").  		 */ -		if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || -		    ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc) || -		    ieee80211_is_disassoc(fc)) +		if (ieee80211_is_mgmt(fc) && +		    (!ieee80211_is_bufferable_mmpdu(fc) || +		     ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))  			return mvm->probe_queue;  		if (info->hw_queue == info->control.vif->cab_queue)  			return mvmvif->cab_queue; |