diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/coex.c | 24 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 8 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 10 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rs.c | 261 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rs.h | 14 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/scan.c | 55 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sf.c | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/utils.c | 19 | 
9 files changed, 239 insertions, 158 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 685f7e8e6943..0489314425cb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -190,7 +190,7 @@ static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {  		cpu_to_le32(0xcc00aaaa),  		cpu_to_le32(0x0000aaaa),  		cpu_to_le32(0xc0004000), -		cpu_to_le32(0x00000000), +		cpu_to_le32(0x00004000),  		cpu_to_le32(0xf0005000),  		cpu_to_le32(0xf0005000),  	}, @@ -213,16 +213,16 @@ static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {  		/* Tx Tx disabled */  		cpu_to_le32(0xaaaaaaaa),  		cpu_to_le32(0xaaaaaaaa), -		cpu_to_le32(0xaaaaaaaa), +		cpu_to_le32(0xeeaaaaaa),  		cpu_to_le32(0xaaaaaaaa),  		cpu_to_le32(0xcc00ff28),  		cpu_to_le32(0x0000aaaa),  		cpu_to_le32(0xcc00aaaa),  		cpu_to_le32(0x0000aaaa), -		cpu_to_le32(0xC0004000), -		cpu_to_le32(0xC0004000), -		cpu_to_le32(0xF0005000), -		cpu_to_le32(0xF0005000), +		cpu_to_le32(0xc0004000), +		cpu_to_le32(0xc0004000), +		cpu_to_le32(0xf0005000), +		cpu_to_le32(0xf0005000),  	},  }; @@ -611,14 +611,14 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)  		bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);  	if (IWL_MVM_BT_COEX_CORUNNING) { -		bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_CORUN_LUT_20 | -						    BT_VALID_CORUN_LUT_40); +		bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 | +						     BT_VALID_CORUN_LUT_40);  		bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING);  	}  	if (IWL_MVM_BT_COEX_MPLUT) {  		bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); -		bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); +		bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT);  	}  	if (mvm->cfg->bt_shared_single_ant) @@ -1262,6 +1262,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	u32 ant_isolation = le32_to_cpup((void *)pkt->data);  	u8 __maybe_unused lower_bound, upper_bound; +	int ret;  	u8 lut;  	struct iwl_bt_coex_cmd *bt_cmd; @@ -1318,5 +1319,8 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,  	memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20,  	       sizeof(bt_cmd->bt4_corun_lut40)); -	return 0; +	ret = iwl_mvm_send_cmd(mvm, &cmd); + +	kfree(bt_cmd); +	return ret;  } diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 9426905de6b2..d73a89ecd78a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -183,9 +183,9 @@ enum iwl_scan_type {   *	this number of packets were received (typically 1)   * @passive2active: is auto switching from passive to active during scan allowed   * @rxchain_sel_flags: RXON_RX_CHAIN_* - * @max_out_time: in usecs, max out of serving channel time + * @max_out_time: in TUs, max out of serving channel time   * @suspend_time: how long to pause scan when returning to service channel: - *	bits 0-19: beacon interal in usecs (suspend before executing) + *	bits 0-19: beacon interal in TUs (suspend before executing)   *	bits 20-23: reserved   *	bits 24-31: number of beacons (suspend between channels)   * @rxon_flags: RXON_FLG_* @@ -383,8 +383,8 @@ enum scan_framework_client {   * @quiet_plcp_th:	quiet channel num of packets threshold   * @good_CRC_th:	passive to active promotion threshold   * @rx_chain:		RXON rx chain. - * @max_out_time:	max uSec to be out of assoceated channel - * @suspend_time:	pause scan this long when returning to service channel + * @max_out_time:	max TUs to be out of assoceated channel + * @suspend_time:	pause scan this TUs when returning to service channel   * @flags:		RXON flags   * @filter_flags:	RXONfilter   * @tx_cmd:		tx command for active scan; for 2GHz and for 5GHz. diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4dd9ff43b8b6..b41dc84e9431 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1007,7 +1007,7 @@ 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_SYNC, len, cmd); +	ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd);  	if (ret)  		IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);  } @@ -1023,7 +1023,7 @@ static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm)  	if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))  		return; -	ieee80211_iterate_active_interfaces( +	ieee80211_iterate_active_interfaces_atomic(  		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,  		iwl_mvm_mc_iface_iterator, &iter_data);  } @@ -1332,6 +1332,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  		 */  		iwl_mvm_remove_time_event(mvm, mvmvif,  					  &mvmvif->time_event_data); +		iwl_mvm_sf_update(mvm, vif, false);  		WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC));  	} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |  			      BSS_CHANGED_QOS)) { @@ -1806,6 +1807,11 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,  	mutex_lock(&mvm->mutex); +	if (!iwl_mvm_is_idle(mvm)) { +		ret = -EBUSY; +		goto out; +	} +  	switch (mvm->scan_status) {  	case IWL_MVM_SCAN_OS:  		IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d564233a65da..f1ec0986c3c9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1003,6 +1003,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)  	return mvmvif->low_latency;  } +/* Assoc status */ +bool iwl_mvm_is_idle(struct iwl_mvm *mvm); +  /* Thermal management and CT-kill */  void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);  void iwl_mvm_tt_handler(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 568abd61b14f..e1c838899363 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -59,7 +59,7 @@  /* max allowed rate miss before sync LQ cmd */  #define IWL_MISSED_RATE_MAX		15  #define RS_STAY_IN_COLUMN_TIMEOUT       (5*HZ) - +#define RS_IDLE_TIMEOUT                 (5*HZ)  static u8 rs_ht_to_legacy[] = {  	[IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, @@ -142,7 +142,7 @@ enum rs_column_mode {  	RS_MIMO2,  }; -#define MAX_NEXT_COLUMNS 5 +#define MAX_NEXT_COLUMNS 7  #define MAX_COLUMN_CHECKS 3  typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm, @@ -212,8 +212,10 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_LEGACY_ANT_B,  			RS_COLUMN_SISO_ANT_A,  			RS_COLUMN_SISO_ANT_B, -			RS_COLUMN_MIMO2, -			RS_COLUMN_MIMO2_SGI, +			RS_COLUMN_INVALID, +			RS_COLUMN_INVALID, +			RS_COLUMN_INVALID, +			RS_COLUMN_INVALID,  		},  	},  	[RS_COLUMN_LEGACY_ANT_B] = { @@ -223,8 +225,10 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_LEGACY_ANT_A,  			RS_COLUMN_SISO_ANT_A,  			RS_COLUMN_SISO_ANT_B, -			RS_COLUMN_MIMO2, -			RS_COLUMN_MIMO2_SGI, +			RS_COLUMN_INVALID, +			RS_COLUMN_INVALID, +			RS_COLUMN_INVALID, +			RS_COLUMN_INVALID,  		},  	},  	[RS_COLUMN_SISO_ANT_A] = { @@ -235,7 +239,9 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_MIMO2,  			RS_COLUMN_SISO_ANT_A_SGI,  			RS_COLUMN_SISO_ANT_B_SGI, -			RS_COLUMN_MIMO2_SGI, +			RS_COLUMN_LEGACY_ANT_A, +			RS_COLUMN_LEGACY_ANT_B, +			RS_COLUMN_INVALID,  		},  		.checks = {  			rs_siso_allow, @@ -249,7 +255,9 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_MIMO2,  			RS_COLUMN_SISO_ANT_B_SGI,  			RS_COLUMN_SISO_ANT_A_SGI, -			RS_COLUMN_MIMO2_SGI, +			RS_COLUMN_LEGACY_ANT_A, +			RS_COLUMN_LEGACY_ANT_B, +			RS_COLUMN_INVALID,  		},  		.checks = {  			rs_siso_allow, @@ -265,6 +273,8 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_SISO_ANT_A,  			RS_COLUMN_SISO_ANT_B,  			RS_COLUMN_MIMO2, +			RS_COLUMN_LEGACY_ANT_A, +			RS_COLUMN_LEGACY_ANT_B,  		},  		.checks = {  			rs_siso_allow, @@ -281,6 +291,8 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_SISO_ANT_B,  			RS_COLUMN_SISO_ANT_A,  			RS_COLUMN_MIMO2, +			RS_COLUMN_LEGACY_ANT_A, +			RS_COLUMN_LEGACY_ANT_B,  		},  		.checks = {  			rs_siso_allow, @@ -296,6 +308,8 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_SISO_ANT_A_SGI,  			RS_COLUMN_SISO_ANT_B_SGI,  			RS_COLUMN_MIMO2_SGI, +			RS_COLUMN_LEGACY_ANT_A, +			RS_COLUMN_LEGACY_ANT_B,  		},  		.checks = {  			rs_mimo_allow, @@ -311,6 +325,8 @@ static const struct rs_tx_column rs_tx_columns[] = {  			RS_COLUMN_SISO_ANT_A,  			RS_COLUMN_SISO_ANT_B,  			RS_COLUMN_MIMO2, +			RS_COLUMN_LEGACY_ANT_A, +			RS_COLUMN_LEGACY_ANT_B,  		},  		.checks = {  			rs_mimo_allow, @@ -503,10 +519,12 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)  	window->average_tpt = IWL_INVALID_VALUE;  } -static void rs_rate_scale_clear_tbl_windows(struct iwl_scale_tbl_info *tbl) +static void rs_rate_scale_clear_tbl_windows(struct iwl_mvm *mvm, +					    struct iwl_scale_tbl_info *tbl)  {  	int i; +	IWL_DEBUG_RATE(mvm, "Clearing up window stats\n");  	for (i = 0; i < IWL_RATE_COUNT; i++)  		rs_rate_scale_clear_window(&tbl->win[i]);  } @@ -992,6 +1010,13 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,  		return;  	} +#ifdef CONFIG_MAC80211_DEBUGFS +	/* Disable last tx check if we are debugging with fixed rate */ +	if (lq_sta->dbg_fixed_rate) { +		IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n"); +		return; +	} +#endif  	if (!ieee80211_is_data(hdr->frame_control) ||  	    info->flags & IEEE80211_TX_CTL_NO_ACK)  		return; @@ -1034,6 +1059,18 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,  			mac_index++;  	} +	if (time_after(jiffies, +		       (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { +		int tid; +		IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); +		for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) +			ieee80211_stop_tx_ba_session(sta, tid); + +		iwl_mvm_rs_rate_init(mvm, sta, sband->band, false); +		return; +	} +	lq_sta->last_tx = jiffies; +  	/* Here we actually compare this rate to the latest LQ command */  	if ((mac_index < 0) ||  	    (rate.sgi != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || @@ -1186,9 +1223,26 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,  	lq_sta->visited_columns = 0;  } +static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta, +				   const struct rs_tx_column *column) +{ +	switch (column->mode) { +	case RS_LEGACY: +		return lq_sta->max_legacy_rate_idx; +	case RS_SISO: +		return lq_sta->max_siso_rate_idx; +	case RS_MIMO2: +		return lq_sta->max_mimo2_rate_idx; +	default: +		WARN_ON_ONCE(1); +	} + +	return lq_sta->max_legacy_rate_idx; +} +  static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, -				      const struct rs_tx_column *column, -				      u32 bw) +					    const struct rs_tx_column *column, +					    u32 bw)  {  	/* Used to choose among HT tables */  	const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; @@ -1438,7 +1492,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)  				IWL_DEBUG_RATE(mvm,  					       "LQ: stay in table clear win\n"); -				rs_rate_scale_clear_tbl_windows(tbl); +				rs_rate_scale_clear_tbl_windows(mvm, tbl);  			}  		} @@ -1446,8 +1500,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)  		 * bitmaps and stats in active table (this will become the new  		 * "search" table). */  		if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { -			IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); -			rs_rate_scale_clear_tbl_windows(tbl); +			rs_rate_scale_clear_tbl_windows(mvm, tbl);  		}  	}  } @@ -1485,14 +1538,14 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,  					 struct ieee80211_sta *sta,  					 struct iwl_scale_tbl_info *tbl)  { -	int i, j, n; +	int i, j, max_rate;  	enum rs_column next_col_id;  	const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];  	const struct rs_tx_column *next_col;  	allow_column_func_t allow_func;  	u8 valid_ants = mvm->fw->valid_tx_ant;  	const u16 *expected_tpt_tbl; -	s32 tpt, max_expected_tpt; +	u16 tpt, max_expected_tpt;  	for (i = 0; i < MAX_NEXT_COLUMNS; i++) {  		next_col_id = curr_col->next_columns[i]; @@ -1535,11 +1588,11 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,  		if (WARN_ON_ONCE(!expected_tpt_tbl))  			continue; -		max_expected_tpt = 0; -		for (n = 0; n < IWL_RATE_COUNT; n++) -			if (expected_tpt_tbl[n] > max_expected_tpt) -				max_expected_tpt = expected_tpt_tbl[n]; +		max_rate = rs_get_max_allowed_rate(lq_sta, next_col); +		if (WARN_ON_ONCE(max_rate == IWL_RATE_INVALID)) +			continue; +		max_expected_tpt = expected_tpt_tbl[max_rate];  		if (tpt >= max_expected_tpt) {  			IWL_DEBUG_RATE(mvm,  				       "Skip column %d: can't beat current TPT. Max expected %d current %d\n", @@ -1547,14 +1600,15 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,  			continue;  		} +		IWL_DEBUG_RATE(mvm, +			       "Found potential column %d. Max expected %d current %d\n", +			       next_col_id, max_expected_tpt, tpt);  		break;  	}  	if (i == MAX_NEXT_COLUMNS)  		return RS_COLUMN_INVALID; -	IWL_DEBUG_RATE(mvm, "Found potential column %d\n", next_col_id); -  	return next_col_id;  } @@ -1640,85 +1694,76 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,  {  	enum rs_action action = RS_ACTION_STAY; -	/* Too many failures, decrease rate */  	if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {  		IWL_DEBUG_RATE(mvm, -			       "decrease rate because of low SR\n"); -		action = RS_ACTION_DOWNSCALE; -	/* No throughput measured yet for adjacent rates; try increase. */ -	} else if ((low_tpt == IWL_INVALID_VALUE) && -		   (high_tpt == IWL_INVALID_VALUE)) { -		if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) { -			IWL_DEBUG_RATE(mvm, -				       "Good SR and no high rate measurement. " -				       "Increase rate\n"); -			action = RS_ACTION_UPSCALE; -		} else if (low != IWL_RATE_INVALID) { -			IWL_DEBUG_RATE(mvm, -				       "Remain in current rate\n"); -			action = RS_ACTION_STAY; -		} +			       "Decrease rate because of low SR\n"); +		return RS_ACTION_DOWNSCALE;  	} -	/* Both adjacent throughputs are measured, but neither one has better -	 * throughput; we're using the best rate, don't change it! -	 */ -	else if ((low_tpt != IWL_INVALID_VALUE) && -		 (high_tpt != IWL_INVALID_VALUE) && -		 (low_tpt < current_tpt) && -		 (high_tpt < current_tpt)) { +	if ((low_tpt == IWL_INVALID_VALUE) && +	    (high_tpt == IWL_INVALID_VALUE) && +	    (high != IWL_RATE_INVALID)) {  		IWL_DEBUG_RATE(mvm, -			       "Both high and low are worse. " -			       "Maintain rate\n"); -		action = RS_ACTION_STAY; +			       "No data about high/low rates. Increase rate\n"); +		return RS_ACTION_UPSCALE;  	} -	/* At least one adjacent rate's throughput is measured, -	 * and may have better performance. -	 */ -	else { -		/* Higher adjacent rate's throughput is measured */ -		if (high_tpt != IWL_INVALID_VALUE) { -			/* Higher rate has better throughput */ -			if (high_tpt > current_tpt && -			    sr >= IWL_RATE_INCREASE_TH) { -				IWL_DEBUG_RATE(mvm, -					       "Higher rate is better and good " -					       "SR. Increate rate\n"); -				action = RS_ACTION_UPSCALE; -			} else { -				IWL_DEBUG_RATE(mvm, -					       "Higher rate isn't better OR " -					       "no good SR. Maintain rate\n"); -				action = RS_ACTION_STAY; -			} +	if ((high_tpt == IWL_INVALID_VALUE) && +	    (high != IWL_RATE_INVALID) && +	    (low_tpt != IWL_INVALID_VALUE) && +	    (low_tpt < current_tpt)) { +		IWL_DEBUG_RATE(mvm, +			       "No data about high rate and low rate is worse. Increase rate\n"); +		return RS_ACTION_UPSCALE; +	} -		/* Lower adjacent rate's throughput is measured */ -		} else if (low_tpt != IWL_INVALID_VALUE) { -			/* Lower rate has better throughput */ -			if (low_tpt > current_tpt) { -				IWL_DEBUG_RATE(mvm, -					       "Lower rate is better. " -					       "Decrease rate\n"); -				action = RS_ACTION_DOWNSCALE; -			} else if (sr >= IWL_RATE_INCREASE_TH) { -				IWL_DEBUG_RATE(mvm, -					       "Lower rate isn't better and " -					       "good SR. Increase rate\n"); -				action = RS_ACTION_UPSCALE; -			} -		} +	if ((high_tpt != IWL_INVALID_VALUE) && +	    (high_tpt > current_tpt)) { +		IWL_DEBUG_RATE(mvm, +			       "Higher rate is better. Increate rate\n"); +		return RS_ACTION_UPSCALE;  	} -	/* Sanity check; asked for decrease, but success rate or throughput -	 * has been good at old rate.  Don't change it. -	 */ -	if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID) && -	    ((sr > IWL_RATE_HIGH_TH) || -	     (current_tpt > (100 * tbl->expected_tpt[low])))) { +	if ((low_tpt != IWL_INVALID_VALUE) && +	    (high_tpt != IWL_INVALID_VALUE) && +	    (low_tpt < current_tpt) && +	    (high_tpt < current_tpt)) { +		IWL_DEBUG_RATE(mvm, +			       "Both high and low are worse. Maintain rate\n"); +		return RS_ACTION_STAY; +	} + +	if ((low_tpt != IWL_INVALID_VALUE) && +	    (low_tpt > current_tpt)) { +		IWL_DEBUG_RATE(mvm, +			       "Lower rate is better\n"); +		action = RS_ACTION_DOWNSCALE; +		goto out; +	} + +	if ((low_tpt == IWL_INVALID_VALUE) && +	    (low != IWL_RATE_INVALID)) {  		IWL_DEBUG_RATE(mvm, -			       "Sanity check failed. Maintain rate\n"); -		action = RS_ACTION_STAY; +			       "No data about lower rate\n"); +		action = RS_ACTION_DOWNSCALE; +		goto out; +	} + +	IWL_DEBUG_RATE(mvm, "Maintain rate\n"); + +out: +	if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) { +		if (sr >= RS_SR_NO_DECREASE) { +			IWL_DEBUG_RATE(mvm, +				       "SR is above NO DECREASE. Avoid downscale\n"); +			action = RS_ACTION_STAY; +		} else if (current_tpt > (100 * tbl->expected_tpt[low])) { +			IWL_DEBUG_RATE(mvm, +				       "Current TPT is higher than max expected in low rate. Avoid downscale\n"); +			action = RS_ACTION_STAY; +		} else { +			IWL_DEBUG_RATE(mvm, "Decrease rate\n"); +		}  	}  	return action; @@ -1792,6 +1837,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,  			       "Aggregation changed: prev %d current %d. Update expected TPT table\n",  			       prev_agg, lq_sta->is_agg);  		rs_set_expected_tpt_table(lq_sta, tbl); +		rs_rate_scale_clear_tbl_windows(mvm, tbl);  	}  	/* current tx rate */ @@ -2021,7 +2067,7 @@ lq_update:  		if (lq_sta->search_better_tbl) {  			/* Access the "search" table, clear its history. */  			tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); -			rs_rate_scale_clear_tbl_windows(tbl); +			rs_rate_scale_clear_tbl_windows(mvm, tbl);  			/* Use new "search" start rate */  			index = tbl->rate.index; @@ -2042,8 +2088,18 @@ lq_update:  		 * stay with best antenna legacy modulation for a while  		 * before next round of mode comparisons. */  		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); -		if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported) { +		if (is_legacy(&tbl1->rate)) {  			IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); + +			if (tid != IWL_MAX_TID_COUNT) { +				tid_data = &sta_priv->tid_data[tid]; +				if (tid_data->state != IWL_AGG_OFF) { +					IWL_DEBUG_RATE(mvm, +						       "Stop aggregation on tid %d\n", +						       tid); +					ieee80211_stop_tx_ba_session(sta, tid); +				} +			}  			rs_set_stay_in_table(mvm, 1, lq_sta);  		} else {  		/* If we're in an HT mode, and all 3 mode switch actions @@ -2342,9 +2398,10 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  	lq_sta->lq.sta_id = sta_priv->sta_id;  	for (j = 0; j < LQ_SIZE; j++) -		rs_rate_scale_clear_tbl_windows(&lq_sta->lq_info[j]); +		rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]);  	lq_sta->flush_timer = 0; +	lq_sta->last_tx = jiffies;  	IWL_DEBUG_RATE(mvm,  		       "LQ: *** rate scale station global init for station %d ***\n", @@ -2388,11 +2445,22 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		lq_sta->is_vht = true;  	} -	IWL_DEBUG_RATE(mvm, -		       "SISO-RATE=%X MIMO2-RATE=%X VHT=%d\n", +	lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, +						    BITS_PER_LONG); +	lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, +						  BITS_PER_LONG); +	lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, +						   BITS_PER_LONG); + +	IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n", +		       lq_sta->active_legacy_rate,  		       lq_sta->active_siso_rate,  		       lq_sta->active_mimo2_rate,  		       lq_sta->is_vht); +	IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", +		       lq_sta->max_legacy_rate_idx, +		       lq_sta->max_siso_rate_idx, +		       lq_sta->max_mimo2_rate_idx);  	/* These values will be overridden later */  	lq_sta->lq.single_stream_ant_msk = @@ -2547,6 +2615,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,  	if (is_siso(&rate)) {  		num_rates = RS_SECONDARY_SISO_NUM_RATES;  		num_retries = RS_SECONDARY_SISO_RETRIES; +		lq_cmd->mimo_delim = index;  	} else if (is_legacy(&rate)) {  		num_rates = RS_SECONDARY_LEGACY_NUM_RATES;  		num_retries = RS_LEGACY_RETRIES_PER_RATE; @@ -2749,7 +2818,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,  		return -ENOMEM;  	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); -	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", +	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%lX\n",  			lq_sta->total_failed, lq_sta->total_success,  			lq_sta->active_legacy_rate);  	desc += sprintf(buff+desc, "fixed rate 0x%X\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 3332b396011e..0acfac96a56c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -156,6 +156,7 @@ enum {  #define IWL_RATE_HIGH_TH		10880	/*  85% */  #define IWL_RATE_INCREASE_TH		6400	/*  50% */  #define RS_SR_FORCE_DECREASE		1920	/*  15% */ +#define RS_SR_NO_DECREASE		10880	/*  85% */  #define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000) /* 4 milliseconds */  #define LINK_QUAL_AGG_TIME_LIMIT_MAX	(8000) @@ -310,13 +311,20 @@ struct iwl_lq_sta {  	u32 visited_columns;    /* Bitmask marking which Tx columns were  				 * explored during a search cycle  				 */ +	u64 last_tx;  	bool is_vht;  	enum ieee80211_band band;  	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ -	u16 active_legacy_rate; -	u16 active_siso_rate; -	u16 active_mimo2_rate; +	unsigned long active_legacy_rate; +	unsigned long active_siso_rate; +	unsigned long active_mimo2_rate; + +	/* Highest rate per Tx mode */ +	u8 max_legacy_rate_idx; +	u8 max_siso_rate_idx; +	u8 max_mimo2_rate_idx; +  	s8 max_rate_idx;     /* Max rate set by user */  	u8 missed_rate_counter; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index c91dc8498852..c28de54c75d4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -277,51 +277,22 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,  					    IEEE80211_IFACE_ITER_NORMAL,  					    iwl_mvm_scan_condition_iterator,  					    &global_bound); -	/* -	 * Under low latency traffic passive scan is fragmented meaning -	 * that dwell on a particular channel will be fragmented. Each fragment -	 * dwell time is 20ms and fragments period is 105ms. Skipping to next -	 * channel will be delayed by the same period - 105ms. So suspend_time -	 * parameter describing both fragments and channels skipping periods is -	 * set to 105ms. This value is chosen so that overall passive scan -	 * duration will not be too long. Max_out_time in this case is set to -	 * 70ms, so for active scanning operating channel will be left for 70ms -	 * while for passive still for 20ms (fragment dwell). -	 */ -	if (global_bound) { -		if (!iwl_mvm_low_latency(mvm)) { -			params->suspend_time = ieee80211_tu_to_usec(100); -			params->max_out_time = ieee80211_tu_to_usec(600); -		} else { -			params->suspend_time = ieee80211_tu_to_usec(105); -			/* P2P doesn't support fragmented passive scan, so -			 * configure max_out_time to be at least longest dwell -			 * time for passive scan. -			 */ -			if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { -				params->max_out_time = ieee80211_tu_to_usec(70); -				params->passive_fragmented = true; -			} else { -				u32 passive_dwell; -				/* -				 * Use band G so that passive channel dwell time -				 * will be assigned with maximum value. -				 */ -				band = IEEE80211_BAND_2GHZ; -				passive_dwell = iwl_mvm_get_passive_dwell(band); -				params->max_out_time = -					ieee80211_tu_to_usec(passive_dwell); -			} -		} +	if (!global_bound) +		goto not_bound; + +	params->suspend_time = 100; +	params->max_out_time = 600; + +	if (iwl_mvm_low_latency(mvm)) { +		params->suspend_time = 250; +		params->max_out_time = 250;  	} +not_bound: +  	for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { -		if (params->passive_fragmented) -			params->dwell[band].passive = 20; -		else -			params->dwell[band].passive = -				iwl_mvm_get_passive_dwell(band); +		params->dwell[band].passive = iwl_mvm_get_passive_dwell(band);  		params->dwell[band].active = iwl_mvm_get_active_dwell(band,  								      n_ssids);  	} @@ -761,7 +732,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,  	int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;  	int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;  	int head = 0; -	int tail = band_2ghz + band_5ghz; +	int tail = band_2ghz + band_5ghz - 1;  	u32 ssid_bitmap;  	int cmd_len;  	int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 8401627c0030..88809b2d1654 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -274,7 +274,8 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,  				return -EINVAL;  			if (changed_vif->type != NL80211_IFTYPE_STATION) {  				new_state = SF_UNINIT; -			} else if (changed_vif->bss_conf.assoc) { +			} else if (changed_vif->bss_conf.assoc && +				   changed_vif->bss_conf.dtim_period) {  				mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);  				sta_id = mvmvif->ap_sta_id;  				new_state = SF_FULL_ON; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index d619851745a1..2180902266ae 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -644,3 +644,22 @@ bool iwl_mvm_low_latency(struct iwl_mvm *mvm)  	return result;  } + +static void iwl_mvm_idle_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) +{ +	bool *idle = _data; + +	if (!vif->bss_conf.idle) +		*idle = false; +} + +bool iwl_mvm_is_idle(struct iwl_mvm *mvm) +{ +	bool idle = true; + +	ieee80211_iterate_active_interfaces_atomic( +			mvm->hw, IEEE80211_IFACE_ITER_NORMAL, +			iwl_mvm_idle_iter, &idle); + +	return idle; +}  | 

