[bug 667] Fix the notorious "No space for Tx" bug.

We send SYSTEM_CONFIG command after the TGI_KEY command if hardware
encryption is enabled. It sometimes causes a firmware stall (firmware
doesn't respond to any request) and finally bungs up the Tx send queue.
The solution is to send SYSTEM_CONFIG command in the post association
stage from a workqueue.

Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 93ed871..f3048f8 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -3589,6 +3589,12 @@
 	up(&priv->sem);
 }
 
+static void ipw_system_config(void *data)
+{
+	struct ipw_priv *priv = data;
+	ipw_send_system_config(priv, &priv->sys_config);
+}
+
 struct ipw_status_code {
 	u16 status;
 	const char *reason;
@@ -4060,6 +4066,8 @@
 
 					priv->status &= ~STATUS_ASSOCIATING;
 					priv->status |= STATUS_ASSOCIATED;
+					queue_work(priv->workqueue,
+						   &priv->system_config);
 
 #ifdef CONFIG_IPW_QOS
 #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
@@ -5553,45 +5561,36 @@
 {
 	switch (priv->ieee->sec.level) {
 	case SEC_LEVEL_3:
-		if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY))
-			break;
+		if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
+			ipw_send_tgi_tx_key(priv,
+					    DCT_FLAG_EXT_SECURITY_CCM,
+					    priv->ieee->sec.active_key);
 
-		ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_CCM,
-				    priv->ieee->sec.active_key);
 		ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
-
 		priv->sys_config.disable_unicast_decryption = 0;
 		priv->sys_config.disable_multicast_decryption = 0;
 		priv->ieee->host_decrypt = 0;
-		if (ipw_send_system_config(priv, &priv->sys_config))
-			IPW_ERROR("ipw_send_system_config failed\n");
-
 		break;
 	case SEC_LEVEL_2:
-		if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY))
-			break;
-
-		ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_TKIP,
-				    priv->ieee->sec.active_key);
+		if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
+			ipw_send_tgi_tx_key(priv,
+					    DCT_FLAG_EXT_SECURITY_TKIP,
+					    priv->ieee->sec.active_key);
 
 		priv->sys_config.disable_unicast_decryption = 1;
 		priv->sys_config.disable_multicast_decryption = 1;
 		priv->ieee->host_decrypt = 1;
-		if (ipw_send_system_config(priv, &priv->sys_config))
-			IPW_ERROR("ipw_send_system_config failed\n");
-
 		break;
 	case SEC_LEVEL_1:
 		ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
-
 		priv->sys_config.disable_unicast_decryption = 0;
 		priv->sys_config.disable_multicast_decryption = 0;
 		priv->ieee->host_decrypt = 0;
-		if (ipw_send_system_config(priv, &priv->sys_config))
-			IPW_ERROR("ipw_send_system_config failed\n");
-
 		break;
 	case SEC_LEVEL_0:
+		priv->sys_config.disable_unicast_decryption = 1;
+		priv->sys_config.disable_multicast_decryption = 1;
+		break;
 	default:
 		break;
 	}
@@ -10113,6 +10112,7 @@
 	INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv);
 	INIT_WORK(&priv->associate, ipw_bg_associate, priv);
 	INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv);
+	INIT_WORK(&priv->system_config, ipw_system_config, priv);
 	INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv);
 	INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv);
 	INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv);
@@ -10206,10 +10206,10 @@
 		priv->ieee->sec.level = sec->level;
 		priv->ieee->sec.flags |= SEC_LEVEL;
 		priv->status |= STATUS_SECURITY_UPDATED;
-	}
 
-	if (!priv->ieee->host_encrypt)
-		ipw_set_hwcrypto_keys(priv);
+		if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
+			ipw_set_hwcrypto_keys(priv);
+	}
 
 	/* To match current functionality of ipw2100 (which works well w/
 	 * various supplicants, we don't force a disassociate if the