diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/Kconfig | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/cfg80211.c | 83 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/commands.c | 113 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/commands.h | 94 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/debugfs.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/eeprom.c | 51 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/eeprom.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/fw.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/hal.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/iwm.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/lmac.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 93 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/netdev.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/rx.c | 226 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/sdio.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/tx.c | 67 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/umac.h | 41 |
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 @@ | |||
1 | config IWM | 1 | config 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, | |||
682 | static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, | 672 | static 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 | ||
729 | int 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 | |||
737 | int 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 | |||
745 | int 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 | |||
725 | static struct cfg80211_ops iwm_cfg80211_ops = { | 756 | static 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 | ||
743 | static const u32 cipher_suites[] = { | 777 | static 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 | ||
103 | static int modparam_wiwi = COEX_MODE_CM; | ||
104 | module_param_named(wiwi, modparam_wiwi, int, 0644); | ||
105 | MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)"); | ||
106 | |||
97 | static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = | 107 | static 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] = | |||
117 | static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = | 127 | static 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 | ||
193 | int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) | 203 | int 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 | ||
288 | int 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 | |||
278 | int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) | 299 | int 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 | ||
807 | int 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 | |||
786 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) | 820 | int 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 | |||
938 | int 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 | |||
969 | int 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 */ |
156 | enum { | 211 | enum { |
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 | ||
444 | struct iwm_umac_pwr_trigger { | ||
445 | struct iwm_umac_wifi_if hdr; | ||
446 | __le32 reseved; | ||
447 | } __attribute__ ((packed)); | ||
448 | |||
385 | struct iwm_umac_cmd_stats_req { | 449 | struct iwm_umac_cmd_stats_req { |
386 | __le32 flags; | 450 | __le32 flags; |
387 | } __attribute__ ((packed)); | 451 | } __attribute__ ((packed)); |
388 | 452 | ||
453 | struct 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 | |||
465 | struct 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 */ |
390 | int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); | 474 | int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); |
391 | int iwm_send_prio_table(struct iwm_priv *iwm); | 475 | int 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); | |||
393 | int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); | 477 | int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); |
394 | int iwm_send_calib_results(struct iwm_priv *iwm); | 478 | int iwm_send_calib_results(struct iwm_priv *iwm); |
395 | int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); | 479 | int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); |
480 | int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit); | ||
396 | 481 | ||
397 | /* UMAC commands */ | 482 | /* UMAC commands */ |
398 | int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, | 483 | int 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); | |||
407 | int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); | 492 | int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); |
408 | int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); | 493 | int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); |
409 | int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); | 494 | int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); |
495 | int iwm_tx_power_trigger(struct iwm_priv *iwm); | ||
410 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); | 496 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); |
411 | int iwm_send_umac_channel_list(struct iwm_priv *iwm); | 497 | int iwm_send_umac_channel_list(struct iwm_priv *iwm); |
412 | int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, | 498 | int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, |
413 | int ssid_num); | 499 | int ssid_num); |
414 | int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); | 500 | int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); |
501 | int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, | ||
502 | struct iwm_umac_notif_stop_resume_tx *ntf); | ||
503 | int iwm_send_pmkid_update(struct iwm_priv *iwm, | ||
504 | struct cfg80211_pmksa *pmksa, u32 command); | ||
415 | 505 | ||
416 | /* UDMA commands */ | 506 | /* UDMA commands */ |
417 | int iwm_target_reset(struct iwm_priv *iwm); | 507 | int 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 | ||
154 | int 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 | |||
180 | u32 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 | |||
149 | int iwm_eeprom_init(struct iwm_priv *iwm) | 200 | int 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 | |||
90 | enum { | 101 | enum { |
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 { | |||
110 | int iwm_eeprom_init(struct iwm_priv *iwm); | 121 | int iwm_eeprom_init(struct iwm_priv *iwm); |
111 | void iwm_eeprom_exit(struct iwm_priv *iwm); | 122 | void iwm_eeprom_exit(struct iwm_priv *iwm); |
112 | u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); | 123 | u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); |
124 | int iwm_eeprom_fat_channels(struct iwm_priv *iwm); | ||
125 | u32 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 | */ |
417 | int iwm_hal_send_host_cmd(struct iwm_priv *iwm, | 418 | int 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 | ||
133 | struct iwm_tid_info { | ||
134 | __le16 last_seq_num; | ||
135 | bool stopped; | ||
136 | struct mutex mutex; | ||
137 | }; | ||
138 | |||
132 | struct iwm_sta_info { | 139 | struct 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 | ||
139 | struct iwm_tx_info { | 147 | struct iwm_tx_info { |
@@ -183,6 +191,8 @@ struct iwm_key { | |||
183 | struct iwm_tx_queue { | 191 | struct 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); | |||
335 | int iwm_down(struct iwm_priv *iwm); | 349 | int iwm_down(struct iwm_priv *iwm); |
336 | 350 | ||
337 | /* TX API */ | 351 | /* TX API */ |
352 | int iwm_tid_to_queue(u16 tid); | ||
338 | void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); | 353 | void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); |
339 | void iwm_tx_worker(struct work_struct *work); | 354 | void iwm_tx_worker(struct work_struct *work); |
340 | int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); | 355 | int 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 */ | ||
191 | struct 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; | |||
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) | |
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 | */ |
77 | static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | 78 | static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; |
78 | 79 | ||
80 | int 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 | |||
79 | static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) | 88 | static 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 | ||
506 | static 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 | |||
503 | static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, | 518 | static 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 | ||
737 | static 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 | |||
716 | static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, | 750 | static 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 | ||
1090 | static 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 | |||
1055 | static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, | 1155 | static 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) | ||
1082 | static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, | 1189 | static 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 | ||
1537 | static 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 | |||
1408 | static void iwm_rx_process_packet(struct iwm_priv *iwm, | 1564 | static 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 | }; |
403 | MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin"); | ||
404 | MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin"); | ||
405 | MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin"); | ||
402 | 406 | ||
403 | static int iwm_sdio_probe(struct sdio_func *func, | 407 | static 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 | ||
495 | static const struct sdio_device_id iwm_sdio_ids[] = { | 499 | static 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 | }; |
500 | MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); | 506 | MODULE_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 | ||
335 | static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, | 336 | static 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 | |||
359 | void iwm_tx_worker(struct work_struct *work) | 358 | void 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 | ||
693 | struct iwm_umac_notif_stats { | 714 | struct 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 | |||
768 | struct 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 */ |
741 | struct iwm_umac_wifi_if { | 778 | struct iwm_umac_wifi_if { |
742 | u8 oid; | 779 | u8 oid; |