aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2005-07-13 13:25:38 -0400
committerJames Ketrenos <jketreno@linux.intel.com>2005-11-07 18:50:19 -0500
commitd8bad6df045249cd1cff6a0d167c8f1b9caade7e (patch)
tree356a0688be3efd57fa0d7182f30bba6887986750
parentf57ce7ce9c7498fe9c4090aaf389c89f3bd70f7e (diff)
[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>
-rw-r--r--drivers/net/wireless/ipw2200.c46
-rw-r--r--drivers/net/wireless/ipw2200.h1
2 files changed, 24 insertions, 23 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 93ed8718fd6b..f3048f8e8238 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -3589,6 +3589,12 @@ static void ipw_bg_disassociate(void *data)
3589 up(&priv->sem); 3589 up(&priv->sem);
3590} 3590}
3591 3591
3592static void ipw_system_config(void *data)
3593{
3594 struct ipw_priv *priv = data;
3595 ipw_send_system_config(priv, &priv->sys_config);
3596}
3597
3592struct ipw_status_code { 3598struct ipw_status_code {
3593 u16 status; 3599 u16 status;
3594 const char *reason; 3600 const char *reason;
@@ -4060,6 +4066,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
4060 4066
4061 priv->status &= ~STATUS_ASSOCIATING; 4067 priv->status &= ~STATUS_ASSOCIATING;
4062 priv->status |= STATUS_ASSOCIATED; 4068 priv->status |= STATUS_ASSOCIATED;
4069 queue_work(priv->workqueue,
4070 &priv->system_config);
4063 4071
4064#ifdef CONFIG_IPW_QOS 4072#ifdef CONFIG_IPW_QOS
4065#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ 4073#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
@@ -5553,45 +5561,36 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv)
5553{ 5561{
5554 switch (priv->ieee->sec.level) { 5562 switch (priv->ieee->sec.level) {
5555 case SEC_LEVEL_3: 5563 case SEC_LEVEL_3:
5556 if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) 5564 if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
5557 break; 5565 ipw_send_tgi_tx_key(priv,
5566 DCT_FLAG_EXT_SECURITY_CCM,
5567 priv->ieee->sec.active_key);
5558 5568
5559 ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_CCM,
5560 priv->ieee->sec.active_key);
5561 ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); 5569 ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
5562
5563 priv->sys_config.disable_unicast_decryption = 0; 5570 priv->sys_config.disable_unicast_decryption = 0;
5564 priv->sys_config.disable_multicast_decryption = 0; 5571 priv->sys_config.disable_multicast_decryption = 0;
5565 priv->ieee->host_decrypt = 0; 5572 priv->ieee->host_decrypt = 0;
5566 if (ipw_send_system_config(priv, &priv->sys_config))
5567 IPW_ERROR("ipw_send_system_config failed\n");
5568
5569 break; 5573 break;
5570 case SEC_LEVEL_2: 5574 case SEC_LEVEL_2:
5571 if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) 5575 if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
5572 break; 5576 ipw_send_tgi_tx_key(priv,
5573 5577 DCT_FLAG_EXT_SECURITY_TKIP,
5574 ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_TKIP, 5578 priv->ieee->sec.active_key);
5575 priv->ieee->sec.active_key);
5576 5579
5577 priv->sys_config.disable_unicast_decryption = 1; 5580 priv->sys_config.disable_unicast_decryption = 1;
5578 priv->sys_config.disable_multicast_decryption = 1; 5581 priv->sys_config.disable_multicast_decryption = 1;
5579 priv->ieee->host_decrypt = 1; 5582 priv->ieee->host_decrypt = 1;
5580 if (ipw_send_system_config(priv, &priv->sys_config))
5581 IPW_ERROR("ipw_send_system_config failed\n");
5582
5583 break; 5583 break;
5584 case SEC_LEVEL_1: 5584 case SEC_LEVEL_1:
5585 ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); 5585 ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
5586
5587 priv->sys_config.disable_unicast_decryption = 0; 5586 priv->sys_config.disable_unicast_decryption = 0;
5588 priv->sys_config.disable_multicast_decryption = 0; 5587 priv->sys_config.disable_multicast_decryption = 0;
5589 priv->ieee->host_decrypt = 0; 5588 priv->ieee->host_decrypt = 0;
5590 if (ipw_send_system_config(priv, &priv->sys_config))
5591 IPW_ERROR("ipw_send_system_config failed\n");
5592
5593 break; 5589 break;
5594 case SEC_LEVEL_0: 5590 case SEC_LEVEL_0:
5591 priv->sys_config.disable_unicast_decryption = 1;
5592 priv->sys_config.disable_multicast_decryption = 1;
5593 break;
5595 default: 5594 default:
5596 break; 5595 break;
5597 } 5596 }
@@ -10113,6 +10112,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv)
10113 INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); 10112 INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv);
10114 INIT_WORK(&priv->associate, ipw_bg_associate, priv); 10113 INIT_WORK(&priv->associate, ipw_bg_associate, priv);
10115 INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); 10114 INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv);
10115 INIT_WORK(&priv->system_config, ipw_system_config, priv);
10116 INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); 10116 INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv);
10117 INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); 10117 INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv);
10118 INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); 10118 INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv);
@@ -10206,10 +10206,10 @@ static void shim__set_security(struct net_device *dev,
10206 priv->ieee->sec.level = sec->level; 10206 priv->ieee->sec.level = sec->level;
10207 priv->ieee->sec.flags |= SEC_LEVEL; 10207 priv->ieee->sec.flags |= SEC_LEVEL;
10208 priv->status |= STATUS_SECURITY_UPDATED; 10208 priv->status |= STATUS_SECURITY_UPDATED;
10209 }
10210 10209
10211 if (!priv->ieee->host_encrypt) 10210 if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
10212 ipw_set_hwcrypto_keys(priv); 10211 ipw_set_hwcrypto_keys(priv);
10212 }
10213 10213
10214 /* To match current functionality of ipw2100 (which works well w/ 10214 /* To match current functionality of ipw2100 (which works well w/
10215 * various supplicants, we don't force a disassociate if the 10215 * various supplicants, we don't force a disassociate if the
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 915f469fa1d6..28667d3c946a 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1205,6 +1205,7 @@ struct ipw_priv {
1205 struct work_struct adhoc_check; 1205 struct work_struct adhoc_check;
1206 struct work_struct associate; 1206 struct work_struct associate;
1207 struct work_struct disassociate; 1207 struct work_struct disassociate;
1208 struct work_struct system_config;
1208 struct work_struct rx_replenish; 1209 struct work_struct rx_replenish;
1209 struct work_struct request_scan; 1210 struct work_struct request_scan;
1210 struct work_struct adapter_restart; 1211 struct work_struct adapter_restart;