diff options
Diffstat (limited to 'drivers/net/wireless/intel')
20 files changed, 184 insertions, 74 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index c5f2ddf9b0fe..e5a2fc738ac3 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -91,7 +91,6 @@ config IWLWIFI_BCAST_FILTERING  config IWLWIFI_PCIE_RTPM         bool "Enable runtime power management mode for PCIe devices"         depends on IWLMVM && PM && EXPERT -       default false         help           Say Y here to enable runtime power management for PCIe           devices.  If enabled, the device will go into low power mode diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index 3721a3ed358b..f824bebceb06 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -211,7 +211,7 @@ enum {   * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end   * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use.   * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. - * @T2_V2_START_IMMEDIATELY: start time event immediately + * @TE_V2_START_IMMEDIATELY: start time event immediately   * @TE_V2_DEP_OTHER: depends on another time event   * @TE_V2_DEP_TSF: depends on a specific time   * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC @@ -230,7 +230,7 @@ enum iwl_time_event_policy {  	TE_V2_NOTIF_HOST_FRAG_END = BIT(5),  	TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),  	TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), -	T2_V2_START_IMMEDIATELY = BIT(11), +	TE_V2_START_IMMEDIATELY = BIT(11),  	/* placement characteristics */  	TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 67aefc8fc9ac..7bd704a3e640 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -8,6 +8,7 @@   * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@   * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -942,7 +944,6 @@ dump_trans_data:  out:  	iwl_fw_free_dump_desc(fwrt); -	fwrt->dump.trig = NULL;  	clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);  	IWL_DEBUG_INFO(fwrt, "WRT dump done\n");  } @@ -1112,6 +1113,14 @@ void iwl_fw_error_dump_wk(struct work_struct *work)  	    fwrt->ops->dump_start(fwrt->ops_ctx))  		return; +	if (fwrt->ops && fwrt->ops->fw_running && +	    !fwrt->ops->fw_running(fwrt->ops_ctx)) { +		IWL_ERR(fwrt, "Firmware not running - cannot dump error\n"); +		iwl_fw_free_dump_desc(fwrt); +		clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); +		goto out; +	} +  	if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {  		/* stop recording */  		iwl_fw_dbg_stop_recording(fwrt); @@ -1145,7 +1154,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work)  			iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl);  		}  	} - +out:  	if (fwrt->ops && fwrt->ops->dump_end)  		fwrt->ops->dump_end(fwrt->ops_ctx);  } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 223fb77a3aa9..72259bff9922 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -8,6 +8,7 @@   * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@   * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -91,6 +93,7 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)  	if (fwrt->dump.desc != &iwl_dump_desc_assert)  		kfree(fwrt->dump.desc);  	fwrt->dump.desc = NULL; +	fwrt->dump.trig = NULL;  }  void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h index e57ff92a68ae..3da468d2cc92 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h @@ -75,6 +75,20 @@ static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt)  	cancel_delayed_work_sync(&fwrt->timestamp.wk);  } +static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) +{ +	cancel_delayed_work_sync(&fwrt->timestamp.wk); +} + +static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) +{ +	if (!fwrt->timestamp.delay) +		return; + +	schedule_delayed_work(&fwrt->timestamp.wk, +			      round_jiffies_relative(fwrt->timestamp.delay)); +} +  #else  static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,  					  struct dentry *dbgfs_dir) @@ -84,4 +98,8 @@ static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,  static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {} +static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {} + +static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} +  #endif /* CONFIG_IWLWIFI_DEBUGFS */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index c39fe84bb4c4..2efac307909e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -77,8 +77,14 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,  }  IWL_EXPORT_SYMBOL(iwl_fw_runtime_init); -void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt) +void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt)  { -	iwl_fw_cancel_timestamp(fwrt); +	iwl_fw_suspend_timestamp(fwrt);  } -IWL_EXPORT_SYMBOL(iwl_fw_runtime_exit); +IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend); + +void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt) +{ +	iwl_fw_resume_timestamp(fwrt); +} +IWL_EXPORT_SYMBOL(iwl_fw_runtime_resume); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index e25c049f980f..3fb940ebd74a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -6,6 +6,7 @@   * GPL LICENSE SUMMARY   *   * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -26,6 +27,7 @@   * BSD LICENSE   *   * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -68,6 +70,7 @@  struct iwl_fw_runtime_ops {  	int (*dump_start)(void *ctx);  	void (*dump_end)(void *ctx); +	bool (*fw_running)(void *ctx);  };  #define MAX_NUM_LMAC 2 @@ -150,6 +153,10 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,  void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt); +void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt); + +void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt); +  static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt,  					    enum iwl_ucode_type cur_fw_img)  { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 0e6cf39285f4..2efe9b099556 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1098,6 +1098,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)  	/* make sure the d0i3 exit work is not pending */  	flush_work(&mvm->d0i3_exit_work); +	iwl_fw_runtime_suspend(&mvm->fwrt); +  	ret = iwl_trans_suspend(trans);  	if (ret)  		return ret; @@ -2012,6 +2014,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)  	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; +	iwl_fw_runtime_resume(&mvm->fwrt); +  	return ret;  } @@ -2038,6 +2042,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)  	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; +	iwl_fw_runtime_suspend(&mvm->fwrt); +  	/* start pseudo D3 */  	rtnl_lock();  	err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); @@ -2098,6 +2104,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)  	__iwl_mvm_resume(mvm, true);  	rtnl_unlock(); +	iwl_fw_runtime_resume(&mvm->fwrt); +  	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;  	iwl_abort_notification_waits(&mvm->notif_wait); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index a7892c1254a2..9c436d8d001d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -8,6 +8,7 @@   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -1281,9 +1283,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,  {  	int ret; -	if (!iwl_mvm_firmware_running(mvm)) -		return -EIO; -  	ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);  	if (ret)  		return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 2f22e14e00fe..8ba16fc24e3a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -438,7 +438,8 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	}  	/* Allocate the CAB queue for softAP and GO interfaces */ -	if (vif->type == NL80211_IFTYPE_AP) { +	if (vif->type == NL80211_IFTYPE_AP || +	    vif->type == NL80211_IFTYPE_ADHOC) {  		/*  		 * For TVQM this will be overwritten later with the FW assigned  		 * queue value (when queue is enabled). diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8aed40a8bc38..ebf511150f4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -8,6 +8,7 @@   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -2106,15 +2107,40 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,  	if (ret)  		goto out_remove; -	ret = iwl_mvm_add_mcast_sta(mvm, vif); -	if (ret) -		goto out_unbind; - -	/* Send the bcast station. At this stage the TBTT and DTIM time events -	 * are added and applied to the scheduler */ -	ret = iwl_mvm_send_add_bcast_sta(mvm, vif); -	if (ret) -		goto out_rm_mcast; +	/* +	 * This is not very nice, but the simplest: +	 * For older FWs adding the mcast sta before the bcast station may +	 * cause assert 0x2b00. +	 * This is fixed in later FW so make the order of removal depend on +	 * the TLV +	 */ +	if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) { +		ret = iwl_mvm_add_mcast_sta(mvm, vif); +		if (ret) +			goto out_unbind; +		/* +		 * Send the bcast station. At this stage the TBTT and DTIM time +		 * events are added and applied to the scheduler +		 */ +		ret = iwl_mvm_send_add_bcast_sta(mvm, vif); +		if (ret) { +			iwl_mvm_rm_mcast_sta(mvm, vif); +			goto out_unbind; +		} +	} else { +		/* +		 * Send the bcast station. At this stage the TBTT and DTIM time +		 * events are added and applied to the scheduler +		 */ +		iwl_mvm_send_add_bcast_sta(mvm, vif); +		if (ret) +			goto out_unbind; +		iwl_mvm_add_mcast_sta(mvm, vif); +		if (ret) { +			iwl_mvm_send_rm_bcast_sta(mvm, vif); +			goto out_unbind; +		} +	}  	/* must be set before quota calculations */  	mvmvif->ap_ibss_active = true; @@ -2144,7 +2170,6 @@ out_quota_failed:  	iwl_mvm_power_update_mac(mvm);  	mvmvif->ap_ibss_active = false;  	iwl_mvm_send_rm_bcast_sta(mvm, vif); -out_rm_mcast:  	iwl_mvm_rm_mcast_sta(mvm, vif);  out_unbind:  	iwl_mvm_binding_remove_vif(mvm, vif); @@ -2682,6 +2707,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,  		/* enable beacon filtering */  		WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); + +		iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, +				     false); +  		ret = 0;  	} else if (old_state == IEEE80211_STA_AUTHORIZED &&  		   new_state == IEEE80211_STA_ASSOC) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2d28e0804218..89ff02d7c876 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -90,6 +90,7 @@  #include "fw/runtime.h"  #include "fw/dbg.h"  #include "fw/acpi.h" +#include "fw/debugfs.h"  #define IWL_MVM_MAX_ADDRESSES		5  /* RSSI offset for WkP */ @@ -1783,6 +1784,7 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)  static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)  { +	iwl_fw_cancel_timestamp(&mvm->fwrt);  	iwl_free_fw_paging(&mvm->fwrt);  	clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);  	iwl_fw_dump_conf_clear(&mvm->fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 5d525a0023dc..ab7fb5aad984 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -8,6 +8,7 @@   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@   * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.   * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH   * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018        Intel Corporation   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -552,9 +554,15 @@ static void iwl_mvm_fwrt_dump_end(void *ctx)  	iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);  } +static bool iwl_mvm_fwrt_fw_running(void *ctx) +{ +	return iwl_mvm_firmware_running(ctx); +} +  static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {  	.dump_start = iwl_mvm_fwrt_dump_start,  	.dump_end = iwl_mvm_fwrt_dump_end, +	.fw_running = iwl_mvm_fwrt_fw_running,  };  static struct iwl_op_mode * @@ -802,7 +810,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,  	iwl_mvm_leds_exit(mvm);  	iwl_mvm_thermal_exit(mvm);   out_free: -	iwl_fw_runtime_exit(&mvm->fwrt);  	iwl_fw_flush_dump(&mvm->fwrt);  	if (iwlmvm_mod_params.init_dbg) @@ -843,7 +850,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)  #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)  	kfree(mvm->d3_resume_sram);  #endif -	iwl_fw_runtime_exit(&mvm->fwrt);  	iwl_trans_op_mode_leave(mvm->trans);  	iwl_phy_db_free(mvm->phy_db); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 60abb0084ee5..47f4c7a1d80d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2684,7 +2684,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,  				struct ieee80211_sta *sta,  				struct iwl_lq_sta *lq_sta,  				enum nl80211_band band, -				struct rs_rate *rate) +				struct rs_rate *rate, +				bool init)  {  	int i, nentries;  	unsigned long active_rate; @@ -2738,14 +2739,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,  	 */  	if (sta->vht_cap.vht_supported &&  	    best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { -		switch (sta->bandwidth) { -		case IEEE80211_STA_RX_BW_160: -		case IEEE80211_STA_RX_BW_80: -		case IEEE80211_STA_RX_BW_40: +		/* +		 * In AP mode, when a new station associates, rs is initialized +		 * immediately upon association completion, before the phy +		 * context is updated with the association parameters, so the +		 * sta bandwidth might be wider than the phy context allows. +		 * To avoid this issue, always initialize rs with 20mhz +		 * bandwidth rate, and after authorization, when the phy context +		 * is already up-to-date, re-init rs with the correct bw. +		 */ +		u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); + +		switch (bw) { +		case RATE_MCS_CHAN_WIDTH_40: +		case RATE_MCS_CHAN_WIDTH_80: +		case RATE_MCS_CHAN_WIDTH_160:  			initial_rates = rs_optimal_rates_vht;  			nentries = ARRAY_SIZE(rs_optimal_rates_vht);  			break; -		case IEEE80211_STA_RX_BW_20: +		case RATE_MCS_CHAN_WIDTH_20:  			initial_rates = rs_optimal_rates_vht_20mhz;  			nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz);  			break; @@ -2756,7 +2768,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,  		active_rate = lq_sta->active_siso_rate;  		rate->type = LQ_VHT_SISO; -		rate->bw = rs_bw_from_sta_bw(sta); +		rate->bw = bw;  	} else if (sta->ht_cap.ht_supported &&  		   best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {  		initial_rates = rs_optimal_rates_ht; @@ -2839,7 +2851,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,  	tbl = &(lq_sta->lq_info[active_tbl]);  	rate = &tbl->rate; -	rs_get_initial_rate(mvm, sta, lq_sta, band, rate); +	rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init);  	rs_init_optimal_rate(mvm, sta, lq_sta);  	WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index a3f7c1bf3cc8..580de5851fc7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);  	struct iwl_mvm_key_pn *ptk_pn; +	int res;  	u8 tid, keyidx;  	u8 pn[IEEE80211_CCMP_PN_LEN];  	u8 *extiv; @@ -127,12 +128,13 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,  	pn[4] = extiv[1];  	pn[5] = extiv[0]; -	if (memcmp(pn, ptk_pn->q[queue].pn[tid], -		   IEEE80211_CCMP_PN_LEN) <= 0) +	res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN); +	if (res < 0) +		return -1; +	if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN))  		return -1; -	if (!(stats->flag & RX_FLAG_AMSDU_MORE)) -		memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); +	memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);  	stats->flag |= RX_FLAG_PN_VALIDATED;  	return 0; @@ -314,28 +316,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,  }  /* - * returns true if a packet outside BA session is a duplicate and - * should be dropped + * returns true if a packet is a duplicate and should be dropped. + * Updates AMSDU PN tracking info   */ -static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, -				  struct ieee80211_rx_status *rx_status, -				  struct ieee80211_hdr *hdr, -				  struct iwl_rx_mpdu_desc *desc) +static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, +			   struct ieee80211_rx_status *rx_status, +			   struct ieee80211_hdr *hdr, +			   struct iwl_rx_mpdu_desc *desc)  {  	struct iwl_mvm_sta *mvm_sta;  	struct iwl_mvm_rxq_dup_data *dup_data; -	u8 baid, tid, sub_frame_idx; +	u8 tid, sub_frame_idx;  	if (WARN_ON(IS_ERR_OR_NULL(sta)))  		return false; -	baid = (le32_to_cpu(desc->reorder_data) & -		IWL_RX_MPDU_REORDER_BAID_MASK) >> -		IWL_RX_MPDU_REORDER_BAID_SHIFT; - -	if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) -		return false; -  	mvm_sta = iwl_mvm_sta_from_mac80211(sta);  	dup_data = &mvm_sta->dup_data[queue]; @@ -365,6 +360,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,  		     dup_data->last_sub_frame[tid] >= sub_frame_idx))  		return true; +	/* Allow same PN as the first subframe for following sub frames */ +	if (dup_data->last_seq[tid] == hdr->seq_ctrl && +	    sub_frame_idx > dup_data->last_sub_frame[tid] && +	    desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) +		rx_status->flag |= RX_FLAG_ALLOW_SAME_PN; +  	dup_data->last_seq[tid] = hdr->seq_ctrl;  	dup_data->last_sub_frame[tid] = sub_frame_idx; @@ -971,7 +972,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,  		if (ieee80211_is_data(hdr->frame_control))  			iwl_mvm_rx_csum(sta, skb, desc); -		if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { +		if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) {  			kfree_skb(skb);  			goto out;  		} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 6b2674e02606..630e23cb0ffb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2039,7 +2039,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	struct iwl_trans_txq_scd_cfg cfg = {  		.fifo = IWL_MVM_TX_FIFO_MCAST,  		.sta_id = msta->sta_id, -		.tid = IWL_MAX_TID_COUNT, +		.tid = 0,  		.aggregate = false,  		.frame_limit = IWL_FRAME_LIMIT,  	}; @@ -2053,6 +2053,17 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		return -ENOTSUPP;  	/* +	 * In IBSS, ieee80211_check_queues() sets the cab_queue to be +	 * invalid, so make sure we use the queue we want. +	 * Note that this is done here as we want to avoid making DQA +	 * changes in mac80211 layer. +	 */ +	if (vif->type == NL80211_IFTYPE_ADHOC) { +		vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; +		mvmvif->cab_queue = vif->cab_queue; +	} + +	/*  	 * While in previous FWs we had to exclude cab queue from TFD queue  	 * mask, now it is needed as any other queue.  	 */ @@ -2079,24 +2090,13 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	if (iwl_mvm_has_new_tx_api(mvm)) {  		int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue,  						    msta->sta_id, -						    IWL_MAX_TID_COUNT, +						    0,  						    timeout);  		mvmvif->cab_queue = queue;  	} else if (!fw_has_api(&mvm->fw->ucode_capa, -			       IWL_UCODE_TLV_API_STA_TYPE)) { -		/* -		 * In IBSS, ieee80211_check_queues() sets the cab_queue to be -		 * invalid, so make sure we use the queue we want. -		 * Note that this is done here as we want to avoid making DQA -		 * changes in mac80211 layer. -		 */ -		if (vif->type == NL80211_IFTYPE_ADHOC) { -			vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; -			mvmvif->cab_queue = vif->cab_queue; -		} +			       IWL_UCODE_TLV_API_STA_TYPE))  		iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0,  				   &cfg, timeout); -	}  	return 0;  } @@ -2115,7 +2115,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0);  	iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, -			    IWL_MAX_TID_COUNT, 0); +			    0, 0);  	ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);  	if (ret) @@ -3170,8 +3170,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,  	int ret, size;  	u32 status; +	/* This is a valid situation for GTK removal */  	if (sta_id == IWL_MVM_INVALID_STA) -		return -EINVAL; +		return 0;  	key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &  				 STA_KEY_FLG_KEYID_MSK); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 200ab50ec86b..acb217e666db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -616,7 +616,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,  	time_cmd.repeat = 1;  	time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |  				      TE_V2_NOTIF_HOST_EVENT_END | -				      T2_V2_START_IMMEDIATELY); +				      TE_V2_START_IMMEDIATELY);  	if (!wait_for_notif) {  		iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); @@ -803,7 +803,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,  	time_cmd.repeat = 1;  	time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |  				      TE_V2_NOTIF_HOST_EVENT_END | -				      T2_V2_START_IMMEDIATELY); +				      TE_V2_START_IMMEDIATELY);  	return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);  } @@ -913,6 +913,8 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,  	time_cmd.interval = cpu_to_le32(1);  	time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |  				      TE_V2_ABSENCE); +	if (!apply_time) +		time_cmd.policy |= cpu_to_le16(TE_V2_START_IMMEDIATELY);  	return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index dda77b327c98..af6dfceab6b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -419,11 +419,11 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,  {  	struct ieee80211_key_conf *keyconf = info->control.hw_key;  	u8 *crypto_hdr = skb_frag->data + hdrlen; +	enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM;  	u64 pn;  	switch (keyconf->cipher) {  	case WLAN_CIPHER_SUITE_CCMP: -	case WLAN_CIPHER_SUITE_CCMP_256:  		iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);  		iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);  		break; @@ -447,13 +447,16 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,  		break;  	case WLAN_CIPHER_SUITE_GCMP:  	case WLAN_CIPHER_SUITE_GCMP_256: +		type = TX_CMD_SEC_GCMP; +		/* Fall through */ +	case WLAN_CIPHER_SUITE_CCMP_256:  		/* TODO: Taking the key from the table might introduce a race  		 * when PTK rekeying is done, having an old packets with a PN  		 * based on the old key but the message encrypted with a new  		 * one.  		 * Need to handle this.  		 */ -		tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TX_CMD_SEC_KEY_FROM_TABLE; +		tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE;  		tx_cmd->key[0] = keyconf->hw_key_idx;  		iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);  		break; @@ -645,7 +648,11 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)  		if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||  		    info.control.vif->type == NL80211_IFTYPE_AP ||  		    info.control.vif->type == NL80211_IFTYPE_ADHOC) { -			sta_id = mvmvif->bcast_sta.sta_id; +			if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE) +				sta_id = mvmvif->bcast_sta.sta_id; +			else +				sta_id = mvmvif->mcast_sta.sta_id; +  			queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,  							   hdr->frame_control);  			if (queue < 0) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 6d0a907d5ba5..fabae0f60683 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -147,7 +147,7 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans,  	/* Sanity check on number of chunks */  	num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); -	if (num_tbs >= trans_pcie->max_tbs) { +	if (num_tbs > trans_pcie->max_tbs) {  		IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);  		return;  	} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 3f85713c41dc..1a566287993d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -378,7 +378,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,  	/* Sanity check on number of chunks */  	num_tbs = iwl_pcie_tfd_get_num_tbs(trans, tfd); -	if (num_tbs >= trans_pcie->max_tbs) { +	if (num_tbs > trans_pcie->max_tbs) {  		IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);  		/* @todo issue fatal error, it is quite serious situation */  		return;  | 

