iwlwifi: avoid sending too many commands

When the PAN context is unused, there's no
need to continually update it in the device.
So track which contexts are active (with the
special case that the WLAN context is always
active ...) and only send their commands to
the device when needed.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index d03ba6a..a63582f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -287,6 +287,15 @@
 	ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
 	ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
 
+	/*
+	 * If the PAN context is inactive, then we don't need
+	 * to update the PAN parameters, the last thing we'll
+	 * have done before it goes inactive is making the PAN
+	 * parameters be WLAN-only.
+	 */
+	if (!ctx_pan->is_active)
+		return 0;
+
 	memset(&cmd, 0, sizeof(cmd));
 
 	/* only 2 slots are currently allowed */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index df2edcc..a19671d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -110,6 +110,9 @@
 	if (!iwl_is_alive(priv))
 		return -EBUSY;
 
+	if (!ctx->is_active)
+		return 0;
+
 	/* always get timestamp with Rx frame */
 	ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 
@@ -4301,6 +4304,8 @@
 	for (i = 0; i < NUM_IWL_RXON_CTX; i++)
 		priv->contexts[i].ctxid = i;
 
+	priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
+	priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
 	priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
 	priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
 	priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index a763103..f67cab5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -196,6 +196,9 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
+	if (!ctx->is_active)
+		return;
+
 	ctx->qos_data.def_qos_parm.qos_flags = 0;
 
 	if (ctx->qos_data.qos_active)
@@ -2008,9 +2011,14 @@
 	 */
 	priv->iw_mode = vif->type;
 
+	ctx->is_active = true;
+
 	err = iwl_set_mode(priv, vif);
-	if (err)
+	if (err) {
+		if (!ctx->always_active)
+			ctx->is_active = false;
 		goto out_err;
+	}
 
 	if (priv->cfg->advanced_bt_coexist &&
 	    vif->type == NL80211_IFTYPE_ADHOC) {
@@ -2052,6 +2060,9 @@
 	iwl_scan_cancel_timeout(priv, 100);
 	iwl_set_mode(priv, vif);
 
+	if (!ctx->always_active)
+		ctx->is_active = false;
+
 	if (priv->scan_vif == vif) {
 		scan_completed = true;
 		priv->scan_vif = NULL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 504ff0f..4e3a692 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1116,6 +1116,13 @@
 	const u8 *ac_to_queue;
 	u8 mcast_queue;
 
+	/*
+	 * We could use the vif to indicate active, but we
+	 * also need it to be active during disabling when
+	 * we already removed the vif for type setting.
+	 */
+	bool always_active, is_active;
+
 	enum iwl_rxon_context_id ctxid;
 
 	u32 interface_modes, exclusive_interface_modes;