diff options
author | Zhu Yi <yi.zhu@intel.com> | 2005-07-13 13:25:38 -0400 |
---|---|---|
committer | James Ketrenos <jketreno@linux.intel.com> | 2005-11-07 18:50:19 -0500 |
commit | d8bad6df045249cd1cff6a0d167c8f1b9caade7e (patch) | |
tree | 356a0688be3efd57fa0d7182f30bba6887986750 /drivers/net/wireless/ipw2200.c | |
parent | f57ce7ce9c7498fe9c4090aaf389c89f3bd70f7e (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>
Diffstat (limited to 'drivers/net/wireless/ipw2200.c')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 46 |
1 files changed, 23 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 | ||
3592 | static void ipw_system_config(void *data) | ||
3593 | { | ||
3594 | struct ipw_priv *priv = data; | ||
3595 | ipw_send_system_config(priv, &priv->sys_config); | ||
3596 | } | ||
3597 | |||
3592 | struct ipw_status_code { | 3598 | struct 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 |