diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/main.c')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 93 |
1 files changed, 88 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 222eb2cf1b30..23856d359e12 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/sched.h> | 41 | #include <linux/sched.h> |
42 | #include <linux/ieee80211.h> | 42 | #include <linux/ieee80211.h> |
43 | #include <linux/wireless.h> | 43 | #include <linux/wireless.h> |
44 | #include <linux/slab.h> | ||
44 | 45 | ||
45 | #include "iwm.h" | 46 | #include "iwm.h" |
46 | #include "debug.h" | 47 | #include "debug.h" |
@@ -64,9 +65,10 @@ static struct iwm_conf def_iwm_conf = { | |||
64 | BIT(PHY_CALIBRATE_TX_IQ_CMD) | | 65 | BIT(PHY_CALIBRATE_TX_IQ_CMD) | |
65 | BIT(PHY_CALIBRATE_RX_IQ_CMD) | | 66 | BIT(PHY_CALIBRATE_RX_IQ_CMD) | |
66 | BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), | 67 | BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), |
68 | .ct_kill_entry = 110, | ||
69 | .ct_kill_exit = 110, | ||
67 | .reset_on_fatal_err = 1, | 70 | .reset_on_fatal_err = 1, |
68 | .auto_connect = 1, | 71 | .auto_connect = 1, |
69 | .wimax_not_present = 0, | ||
70 | .enable_qos = 1, | 72 | .enable_qos = 1, |
71 | .mode = UMAC_MODE_BSS, | 73 | .mode = UMAC_MODE_BSS, |
72 | 74 | ||
@@ -78,8 +80,8 @@ static struct iwm_conf def_iwm_conf = { | |||
78 | 80 | ||
79 | .assoc_timeout = 2, | 81 | .assoc_timeout = 2, |
80 | .roam_timeout = 10, | 82 | .roam_timeout = 10, |
81 | .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G, | 83 | .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G | |
82 | .coexist_mode = COEX_MODE_CM, | 84 | WIRELESS_MODE_11N, |
83 | 85 | ||
84 | /* IBSS */ | 86 | /* IBSS */ |
85 | .ibss_band = UMAC_BAND_2GHZ, | 87 | .ibss_band = UMAC_BAND_2GHZ, |
@@ -92,6 +94,10 @@ static int modparam_reset; | |||
92 | module_param_named(reset, modparam_reset, bool, 0644); | 94 | module_param_named(reset, modparam_reset, bool, 0644); |
93 | MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); | 95 | MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); |
94 | 96 | ||
97 | static int modparam_wimax_enable = 1; | ||
98 | module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644); | ||
99 | MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])"); | ||
100 | |||
95 | int iwm_mode_to_nl80211_iftype(int mode) | 101 | int iwm_mode_to_nl80211_iftype(int mode) |
96 | { | 102 | { |
97 | switch (mode) { | 103 | switch (mode) { |
@@ -134,6 +140,17 @@ static void iwm_disconnect_work(struct work_struct *work) | |||
134 | cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); | 140 | cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); |
135 | } | 141 | } |
136 | 142 | ||
143 | static void iwm_ct_kill_work(struct work_struct *work) | ||
144 | { | ||
145 | struct iwm_priv *iwm = | ||
146 | container_of(work, struct iwm_priv, ct_kill_delay.work); | ||
147 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
148 | |||
149 | IWM_INFO(iwm, "CT kill delay timeout\n"); | ||
150 | |||
151 | wiphy_rfkill_set_hw_state(wiphy, false); | ||
152 | } | ||
153 | |||
137 | static int __iwm_up(struct iwm_priv *iwm); | 154 | static int __iwm_up(struct iwm_priv *iwm); |
138 | static int __iwm_down(struct iwm_priv *iwm); | 155 | static int __iwm_down(struct iwm_priv *iwm); |
139 | 156 | ||
@@ -195,6 +212,33 @@ static void iwm_reset_worker(struct work_struct *work) | |||
195 | mutex_unlock(&iwm->mutex); | 212 | mutex_unlock(&iwm->mutex); |
196 | } | 213 | } |
197 | 214 | ||
215 | static void iwm_auth_retry_worker(struct work_struct *work) | ||
216 | { | ||
217 | struct iwm_priv *iwm; | ||
218 | int i, ret; | ||
219 | |||
220 | iwm = container_of(work, struct iwm_priv, auth_retry_worker); | ||
221 | if (iwm->umac_profile_active) { | ||
222 | ret = iwm_invalidate_mlme_profile(iwm); | ||
223 | if (ret < 0) | ||
224 | return; | ||
225 | } | ||
226 | |||
227 | iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
228 | |||
229 | ret = iwm_send_mlme_profile(iwm); | ||
230 | if (ret < 0) | ||
231 | return; | ||
232 | |||
233 | for (i = 0; i < IWM_NUM_KEYS; i++) | ||
234 | if (iwm->keys[i].key_len) | ||
235 | iwm_set_key(iwm, 0, &iwm->keys[i]); | ||
236 | |||
237 | iwm_set_tx_key(iwm, iwm->default_key); | ||
238 | } | ||
239 | |||
240 | |||
241 | |||
198 | static void iwm_watchdog(unsigned long data) | 242 | static void iwm_watchdog(unsigned long data) |
199 | { | 243 | { |
200 | struct iwm_priv *iwm = (struct iwm_priv *)data; | 244 | struct iwm_priv *iwm = (struct iwm_priv *)data; |
@@ -207,7 +251,7 @@ static void iwm_watchdog(unsigned long data) | |||
207 | 251 | ||
208 | int iwm_priv_init(struct iwm_priv *iwm) | 252 | int iwm_priv_init(struct iwm_priv *iwm) |
209 | { | 253 | { |
210 | int i; | 254 | int i, j; |
211 | char name[32]; | 255 | char name[32]; |
212 | 256 | ||
213 | iwm->status = 0; | 257 | iwm->status = 0; |
@@ -226,7 +270,9 @@ int iwm_priv_init(struct iwm_priv *iwm) | |||
226 | iwm->scan_id = 1; | 270 | iwm->scan_id = 1; |
227 | INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); | 271 | INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); |
228 | INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); | 272 | INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); |
273 | INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work); | ||
229 | INIT_WORK(&iwm->reset_worker, iwm_reset_worker); | 274 | INIT_WORK(&iwm->reset_worker, iwm_reset_worker); |
275 | INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker); | ||
230 | INIT_LIST_HEAD(&iwm->bss_list); | 276 | INIT_LIST_HEAD(&iwm->bss_list); |
231 | 277 | ||
232 | skb_queue_head_init(&iwm->rx_list); | 278 | skb_queue_head_init(&iwm->rx_list); |
@@ -249,6 +295,8 @@ int iwm_priv_init(struct iwm_priv *iwm) | |||
249 | return -EAGAIN; | 295 | return -EAGAIN; |
250 | 296 | ||
251 | skb_queue_head_init(&iwm->txq[i].queue); | 297 | skb_queue_head_init(&iwm->txq[i].queue); |
298 | skb_queue_head_init(&iwm->txq[i].stopped_queue); | ||
299 | spin_lock_init(&iwm->txq[i].lock); | ||
252 | } | 300 | } |
253 | 301 | ||
254 | for (i = 0; i < IWM_NUM_KEYS; i++) | 302 | for (i = 0; i < IWM_NUM_KEYS; i++) |
@@ -256,6 +304,12 @@ int iwm_priv_init(struct iwm_priv *iwm) | |||
256 | 304 | ||
257 | iwm->default_key = -1; | 305 | iwm->default_key = -1; |
258 | 306 | ||
307 | for (i = 0; i < IWM_STA_TABLE_NUM; i++) | ||
308 | for (j = 0; j < IWM_UMAC_TID_NR; j++) { | ||
309 | mutex_init(&iwm->sta_table[i].tid_info[j].mutex); | ||
310 | iwm->sta_table[i].tid_info[j].stopped = false; | ||
311 | } | ||
312 | |||
259 | init_timer(&iwm->watchdog); | 313 | init_timer(&iwm->watchdog); |
260 | iwm->watchdog.function = iwm_watchdog; | 314 | iwm->watchdog.function = iwm_watchdog; |
261 | iwm->watchdog.data = (unsigned long)iwm; | 315 | iwm->watchdog.data = (unsigned long)iwm; |
@@ -436,7 +490,7 @@ static int iwm_config_boot_params(struct iwm_priv *iwm) | |||
436 | int ret; | 490 | int ret; |
437 | 491 | ||
438 | /* check Wimax is off and config debug monitor */ | 492 | /* check Wimax is off and config debug monitor */ |
439 | if (iwm->conf.wimax_not_present) { | 493 | if (!modparam_wimax_enable) { |
440 | u32 data1 = 0x1f; | 494 | u32 data1 = 0x1f; |
441 | u32 addr1 = 0x606BE258; | 495 | u32 addr1 = 0x606BE258; |
442 | 496 | ||
@@ -529,6 +583,7 @@ void iwm_link_off(struct iwm_priv *iwm) | |||
529 | 583 | ||
530 | for (i = 0; i < IWM_TX_QUEUES; i++) { | 584 | for (i = 0; i < IWM_TX_QUEUES; i++) { |
531 | skb_queue_purge(&iwm->txq[i].queue); | 585 | skb_queue_purge(&iwm->txq[i].queue); |
586 | skb_queue_purge(&iwm->txq[i].stopped_queue); | ||
532 | 587 | ||
533 | iwm->txq[i].concat_count = 0; | 588 | iwm->txq[i].concat_count = 0; |
534 | iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; | 589 | iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; |
@@ -587,6 +642,8 @@ static int __iwm_up(struct iwm_priv *iwm) | |||
587 | { | 642 | { |
588 | int ret; | 643 | int ret; |
589 | struct iwm_notif *notif_reboot, *notif_ack = NULL; | 644 | struct iwm_notif *notif_reboot, *notif_ack = NULL; |
645 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
646 | u32 wireless_mode; | ||
590 | 647 | ||
591 | ret = iwm_bus_enable(iwm); | 648 | ret = iwm_bus_enable(iwm); |
592 | if (ret) { | 649 | if (ret) { |
@@ -638,6 +695,8 @@ static int __iwm_up(struct iwm_priv *iwm) | |||
638 | IWM_ERR(iwm, "MAC reading failed\n"); | 695 | IWM_ERR(iwm, "MAC reading failed\n"); |
639 | goto err_disable; | 696 | goto err_disable; |
640 | } | 697 | } |
698 | memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr, | ||
699 | ETH_ALEN); | ||
641 | 700 | ||
642 | /* We can load the FWs */ | 701 | /* We can load the FWs */ |
643 | ret = iwm_load_fw(iwm); | 702 | ret = iwm_load_fw(iwm); |
@@ -646,6 +705,30 @@ static int __iwm_up(struct iwm_priv *iwm) | |||
646 | goto err_disable; | 705 | goto err_disable; |
647 | } | 706 | } |
648 | 707 | ||
708 | ret = iwm_eeprom_fat_channels(iwm); | ||
709 | if (ret) { | ||
710 | IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n"); | ||
711 | goto err_fw; | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * Read our SKU capabilities. | ||
716 | * If it's valid, we AND the configured wireless mode with the | ||
717 | * device EEPROM value as the current profile wireless mode. | ||
718 | */ | ||
719 | wireless_mode = iwm_eeprom_wireless_mode(iwm); | ||
720 | if (wireless_mode) { | ||
721 | iwm->conf.wireless_mode &= wireless_mode; | ||
722 | if (iwm->umac_profile) | ||
723 | iwm->umac_profile->wireless_mode = | ||
724 | iwm->conf.wireless_mode; | ||
725 | } else | ||
726 | IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n", | ||
727 | *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP))); | ||
728 | |||
729 | snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", | ||
730 | iwm->lmac_version, iwm->umac_version); | ||
731 | |||
649 | /* We configure the UMAC and enable the wifi module */ | 732 | /* We configure the UMAC and enable the wifi module */ |
650 | ret = iwm_send_umac_config(iwm, | 733 | ret = iwm_send_umac_config(iwm, |
651 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | | 734 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | |