aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c83
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c113
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h94
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c26
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c51
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.h29
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c9
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h17
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c93
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c226
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c14
-rw-r--r--drivers/net/wireless/iwmc3200wifi/tx.c67
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h41
17 files changed, 784 insertions, 105 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index c25a04371ca8..b9d34a766964 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -1,8 +1,9 @@
1config IWM 1config IWM
2 tristate "Intel Wireless Multicomm 3200 WiFi driver" 2 tristate "Intel Wireless Multicomm 3200 WiFi driver"
3 depends on MMC && WLAN_80211 && EXPERIMENTAL 3 depends on MMC && EXPERIMENTAL
4 depends on CFG80211 4 depends on CFG80211
5 select FW_LOADER 5 select FW_LOADER
6 select IWMC3200TOP
6 help 7 help
7 The Intel Wireless Multicomm 3200 hardware is a combo 8 The Intel Wireless Multicomm 3200 hardware is a combo
8 card with GPS, Bluetooth, WiMax and 802.11 radios. It 9 card with GPS, Bluetooth, WiMax and 802.11 radios. It
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index f3c55658225b..a1d45cce0ebc 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -27,6 +27,7 @@
27#include <linux/etherdevice.h> 27#include <linux/etherdevice.h>
28#include <linux/wireless.h> 28#include <linux/wireless.h>
29#include <linux/ieee80211.h> 29#include <linux/ieee80211.h>
30#include <linux/slab.h>
30#include <net/cfg80211.h> 31#include <net/cfg80211.h>
31 32
32#include "iwm.h" 33#include "iwm.h"
@@ -405,39 +406,21 @@ static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
405{ 406{
406 struct iwm_priv *iwm = wiphy_to_iwm(wiphy); 407 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
407 struct ieee80211_channel *chan = params->channel; 408 struct ieee80211_channel *chan = params->channel;
408 struct cfg80211_bss *bss;
409 409
410 if (!test_bit(IWM_STATUS_READY, &iwm->status)) 410 if (!test_bit(IWM_STATUS_READY, &iwm->status))
411 return -EIO; 411 return -EIO;
412 412
413 /* UMAC doesn't support creating IBSS network with specified bssid. 413 /* UMAC doesn't support creating or joining an IBSS network
414 * This should be removed after we have join only mode supported. */ 414 * with specified bssid. */
415 if (params->bssid) 415 if (params->bssid)
416 return -EOPNOTSUPP; 416 return -EOPNOTSUPP;
417 417
418 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
419 params->ssid, params->ssid_len);
420 if (!bss) {
421 iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
422 schedule_timeout_interruptible(2 * HZ);
423 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
424 params->ssid, params->ssid_len);
425 }
426 /* IBSS join only mode is not supported by UMAC ATM */
427 if (bss) {
428 cfg80211_put_bss(bss);
429 return -EOPNOTSUPP;
430 }
431
432 iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); 418 iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
433 iwm->umac_profile->ibss.band = chan->band; 419 iwm->umac_profile->ibss.band = chan->band;
434 iwm->umac_profile->ibss.channel = iwm->channel; 420 iwm->umac_profile->ibss.channel = iwm->channel;
435 iwm->umac_profile->ssid.ssid_len = params->ssid_len; 421 iwm->umac_profile->ssid.ssid_len = params->ssid_len;
436 memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); 422 memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
437 423
438 if (params->bssid)
439 memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
440
441 return iwm_send_mlme_profile(iwm); 424 return iwm_send_mlme_profile(iwm);
442} 425}
443 426
@@ -490,12 +473,12 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
490 return 0; 473 return 0;
491 } 474 }
492 475
476 if (wpa_version & NL80211_WPA_VERSION_1)
477 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
478
493 if (wpa_version & NL80211_WPA_VERSION_2) 479 if (wpa_version & NL80211_WPA_VERSION_2)
494 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; 480 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
495 481
496 if (wpa_version & NL80211_WPA_VERSION_1)
497 iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
498
499 return 0; 482 return 0;
500} 483}
501 484
@@ -646,6 +629,13 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
646 iwm->default_key = sme->key_idx; 629 iwm->default_key = sme->key_idx;
647 } 630 }
648 631
632 /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
633 if ((iwm->umac_profile->sec.flags &
634 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
635 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
636 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
637 }
638
649 ret = iwm_send_mlme_profile(iwm); 639 ret = iwm_send_mlme_profile(iwm);
650 640
651 if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || 641 if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
@@ -682,10 +672,24 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
682static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, 672static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
683 enum tx_power_setting type, int dbm) 673 enum tx_power_setting type, int dbm)
684{ 674{
675 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
676 int ret;
677
685 switch (type) { 678 switch (type) {
686 case TX_POWER_AUTOMATIC: 679 case TX_POWER_AUTOMATIC:
687 return 0; 680 return 0;
681 case TX_POWER_FIXED:
682 if (!test_bit(IWM_STATUS_READY, &iwm->status))
683 return 0;
684
685 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
686 CFG_TX_PWR_LIMIT_USR, dbm * 2);
687 if (ret < 0)
688 return ret;
689
690 return iwm_tx_power_trigger(iwm);
688 default: 691 default:
692 IWM_ERR(iwm, "Unsupported power type: %d\n", type);
689 return -EOPNOTSUPP; 693 return -EOPNOTSUPP;
690 } 694 }
691 695
@@ -696,7 +700,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
696{ 700{
697 struct iwm_priv *iwm = wiphy_to_iwm(wiphy); 701 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
698 702
699 *dbm = iwm->txpower; 703 *dbm = iwm->txpower >> 1;
700 704
701 return 0; 705 return 0;
702} 706}
@@ -722,6 +726,33 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
722 CFG_POWER_INDEX, iwm->conf.power_index); 726 CFG_POWER_INDEX, iwm->conf.power_index);
723} 727}
724 728
729int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
730 struct cfg80211_pmksa *pmksa)
731{
732 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
733
734 return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
735}
736
737int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
738 struct cfg80211_pmksa *pmksa)
739{
740 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
741
742 return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
743}
744
745int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
746{
747 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
748 struct cfg80211_pmksa pmksa;
749
750 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
751
752 return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH);
753}
754
755
725static struct cfg80211_ops iwm_cfg80211_ops = { 756static struct cfg80211_ops iwm_cfg80211_ops = {
726 .change_virtual_intf = iwm_cfg80211_change_iface, 757 .change_virtual_intf = iwm_cfg80211_change_iface,
727 .add_key = iwm_cfg80211_add_key, 758 .add_key = iwm_cfg80211_add_key,
@@ -738,6 +769,9 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
738 .set_tx_power = iwm_cfg80211_set_txpower, 769 .set_tx_power = iwm_cfg80211_set_txpower,
739 .get_tx_power = iwm_cfg80211_get_txpower, 770 .get_tx_power = iwm_cfg80211_get_txpower,
740 .set_power_mgmt = iwm_cfg80211_set_power_mgmt, 771 .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
772 .set_pmksa = iwm_cfg80211_set_pmksa,
773 .del_pmksa = iwm_cfg80211_del_pmksa,
774 .flush_pmksa = iwm_cfg80211_flush_pmksa,
741}; 775};
742 776
743static const u32 cipher_suites[] = { 777static const u32 cipher_suites[] = {
@@ -783,6 +817,7 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
783 817
784 set_wiphy_dev(wdev->wiphy, dev); 818 set_wiphy_dev(wdev->wiphy, dev);
785 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; 819 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
820 wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS;
786 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 821 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
787 BIT(NL80211_IFTYPE_ADHOC); 822 BIT(NL80211_IFTYPE_ADHOC);
788 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; 823 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 84158b6d35d8..42df7262f9f7 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -41,6 +41,7 @@
41#include <linux/etherdevice.h> 41#include <linux/etherdevice.h>
42#include <linux/ieee80211.h> 42#include <linux/ieee80211.h>
43#include <linux/sched.h> 43#include <linux/sched.h>
44#include <linux/slab.h>
44 45
45#include "iwm.h" 46#include "iwm.h"
46#include "bus.h" 47#include "bus.h"
@@ -77,6 +78,11 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
77 int ret; 78 int ret;
78 u8 oid = hdr->oid; 79 u8 oid = hdr->oid;
79 80
81 if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
82 IWM_ERR(iwm, "Interface is not ready yet");
83 return -EAGAIN;
84 }
85
80 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; 86 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
81 umac_cmd.resp = resp; 87 umac_cmd.resp = resp;
82 88
@@ -94,6 +100,10 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
94 return ret; 100 return ret;
95} 101}
96 102
103static int modparam_wiwi = COEX_MODE_CM;
104module_param_named(wiwi, modparam_wiwi, int, 0644);
105MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)");
106
97static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = 107static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
98{ 108{
99 {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, 109 {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS},
@@ -117,18 +127,18 @@ static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
117static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = 127static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
118{ 128{
119 {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, 129 {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS},
120 {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, 130 {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
121 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, 131 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
122 {5, 5, 0, COEX_CALIBRATION_FLAGS}, 132 {6, 6, 0, COEX_CALIBRATION_FLAGS},
123 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, 133 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
124 {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, 134 {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS},
125 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, 135 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
126 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, 136 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
127 {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, 137 {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
128 {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, 138 {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
129 {1, 1, 0, COEX_RF_ON_FLAGS}, 139 {1, 1, 0, COEX_RF_ON_FLAGS},
130 {1, 1, 0, COEX_RF_OFF_FLAGS}, 140 {1, 1, 0, COEX_RF_OFF_FLAGS},
131 {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, 141 {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
132 {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, 142 {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
133 {1, 1, 0, COEX_RSRVD1_FLAGS}, 143 {1, 1, 0, COEX_RSRVD1_FLAGS},
134 {1, 1, 0, COEX_RSRVD2_FLAGS} 144 {1, 1, 0, COEX_RSRVD2_FLAGS}
@@ -143,7 +153,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
143 153
144 coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; 154 coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK;
145 155
146 switch (iwm->conf.coexist_mode) { 156 switch (modparam_wiwi) {
147 case COEX_MODE_XOR: 157 case COEX_MODE_XOR:
148 case COEX_MODE_CM: 158 case COEX_MODE_CM:
149 coex_enabled = 1; 159 coex_enabled = 1;
@@ -168,7 +178,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
168 COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | 178 COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK |
169 COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; 179 COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK;
170 180
171 switch (iwm->conf.coexist_mode) { 181 switch (modparam_wiwi) {
172 case COEX_MODE_XOR: 182 case COEX_MODE_XOR:
173 memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, 183 memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl,
174 sizeof(iwm_sta_xor_prio_tbl)); 184 sizeof(iwm_sta_xor_prio_tbl));
@@ -179,7 +189,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
179 break; 189 break;
180 default: 190 default:
181 IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", 191 IWM_ERR(iwm, "Invalid coex_mode 0x%x\n",
182 iwm->conf.coexist_mode); 192 modparam_wiwi);
183 break; 193 break;
184 } 194 }
185 } else 195 } else
@@ -187,7 +197,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm)
187 197
188 return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, 198 return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD,
189 &coex_table_cmd, 199 &coex_table_cmd,
190 sizeof(struct iwm_coex_prio_table_cmd), 1); 200 sizeof(struct iwm_coex_prio_table_cmd), 0);
191} 201}
192 202
193int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) 203int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
@@ -275,6 +285,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm)
275 return ret; 285 return ret;
276} 286}
277 287
288int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit)
289{
290 struct iwm_ct_kill_cfg_cmd cmd;
291
292 cmd.entry_threshold = entry;
293 cmd.exit_threshold = exit;
294
295 return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd,
296 sizeof(struct iwm_ct_kill_cfg_cmd), 0);
297}
298
278int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) 299int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
279{ 300{
280 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 301 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
@@ -380,7 +401,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
380 return ret; 401 return ret;
381 402
382 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 403 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
383 CFG_COEX_MODE, iwm->conf.coexist_mode); 404 CFG_COEX_MODE, modparam_wiwi);
384 if (ret < 0) 405 if (ret < 0)
385 return ret; 406 return ret;
386 407
@@ -778,11 +799,24 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
778 return ret; 799 return ret;
779 800
780 ret = wait_event_interruptible_timeout(iwm->mlme_queue, 801 ret = wait_event_interruptible_timeout(iwm->mlme_queue,
781 (iwm->umac_profile_active == 0), 2 * HZ); 802 (iwm->umac_profile_active == 0), 5 * HZ);
782 803
783 return ret ? 0 : -EBUSY; 804 return ret ? 0 : -EBUSY;
784} 805}
785 806
807int iwm_tx_power_trigger(struct iwm_priv *iwm)
808{
809 struct iwm_umac_pwr_trigger pwr_trigger;
810
811 pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER;
812 pwr_trigger.hdr.buf_size =
813 cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) -
814 sizeof(struct iwm_umac_wifi_if));
815
816
817 return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1);
818}
819
786int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) 820int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
787{ 821{
788 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 822 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
@@ -900,3 +934,62 @@ int iwm_target_reset(struct iwm_priv *iwm)
900 934
901 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); 935 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
902} 936}
937
938int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
939 struct iwm_umac_notif_stop_resume_tx *ntf)
940{
941 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
942 struct iwm_umac_cmd umac_cmd;
943 struct iwm_umac_cmd_stop_resume_tx stp_res_cmd;
944 struct iwm_sta_info *sta_info;
945 u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id);
946 int i;
947
948 sta_info = &iwm->sta_table[sta_id];
949 if (!sta_info->valid) {
950 IWM_ERR(iwm, "Invalid STA: %d\n", sta_id);
951 return -EINVAL;
952 }
953
954 umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX;
955 umac_cmd.resp = 0;
956
957 stp_res_cmd.flags = ntf->flags;
958 stp_res_cmd.sta_id = ntf->sta_id;
959 stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk;
960 for (i = 0; i < IWM_UMAC_TID_NR; i++)
961 stp_res_cmd.last_seq_num[i] =
962 sta_info->tid_info[i].last_seq_num;
963
964 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd,
965 sizeof(struct iwm_umac_cmd_stop_resume_tx));
966
967}
968
969int iwm_send_pmkid_update(struct iwm_priv *iwm,
970 struct cfg80211_pmksa *pmksa, u32 command)
971{
972 struct iwm_umac_pmkid_update update;
973 int ret;
974
975 memset(&update, 0, sizeof(struct iwm_umac_pmkid_update));
976
977 update.hdr.oid = UMAC_WIFI_IF_CMD_PMKID_UPDATE;
978 update.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_pmkid_update) -
979 sizeof(struct iwm_umac_wifi_if));
980
981 update.command = cpu_to_le32(command);
982 if (pmksa->bssid)
983 memcpy(&update.bssid, pmksa->bssid, ETH_ALEN);
984 if (pmksa->pmkid)
985 memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
986
987 ret = iwm_send_wifi_if_cmd(iwm, &update,
988 sizeof(struct iwm_umac_pmkid_update), 0);
989 if (ret) {
990 IWM_ERR(iwm, "PMKID update command failed\n");
991 return ret;
992 }
993
994 return 0;
995}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index e24d5b633997..3dfd9f0e9003 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -102,7 +102,6 @@ enum {
102 CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, 102 CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN,
103 CFG_TLC_SUPPORTED_TX_HT_RATES, 103 CFG_TLC_SUPPORTED_TX_HT_RATES,
104 CFG_TLC_SUPPORTED_TX_RATES, 104 CFG_TLC_SUPPORTED_TX_RATES,
105 CFG_TLC_VALID_ANTENNA,
106 CFG_TLC_SPATIAL_STREAM_SUPPORTED, 105 CFG_TLC_SPATIAL_STREAM_SUPPORTED,
107 CFG_TLC_RETRY_PER_RATE, 106 CFG_TLC_RETRY_PER_RATE,
108 CFG_TLC_RETRY_PER_HT_RATE, 107 CFG_TLC_RETRY_PER_HT_RATE,
@@ -136,6 +135,10 @@ enum {
136 CFG_TLC_RENEW_ADDBA_DELAY, 135 CFG_TLC_RENEW_ADDBA_DELAY,
137 CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, 136 CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD,
138 CFG_TLC_IS_STABLE_IN_HT, 137 CFG_TLC_IS_STABLE_IN_HT,
138 CFG_TLC_SR_SIC_1ST_FAIL,
139 CFG_TLC_SR_SIC_1ST_PASS,
140 CFG_TLC_SR_SIC_TOTAL_FAIL,
141 CFG_TLC_SR_SIC_TOTAL_PASS,
139 CFG_RLC_CHAIN_CTRL, 142 CFG_RLC_CHAIN_CTRL,
140 CFG_TRK_TABLE_OP_MODE, 143 CFG_TRK_TABLE_OP_MODE,
141 CFG_TRK_TABLE_RSSI_THRESHOLD, 144 CFG_TRK_TABLE_RSSI_THRESHOLD,
@@ -147,6 +150,58 @@ enum {
147 CFG_MLME_DBG_NOTIF_BLOCK, 150 CFG_MLME_DBG_NOTIF_BLOCK,
148 CFG_BT_OFF_BECONS_INTERVALS, 151 CFG_BT_OFF_BECONS_INTERVALS,
149 CFG_BT_FRAG_DURATION, 152 CFG_BT_FRAG_DURATION,
153 CFG_ACTIVE_CHAINS,
154 CFG_CALIB_CTRL,
155 CFG_CAPABILITY_SUPPORTED_HT_RATES,
156 CFG_HT_MAC_PARAM_INFO,
157 CFG_MIMO_PS_MODE,
158 CFG_HT_DEFAULT_CAPABILIES_INFO,
159 CFG_LED_SC_RESOLUTION_FACTOR,
160 CFG_PTAM_ENERGY_CCK_DET_DEFAULT,
161 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT,
162 CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT,
163 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT,
164 CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT,
165 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT,
166 CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT,
167 CFG_PTAM_ENERGY_CCK_DET_MIN_VAL,
168 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL,
169 CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL,
170 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL,
171 CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL,
172 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL,
173 CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL,
174 CFG_PTAM_ENERGY_CCK_DET_MAX_VAL,
175 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL,
176 CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL,
177 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL,
178 CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL,
179 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL,
180 CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL,
181 CFG_PTAM_ENERGY_CCK_DET_STEP_VAL,
182 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL,
183 CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL,
184 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL,
185 CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL,
186 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL,
187 CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL,
188 CFG_PTAM_LINK_SENS_FA_OFDM_MAX,
189 CFG_PTAM_LINK_SENS_FA_OFDM_MIN,
190 CFG_PTAM_LINK_SENS_FA_CCK_MAX,
191 CFG_PTAM_LINK_SENS_FA_CCK_MIN,
192 CFG_PTAM_LINK_SENS_NRG_DIFF,
193 CFG_PTAM_LINK_SENS_NRG_MARGIN,
194 CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA,
195 CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK,
196 CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD,
197 CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD,
198 CFG_AGG_MGG_ADDBA_BUF_SIZE,
199 CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT,
200 CFG_AGG_MGG_ADDBA_DEBUG_FLAGS,
201 CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD,
202 CFG_SCAN_PERIODIC_COEF_RSSI_HIGH,
203 CFG_11D_ENABLED,
204 CFG_11H_FEATURE_FLAGS,
150 205
151 /* <-- LAST --> */ 206 /* <-- LAST --> */
152 CFG_TBL_FIX_LAST 207 CFG_TBL_FIX_LAST
@@ -155,7 +210,8 @@ enum {
155/* variable size table */ 210/* variable size table */
156enum { 211enum {
157 CFG_NET_ADDR = 0, 212 CFG_NET_ADDR = 0,
158 CFG_PROFILE, 213 CFG_LED_PATTERN_TABLE,
214
159 /* <-- LAST --> */ 215 /* <-- LAST --> */
160 CFG_TBL_VAR_LAST 216 CFG_TBL_VAR_LAST
161}; 217};
@@ -288,6 +344,9 @@ struct iwm_umac_cmd_scan_request {
288/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ 344/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */
289#define UMAC_SEC_FLG_WSC_ON_POS 2 345#define UMAC_SEC_FLG_WSC_ON_POS 2
290#define UMAC_SEC_FLG_WSC_ON_SEED 1 346#define UMAC_SEC_FLG_WSC_ON_SEED 1
347#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \
348 UMAC_SEC_FLG_WSC_ON_POS)
349
291 350
292/* Legacy profile can use only WEP40 and WEP104 for encryption and 351/* Legacy profile can use only WEP40 and WEP104 for encryption and
293 * OPEN or PSK for authentication */ 352 * OPEN or PSK for authentication */
@@ -382,10 +441,35 @@ struct iwm_umac_tx_key_id {
382 u8 reserved[3]; 441 u8 reserved[3];
383} __attribute__ ((packed)); 442} __attribute__ ((packed));
384 443
444struct iwm_umac_pwr_trigger {
445 struct iwm_umac_wifi_if hdr;
446 __le32 reseved;
447} __attribute__ ((packed));
448
385struct iwm_umac_cmd_stats_req { 449struct iwm_umac_cmd_stats_req {
386 __le32 flags; 450 __le32 flags;
387} __attribute__ ((packed)); 451} __attribute__ ((packed));
388 452
453struct iwm_umac_cmd_stop_resume_tx {
454 u8 flags;
455 u8 sta_id;
456 __le16 stop_resume_tid_msk;
457 __le16 last_seq_num[IWM_UMAC_TID_NR];
458 u16 reserved;
459} __attribute__ ((packed));
460
461#define IWM_CMD_PMKID_ADD 1
462#define IWM_CMD_PMKID_DEL 2
463#define IWM_CMD_PMKID_FLUSH 3
464
465struct iwm_umac_pmkid_update {
466 struct iwm_umac_wifi_if hdr;
467 __le32 command;
468 u8 bssid[ETH_ALEN];
469 __le16 reserved;
470 u8 pmkid[WLAN_PMKID_LEN];
471} __attribute__ ((packed));
472
389/* LMAC commands */ 473/* LMAC commands */
390int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); 474int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
391int iwm_send_prio_table(struct iwm_priv *iwm); 475int iwm_send_prio_table(struct iwm_priv *iwm);
@@ -393,6 +477,7 @@ int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
393int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); 477int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
394int iwm_send_calib_results(struct iwm_priv *iwm); 478int iwm_send_calib_results(struct iwm_priv *iwm);
395int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); 479int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
480int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit);
396 481
397/* UMAC commands */ 482/* UMAC commands */
398int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, 483int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
@@ -407,11 +492,16 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
407int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); 492int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
408int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); 493int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
409int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); 494int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
495int iwm_tx_power_trigger(struct iwm_priv *iwm);
410int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); 496int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
411int iwm_send_umac_channel_list(struct iwm_priv *iwm); 497int iwm_send_umac_channel_list(struct iwm_priv *iwm);
412int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, 498int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
413 int ssid_num); 499 int ssid_num);
414int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); 500int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
501int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
502 struct iwm_umac_notif_stop_resume_tx *ntf);
503int iwm_send_pmkid_update(struct iwm_priv *iwm,
504 struct cfg80211_pmksa *pmksa, u32 command);
415 505
416/* UDMA commands */ 506/* UDMA commands */
417int iwm_target_reset(struct iwm_priv *iwm); 507int iwm_target_reset(struct iwm_priv *iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
index 1465379f900a..cbb81befdb55 100644
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c
@@ -21,6 +21,7 @@
21 * 21 *
22 */ 22 */
23 23
24#include <linux/slab.h>
24#include <linux/kernel.h> 25#include <linux/kernel.h>
25#include <linux/bitops.h> 26#include <linux/bitops.h>
26#include <linux/debugfs.h> 27#include <linux/debugfs.h>
@@ -89,7 +90,7 @@ static int iwm_debugfs_dbg_modules_write(void *data, u64 val)
89 for (i = 0; i < __IWM_DM_NR; i++) 90 for (i = 0; i < __IWM_DM_NR; i++)
90 iwm->dbg.dbg_module[i] = 0; 91 iwm->dbg.dbg_module[i] = 0;
91 92
92 for_each_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR) 93 for_each_set_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR)
93 iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level; 94 iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level;
94 95
95 return 0; 96 return 0;
@@ -158,6 +159,29 @@ static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
158 } 159 }
159 160
160 spin_unlock_irqrestore(&txq->queue.lock, flags); 161 spin_unlock_irqrestore(&txq->queue.lock, flags);
162
163 spin_lock_irqsave(&txq->stopped_queue.lock, flags);
164
165 len += snprintf(buf + len, buf_len - len,
166 "\tStopped Queue len: %d\n",
167 skb_queue_len(&txq->stopped_queue));
168 for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) {
169 struct iwm_tx_info *tx_info;
170
171 skb = skb->next;
172 tx_info = skb_to_tx_info(skb);
173
174 len += snprintf(buf + len, buf_len - len,
175 "\tSKB #%d\n", j);
176 len += snprintf(buf + len, buf_len - len,
177 "\t\tsta: %d\n", tx_info->sta);
178 len += snprintf(buf + len, buf_len - len,
179 "\t\tcolor: %d\n", tx_info->color);
180 len += snprintf(buf + len, buf_len - len,
181 "\t\ttid: %d\n", tx_info->tid);
182 }
183
184 spin_unlock_irqrestore(&txq->stopped_queue.lock, flags);
161 } 185 }
162 186
163 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); 187 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
index 365910fbe01e..e80e776b74f7 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -37,6 +37,7 @@
37 */ 37 */
38 38
39#include <linux/kernel.h> 39#include <linux/kernel.h>
40#include <linux/slab.h>
40 41
41#include "iwm.h" 42#include "iwm.h"
42#include "umac.h" 43#include "umac.h"
@@ -66,6 +67,10 @@ static struct iwm_eeprom_entry eeprom_map[] = {
66 [IWM_EEPROM_SKU_CAP] = 67 [IWM_EEPROM_SKU_CAP] =
67 {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, 68 {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN},
68 69
70 [IWM_EEPROM_FAT_CHANNELS_CAP] =
71 {"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF,
72 IWM_EEPROM_FAT_CHANNELS_CAP_LEN},
73
69 [IWM_EEPROM_CALIB_RXIQ_OFFSET] = 74 [IWM_EEPROM_CALIB_RXIQ_OFFSET] =
70 {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, 75 {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN},
71 76
@@ -146,6 +151,52 @@ u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id)
146 return iwm->eeprom + eeprom_map[eeprom_id].offset; 151 return iwm->eeprom + eeprom_map[eeprom_id].offset;
147} 152}
148 153
154int iwm_eeprom_fat_channels(struct iwm_priv *iwm)
155{
156 struct wiphy *wiphy = iwm_to_wiphy(iwm);
157 struct ieee80211_supported_band *band;
158 u16 *channels, i;
159
160 channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP);
161 if (IS_ERR(channels))
162 return PTR_ERR(channels);
163
164 band = wiphy->bands[IEEE80211_BAND_2GHZ];
165 band->ht_cap.ht_supported = true;
166
167 for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++)
168 if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
169 band->ht_cap.ht_supported = false;
170
171 band = wiphy->bands[IEEE80211_BAND_5GHZ];
172 band->ht_cap.ht_supported = true;
173 for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++)
174 if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
175 band->ht_cap.ht_supported = false;
176
177 return 0;
178}
179
180u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm)
181{
182 u16 sku_cap;
183 u32 wireless_mode = 0;
184
185 sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP));
186
187 if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ)
188 wireless_mode |= WIRELESS_MODE_11G;
189
190 if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ)
191 wireless_mode |= WIRELESS_MODE_11A;
192
193 if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE)
194 wireless_mode |= WIRELESS_MODE_11N;
195
196 return wireless_mode;
197}
198
199
149int iwm_eeprom_init(struct iwm_priv *iwm) 200int iwm_eeprom_init(struct iwm_priv *iwm)
150{ 201{
151 int i, ret = 0; 202 int i, ret = 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h
index cdb31a6a1f5f..4e3a3fdab0d3 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.h
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h
@@ -48,6 +48,7 @@ enum {
48 IWM_EEPROM_CARD_ID, 48 IWM_EEPROM_CARD_ID,
49 IWM_EEPROM_RADIO_CONF, 49 IWM_EEPROM_RADIO_CONF,
50 IWM_EEPROM_SKU_CAP, 50 IWM_EEPROM_SKU_CAP,
51 IWM_EEPROM_FAT_CHANNELS_CAP,
51 52
52 IWM_EEPROM_INDIRECT_OFFSET, 53 IWM_EEPROM_INDIRECT_OFFSET,
53 IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, 54 IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET,
@@ -58,14 +59,15 @@ enum {
58 IWM_EEPROM_LAST, 59 IWM_EEPROM_LAST,
59}; 60};
60 61
61#define IWM_EEPROM_SIG_OFF 0x00 62#define IWM_EEPROM_SIG_OFF 0x00
62#define IWM_EEPROM_VERSION_OFF (0x54 << 1) 63#define IWM_EEPROM_VERSION_OFF (0x54 << 1)
63#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) 64#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1)
64#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) 65#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1)
65#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) 66#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1)
66#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) 67#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1)
67#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) 68#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1)
68#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) 69#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1)
70#define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1)
69 71
70#define IWM_EEPROM_SIG_LEN 4 72#define IWM_EEPROM_SIG_LEN 4
71#define IWM_EEPROM_VERSION_LEN 2 73#define IWM_EEPROM_VERSION_LEN 2
@@ -74,6 +76,7 @@ enum {
74#define IWM_EEPROM_CARD_ID_LEN 2 76#define IWM_EEPROM_CARD_ID_LEN 2
75#define IWM_EEPROM_RADIO_CONF_LEN 2 77#define IWM_EEPROM_RADIO_CONF_LEN 2
76#define IWM_EEPROM_SKU_CAP_LEN 2 78#define IWM_EEPROM_SKU_CAP_LEN 2
79#define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40
77#define IWM_EEPROM_INDIRECT_LEN 2 80#define IWM_EEPROM_INDIRECT_LEN 2
78 81
79#define IWM_MAX_EEPROM_DATA_LEN 240 82#define IWM_MAX_EEPROM_DATA_LEN 240
@@ -87,6 +90,14 @@ enum {
87#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) 90#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5)
88#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) 91#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
89 92
93#define IWM_EEPROM_FAT_CHANNELS 20
94/* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */
95#define IWM_EEPROM_FAT_CHANNELS_24 9
96/* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */
97#define IWM_EEPROM_FAT_CHANNELS_52 11
98
99#define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0)
100
90enum { 101enum {
91 IWM_EEPROM_CALIB_CAL_HDR, 102 IWM_EEPROM_CALIB_CAL_HDR,
92 IWM_EEPROM_CALIB_TX_POWER, 103 IWM_EEPROM_CALIB_TX_POWER,
@@ -110,5 +121,7 @@ struct iwm_eeprom_entry {
110int iwm_eeprom_init(struct iwm_priv *iwm); 121int iwm_eeprom_init(struct iwm_priv *iwm);
111void iwm_eeprom_exit(struct iwm_priv *iwm); 122void iwm_eeprom_exit(struct iwm_priv *iwm);
112u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); 123u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id);
124int iwm_eeprom_fat_channels(struct iwm_priv *iwm);
125u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm);
113 126
114#endif 127#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index 6b0bcad758ca..49067092d336 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -217,6 +217,13 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
217 IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), 217 IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date),
218 IWM_BUILD_DAY(build_date)); 218 IWM_BUILD_DAY(build_date));
219 219
220 if (!strcmp(img_name, iwm->bus_ops->umac_name))
221 sprintf(iwm->umac_version, "%02X.%02X",
222 ver->major, ver->minor);
223
224 if (!strcmp(img_name, iwm->bus_ops->lmac_name))
225 sprintf(iwm->lmac_version, "%02X.%02X",
226 ver->major, ver->minor);
220 227
221 err_release_fw: 228 err_release_fw:
222 release_firmware(fw); 229 release_firmware(fw);
@@ -398,6 +405,8 @@ int iwm_load_fw(struct iwm_priv *iwm)
398 iwm_send_prio_table(iwm); 405 iwm_send_prio_table(iwm);
399 iwm_send_calib_results(iwm); 406 iwm_send_calib_results(iwm);
400 iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); 407 iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
408 iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry,
409 iwm->conf.ct_kill_exit);
401 410
402 return 0; 411 return 0;
403 412
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index c430418248b4..229de990379c 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -98,6 +98,7 @@
98 */ 98 */
99#include <linux/kernel.h> 99#include <linux/kernel.h>
100#include <linux/netdevice.h> 100#include <linux/netdevice.h>
101#include <linux/slab.h>
101 102
102#include "iwm.h" 103#include "iwm.h"
103#include "bus.h" 104#include "bus.h"
@@ -411,7 +412,7 @@ static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
411/* 412/*
412 * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC. 413 * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
413 * Sending command to the LMAC is equivalent to sending a 414 * Sending command to the LMAC is equivalent to sending a
414 * regular UMAC command with the LMAC passtrough or the LMAC 415 * regular UMAC command with the LMAC passthrough or the LMAC
415 * wrapper UMAC command IDs. 416 * wrapper UMAC command IDs.
416 */ 417 */
417int iwm_hal_send_host_cmd(struct iwm_priv *iwm, 418int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 1b02a4e2a1ac..79ffa3b98d73 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -65,6 +65,8 @@ struct iwm_conf {
65 u32 sdio_ior_timeout; 65 u32 sdio_ior_timeout;
66 unsigned long calib_map; 66 unsigned long calib_map;
67 unsigned long expected_calib_map; 67 unsigned long expected_calib_map;
68 u8 ct_kill_entry;
69 u8 ct_kill_exit;
68 bool reset_on_fatal_err; 70 bool reset_on_fatal_err;
69 bool auto_connect; 71 bool auto_connect;
70 bool wimax_not_present; 72 bool wimax_not_present;
@@ -79,7 +81,6 @@ struct iwm_conf {
79 u32 assoc_timeout; 81 u32 assoc_timeout;
80 u32 roam_timeout; 82 u32 roam_timeout;
81 u32 wireless_mode; 83 u32 wireless_mode;
82 u32 coexist_mode;
83 84
84 u8 ibss_band; 85 u8 ibss_band;
85 u8 ibss_channel; 86 u8 ibss_channel;
@@ -129,11 +130,18 @@ struct iwm_notif {
129 unsigned long buf_size; 130 unsigned long buf_size;
130}; 131};
131 132
133struct iwm_tid_info {
134 __le16 last_seq_num;
135 bool stopped;
136 struct mutex mutex;
137};
138
132struct iwm_sta_info { 139struct iwm_sta_info {
133 u8 addr[ETH_ALEN]; 140 u8 addr[ETH_ALEN];
134 bool valid; 141 bool valid;
135 bool qos; 142 bool qos;
136 u8 color; 143 u8 color;
144 struct iwm_tid_info tid_info[IWM_UMAC_TID_NR];
137}; 145};
138 146
139struct iwm_tx_info { 147struct iwm_tx_info {
@@ -183,6 +191,8 @@ struct iwm_key {
183struct iwm_tx_queue { 191struct iwm_tx_queue {
184 int id; 192 int id;
185 struct sk_buff_head queue; 193 struct sk_buff_head queue;
194 struct sk_buff_head stopped_queue;
195 spinlock_t lock;
186 struct workqueue_struct *wq; 196 struct workqueue_struct *wq;
187 struct work_struct worker; 197 struct work_struct worker;
188 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; 198 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
@@ -276,12 +286,14 @@ struct iwm_priv {
276 struct iw_statistics wstats; 286 struct iw_statistics wstats;
277 struct delayed_work stats_request; 287 struct delayed_work stats_request;
278 struct delayed_work disconnect; 288 struct delayed_work disconnect;
289 struct delayed_work ct_kill_delay;
279 290
280 struct iwm_debugfs dbg; 291 struct iwm_debugfs dbg;
281 292
282 u8 *eeprom; 293 u8 *eeprom;
283 struct timer_list watchdog; 294 struct timer_list watchdog;
284 struct work_struct reset_worker; 295 struct work_struct reset_worker;
296 struct work_struct auth_retry_worker;
285 struct mutex mutex; 297 struct mutex mutex;
286 298
287 u8 *req_ie; 299 u8 *req_ie;
@@ -290,6 +302,8 @@ struct iwm_priv {
290 int resp_ie_len; 302 int resp_ie_len;
291 303
292 struct iwm_fw_error_hdr *last_fw_err; 304 struct iwm_fw_error_hdr *last_fw_err;
305 char umac_version[8];
306 char lmac_version[8];
293 307
294 char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); 308 char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
295}; 309};
@@ -335,6 +349,7 @@ int iwm_up(struct iwm_priv *iwm);
335int iwm_down(struct iwm_priv *iwm); 349int iwm_down(struct iwm_priv *iwm);
336 350
337/* TX API */ 351/* TX API */
352int iwm_tid_to_queue(u16 tid);
338void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); 353void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
339void iwm_tx_worker(struct work_struct *work); 354void iwm_tx_worker(struct work_struct *work);
340int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); 355int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index 6c1a14c4480f..a855a99e49b8 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -187,6 +187,14 @@ struct iwm_coex_prio_table_cmd {
187 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ 187 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
188 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) 188 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
189 189
190/* CT kill config command */
191struct iwm_ct_kill_cfg_cmd {
192 u32 exit_threshold;
193 u32 reserved;
194 u32 entry_threshold;
195} __attribute__ ((packed));
196
197
190/* LMAC OP CODES */ 198/* LMAC OP CODES */
191#define REPLY_PAD 0x0 199#define REPLY_PAD 0x0
192#define REPLY_ALIVE 0x1 200#define REPLY_ALIVE 0x1
@@ -254,7 +262,7 @@ struct iwm_coex_prio_table_cmd {
254 262
255/* Power Management */ 263/* Power Management */
256#define POWER_TABLE_CMD 0x77 264#define POWER_TABLE_CMD 0x77
257#define SAVE_RESTORE_ADRESS_CMD 0x78 265#define SAVE_RESTORE_ADDRESS_CMD 0x78
258#define REPLY_WATERMARK_CMD 0x79 266#define REPLY_WATERMARK_CMD 0x79
259#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B 267#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B
260#define PD_FLUSH_N_NOTIFICATION 0x7C 268#define PD_FLUSH_N_NOTIFICATION 0x7C
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;
92module_param_named(reset, modparam_reset, bool, 0644); 94module_param_named(reset, modparam_reset, bool, 0644);
93MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); 95MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])");
94 96
97static int modparam_wimax_enable = 1;
98module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644);
99MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])");
100
95int iwm_mode_to_nl80211_iftype(int mode) 101int 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
143static 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
137static int __iwm_up(struct iwm_priv *iwm); 154static int __iwm_up(struct iwm_priv *iwm);
138static int __iwm_down(struct iwm_priv *iwm); 155static 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
215static 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
198static void iwm_watchdog(unsigned long data) 242static 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
208int iwm_priv_init(struct iwm_priv *iwm) 252int 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) |
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 35ec006c2d2c..13a69ebf2a94 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -46,6 +46,7 @@
46 * -> sdio_disable_func() 46 * -> sdio_disable_func()
47 */ 47 */
48#include <linux/netdevice.h> 48#include <linux/netdevice.h>
49#include <linux/slab.h>
49 50
50#include "iwm.h" 51#include "iwm.h"
51#include "commands.h" 52#include "commands.h"
@@ -76,6 +77,14 @@ static int iwm_stop(struct net_device *ndev)
76 */ 77 */
77static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; 78static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
78 79
80int iwm_tid_to_queue(u16 tid)
81{
82 if (tid > IWM_UMAC_TID_NR - 2)
83 return -EINVAL;
84
85 return iwm_1d_to_queue[tid];
86}
87
79static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) 88static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
80{ 89{
81 skb->priority = cfg80211_classify8021d(skb); 90 skb->priority = cfg80211_classify8021d(skb);
@@ -152,6 +161,7 @@ void iwm_if_free(struct iwm_priv *iwm)
152 if (!iwm_to_ndev(iwm)) 161 if (!iwm_to_ndev(iwm))
153 return; 162 return;
154 163
164 cancel_delayed_work_sync(&iwm->ct_kill_delay);
155 free_netdev(iwm_to_ndev(iwm)); 165 free_netdev(iwm_to_ndev(iwm));
156 iwm_priv_deinit(iwm); 166 iwm_priv_deinit(iwm);
157 kfree(iwm->umac_profile); 167 kfree(iwm->umac_profile);
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 771a301003c9..3257d4fad835 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -44,6 +44,7 @@
44#include <linux/ieee80211.h> 44#include <linux/ieee80211.h>
45#include <linux/if_arp.h> 45#include <linux/if_arp.h>
46#include <linux/list.h> 46#include <linux/list.h>
47#include <linux/slab.h>
47#include <net/iw_handler.h> 48#include <net/iw_handler.h>
48 49
49#include "iwm.h" 50#include "iwm.h"
@@ -423,7 +424,9 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
423 if (IS_ERR(ticket_node)) 424 if (IS_ERR(ticket_node))
424 return PTR_ERR(ticket_node); 425 return PTR_ERR(ticket_node);
425 426
426 IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n", 427 IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
428 ticket->action == IWM_RX_TICKET_RELEASE ?
429 "RELEASE" : "DROP",
427 ticket->id); 430 ticket->id);
428 list_add_tail(&ticket_node->node, &iwm->rx_tickets); 431 list_add_tail(&ticket_node->node, &iwm->rx_tickets);
429 432
@@ -500,6 +503,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
500 return 0; 503 return 0;
501} 504}
502 505
506static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm)
507{
508 if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
509 iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
510 (iwm->umac_profile->sec.ucast_cipher ==
511 iwm->umac_profile->sec.mcast_cipher) &&
512 (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN))
513 return 1;
514
515 return 0;
516}
517
503static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, 518static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
504 unsigned long buf_size, 519 unsigned long buf_size,
505 struct iwm_wifi_cmd *cmd) 520 struct iwm_wifi_cmd *cmd)
@@ -565,11 +580,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
565 goto ibss; 580 goto ibss;
566 581
567 if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) 582 if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
568 cfg80211_connect_result(iwm_to_ndev(iwm), 583 if (!iwm_is_open_wep_profile(iwm)) {
569 complete->bssid, 584 cfg80211_connect_result(iwm_to_ndev(iwm),
570 NULL, 0, NULL, 0, 585 complete->bssid,
571 WLAN_STATUS_UNSPECIFIED_FAILURE, 586 NULL, 0, NULL, 0,
572 GFP_KERNEL); 587 WLAN_STATUS_UNSPECIFIED_FAILURE,
588 GFP_KERNEL);
589 } else {
590 /* Let's try shared WEP auth */
591 IWM_ERR(iwm, "Trying WEP shared auth\n");
592 schedule_work(&iwm->auth_retry_worker);
593 }
573 else 594 else
574 cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, 595 cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
575 GFP_KERNEL); 596 GFP_KERNEL);
@@ -713,6 +734,19 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
713 return 0; 734 return 0;
714} 735}
715 736
737static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf,
738 unsigned long buf_size,
739 struct iwm_wifi_cmd *cmd)
740{
741 struct wiphy *wiphy = iwm_to_wiphy(iwm);
742
743 IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n");
744
745 wiphy_rfkill_set_hw_state(wiphy, true);
746
747 return 0;
748}
749
716static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, 750static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
717 unsigned long buf_size, 751 unsigned long buf_size,
718 struct iwm_wifi_cmd *cmd) 752 struct iwm_wifi_cmd *cmd)
@@ -761,7 +795,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
761 } 795 }
762 796
763 bss->bss = kzalloc(bss_len, GFP_KERNEL); 797 bss->bss = kzalloc(bss_len, GFP_KERNEL);
764 if (!bss) { 798 if (!bss->bss) {
765 kfree(bss); 799 kfree(bss);
766 IWM_ERR(iwm, "Couldn't allocate bss\n"); 800 IWM_ERR(iwm, "Couldn't allocate bss\n");
767 return -ENOMEM; 801 return -ENOMEM;
@@ -835,36 +869,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
835 struct iwm_umac_notif_mgt_frame *mgt_frame = 869 struct iwm_umac_notif_mgt_frame *mgt_frame =
836 (struct iwm_umac_notif_mgt_frame *)buf; 870 (struct iwm_umac_notif_mgt_frame *)buf;
837 struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; 871 struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
838 u8 *ie;
839 872
840 IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, 873 IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
841 le16_to_cpu(mgt_frame->len)); 874 le16_to_cpu(mgt_frame->len));
842 875
843 if (ieee80211_is_assoc_req(mgt->frame_control)) { 876 if (ieee80211_is_assoc_req(mgt->frame_control)) {
844 ie = mgt->u.assoc_req.variable;; 877 iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
845 iwm->req_ie_len = 878 - offsetof(struct ieee80211_mgmt,
846 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); 879 u.assoc_req.variable);
847 kfree(iwm->req_ie); 880 kfree(iwm->req_ie);
848 iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, 881 iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
849 iwm->req_ie_len, GFP_KERNEL); 882 iwm->req_ie_len, GFP_KERNEL);
850 } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { 883 } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
851 ie = mgt->u.reassoc_req.variable;; 884 iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
852 iwm->req_ie_len = 885 - offsetof(struct ieee80211_mgmt,
853 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); 886 u.reassoc_req.variable);
854 kfree(iwm->req_ie); 887 kfree(iwm->req_ie);
855 iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, 888 iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
856 iwm->req_ie_len, GFP_KERNEL); 889 iwm->req_ie_len, GFP_KERNEL);
857 } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { 890 } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
858 ie = mgt->u.assoc_resp.variable;; 891 iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
859 iwm->resp_ie_len = 892 - offsetof(struct ieee80211_mgmt,
860 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); 893 u.assoc_resp.variable);
861 kfree(iwm->resp_ie); 894 kfree(iwm->resp_ie);
862 iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, 895 iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
863 iwm->resp_ie_len, GFP_KERNEL); 896 iwm->resp_ie_len, GFP_KERNEL);
864 } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { 897 } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
865 ie = mgt->u.reassoc_resp.variable;; 898 iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
866 iwm->resp_ie_len = 899 - offsetof(struct ieee80211_mgmt,
867 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); 900 u.reassoc_resp.variable);
868 kfree(iwm->resp_ie); 901 kfree(iwm->resp_ie);
869 iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, 902 iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
870 iwm->resp_ie_len, GFP_KERNEL); 903 iwm->resp_ie_len, GFP_KERNEL);
@@ -899,6 +932,8 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
899 case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: 932 case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
900 IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); 933 IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
901 break; 934 break;
935 case WIFI_IF_NTFY_RADIO_PREEMPTION:
936 return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd);
902 case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: 937 case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
903 return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); 938 return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
904 case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: 939 case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
@@ -1052,12 +1087,83 @@ static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf,
1052 return 0; 1087 return 0;
1053} 1088}
1054 1089
1090static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf,
1091 unsigned long buf_size,
1092 struct iwm_wifi_cmd *cmd)
1093{
1094 struct iwm_umac_notif_stop_resume_tx *stp_res_tx =
1095 (struct iwm_umac_notif_stop_resume_tx *)buf;
1096 struct iwm_sta_info *sta_info;
1097 struct iwm_tid_info *tid_info;
1098 u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id);
1099 u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk);
1100 int bit, ret = 0;
1101 bool stop = false;
1102
1103 IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n"
1104 "\tflags: 0x%x\n"
1105 "\tSTA id: %d\n"
1106 "\tTID bitmask: 0x%x\n",
1107 stp_res_tx->flags, stp_res_tx->sta_id,
1108 stp_res_tx->stop_resume_tid_msk);
1109
1110 if (stp_res_tx->flags & UMAC_STOP_TX_FLAG)
1111 stop = true;
1112
1113 sta_info = &iwm->sta_table[sta_id];
1114 if (!sta_info->valid) {
1115 IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n",
1116 sta_id, stp_res_tx->sta_id);
1117 return -EINVAL;
1118 }
1119
1120 for_each_set_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) {
1121 tid_info = &sta_info->tid_info[bit];
1122
1123 mutex_lock(&tid_info->mutex);
1124 tid_info->stopped = stop;
1125 mutex_unlock(&tid_info->mutex);
1126
1127 if (!stop) {
1128 struct iwm_tx_queue *txq;
1129 int queue = iwm_tid_to_queue(bit);
1130
1131 if (queue < 0)
1132 continue;
1133
1134 txq = &iwm->txq[queue];
1135 /*
1136 * If we resume, we have to move our SKBs
1137 * back to the tx queue and queue some work.
1138 */
1139 spin_lock_bh(&txq->lock);
1140 skb_queue_splice_init(&txq->queue, &txq->stopped_queue);
1141 spin_unlock_bh(&txq->lock);
1142
1143 queue_work(txq->wq, &txq->worker);
1144 }
1145
1146 }
1147
1148 /* We send an ACK only for the stop case */
1149 if (stop)
1150 ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx);
1151
1152 return ret;
1153}
1154
1055static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, 1155static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
1056 unsigned long buf_size, 1156 unsigned long buf_size,
1057 struct iwm_wifi_cmd *cmd) 1157 struct iwm_wifi_cmd *cmd)
1058{ 1158{
1059 struct iwm_umac_wifi_if *hdr = 1159 struct iwm_umac_wifi_if *hdr;
1060 (struct iwm_umac_wifi_if *)cmd->buf.payload; 1160
1161 if (cmd == NULL) {
1162 IWM_ERR(iwm, "Couldn't find expected wifi command\n");
1163 return -EINVAL;
1164 }
1165
1166 hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload;
1061 1167
1062 IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " 1168 IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
1063 "oid is 0x%x\n", hdr->oid); 1169 "oid is 0x%x\n", hdr->oid);
@@ -1079,6 +1185,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
1079 return 0; 1185 return 0;
1080} 1186}
1081 1187
1188#define CT_KILL_DELAY (30 * HZ)
1082static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, 1189static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
1083 unsigned long buf_size, struct iwm_wifi_cmd *cmd) 1190 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
1084{ 1191{
@@ -1091,7 +1198,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
1091 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", 1198 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
1092 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); 1199 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
1093 1200
1094 wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED); 1201 if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
1202 /*
1203 * We got a CTKILL event: We bring the interface down in
1204 * oder to cool the device down, and try to bring it up
1205 * 30 seconds later. If it's still too hot, we'll go through
1206 * this code path again.
1207 */
1208 cancel_delayed_work_sync(&iwm->ct_kill_delay);
1209 schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
1210 }
1211
1212 wiphy_rfkill_set_hw_state(wiphy, flags &
1213 (IWM_CARD_STATE_HW_DISABLED |
1214 IWM_CARD_STATE_CTKILL_DISABLED));
1095 1215
1096 return 0; 1216 return 0;
1097} 1217}
@@ -1282,6 +1402,14 @@ int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
1282 1402
1283 switch (le32_to_cpu(hdr->cmd)) { 1403 switch (le32_to_cpu(hdr->cmd)) {
1284 case UMAC_REBOOT_BARKER: 1404 case UMAC_REBOOT_BARKER:
1405 if (test_bit(IWM_STATUS_READY, &iwm->status)) {
1406 IWM_ERR(iwm, "Unexpected BARKER\n");
1407
1408 schedule_work(&iwm->reset_worker);
1409
1410 return 0;
1411 }
1412
1285 return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, 1413 return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
1286 IWM_SRC_UDMA, buf, buf_size); 1414 IWM_SRC_UDMA, buf, buf_size);
1287 case UMAC_ACK_BARKER: 1415 case UMAC_ACK_BARKER:
@@ -1308,6 +1436,7 @@ static const iwm_handler iwm_umac_handlers[] =
1308 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, 1436 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics,
1309 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, 1437 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy,
1310 [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, 1438 [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list,
1439 [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx,
1311 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, 1440 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet,
1312 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, 1441 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper,
1313}; 1442};
@@ -1405,6 +1534,33 @@ static void classify8023(struct sk_buff *skb)
1405 } 1534 }
1406} 1535}
1407 1536
1537static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
1538{
1539 struct wireless_dev *wdev = iwm_to_wdev(iwm);
1540 struct net_device *ndev = iwm_to_ndev(iwm);
1541 struct sk_buff_head list;
1542 struct sk_buff *frame;
1543
1544 IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
1545
1546 __skb_queue_head_init(&list);
1547 ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
1548
1549 while ((frame = __skb_dequeue(&list))) {
1550 ndev->stats.rx_packets++;
1551 ndev->stats.rx_bytes += frame->len;
1552
1553 frame->protocol = eth_type_trans(frame, ndev);
1554 frame->ip_summed = CHECKSUM_NONE;
1555 memset(frame->cb, 0, sizeof(frame->cb));
1556
1557 if (netif_rx_ni(frame) == NET_RX_DROP) {
1558 IWM_ERR(iwm, "Packet dropped\n");
1559 ndev->stats.rx_dropped++;
1560 }
1561 }
1562}
1563
1408static void iwm_rx_process_packet(struct iwm_priv *iwm, 1564static void iwm_rx_process_packet(struct iwm_priv *iwm,
1409 struct iwm_rx_packet *packet, 1565 struct iwm_rx_packet *packet,
1410 struct iwm_rx_ticket_node *ticket_node) 1566 struct iwm_rx_ticket_node *ticket_node)
@@ -1419,36 +1575,46 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
1419 switch (le16_to_cpu(ticket_node->ticket->action)) { 1575 switch (le16_to_cpu(ticket_node->ticket->action)) {
1420 case IWM_RX_TICKET_RELEASE: 1576 case IWM_RX_TICKET_RELEASE:
1421 IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); 1577 IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
1422 classify8023(skb); 1578
1423 iwm_rx_adjust_packet(iwm, packet, ticket_node); 1579 iwm_rx_adjust_packet(iwm, packet, ticket_node);
1580 skb->dev = iwm_to_ndev(iwm);
1581 classify8023(skb);
1582
1583 if (le16_to_cpu(ticket_node->ticket->flags) &
1584 IWM_RX_TICKET_AMSDU_MSK) {
1585 iwm_rx_process_amsdu(iwm, skb);
1586 break;
1587 }
1588
1424 ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); 1589 ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
1425 if (ret < 0) { 1590 if (ret < 0) {
1426 IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " 1591 IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
1427 "%d\n", ret); 1592 "%d\n", ret);
1593 kfree_skb(packet->skb);
1428 break; 1594 break;
1429 } 1595 }
1430 1596
1431 IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); 1597 IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
1432 1598
1433 skb->dev = iwm_to_ndev(iwm); 1599 ndev->stats.rx_packets++;
1600 ndev->stats.rx_bytes += skb->len;
1601
1434 skb->protocol = eth_type_trans(skb, ndev); 1602 skb->protocol = eth_type_trans(skb, ndev);
1435 skb->ip_summed = CHECKSUM_NONE; 1603 skb->ip_summed = CHECKSUM_NONE;
1436 memset(skb->cb, 0, sizeof(skb->cb)); 1604 memset(skb->cb, 0, sizeof(skb->cb));
1437 1605
1438 ndev->stats.rx_packets++;
1439 ndev->stats.rx_bytes += skb->len;
1440
1441 if (netif_rx_ni(skb) == NET_RX_DROP) { 1606 if (netif_rx_ni(skb) == NET_RX_DROP) {
1442 IWM_ERR(iwm, "Packet dropped\n"); 1607 IWM_ERR(iwm, "Packet dropped\n");
1443 ndev->stats.rx_dropped++; 1608 ndev->stats.rx_dropped++;
1444 } 1609 }
1445 break; 1610 break;
1446 case IWM_RX_TICKET_DROP: 1611 case IWM_RX_TICKET_DROP:
1447 IWM_DBG_RX(iwm, DBG, "DROP packet\n"); 1612 IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n",
1613 le16_to_cpu(ticket_node->ticket->flags));
1448 kfree_skb(packet->skb); 1614 kfree_skb(packet->skb);
1449 break; 1615 break;
1450 default: 1616 default:
1451 IWM_ERR(iwm, "Unknow ticket action: %d\n", 1617 IWM_ERR(iwm, "Unknown ticket action: %d\n",
1452 le16_to_cpu(ticket_node->ticket->action)); 1618 le16_to_cpu(ticket_node->ticket->action));
1453 kfree_skb(packet->skb); 1619 kfree_skb(packet->skb);
1454 } 1620 }
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 8b1de84003ca..1eafd6dec3fd 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -63,6 +63,7 @@
63 */ 63 */
64 64
65#include <linux/kernel.h> 65#include <linux/kernel.h>
66#include <linux/slab.h>
66#include <linux/netdevice.h> 67#include <linux/netdevice.h>
67#include <linux/debugfs.h> 68#include <linux/debugfs.h>
68#include <linux/mmc/sdio_ids.h> 69#include <linux/mmc/sdio_ids.h>
@@ -224,8 +225,6 @@ static int if_sdio_disable(struct iwm_priv *iwm)
224 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); 225 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
225 int ret; 226 int ret;
226 227
227 iwm_reset(iwm);
228
229 sdio_claim_host(hw->func); 228 sdio_claim_host(hw->func);
230 sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); 229 sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
231 if (ret < 0) 230 if (ret < 0)
@@ -237,6 +236,8 @@ static int if_sdio_disable(struct iwm_priv *iwm)
237 236
238 iwm_sdio_rx_free(hw); 237 iwm_sdio_rx_free(hw);
239 238
239 iwm_reset(iwm);
240
240 IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); 241 IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n");
241 242
242 return 0; 243 return 0;
@@ -399,6 +400,9 @@ static struct iwm_if_ops if_sdio_ops = {
399 .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", 400 .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin",
400 .lmac_name = "iwmc3200wifi-lmac-sdio.bin", 401 .lmac_name = "iwmc3200wifi-lmac-sdio.bin",
401}; 402};
403MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin");
404MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin");
405MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin");
402 406
403static int iwm_sdio_probe(struct sdio_func *func, 407static int iwm_sdio_probe(struct sdio_func *func,
404 const struct sdio_device_id *id) 408 const struct sdio_device_id *id)
@@ -493,8 +497,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
493} 497}
494 498
495static const struct sdio_device_id iwm_sdio_ids[] = { 499static const struct sdio_device_id iwm_sdio_ids[] = {
496 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 500 /* Global/AGN SKU */
497 SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) }, 501 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) },
502 /* BGN SKU */
503 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) },
498 { /* end: all zeroes */ }, 504 { /* end: all zeroes */ },
499}; 505};
500MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); 506MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c
index e3b4f7902daf..f6a02f123f31 100644
--- a/drivers/net/wireless/iwmc3200wifi/tx.c
+++ b/drivers/net/wireless/iwmc3200wifi/tx.c
@@ -64,6 +64,7 @@
64 * (i.e. half of the max size). [iwm_tx_worker] 64 * (i.e. half of the max size). [iwm_tx_worker]
65 */ 65 */
66 66
67#include <linux/slab.h>
67#include <linux/skbuff.h> 68#include <linux/skbuff.h>
68#include <linux/netdevice.h> 69#include <linux/netdevice.h>
69#include <linux/ieee80211.h> 70#include <linux/ieee80211.h>
@@ -329,7 +330,7 @@ static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
329 330
330 memcpy(buf + sizeof(*hdr), skb->data, skb->len); 331 memcpy(buf + sizeof(*hdr), skb->data, skb->len);
331 332
332 return 0; 333 return umac_cmd.seq_num;
333} 334}
334 335
335static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, 336static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
@@ -354,16 +355,15 @@ static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
354 return ret; 355 return ret;
355} 356}
356 357
357#define CONFIG_IWM_TX_CONCATENATED 1
358
359void iwm_tx_worker(struct work_struct *work) 358void iwm_tx_worker(struct work_struct *work)
360{ 359{
361 struct iwm_priv *iwm; 360 struct iwm_priv *iwm;
362 struct iwm_tx_info *tx_info = NULL; 361 struct iwm_tx_info *tx_info = NULL;
363 struct sk_buff *skb; 362 struct sk_buff *skb;
364 int cmdlen, ret;
365 struct iwm_tx_queue *txq; 363 struct iwm_tx_queue *txq;
366 int pool_id; 364 struct iwm_sta_info *sta_info;
365 struct iwm_tid_info *tid_info;
366 int cmdlen, ret, pool_id;
367 367
368 txq = container_of(work, struct iwm_tx_queue, worker); 368 txq = container_of(work, struct iwm_tx_queue, worker);
369 iwm = container_of(txq, struct iwm_priv, txq[txq->id]); 369 iwm = container_of(txq, struct iwm_priv, txq[txq->id]);
@@ -373,19 +373,46 @@ void iwm_tx_worker(struct work_struct *work)
373 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && 373 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
374 !skb_queue_empty(&txq->queue)) { 374 !skb_queue_empty(&txq->queue)) {
375 375
376 spin_lock_bh(&txq->lock);
376 skb = skb_dequeue(&txq->queue); 377 skb = skb_dequeue(&txq->queue);
378 spin_unlock_bh(&txq->lock);
379
377 tx_info = skb_to_tx_info(skb); 380 tx_info = skb_to_tx_info(skb);
381 sta_info = &iwm->sta_table[tx_info->sta];
382 if (!sta_info->valid) {
383 IWM_ERR(iwm, "Trying to send a frame to unknown STA\n");
384 kfree_skb(skb);
385 continue;
386 }
387
388 tid_info = &sta_info->tid_info[tx_info->tid];
389
390 mutex_lock(&tid_info->mutex);
391
392 /*
393 * If the RAxTID is stopped, we queue the skb to the stopped
394 * queue.
395 * Whenever we'll get a UMAC notification to resume the tx flow
396 * for this RAxTID, we'll merge back the stopped queue into the
397 * regular queue. See iwm_ntf_stop_resume_tx() from rx.c.
398 */
399 if (tid_info->stopped) {
400 IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n",
401 tx_info->sta, tx_info->tid);
402 spin_lock_bh(&txq->lock);
403 skb_queue_tail(&txq->stopped_queue, skb);
404 spin_unlock_bh(&txq->lock);
405
406 mutex_unlock(&tid_info->mutex);
407 continue;
408 }
409
378 cmdlen = IWM_UDMA_HDR_LEN + skb->len; 410 cmdlen = IWM_UDMA_HDR_LEN + skb->len;
379 411
380 IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " 412 IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: "
381 "%d, color: %d\n", txq->id, skb, tx_info->sta, 413 "%d, color: %d\n", txq->id, skb, tx_info->sta,
382 tx_info->color); 414 tx_info->color);
383 415
384#if !CONFIG_IWM_TX_CONCATENATED
385 /* temporarily keep this to comparing the performance */
386 ret = iwm_send_packet(iwm, skb, pool_id);
387#else
388
389 if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) 416 if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE)
390 iwm_tx_send_concat_packets(iwm, txq); 417 iwm_tx_send_concat_packets(iwm, txq);
391 418
@@ -393,14 +420,21 @@ void iwm_tx_worker(struct work_struct *work)
393 if (ret) { 420 if (ret) {
394 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " 421 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue "
395 "%d, Tx worker stopped\n", txq->id); 422 "%d, Tx worker stopped\n", txq->id);
423 spin_lock_bh(&txq->lock);
396 skb_queue_head(&txq->queue, skb); 424 skb_queue_head(&txq->queue, skb);
425 spin_unlock_bh(&txq->lock);
426
427 mutex_unlock(&tid_info->mutex);
397 break; 428 break;
398 } 429 }
399 430
400 txq->concat_ptr = txq->concat_buf + txq->concat_count; 431 txq->concat_ptr = txq->concat_buf + txq->concat_count;
401 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); 432 tid_info->last_seq_num =
433 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
402 txq->concat_count += ALIGN(cmdlen, 16); 434 txq->concat_count += ALIGN(cmdlen, 16);
403#endif 435
436 mutex_unlock(&tid_info->mutex);
437
404 kfree_skb(skb); 438 kfree_skb(skb);
405 } 439 }
406 440
@@ -419,14 +453,14 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
419 struct iwm_priv *iwm = ndev_to_iwm(netdev); 453 struct iwm_priv *iwm = ndev_to_iwm(netdev);
420 struct net_device *ndev = iwm_to_ndev(iwm); 454 struct net_device *ndev = iwm_to_ndev(iwm);
421 struct wireless_dev *wdev = iwm_to_wdev(iwm); 455 struct wireless_dev *wdev = iwm_to_wdev(iwm);
422 u8 *dst_addr;
423 struct iwm_tx_info *tx_info; 456 struct iwm_tx_info *tx_info;
424 struct iwm_tx_queue *txq; 457 struct iwm_tx_queue *txq;
425 struct iwm_sta_info *sta_info; 458 struct iwm_sta_info *sta_info;
426 u8 sta_id; 459 u8 *dst_addr, sta_id;
427 u16 queue; 460 u16 queue;
428 int ret; 461 int ret;
429 462
463
430 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { 464 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
431 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " 465 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
432 "not associated\n"); 466 "not associated\n");
@@ -440,7 +474,8 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
440 txq = &iwm->txq[queue]; 474 txq = &iwm->txq[queue];
441 475
442 /* No free space for Tx, tx_worker is too slow */ 476 /* No free space for Tx, tx_worker is too slow */
443 if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { 477 if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) ||
478 (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) {
444 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); 479 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
445 netif_stop_subqueue(netdev, queue); 480 netif_stop_subqueue(netdev, queue);
446 return NETDEV_TX_BUSY; 481 return NETDEV_TX_BUSY;
@@ -477,7 +512,9 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
477 else 512 else
478 tx_info->tid = IWM_UMAC_MGMT_TID; 513 tx_info->tid = IWM_UMAC_MGMT_TID;
479 514
515 spin_lock_bh(&iwm->txq[queue].lock);
480 skb_queue_tail(&iwm->txq[queue].queue, skb); 516 skb_queue_tail(&iwm->txq[queue].queue, skb);
517 spin_unlock_bh(&iwm->txq[queue].lock);
481 518
482 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); 519 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
483 520
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index c5a14ae3160a..7f54a145ca65 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -83,6 +83,20 @@ struct iwm_udma_out_wifi_hdr {
83 ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ 83 ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
84 (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) 84 (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
85 85
86/* STA ID and color */
87#define STA_ID_SEED (0x0f)
88#define STA_ID_POS (0)
89#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS)
90
91#define STA_COLOR_SEED (0x7)
92#define STA_COLOR_POS (4)
93#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS)
94
95#define STA_ID_N_COLOR_COLOR(id_n_color) \
96 (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS)
97#define STA_ID_N_COLOR_ID(id_n_color) \
98 (((id_n_color) & STA_ID_MSK) >> STA_ID_POS)
99
86/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ 100/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */
87#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 101#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0
88#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF 102#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF
@@ -260,6 +274,9 @@ struct iwm_udma_out_wifi_hdr {
260#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 274#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16
261#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 275#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17
262#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 276#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18
277#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19
278#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A
279
263#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA 280#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA
264#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB 281#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB
265#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC 282#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC
@@ -281,6 +298,7 @@ struct iwm_udma_out_wifi_hdr {
281#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B 298#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B
282#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C 299#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C
283#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E 300#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E
301#define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F
284#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 302#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20
285 303
286/* UMAC WiFi interface ports */ 304/* UMAC WiFi interface ports */
@@ -687,19 +705,24 @@ struct iwm_umac_notif_rx_ticket {
687/* Tx/Rx rates window (number of max of last update window per second) */ 705/* Tx/Rx rates window (number of max of last update window per second) */
688#define UMAC_NTF_RATE_SAMPLE_NR 4 706#define UMAC_NTF_RATE_SAMPLE_NR 4
689 707
708/* Max numbers of bits required to go through all antennae in bitmasks */
709#define UMAC_PHY_NUM_CHAINS 3
710
690#define IWM_UMAC_MGMT_TID 8 711#define IWM_UMAC_MGMT_TID 8
691#define IWM_UMAC_TID_NR 8 712#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */
692 713
693struct iwm_umac_notif_stats { 714struct iwm_umac_notif_stats {
694 struct iwm_umac_wifi_in_hdr hdr; 715 struct iwm_umac_wifi_in_hdr hdr;
695 __le32 flags; 716 __le32 flags;
696 __le32 timestamp; 717 __le32 timestamp;
697 __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ 718 __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */
698 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; 719 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
699 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; 720 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
721 __le32 chain_energy[UMAC_PHY_NUM_CHAINS];
700 s32 rssi_dbm; 722 s32 rssi_dbm;
701 s32 noise_dbm; 723 s32 noise_dbm;
702 __le32 supp_rates; 724 __le32 supp_rates;
725 __le32 supp_ht_rates;
703 __le32 missed_beacons; 726 __le32 missed_beacons;
704 __le32 rx_beacons; 727 __le32 rx_beacons;
705 __le32 rx_dir_pkts; 728 __le32 rx_dir_pkts;
@@ -737,6 +760,20 @@ struct iwm_umac_notif_stats {
737 __le32 roam_ap_loadblance; 760 __le32 roam_ap_loadblance;
738} __attribute__ ((packed)); 761} __attribute__ ((packed));
739 762
763#define UMAC_STOP_TX_FLAG 0x1
764#define UMAC_RESUME_TX_FLAG 0x2
765
766#define LAST_SEQ_NUM_INVALID 0xFFFF
767
768struct iwm_umac_notif_stop_resume_tx {
769 struct iwm_umac_wifi_in_hdr hdr;
770 u8 flags; /* UMAC_*_TX_FLAG_* */
771 u8 sta_id;
772 __le16 stop_resume_tid_msk; /* tid bitmask */
773} __attribute__ ((packed));
774
775#define UMAC_MAX_NUM_PMKIDS 4
776
740/* WiFi interface wrapper header */ 777/* WiFi interface wrapper header */
741struct iwm_umac_wifi_if { 778struct iwm_umac_wifi_if {
742 u8 oid; 779 u8 oid;